<?php
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');

require_once 'include/dir_inc.php';
require_once dirname(__DIR__) . '/modules/AnalyticReporting/profiles/FunctionWrapper.php';
require_once dirname(__DIR__) . '/modules/AnalyticReporting/profiles/PreInstall.php';
require_once __DIR__ . '/ARSchemaFactory.php';

function pre_install()
{
    global $sugar_config, $sugar_version, $suitecrm_version;
    $adb = DBManagerFactory::getInstance();

    $schema = ARSchemaFactory::getInstance($adb->dbType, $adb);
    //check if table already exists
    $moduleTableExists = $schema->ifTableExistsAndNotEmpty('advancedreports');
    // Create tables
    $schema->create();

    if(!$moduleTableExists){
        // Lock, import, unlock reports
        $schema->lock("advancedreports");
        importSQLFromFile($adb, "reports");
        $schema->unlock("advancedreports");

        // Lock, import, unlock categories
        $schema->lock("advancedreports_categories");
        $schema->lock("advancedreports_templates");
        importSQLFromFile($adb, "categories");
        $schema->unlock("advancedreports_categories");
        $schema->unlock("advancedreports_templates");
    }else{
        echo "Previous installation detected, SQL data importing skipped, \n<br />";
    }

    if ($schema->ifTableExistsAndNotEmpty('advancedreports_dashboards') === false) {
        $schema->lock('advancedreports_dashboards');
        $schema->lock('advancedreports_widgets');

        importDashboardData($adb);

        $schema->unlock('advancedreports_dashboards');
        $schema->unlock('advancedreports_widgets');
        echo "Dashboard data imported!!! \n<br />";
    } else {
        echo "Skipping dashboard data import \n<br />";
    }

    // Decode base65encode'd files for non Sugar ondemand
    if(!empty($suitecrm_version)) {
        decodeFiles();
    }

    // Add 'm' prefixes to fields
    // $schema->patchReports();

    // Add view and export permissions (increment existing permission levels);
    // echo "Started to patch permissions \n<br />";
    // $schema->patchPermissions();
    // echo "Finished patching permissions \n<br />";

    initConfig($adb);
    $postInstall = new PreInstall($adb, !$moduleTableExists);
    $postInstall->run();

    echo "AnalyticReporting installation script done.\n<br />";
    cleanup();
    echo "Temporary files removed successfully.\n<br />";
}

/**
 * Set initial config after config table has been created
 */
function initConfig($adb)
{
    echo "Set initial config...\n<br />";

    // Load manifest file
    require_once dirname(__DIR__) . '/manifest.php';

    // Array of config values which should be always overwritten
    $alwaysOverwrite = array(
        "version",
        "moduleVersion"
    );

    // Override if value is value
    $overrideIf = array(
    );

    $config = array(
        'version' => 'sugarcrm',
        'limit' => '20',
        'dateformat' => 'd-m-Y',
        'builderPublicAccess' => 'false',
        'reportTreeAdminAccess' => 'false',
        'showNullValues' => 'false',
        'apiEndpoint' => 'http://api.dev.itsapiens.eu/',
        'key' => '',
        'moduleVersion' => $manifest['version'],
        'fileNameLength' => '15',
        'addTimestampToFileName' => 'true',
        'addOriginInfoToEmail' => false,
        'userCountLimit' => 200,
        'forceApi' => false,
        'forceApiDiagnostics' => false,
        'clearAllOutputBuffers' => false,
        'queueForScheduledReport' => false,
        'logLevel' => "ALL",
        'logLastLimit' => 100, // Show only n last log records
        // TODO: IMPLEMENT THIS
        'logClearLimit' => 1000, // Clear logs if more than n records are in table
        'gSyncApiEndpoint' => 'https://api.g-sync.itsapiens.eu/',
        'skipDeleted' => true,
        'plan' => 'BASIC',
        'resendStartedSchedule' => true,
        'resendStartedScheduleHours' => 2,
    );

    // Try to add key file in config if exists
    $keyFile = dirname(__DIR__) . '/modules/AnalyticReporting/key.php';
    if(FunctionWrapper::_is_file($keyFile)) {
        echo "Key found, adding...\n<br />";
        $key = implode("\n", FunctionWrapper::_file($keyFile));
        // Add key contents to keyValue array
        $config["key"] = $key;
    }

    // Insert config values
    foreach ($config as $key => $value) {
        $found = $adb->getOne("SELECT COUNT(*) AS count FROM advancedreports_config WHERE id = '{$key}'");
        if($found < 1) {
            $adb->query("INSERT INTO advancedreports_config (id, value) VALUES ('{$key}', '{$value}')");
        } else {
            // Check if this key should always be overwritten
            if(in_array($key, $alwaysOverwrite)) {
                $adb->query("UPDATE advancedreports_config SET value = '{$value}' WHERE id = '{$key}'");
            }
//            else if(in_array($key, $overrideIf)) {
//                // Should use $config[$key] value if $existingValue is the same as $overrideIf[$key] value
//                $existingValue = $adb->getOne("SELECT value FROM advancedreports_config WHERE id = '{$key}'");
//                if($existingValue == $overrideIf[$key]) {
//                    $adb->query("UPDATE advancedreports_config SET value = '{$value}' WHERE id = '{$key}'");
//                }
//            }
        }
    }
    echo "Done.\n<br />";
}

