echo "ERROR: You need to supply the path to the System Root";
    print_usage();
    exit(1);
}
if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT . '/core/include/init.inc')) {
    echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
    print_usage();
    exit(1);
}
require_once $SYSTEM_ROOT . '/core/include/init.inc';
$root_user = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('root_user');
if (!$GLOBALS['SQ_SYSTEM']->setCurrentUser($root_user)) {
    echo "ERROR: Failed logging in as root user\n";
    exit;
}
$ROOT_NODE = getCLIArg('rootnode');
if (!$ROOT_NODE) {
    $ROOT_NODE = 1;
}
// Get all the bodycopy divs
$assetids = array_keys($GLOBALS['SQ_SYSTEM']->am->getChildren($ROOT_NODE, 'bodycopy_div'));
echo "Regenerating content file for " . count($assetids) . " assets\n";
$count = 0;
foreach ($assetids as $assetid) {
    $bodycopy_div = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
    $bodycopy_div_edit_fns = $bodycopy_div->getEditFns();
    $bodycopy_div_edit_fns->generateContentFile($bodycopy_div);
    $GLOBALS['SQ_SYSTEM']->am->forgetAsset($bodycopy_div, TRUE);
    $count++;
    echo $count % 10 ? '.' : '';
}
 $result = MatrixDAL::executePdoAll($query);
 $sorted_result = array();
 // now we have to sort them nicely to report
 while (count($result) > 0) {
     // grab a random element from remaining result
     $url_info = array_shift($result);
     // find chained elements redirecting from it, i.e trace in normal redirect order. e.g A->B->C->D, starting from B, it will find C and D
     $redirects_chain_from = recursiveTrace($url_info['remap_url'], $result, TRUE);
     // find chained elements redirecting to it, i.e trace in reversed order.  e.g A->B->C->D, starting from B, it will find A
     $redirects_chain_to = recursiveTrace($url_info['url'], $result, FALSE);
     // add the current element to it
     array_push($redirects_chain_to, $url_info);
     // now we found a complete chain of redirects...
     $sorted_result[] = array_merge($redirects_chain_to, $redirects_chain_from);
 }
 if (getCLIArg('execute') && !empty($sorted_result)) {
     // ignore infinite loop, those loops have to be broken with other options first
     foreach ($sorted_result as $index => $data) {
         if ($data[0]['url'] === $data[count($data) - 1]['remap_url']) {
             unset($sorted_result[$index]);
         }
     }
     // break them
     $chain_count = count($sorted_result);
     $count = breakRemapChains($sorted_result);
     echo $count . " short remaps added to replace {$chain_count} chains\n";
 } else {
     // display them
     $count = count($sorted_result);
     if (empty($count)) {
         echo "NONE\n";
    print_usage();
    exit(1);
}
$replace_to = getCLIArg('replace');
if ($replace_to === FALSE) {
    echo "\nERROR: Enter the string to replace.\n\n";
    print_usage();
    exit(1);
}
$replace_to = preg_replace('/[^a-zA-Z0-9\\-$_@.!*~(),]/', '', $replace_to);
if ($replace_from == $replace_to) {
    echo "Search and replace string are same: '" . $replace_from . "'. Nothing to update.\n\n";
    exit;
}
// Whether to replace site/root URLs
$include_site_urls = getCLIArg('include-site-urls');
if (ini_get('memory_limit') != '-1') {
    ini_set('memory_limit', '-1');
}
require_once $SYSTEM_ROOT . '/core/include/init.inc';
echo "The search string '" . $replace_from . "' will be replaced by '" . $replace_to . "' in the webpaths system wide.\n\n";
if (empty($replace_to)) {
    echo "WARNING: The 'replace' string is empty. This means all the 'search' string will be removed in the webpaths, which can result into webpath conflits.\n";
    echo "For example with 'search' => '0' and 'replace' => '' can result into following:\n";
    echo "'www.test.com/1001' to www.test.com/11'\n";
    echo "'www.test.com/1100' to www.test.com/11'\n\n";
}
echo "It highly recommended to backup the system before running this script.\n";
echo "Are you sure you want to proceed (Y/n)? \n";
$yes_no = rtrim(fgets(STDIN, 4094));
if ($yes_no != 'Y') {
    $allow_unrestricted_access = TRUE;
} else {
    if (isset($_SERVER['argv'][4]) && $_SERVER['argv'][4] == '--sort') {
        $SORTING = TRUE;
    }
}
if (isset($_SERVER['argv'][5]) && $_SERVER['argv'][5] == '--sort') {
    $SORTING = TRUE;
} else {
    if (isset($_SERVER['argv'][5]) && $_SERVER['argv'][5] != '--sort') {
        echo "ERROR: Fifth argument passed can only be '--sort'";
        exit;
    }
}
// should we skip virus check?
$skip_virus_check = getCLIArg('skip-virus-check');
if ($skip_virus_check) {
    $GLOBALS['SQ_SKIP_VIRUS_SCAN'] = TRUE;
}
require_once $SYSTEM_ROOT . '/core/include/init.inc';
require_once SQ_FUDGE_PATH . '/general/file_system.inc';
$GLOBALS['SQ_SYSTEM']->am->includeAsset('file');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('image');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('pdf_file');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('word_doc');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('excel_doc');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('powerpoint_doc');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('rtf_file');
$GLOBALS['SQ_SYSTEM']->am->includeAsset('text_file');
$GLOBALS['SQ_SYSTEM']->setRunLevel(SQ_RUN_LEVEL_FORCED);
/**
// Array(
//		Array(
//			"table"			=> Table that needs checking/fixing
//			"values" 		=> Array of field names whose values needs checking/fixing
//			"asset_assoc"	=> TRUE if the table record is assoicated with an asset ("does the table has 'assetid' field?")
//		),
//	)
//
// NOTE 1: 	If the value field holds serialised value then script must handle that field accourdingly.
//			Currently "custom_val" field of "ast_attr_val" table of attribute types 'option_list','email_format','parameter_map','serialise',
//			'http_request' and 'oauth', and	"data" field of "trig" are only ones that are treated as serialsed values by this script.
// NOTE 2:	There are two entries for 'internal_msg' table below because one targets the messages that are assoicated with an asset,
// 			while other targets non-asset specific messages (message that has empty assetid field, like internal message sent by user or trigger action).
//
$tables = array(array('table' => 'ast', 'values' => array('name', 'short_name'), 'asset_assoc' => TRUE), array('table' => 'ast_attr_val', 'values' => array('custom_val'), 'asset_assoc' => TRUE), array('table' => 'ast_mdata_val', 'values' => array('value'), 'asset_assoc' => TRUE), array('table' => 'ast_mdata_dflt_val', 'values' => array('default_val'), 'asset_assoc' => TRUE), array('table' => 'ast_attr_uniq_val', 'values' => array('custom_val'), 'asset_assoc' => TRUE), array('table' => 'internal_msg', 'values' => array('subject', 'body'), 'asset_assoc' => TRUE), array('table' => 'internal_msg', 'values' => array('subject', 'body'), 'asset_assoc' => FALSE), array('table' => 'trig', 'values' => array('name', 'data', 'description', 'category'), 'asset_assoc' => FALSE), array('table' => 'thes_term', 'values' => array('term'), 'asset_assoc' => FALSE), array('table' => 'ast_lookup', 'values' => array('url'), 'asset_assoc' => TRUE), array('table' => 'ast_lookup_remap', 'values' => array('url', 'remap_url'), 'asset_assoc' => FALSE), array('table' => 'ast_lookup_value', 'values' => array('url', 'name'), 'asset_assoc' => FALSE), array('table' => 'ast_url', 'values' => array('url'), 'asset_assoc' => TRUE), array('table' => 'cache', 'values' => array('url'), 'asset_assoc' => TRUE));
$TABLES = getCLIArg('skip-tables');
if (!empty($TABLES)) {
    $skip_tables = explode(',', $TABLES);
    $relevant_tables = array();
    foreach ($tables as $index => $table_data) {
        if (in_array($table_data['table'], $skip_tables)) {
            unset($tables[$index]);
        }
        //end if
        $relevant_tables[] = $table_data['table'];
    }
    //end forach
    // Warn if the specified table is not relevant to this script
    $invalid_tables = array_diff($skip_tables, $relevant_tables);
    if (!empty($invalid_tables)) {
        echo "WARNING: Unrecognised table name(s) entered in 'skip-tables' parameter. Make sure you are not using 'sq_' or 'sq_rb_' prefix:\n" . implode($invalid_tables, "\n");
}
if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT . '/core/include/init.inc')) {
    echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
    print_usage();
    exit(1);
}
$FIX_DB = getCLIArg('fix-db');
if ($FIX_DB) {
    echo "\nIMPORTANT: You running the script in 'fix db' mode. Are you sure you want to proceed (Y/N)? \n";
    $yes_no = rtrim(fgets(STDIN, 4094));
    if (strtolower($yes_no) != 'y') {
        echo "\nScript aborted. \n";
        exit;
    }
}
$INCLUDE_ROLLBACK = getCLIArg('include-rollback');
if (ini_get('memory_limit') != '-1') {
    ini_set('memory_limit', '-1');
}
require_once $SYSTEM_ROOT . '/core/include/init.inc';
// Matrix attribute types with serialised value
$serialsed_attrs = array('option_list', 'email_format', 'parameter_map', 'serialise', 'http_request', 'oauth');
$GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
if ($FIX_DB) {
    $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
}
$sql = "SELECT attrid FROM sq_ast_attr WHERE type IN ('" . implode("','", $serialsed_attrs) . "')";
$serialise_attrids = array_keys(MatrixDAL::executeSqlGrouped($sql));
// Select the entries in the asset attribute value tables with serialsed data
$count = 0;
$invalid_count = 0;
$keep_site_assetids = getCLIArg('sites-to-keep');
if (!_valid_site_assetids($keep_site_assetids)) {
    echo "ERROR: You need to specify the comma seperated list of valid site asset ids that to be kept.\n";
    print_usage();
}
$delete_site_assetids = getCLIArg('sites-to-delete');
if (!_valid_site_assetids($delete_site_assetids)) {
    echo "ERROR: You need to specify the comma seperated list of valid site asset ids that are to be deleted.\n";
    print_usage();
}
$REWRITE_URLS = getCLIArg('rewrite-urls');
if (!_valid_site_url($REWRITE_URLS)) {
    echo "ERROR: You need to specify the comma seperated list of valid urls (full URL with protocol bit) to rewrite ./?a=[ASSETID] links to.\n";
    print_usage();
}
$report_mode = !getCLIArg('execute');
if (!$report_mode) {
    echo "WARNING: The script will go through all the assets in the site to keep and rewrite the asset id links (./?a=xxx) in asset attribute and metadata values that are linked to the site to keep, but not to site to 'delete'. It highly recommended to backup the system before running this script.\n";
    echo "Are you sure you want to proceed (Y/n)? \n";
    $yes_no = rtrim(fgets(STDIN, 4094));
    if ($yes_no != 'Y') {
        echo "\nScript aborted. \n";
        exit;
    }
}
// Be the root user
$root_user = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('root_user');
if (!$GLOBALS['SQ_SYSTEM']->setCurrentUser($root_user)) {
    trigger_error("Failed logging in as root user\n", E_USER_ERROR);
    exit(1);
}
if (!$SYSTEM_ROOT) {
    echo "ERROR: You need to supply the path to the System Root\n";
    print_usage();
    exit(1);
}
if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT . '/core/include/init.inc')) {
    echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
    print_usage();
    exit(1);
}
require_once $SYSTEM_ROOT . '/core/include/init.inc';
if (ini_get('memory_limit') != '-1') {
    ini_set('memory_limit', '-1');
}
$toFix = getCLIArg('fix');
$toEmail = getCLIArg('email');
// asset is Live, Safe Editting, Approved To Go Live, Under Construction, Safe Edit Approved to Go Live but it has running workflow by mistake.
$where = MatrixDAL::getDbType() === 'oci' ? ' AND DBMS_LOB.GETLENGTH(w.wflow) > 0' : ' AND w.wflow IS NOT NULL';
$sql = 'SELECT a.assetid, a.status FROM sq_ast_wflow w, sq_ast a WHERE a.assetid = w.assetid AND a.status IN (2, 8, 16, 64, 256)' . $where;
try {
    $query = MatrixDAL::preparePdoQuery($sql);
    $assets_should_not_have_workflow = MatrixDAL::executePdoAssoc($query);
} catch (Exception $e) {
    echo "ERROR: " . $e->getMessage() . "\n";
    exit(1);
}
// asset is Pending Approval but it does't have running workflow by mistake.
$where = MatrixDAL::getDbType() === 'oci' ? ' AND (w.wflow IS NULL OR DBMS_LOB.GETLENGTH(w.wflow) = 0)' : ' AND w.wflow IS NULL';
$sql = 'SELECT a.assetid, a.status FROM sq_ast a LEFT JOIN sq_ast_wflow w ON a.assetid = w.assetid WHERE a.status IN (4)' . $where;
try {
    $query = MatrixDAL::preparePdoQuery($sql);
        $include_users[$key] = MatrixDAL::quote($include_users[$key]);
    }
    $include_user_sql = ' AND userid IN (' . implode(', ', $include_users) . ')';
}
// exclude user condition
$exclude_user_string = getCLIArg('excludeuser');
$exclude_user_sql = '';
if (!empty($exclude_user_string)) {
    $exclude_users = explode(',', $exclude_user_string);
    foreach ($exclude_users as $key => $value) {
        $exclude_users[$key] = MatrixDAL::quote($exclude_users[$key]);
    }
    $exclude_user_sql = ' AND userid NOT IN (' . implode(', ', $exclude_users) . ')';
}
// permission type condition
$type_string = getCLIArg('type');
$type_sql = '';
if (!empty($type_string)) {
    $types = explode(',', $type_string);
    foreach ($types as $key => $value) {
        $types[$key] = MatrixDAL::quote($types[$key]);
    }
    $type_sql = ' AND permission IN (' . implode(', ', $types) . ')';
}
$sql = $sql . $in_clause_sql . $include_user_sql . $exclude_user_sql . $type_sql;
// confirmation to proceed
$message = "This script is about to remove ALL permissions for assets under root node:" . $root_nodes_string;
if (!empty($include_user_string)) {
    $message .= " assigned to user:" . $include_user_string;
}
if (!empty($exclude_user_string)) {