<?php

  /**
   * Foundation for all upgrade scripts
   * 
   * @package angie.library.application
   * @subpackage upgrader
   */
  abstract class AngieApplicationUpgradeScript {
  
    /**
     * Initial system version
     *
     * @var string
     */
    public $from_version;
    
    /**
     * Final system version
     *
     * @var string
     */
    public $to_version;
    
    /**
     * Return upgrade actions
     *
     * @return array
     */
    function getActions() {
    	return null;
    } // getActions
    
    /**
     * Return from version
     *
     * @return float
     */
    function getFromVersion() {
    	return $this->from_version;
    } // getFromVersion
    
    /**
     * Return to version
     *
     * @return float
     */
    function getToVersion() {
    	return $this->to_version;
    } // getToVersion
    
    /**
     * Identify this uprade script
     *
     * @return string
     */
    function getGroup() {
    	return (string) $this->from_version . '-' . (string) $this->to_version;
    } // getGroup
    
    /**
     * Start upgrade by creating backup
     *
     * @return boolean
     */
    function startUpgrade() {
      $version_file = $this->getVersionFilePath();
      
      if(is_file($version_file)) {
        if(!is_writable($version_file)) {
          return 'Version file not writable';
        } // if
      } else {
        return 'Version file not found';        
      } // if
      
      $work_path = ENVIRONMENT_PATH . '/work';
      if(is_dir($work_path)) {
        if(is_writable($work_path)) {
          $tables = DB::listTables(TABLE_PREFIX);
          if(is_foreachable($tables)) {
            try {
              DB::exportToFile($tables, $work_path . '/database-backup-' . date('Y-m-d-H-i-s') . '.sql', true, true);
            } catch(Exception $e) {
              return $e->getMessage();
            } // try
            
            return true;
          } else {
            return 'There are no activeCollab tables in the database';
          } // if
        } else {
          return "Work folder not writable";
        } // if
      } else {
        return "Work folder not found. Expected location: $work_path";
      } // if
    } // startUpgrade

    /**
     * Schedule index rebuild
     *
     * @return boolean
     */
    function scheduleIndexesRebuild() {
      try {
        $config_options_table = TABLE_PREFIX . 'config_options';

        if(DB::executeFirstCell("SELECT COUNT(*) FROM $config_options_table WHERE name = 'require_index_rebuild'")) {
          DB::execute("UPDATE $config_options_table SET value = ? WHERE name = 'require_index_rebuild'", serialize(true));
        } else {
          DB::execute("INSERT INTO $config_options_table (name, module, value) VALUES ('require_index_rebuild', 'system', ?)", serialize(true));
        } // if
      } catch(Exception $e) {
        return $e->getMessage();
      } // try

      return true;
    } // scheduleIndexesRebuild
    
    /**
     * This action will write entry in upgrade history
     *
     * @return boolean
     */
    function endUpgrade() {
      try {
        $final_version = $this->getToVersion();
        
        DB::execute('INSERT INTO ' . TABLE_PREFIX . 'update_history SET version = ?, created_on = UTC_TIMESTAMP()', array($final_version));
        file_put_contents($this->getVersionFilePath(), "<?php\n\n  define('APPLICATION_VERSION', " . var_export($final_version, true) . ");");
        
        $frameworks = explode(',', APPLICATION_FRAMEWORKS);
        $modules = DB::executeFirstColumn('SELECT name FROM ' . TABLE_PREFIX . 'modules WHERE is_enabled = ?', true);
        
        AngieApplication::rebuildLocalization($frameworks, $modules, $final_version);
        AngieApplication::rebuildAssets($frameworks, $modules, $final_version);
        
        cache_clear(true);

        // ---------------------------------------------------
        //  Clear compiled templates
        // ---------------------------------------------------

        $dir = ENVIRONMENT_PATH . '/compile/';

        if(is_dir($dir)) {
          foreach(glob($dir.'*.tpl.php') as $v){
            @unlink($v);
          } // foreach
        } // if

      } catch(Exception $e) {
        return $e->getMessage();
      } // try
      
      return true;
    } // endUpgrade
    
    // ---------------------------------------------------
    //  Utilities
    // ---------------------------------------------------

    /**
     * Cached array of isModuleInstalled() results
     *
     * @var array
     */
    private $is_module_installed = array();

    /**
     * Returns true if module is installed
     *
     * @param $module_name
     * @return boolean
     */
    function isModuleInstalled($module_name) {
      if(!array_key_exists($module_name, $this->is_module_installed)) {
        $this->is_module_installed[$module_name] = (boolean) DB::executeFirstCell('SELECT COUNT(*) FROM ' . TABLE_PREFIX . 'modules WHERE name = ?', $module_name);
      } // if

      return $this->is_module_installed[$module_name];
    } // isModuleInstalled
    
    /**
     * Return path of the version file
     * 
     * @return string
     */
    function getVersionFilePath() {
      return CONFIG_PATH . '/version.php';
    } // getVersionFilePath

    /**
     * Return list of table fields
     *
     * @param string $table_name
     * @return array
     */
    function listTableFields($table_name) {
      return DB::listTableFields($table_name);
    } // listTableColumns

    /**
     * Return list of table indexes
     *
     * @param string $table_name
     * @return array
     */
    function listTableIndexes($table_name) {
      if(method_exists('DB', 'listTableIndexes')) {
        return DB::listTableIndexes($table_name);
      } else {
        $rows = DB::execute("SHOW INDEXES FROM $table_name");
        if(is_foreachable($rows)) {
          $indexes = array();

          foreach($rows as $row) {
            $key_name = $row['Key_name'];

            if(!in_array($key_name, $indexes)) {
              $indexes[] = $key_name;
            } // if
          } // foreach

          return $indexes;
        } // if

        return array();
      } // if
    } // listTableIndexes
    
  }