/**
 * Import base data into AnalyticReporting table from import.sql
 */
function importSQLFromFile($adb, $filePostfix = 'reports')
{
    // CE have different SQL import file than other
    $fileName = "importpro_{$filePostfix}.txt";
    if($GLOBALS['sugar_flavor'] == 'CE') {
        $fileName = "importce_{$filePostfix}.txt";
    }else if($GLOBALS['sugar_flavor'] == 'ENT'){
        $fileName = "importent_{$filePostfix}.txt";
    }

    // Import SQL into tables (cache/upgrades/temp/<HASH>/import.sql)
    $filePath = __DIR__ . '/' . $fileName; // @ONDEMANDFIX

    // Temporary variable, used to store current query
    $templine = '';
    $successCount = 0;
    $errorCount = 0;

    // Read in entire file
    $lines = FunctionWrapper::_file($filePath);

    //[#5932 Start]
    $installedModuleList = array_merge($GLOBALS['moduleList'],$GLOBALS['beanList']);

    $checkIfModuleExists = true;
    $reportsCounter = 0;
    //[#5932 End]
    foreach ($lines as $line) {
        // Skip it if it's a comment
        if (substr($line, 0, 2) == '--' || $line == '') {
            continue;
        }

        // Remove apostrophes (`) if not MYSQL, because MSSQL and other DB's don't support it
        if($adb->dbType !== 'mysql') {
            $line = str_replace("`", "", $line);
        }

        /**
         * TODO: Find better solution
         * TODO: This will work, only if last column in schema is calculatedFields (varbinary)
         * Convert calculatedFields from '' to NULL,
         * because MSSQL can't explicitly convert varchar to varbinary.
         * This solution has been added because some exported reports from database,
         * export '' instead of NULL or BLOB entry (javascript array []).
         */
        $line = str_replace("'')", "NULL)", $line);

        //[#5932 Start]
        $reportsCounter++;
        if($checkIfModuleExists){
            if(substr($line, 0, 6) == 'INSERT'){
                $reportsCounter--;
                //Stop cheking if module exists on category import
                if (strpos($line, 'advancedreports_categories') !== false) {
                    $checkIfModuleExists = false;
                }
            }else{
                $dividedLine = explode(',', $line, 6);
                $reportModules = array();
                $mainModulename = trim(str_replace("'", "", $dividedLine[3]));
                //empty in combined reports
                if(!empty($mainModulename)) {
                    $reportModules[] = $mainModulename;
                }

                //decode from hexadecimal
                $modules = json_decode(pack("H*" , substr($dividedLine[4],3)));
                if(!empty($modules)) {
                    foreach($modules as $module) {
                        $reportModules[] = trim($module[0]);
                    }
                }

                foreach($reportModules as $module){
                    if(!in_array($module, $installedModuleList)){
                        $reportsCounter--;
                        if(substr(trim($line), -1, 1) == ';'){
                            $line = ";";
                        }else{
                            $line = "";
                        }
                        break;
                    }
                }
            }
        }
        //[#5932 End]
        // Add this line to the current segment
        $templine .= $line;
        // If it has a semicolon at the end, it's the end of the query
        if (substr(trim($line), -1, 1) == ';') {
            //import only if there is something to import
            if($reportsCounter>0){
                //remove extra comma
                if (substr(trim($templine), -3, 1) == ','){
                    $templine = substr($templine, 0, -3);
                    $templine.=";";
                }elseif(substr(trim($templine), -2, 1) == ','){
                    $templine = substr($templine, 0, -2);
                    $templine.=";";
                }
                // Perform the query
                $result = $adb->query($templine);
                if($result) {
                    // Query performed sucessfully
                    $successCount++;
                } else {
                    // Error while performing query
                    $errorCount++;
                    echo "Error performing query <b>$templine: {$adb->lastDbError()}</b>\n<br />";
                }
            }
            // Reset temp variable to empty
            $templine = '';
            $reportsCounter=0;
        }
    }

    echo "SQL data imported successfully for {$filePostfix} ($successCount suceess, $errorCount errors)\n<br />";
}

