function filter_out_linked_records($rel_list, $lhs_field, $operator, $rhs_value)
{
    $new_rel_list = array();
    foreach ($rel_list as $key => $rel_object) {
        if (compare_values($rel_object, $lhs_field, $operator, $rhs_value) === false) {
            unset($rel_list[$key]);
        }
    }
    $rel_list = array_values($rel_list);
    return $rel_list;
    //end function filter_out_linked_records
}
    public function compare($recordA, $recordB) {
        foreach ($this->sortingConfigurations as $sortingConfiguration) {
            $columnName = $sortingConfiguration->getColumnName();

            $a = $this->getColumnValue($recordA, $columnName);
            $b = $this->getColumnValue($recordB, $columnName);

            $result = compare_values($a, $b, $sortingConfiguration->isSortAscending);
            if ($result != 0) {
                return $result;
            }
        }

        return 0;
    }
/**
 * pretty_print_test
 * @param string $filename 
 */
function pretty_print_test($data, $test_name)
{
    echo "\n" . $test_name . "\n";
    $sub_test_name = "json_encode > json_decode";
    $result = json_decode(json_encode($data));
    if (compare_values($data, $result)) {
        echo $sub_test_name . " - okay\n";
    } else {
        echo $sub_test_name . " - FAIL!\n";
        die;
    }
    $sub_test_name = "json_encode > pretty_json > json_decode";
    $result = json_decode(pretty_json(json_encode($data)));
    if (compare_values($data, $result)) {
        echo $sub_test_name . " - okay\n";
    } else {
        echo $sub_test_name . " - FAIL!\n";
        die;
    }
}
function compare_rules(&$gold, &$test, $check_updates)
{
    $return_val = array();
    foreach ($gold as $rule => $info) {
        if (isset($test[$rule])) {
            if (!$check_updates || $info['u'] == $test[$rule]['u']) {
                if (!compare_values($info['v'], $test[$rule]['v'])) {
                    $return_val[] = 'Rule "' . $rule . '": value should be ' . $info['v'] . ', is ' . $test[$rule]['v'];
                }
            } else {
                if ($check_updates) {
                    $return_val[] = 'Rule "' . $rule . '": update should be ' . $info['u'] . ', is ' . $test[$rule]['u'];
                }
            }
        } else {
            $return_val[] = 'Does not contain rule "' . $rule . '"';
        }
    }
    return $return_val;
}
function compare_values($a, $b, $isOrderAscending = TRUE) {
    $result = 0;

    if (isset($a)) {
        if (isset($b)) {
            $isCompositeA = is_array($a) || is_object($a);
            $isCompositeB = is_array($b) || is_object($b);
            if ($isCompositeA) {
                if ($isCompositeB) {
                    $array_a = is_object($a) ? get_object_vars($a) : $a;
                    $array_b = is_object($b) ? get_object_vars($b) : $b;

                    for ($i = 0, $count = max(count($array_a), count($array_b)); ($i < $count) && ($result == 0); $i++) {
                        $recordA = each($array_a);
                        $recordB = each($array_b);
                        if ($recordA === FALSE) {
                            if ($recordB === FALSE) {
                                break;
                            }
                            else {
                                $result = -1;
                            }
                        }
                        elseif ($recordB === FALSE) {
                            $result = 1;
                        }
                        else {
                            $result = compare_values($recordA['key'], $recordB['key'], $isOrderAscending);
                            if ($result == 0) {
                                $result = compare_values($recordA['value'], $recordB['value'], $isOrderAscending);
                            }
                        }
                    }
                }
                else {
                    $result = 1;
                }
            }
            elseif ($isCompositeB) {
                $result = -1;
            }
            elseif (is_numeric($a) && is_numeric($b)) {
                $delta = $a - $b;
                $result = ($delta > 0)
                    ? 1
                    : (($delta < 0) ? -1 : 0);
            }
            else {
                $result = strcasecmp($a, $b);
            }
        }
        else {
            $result = 1;
        }
    }
    elseif (isset($b)) {
        $result = -1;
    }

    if (($result != 0) && !$isOrderAscending) {
        $result *= -1;
    }

    return $result;
}
    protected function gatherChanges(DataControllerCallContext $callcontext, DatasetMetaData $originalDataset, DatasetMetaData $modifiedDataset, array $observers = NULL) {
        foreach ($modifiedDataset->getColumns(FALSE) as $modifiedColumn) {
            $originalColumn = $originalDataset->findColumn($modifiedColumn->name);
            if (!isset($originalColumn)) {
                // preparing new included & excluded columns
                if ($modifiedColumn->isUsed()) {
                    $callcontext->changeAction->newIncludedColumns[$modifiedColumn->name] = $modifiedColumn;
                }
                else {
                    $callcontext->changeAction->newExcludedColumns[$modifiedColumn->name] = $modifiedColumn;
                }

                // checking if new column marked as part of primary key
                if ($modifiedColumn->isKey()) {
                    $callcontext->changeAction->isKeyUpdated = TRUE;
                }
            }
        }

        foreach ($originalDataset->getColumns(FALSE) as $originalColumn) {
            $modifiedColumn = $modifiedDataset->findColumn($originalColumn->name);
            if (isset($modifiedColumn)) {
                $isColumnUpdated = FALSE;

                // preparing restored columns
                if (!$originalColumn->isUsed() && $modifiedColumn->isUsed()) {
                    $callcontext->changeAction->restoredColumns[$originalColumn->name] = $originalColumn;
                }

                // preparing excluded columns
                if ($originalColumn->isUsed() && !$modifiedColumn->isUsed()) {
                    $callcontext->changeAction->excludedColumns[$originalColumn->name] = $originalColumn;
                    // excluding a column which is part of primary key
                    if ($originalColumn->isKey()) {
                        $callcontext->changeAction->isKeyUpdated = TRUE;
                    }
                }

                // preparing relocated columns
                if ($originalColumn->columnIndex != $modifiedColumn->columnIndex) {
                    $callcontext->changeAction->updatedIndexColumns[$originalColumn->name] = $originalColumn;
                }

                // preparing columns with changed data type
                if (($originalColumn->type->applicationType != $modifiedColumn->type->applicationType)
                        || ($originalColumn->type->getLogicalApplicationType() != $modifiedColumn->type->getLogicalApplicationType())) {
                    // marking that the column data type was updated
                    if ($modifiedColumn->isUsed()) {
                        $callcontext->changeAction->updatedDataTypeIncludedColumns[$originalColumn->name] = $originalColumn;
                        // updating type a column which is part of the primary key
                        if ($originalColumn->isKey()) {
                            $callcontext->changeAction->isKeyUpdated = TRUE;
                        }
                    }
                    else {
                        $callcontext->changeAction->updatedDataTypeExcludedColumns[$originalColumn->name] = $originalColumn;
                    }
                    // checking if old & new types are compatible
                    if ($this->checkIfDataTypeCompatible($originalColumn->type, $modifiedColumn->type)) {
                        $callcontext->changeAction->updatedDataTypeCompatibleColumns[$originalColumn->name] = $originalColumn;
                    }

                    $isColumnUpdated = TRUE;
                }

                // checking if any column properties were updated
                if (($originalColumn->publicName != $modifiedColumn->publicName)
                        || ($originalColumn->description != $modifiedColumn->description)
                        || ($originalColumn->source != $modifiedColumn->source)) {
                    $isColumnUpdated = TRUE;
                }

                // checking if a column in primary key was added or removed
                if ($originalColumn->isKey() != $modifiedColumn->isKey()) {
                    $isColumnUpdated = TRUE;
                    $callcontext->changeAction->isKeyUpdated = TRUE;
                }

                // preparing updated columns
                if ($isColumnUpdated) {
                    $callcontext->changeAction->updatedColumns[$originalColumn->name] = $originalColumn;
                }
            }
            else {
                // preparing deleted columns
                $callcontext->changeAction->deletedColumns[$originalColumn->name] = $originalColumn;

                // deleting a column which is part of the primary key
                if ($originalColumn->isKey()) {
                    $callcontext->changeAction->isKeyUpdated = TRUE;
                }
            }
        }

        // preparing updated dataset
        if (($originalDataset->publicName != $modifiedDataset->publicName)
                || ($originalDataset->description != $modifiedDataset->description)
                || (compare_values($originalDataset->source, $modifiedDataset->source) != 0)
                || (compare_values($originalDataset->aliases, $modifiedDataset->aliases) != 0)) {
            $callcontext->changeAction->isDatasetUpdated = TRUE;
        }
    }