function getFileCSVContent($file)
{
    $fileContent = FunctionWrapper::_file($file);

    $rows = [];
    foreach ($fileContent as $row) {
        if (!$row) continue;

        $rows[] = str_getcsv($row);
    }

    return $rows;
}

function generateInsertQueries($rows, $tableName, $sep)
{
    $queries = [ ];

    foreach ($rows as $row) {
        $values = [ ];
        $fieldList = join(', ', array_keys($row));

        foreach (array_values($row) as $value) {
            $values[] = "{$sep}{$value}{$sep}";
        }

        $values = join(', ', $values);

        $queries[ ] = "INSERT {$tableName} ({$fieldList}) VALUES ({$values})";
    }

    return $queries;
}

function formData($rows, $fields)
{
    $items = [ ];
    foreach ($rows as $row) {
        $item = array_combine($fields, $row);

        foreach ([ 'filters', 'settings' ] as $key) {
            if (isset($item[ $key ])) {
                $item[ $key ] = base64_decode($item[ $key ]);
            }
        }

        $items[ ] = $item;
    }

    return $items;
}

function importDashboardData($adb)
{
    // csv should start with field list
    $files = [
        'advancedreports_dashboards' => 'advancedreports_dashboards.txt',
        'advancedreports_widgets'    => 'advancedreports_widgets.txt',
    ];

    foreach ($files as $tableName => $file) {
        $filePath = __DIR__ . '/' . $file; // @ONDEMANDFIX

        $rows = getFileCSVContent($filePath);

        $fields = array_shift($rows);

        $rows = formData($rows, $fields);

        $sep = ($adb->dbType !== 'mysql') ? "`" : "'";

        $queries = generateInsertQueries($rows, $tableName, $sep);

        foreach ($queries as $query) {
            $adb->query($query);
        }
    }
}

//Perform cleanup operations
function cleanup()
{
    $keyFile = dirname(__DIR__) . '/modules/AnalyticReporting/key.php';
    if(@FunctionWrapper::_file_exists($keyFile)) {
        if(suhosin_function_exists("chmod")){
            @FunctionWrapper::_chmod($keyFile, 0777);
        }
        // Try to delete key file
        if(suhosin_function_exists("unlink")){
            @FunctionWrapper::_unlink($keyFile);
        }
    }
}

function suhosin_function_exists($func)
{
    if (extension_loaded('suhosin')) {
        $suhosin = @ini_get("suhosin.executor.func.blacklist");
        if (empty($suhosin) == false) {
            $suhosin = explode(',', $suhosin);

            return (function_exists($func) == true && array_search($func, $suhosin) === false);
        }
    }

    return function_exists($func);
}

/**
 * Decode encoded files
 *
 * @return void
 */
function decodeFiles()
{
    // Entrypoint which should be base64decode'd, to allow use on different systems than Sugar on demand
    $decodeEntrypoints = array(
        'modules/AnalyticReporting/connectors/SuiteAPIClient.php',
        'modules/AnalyticReporting/polyfills/safeCount.php',
        'modules/AnalyticReporting/polyfills/getSugarSmarty.php'
    );

    echo "Start to decode files... ";

    foreach($decodeEntrypoints as $entrypoint) {
        $filePath = dirname(__DIR__) . "/{$entrypoint}";
        $fileToDecode = @FunctionWrapper::_file_get_contents($filePath);

        @FunctionWrapper::_file_put_contents($filePath, base64_decode($fileToDecode));
    }

    echo "Success!\n<br />";
}