<?php

class DebugController extends Controller
{

  public $layout = '//layouts/column2';

  /**
   * is debugmode session var present and enabled?
   *
   * @return boolean
   */
  public static function isInDebugMode()
  {
    return isset ( app ()->session ['debugMode'] ) && app ()->session ['debugMode'] === 'enable';
  }

  /**
   * enable debugmode session var
   */
  public static function enableDebugMode()
  {
    app ()->session ['debugMode'] = 'enable';
  }

  /**
   * delete debugmode session var
   */
  public static function disableDebugMode()
  {
    unset ( app ()->session ['debugMode'] );
  }

  /**
   * does the user have the debug priv?
   *
   * @return boolean
   */
  public static function canDebug()
  {
    if (paramdeep ( 'debug', 'strictCheck' ))
      return AuthAssignment::model ()->exists ( "itemname='debug' AND userid=:id", array (
          ':id' => user ()->id 
      ) );
    else
      return user ()->checkAccess ( 'debug' );
  }

  /**
   * is debugmode session var present and the user have debug priv?
   *
   * @return boolean
   */
  public static function isDebugging()
  {
    return self::canDebug () && self::isInDebugMode ();
  }

  public static function initDebugUser()
  {
    if (self::isDebugging ())
    {
      if (paramdeep ( 'debug', 'showMissingMigrations' ))
      {
        $migs = DebugHelper::getMigrationsInfo ();
        if (count ( $migs->dbMigrations ) != count ( $migs->fileMigrations ))
          user ()->setFlash ( 'warning', 'There are uncommitted migrations (DB=' . count ( $migs->dbMigrations ) . ', FILE=' . count ( $migs->fileMigrations ) . ')!' . '<a href="' . url ( 'debug/migrations' ) . '">View</a>' );
      }
    }
  }

  protected function beforeAction($event)
  {
    access_denied_check ( null, ! self::canDebug (), "User is not a debugger!" );
    $publicPages = array (
        'EnableDebug',
        'DisableDebug' 
    );
    if (self::isInDebugMode () || (array_value_exists ( $publicPages, $event->id )))
    {
      set_time_limit ( 0 );
      return parent::beforeAction ( $event );
    }
    else
    {
      $this->redirect ( url ( 'debug/EnableDebug', array (
          'return' => $event->id 
      ) ) );
      parent::beforeAction ( $event );
      return false;
    }
  }

  public static function yiic($args, &$return)
  {
    // $args = array('yiic', 'migrate', 'down', '--interactive=0');
    $runner = new CConsoleCommandRunner ();
    $commandPath = Yii::getFrameworkPath () . DIRECTORY_SEPARATOR . 'cli' . DIRECTORY_SEPARATOR . 'commands';
    $runner->addCommands ( $commandPath );
    ob_start ();
    $return = $runner->run ( $args );
    $result = ob_get_clean ();
    return $result;
  }

  public function getMigrateHelp()
  {
    return "      * yiic migrate
        Applies ALL new migrations. This is equivalent to 'yiic migrate up'.
  
        * yiic migrate create create_user_table
        Creates a new migration named 'create_user_table'.
  
        * yiic migrate up 3
        Applies the next 3 new migrations.
  
        * yiic migrate down
        Reverts the last applied migration.
  
        * yiic migrate down 3
        Reverts the last 3 applied migrations.
  
        * yiic migrate to 101129_185401
        Migrates up or down to version 101129_185401.
  
        * yiic migrate mark 101129_185401
        Modifies the migration history up or down to version 101129_185401.
        No actual migration will be performed.
  
        * yiic migrate history
        Shows all previously applied migration information.
  
        * yiic migrate history 10
        Shows the last 10 applied migrations.
  
        * yiic migrate new
        Shows all new migrations.
  
        * yiic migrate new 10
        Shows the next 10 migrations that have not been applied.";
  }

  public static function getRuntimeSize()
  {
    if (! self::isInDebugMode ())
      return "";
    return formatBytes ( dirSize ( app ()->runtimePath ) + dirSize ( app ()->assetManager->basePath ) );
  }

  const DYNCONFIG_ROOT = 'dynconfig';

  const DYNCONFIG_DEBUGTOOLBAR = 'debug-toolbar';

  const DYNCONFIG_AUTOENABLE = 'debug-auto-enable';

  const DYNCONFIG_YII_DEBUG = 'yii-debug';

  const DYNCONFIG_MAINTENANCE_MODE = 'maintenance-mode';

  public static function getCurrentDynconfig()
  {
    $dynconfig = config ( self::DYNCONFIG_ROOT );
    if ($dynconfig == null || ! is_array ( $dynconfig ))
      $dynconfig = array ();
    if (! array_key_exists ( self::DYNCONFIG_DEBUGTOOLBAR, $dynconfig ))
      $dynconfig [self::DYNCONFIG_DEBUGTOOLBAR] = false;
    if (! array_key_exists ( self::DYNCONFIG_AUTOENABLE, $dynconfig ))
      $dynconfig [self::DYNCONFIG_AUTOENABLE] = false;
    if (! array_key_exists ( self::DYNCONFIG_YII_DEBUG, $dynconfig ))
      $dynconfig [self::DYNCONFIG_YII_DEBUG] = false;
    if (! array_key_exists ( self::DYNCONFIG_MAINTENANCE_MODE, $dynconfig ))
      $dynconfig [self::DYNCONFIG_MAINTENANCE_MODE] = false;
    return $dynconfig;
  }
  
  // ////////////////////////////////////////////////////////////////////
  // /////////////// A C T I O N S /////////////////
  // ////////////////////////////////////////////////////////////////////
  public function actionLoggers()
  {
    $routes = logger_routes ();
    $this->render ( 'log/loggers', get_defined_vars () );
  }

  public function actionLoggerCreate($type)
  {
    $this->render ( 'log/create', get_defined_vars () );
  }

  public function actionLoggerSwitch($loggerId, $field, $value)
  {
    $configPath = pathCombine ( app ()->basePath, 'config' );
    $routeConfigFile = pathCombine ( $configPath, "logger_{$loggerId}.php" );
    
    $config = array ();
    if (fileExists ( $routeConfigFile ))
    {
      $dataArray = include ($routeConfigFile);
      $config = array_merge_ex ( $config, $dataArray );
    }
    
    if ($field == 'enabled')
    {
      $value = $value == '1';
      array_set_by_path ( $config, array (
          'configWeb',
          'components',
          'log',
          'routes',
          $loggerId,
          'enabled' 
      ), $value );
    }
    
    file_put_contents ( $routeConfigFile, array_from_array_to_code ( $config, true ) );
    
    $this->redirectTo ( 'debug/loggers' );
  }

  public function actionLoggersLog($message, $level, $category)
  {
    logger ()->log ( $message, $level, $category );
    $this->redirectTo ( 'debug/loggers' );
  }

  public function actionLoggerDelete($loggerId)
  {
    @unlink ( pathCombine ( app ()->basePath, 'config', "logger_{$loggerId}.php" ) );
    $this->redirectTo ( 'debug/loggers' );
  }

  public function actionDbRepairTable()
  {
    $repairAll = isset ( $_REQUEST ['repair_all'] );
    $repairSingle = array_get ( $_REQUEST, 'repair_single' );
    
    $tableNames = query ( "SELECT DISTINCT TABLE_NAME AS 'table' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=:db ORDER BY TABLE_NAME", array (
        ':db' => getDbName () 
    ), false, true );
    
    $tables = array ();
    foreach ( $tableNames as $t )
    {
      $tableName = $t->table;
      $tinfo = array ();
      $tinfo [0] = array ();
      $tinfo [0] ['Table'] = null;
      $tinfo [0] ['Op'] = null;
      $tinfo [0] ['Msg_type'] = null;
      $tinfo [0] ['Msg_text'] = null;
      $tables [$tableName] = $tinfo;
    }
    
    if ($repairAll)
      foreach ( $tables as $tableName => $tableMessages )
      {
        $results = query ( "REPAIR TABLE {$tableName}", array (), false, false );
        $tables [$tableName] = $results;
      }
    
    if (! isEmptyOrWhitespace ( $repairSingle ))
    {
      $results = query ( "REPAIR TABLE {$repairSingle}", array (), false, false );
      $tables [$repairSingle] = $results;
    }
    
    $this->render ( 'DbRepairTable', get_defined_vars () );
  }

  public function actionYiiEnv()
  {
    $env = array_get ( $_REQUEST, 'env', null );
    if (! isEmptyOrWhitespace ( $env ))
    {
      // system("reg add \"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\" /v \"YII_ENVIRONMENT\" /t REG_SZ /d \"$env\"");
      // system("setx YII_ENVIRONMENT $env /M");
      putenv ( "YII_ENVIRONMENT=$env" );
    }
    $this->render ( 'yiienv' );
  }

  public function actionUpdateGui()
  {
    $this->render ( 'updategui' );
  }

  public function actiontranslations()
  {
    $langs = LanguageInfo::getLanguages ();
    $this->render ( 'translations/index', get_defined_vars () );
  }

  public function actiontranslate($language)
  {
    $langs = LanguageInfo::getLanguages ();
    $l = $langs [$language];
    $action = array_get ( $_REQUEST, 'action' );
    
    if ($action == "translate")
    {
      foreach ( $_REQUEST as $key => $value )
      {
        if (startsWith ( $key, "message_" ) && is_array_ex ( $value ))
        {
          $message_action = $value ['action'];
          $toBeTranslated = $message_action == 'translate';
          $toBeIgnored = $message_action == 'ignore';
          $toBeRemoved = $message_action == 'remove';
          $toBeCustom = $message_action == 'custom';
          $message_category = $value ['category'];
          $message_original = $value ['message_original'];
          $message_translation = $value ['message_translation'];
          if ($toBeIgnored || $toBeTranslated || $toBeRemoved || $toBeCustom)
          {
            if ($toBeRemoved)
            {
              // logLine("REMOVED ==> [$message_category] $message_original");
              $l->removeMessageType ( 'untranslated', $message_category, $message_original );
            }
            elseif ($toBeCustom)
            {
              // logLine("CUSTOM ==> [$message_category] $message_original");
              $l->removeMessageType ( 'untranslated', $message_category, $message_original );
              $l->addMessageType ( 'custom', $message_category, $message_original );
            }
            elseif ($toBeIgnored)
            {
              // logLine("IGNORED ==> [$message_category] $message_original");
              $l->removeMessageType ( 'untranslated', $message_category, $message_original );
              $l->addMessageType ( 'ignored', $message_category, $message_original );
            }
            else
            {
              // logLine("TRANSLATED ==> [$message_category] $message_original => $message_translation");
              $l->removeMessageType ( 'untranslated', $message_category, $message_original );
              $l->addMessageType ( null, $message_category, $message_original, $message_translation );
            }
          }
        }
      }
    }
    
    $this->render ( 'translations/translate', get_defined_vars () );
  }

  public function actionruntime_config()
  {
    $separator = "|";
    
    $leaves = Environment::getConfigLeaves ( config (), $separator );
    
    $runtimeConfigFilename = __DIR__ . '/../config/runtime.php';
    if (fileExists ( $runtimeConfigFilename ))
    {
      $runtimeConfigArray = include ($runtimeConfigFilename);
      $runtimeLeaves = Environment::getConfigLeaves ( $runtimeConfigArray, $separator );
    }
    else
    {
      $runtimeLeaves = array ();
    }
    
    $this->render ( 'runtime_config', get_defined_vars () );
  }

  public function actionmodel_createRelation()
  {
    $step = array_get ( $_REQUEST, 'step', 'step1_choose_models' );
    $this->render ( "model_create_relation/$step" );
  }

  public function actionModel_Create()
  {
    $action = strtolower ( $_REQUEST ['debug_createmodel_action'] );
    
    if (isEmpty ( $action ))
    {
      $files = getFiles ( pathCombine ( app ()->basePath, 'models' ), "*.php" );
      $classListHtml = "";
      foreach ( $files as $f )
      {
        $model = basename ( $f );
        $model = endsWithGet ( $model, ".php" );
        if (class_exists ( $model ))
        {
          $parents = class_parents ( $model );
          if (array_key_exists ( 'ActiveRecord', $parents ))
          {
            $classListHtml [] = "<option value=\"$model\">$model</option>";
          }
          else
          {
            // logLine($model);
          }
        }
      }
      $classListHtml = implode ( PHP_EOL, $classListHtml );
      $this->renderHtml ( "
          <form>
          <input type=\"hidden\" name=\"debug_createmodel_action\" value=\"prepare\" />
          <select name=\"class\">
          $classListHtml
          </select>
          <input type=\"submit\" />
          </form>
          ", false, false );
    }
    elseif ($action == 'prepare')
    {
      $class = $_REQUEST ['class'];
      $model = new $class ();
      // $model = new ActiveRecord();
      $html = "<h2>$class</h2>";
      $html .= "<form method=\"post\">";
      $html .= "<input type=\"hidden\" name=\"debug_createmodel_action\" value=\"create\" />";
      $html .= "<input type=\"hidden\" name=\"debug_createmodel_class\" value=\"$class\" />";
      foreach ( $model->attributeNames () as $attr )
        $html .= "$attr=[" . $model->getAttributeGuiControl ( $attr ) . "]<br>\n";
      $html .= "<input type=\"submit\" />";
      $html .= "</form>";
      $this->renderHtml ( $html, false, false );
    }
    elseif ($action == 'create')
    {
      $class = $_REQUEST ['debug_createmodel_class'];
      $attributes = $_REQUEST [$class];
      $model = new $class ();
      // $model = new ActiveRecord();
      $model->setAttributes ( $attributes, false );
      if ($model->insert ())
      {
        $html = "created class [$class] with PK=[" . _2str ( $model->getPrimaryKey () ) . "]";
      }
      else
      {
        $html = "error on INSERT";
      }
      $this->renderHtml ( $html, false, false );
    }
    else
    {
      $this->renderText ( "ACTION NOT FOUND" );
    }
  }

  public function actionModel_Delete($modelName, $pk)
  {
    $pk = unserialize ( base64_decode ( $pk ) );
    $model = new $modelName ();
    $model = $model::model ()->findByPk ( $pk );
    if ($model == null)
      $this->renderText ( "not found" );
    elseif ($model->delete ())
      $this->renderText ( "deleted" );
    else
      $this->renderText ( "NOT deleted" );
  }

  public function actionModel_Edit()
  {
    $modelName = $_REQUEST ['class'];
    if (! isset ( $_REQUEST ['edit'] ))
    {
      $restOfQuery = $_REQUEST ['query'];
      
      $classListHtml = "";
      foreach ( DebugHelper::getARModels () as $modelNameAR )
      {
        $model = new $modelNameAR ();
        $modelLabel = "$modelNameAR (" . _2str ( $model->tableSchema->primaryKey ) . ")";
        if ($modelNameAR != $modelName)
          $classListHtml [] = "<option value=\"$modelNameAR\">$modelLabel</option>";
        else
          $classListHtml [] = "<option value=\"$modelNameAR\" selected>$modelLabel</option>";
      }
      $classListHtml = implode ( PHP_EOL, $classListHtml );
      $html_form = "
      <form method=\"post\">
      SELECT t.* FROM <select name=\"class\">
      $classListHtml
      </select> AS t
      <br>
      <textarea name=\"query\" cols=\"30\" rows=\"10\">$restOfQuery</textarea>
      <br>
      <input type=\"submit\" />
      </form><br>
      " . PHP_EOL;
      
      $html = "";
      $html .= $html_form;
      
      if (! isEmpty ( $modelName ))
      {
        $model = new $modelName ();
        // $model = new ActiveRecord();
        $table = $model->tableName ();
        
        $query = "SELECT t.* FROM $table AS t $restOfQuery";
        
        $html .= "<h5>$query</h5>";
        $html .= "<hr />";
        
        $results = query ( $query, array (), false, false );
        foreach ( $results as $row )
        {
          $model = new $modelName ();
          // $model = new ActiveRecord();
          $model->setAttributes ( $row, false );
          
          $pk = $model->getPrimaryKey ();
          $pkLabel = is_string ( $pk ) ? $pk : _2str ( $pk );
          $pkLink = base64_encode ( serialize ( $pk ) );
          
          $deleteLink = url ( 'debug/model_delete', array (
              'modelName' => $modelName,
              'pk' => $pkLink 
          ) );
          $html .= "$pkLabel - <a href=\"?class=$modelName&edit=$pkLink\">EDIT</a> - <a href=\"$deleteLink\">DELETE</a><br>";
        }
        
        $html .= "<hr />";
        // $model->getPrimaryKey()
      }
      
      $this->renderHtml ( $html, false, false );
    }
    else
    {
      $pk = unserialize ( base64_decode ( $_REQUEST ['edit'] ) );
      
      if (isset ( $_REQUEST [$modelName] ))
      {
        $model = new $modelName ();
        $model = $model::model ()->findByPk ( $pk );
        $model->setAttributes ( $_REQUEST [$modelName], false );
        if ($model->update ())
        {
          $html .= "saved!<br>";
        }
        else
        {
          $html .= "NOT saved!<br>";
        }
      }
      
      $model = new $modelName ();
      // $model = new ActiveRecord();
      $model = $model::model ()->findByPk ( $pk );
      if ($model == null)
        $html .= "model not found";
      else
      {
        $html .= "<h2>$modelName</h2>";
        $html .= "<form method=\"post\">";
        $html .= "<input type=\"hidden\" name=\"edit\" value=\"$_REQUEST[edit]\" />";
        $html .= "<input type=\"hidden\" name=\"class\" value=\"$modelName\" />";
        foreach ( $model->attributeNames () as $attr )
        {
          $column = $model->tableSchema->getColumn ( $attr );
          // $column = new CDbColumnSchema;
          $html .= "$attr=[" . $model->getAttributeGuiControl ( $attr ) . "](TYPE=$column->type)<br>\n";
        }
        $html .= "<input type=\"submit\" />";
        $html .= "</form>";
      }
      $this->renderHtml ( $html, false, false );
    }
  }

  public function actionScheduledTasks()
  {
    $this->render ( 'scheduledTasks', array (
        'tasks' => DebugHelper::getScheduledTasks () 
    ) );
  }

  public function actionFlashMessages()
  {
    if ($_REQUEST ['action'] == 'create')
    {
      if ($_REQUEST ['flash_type'] == 'file')
      {
        $flash = new FlashMessage ();
        
        $flash->content = $_REQUEST ['flash_message'];
        $flash->permanent = $_REQUEST ['flash_permanent'];
        $flash->type = FlashMessage::TYPE_FILE;
        $flash->level = $_REQUEST ['flash_level'];
        $flash->target = $_REQUEST ['flash_target'];
        if (! isEmpty ( $_REQUEST ['flash_custom_target'] ))
          $flash->custom_target = $_REQUEST ['flash_target'] . "_" . $_REQUEST ['flash_custom_target'];
        
        user ()->setFlashEx ( $flash );
      }
      if ($_REQUEST ['flash_type'] == 'session')
        user ()->setFlash ( $_REQUEST ['flash_level'], $_REQUEST ['flash_message'] );
      $this->redirectTo ( 'debug/FlashMessages' );
      return;
    }
    
    if ($_REQUEST ['action'] == 'delete')
    {
      $flashes = app ()->getFlashMessages ();
      foreach ( $flashes as $flash )
      {
        if ($flash->id == $_REQUEST ['flash'])
        {
          unlink ( $flash->filename );
        }
      }
      $this->redirectTo ( 'debug/FlashMessages' );
      return;
    }
    
    $this->render ( 'flashMessages', array (
        'messages' => app ()->getFlashMessages () 
    ) );
  }

  public function actionApache_restart()
  {
    DebugHelper::apache_restart ();
    $this->redirect ( 'debug' );
  }

  public function actionMysql_restart()
  {
    DebugHelper::mysql_restart ();
    $this->redirect ( 'debug/index' );
  }

  public function actionRename($path)
  {
    $newPath = $_REQUEST ['newPath'];
    // logLine("$path => $newPath");
    if (file_exists ( $path ))
    {
      $dir = dirname ( $path );
      if (! isEmpty ( $newPath ))
      {
        shell_exec ( "rename \"$path\" \"$newPath\"" );
        $this->redirectTo ( 'debug/fileExplorer', array (
            'path' => $dir 
        ) );
      }
      else
      {
        $this->render ( 'rename', array (
            'path' => $path 
        ) );
      }
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionUtilities()
  {
    $this->redirect ( url ( 'debug' ) );
  }

  public function actionProcessKill($pid)
  {
    $redirectTimeout = 3;
    $this->redirectTimed ( url ( "debug/processes" ), $redirectTimeout );
    $result = DebugHelper::killProcess ( $pid );
    if ($result === false)
      $result = "TSKILL NOUT FOUND";
    $this->renderText ( "<pre>$result</pre>You will be redirected in $redirectTimeout seconds..." );
  }

  public function actionProcesses()
  {
    $info = DebugHelper::getProcesses ();
    if ($info == null)
      throw new CHttpException ( 500, "Command TASKLIST not found" );
    $info->columns [] = "Actions";
    $procs = $info->processes;
    foreach ( $procs as $index => $row )
    {
      $item = $info->infos [$index];
      $urlKill = url ( "debug/ProcessKill", array (
          'pid' => $item->getPid () 
      ) );
      $row [] = "<a class=\"icon-remove\" href=\"$urlKill\"></a>";
      $procs [$index] = $row;
    }
    $this->renderTable ( "Processes", "icon-tasks", $info->columns, $procs );
  }

  public function actionServices()
  {
    $columns = array (
        "name",
        "description",
        "type",
        "state",
        "win32ExitCode",
        "serviceExitCode",
        "checkpoint",
        "waithint",
        "pid",
        "flags" 
    );
    $rows = array_to_matrix ( DebugHelper::getServicesEx (), "toArray" );
    $this->renderTable ( "Services", "", $columns, $rows );
  }

  public function actionEnableDebug($return = null)
  {
    $ok = false;
    if (! empty ( $_REQUEST ['debugme'] ))
    {
      if (kria_password ( $_REQUEST ['debugme'] ) == paramdeep ( 'debug', 'password' ))
      {
        $ok = true;
        self::enableDebugMode ();
        user ()->setFlash ( 'success', t ( 'Debug mode enabled!' ) );
        $this->redirect ( url ( "debug/$return" ) );
        return;
      }
      else
      {
        user ()->setFlash ( 'error', t ( 'Wrong password!' ) );
      }
    }
    $this->render ( 'enableDebug', array (
        'ok' => $ok 
    ) );
  }

  public function actiontest_createNotification()
  {
    $req = new Request ();
    
    if (! isEmpty ( $req->run ))
    {
      $ns = NotificationSetting::model ()->findByPk ( $req->run );
      if ($ns == null)
        user ()->setFlash ( 'error', "Can't find NotificationSetting($req->run)" );
      else
      {
        $randomRowNumber = query ( "select floor(rand()*count(*)) as row, count(*) as total from event_reporting" );
        if ($randomRowNumber->total <= 0)
          user ()->setFlash ( 'warning', "Table event_reporting is empty!" );
        else
        {
          $randomRow = query ( "select * from event_reporting limit $randomRowNumber->row,1" );
          $n = new Notification ();
          $n->read = "0000-00-00 00:00:00";
          $n->epoch = DateTimeEx::nows ();
          $n->object_id = $randomRow->id;
          $n->setting_id = $ns->id;
          $n->status = 'loading';
          if ($n->insert ())
            user ()->setFlash ( 'success', "Created Notification($n->id)" );
          else
            user ()->setFlash ( 'error', "Cannot create a new notification" );
        }
      }
      $this->redirect ( url ( 'debug/test_createNotification' ) );
    }
    
    $notifications = NotificationSetting::model ()->findAll ();
    $this->render ( 'utilities/test_createNotification', array (
        'notifications' => $notifications 
    ) );
  }

  public function actionMigrationBypass($version)
  {
    $m = new Migration ();
    $m->version = $version;
    $m->apply_time = time ();
    $m->insert ();
    $this->redirectTo ( 'debug/migrations' );
  }

  public function actionMigrationBypassTo($version)
  {
    $info = DebugHelper::getMigrationsInfo ();
    
    foreach ( $info->allMigrations as $migrationName )
    {
      if (array_key_exists ( $migrationName, $info->dbMigrations ))
        continue;
      
      if ($version >= $migrationName)
      {
        $m = new Migration ();
        $m->version = $migrationName;
        $m->apply_time = time ();
        $m->insert ();
      }
    }
    
    $this->redirectTo ( 'debug/migrations' );
  }

  public function actionMigrationUp($version = null)
  {
    $versionSpec = isEmpty ( $version ) ? null : substr ( $version, 1, 13 );
    if (! isEmpty ( $versionSpec ))
      $cmd = array (
          'yiic',
          'migrate',
          'to',
          $versionSpec,
          '--interactive=0' 
      );
    else
      $cmd = array (
          'yiic',
          'migrate',
          'up',
          '1',
          '--interactive=0' 
      );
    
    $return = null;
    $result = null;
    $timeout = 3;
    
    try
    {
      $result = self::yiic ( $cmd, $return );
    }
    catch ( Exception $e )
    {
      $timeout = 10;
      $return = "ERROR";
      $result = $e;
    }
    
    $returnUrl = url ( 'debug/migrations' );
    $this->redirectTimed ( $returnUrl, $timeout );
    $this->renderText ( "<pre>RESULT: " . _2str ( $return ) . "\n\n$result</pre><br><b>You will be redirected <a href=\"$returnUrl\">here</a> in $timeout seconds...</b>" );
  }

  public function actionMigrationDown($version = null)
  {
    $versionSpec = isEmpty ( $version ) ? null : substr ( $version, 1, 13 );
    if (! isEmpty ( $versionSpec ))
      $cmd = array (
          'yiic',
          'migrate',
          'to',
          $versionSpec,
          '--interactive=0' 
      );
    else
      $cmd = array (
          'yiic',
          'migrate',
          'down',
          '1',
          '--interactive=0' 
      );
    
    $return = null;
    $result = null;
    $timeout = 3;
    
    try
    {
      $result = self::yiic ( $cmd, $return );
    }
    catch ( Exception $e )
    {
      $timeout = 10;
      $return = "ERROR";
      $result = $e;
    }
    
    $returnUrl = url ( 'debug/migrations' );
    $this->redirectTimed ( $returnUrl, $timeout );
    $this->renderText ( "<pre>RESULT: " . _2str ( $return ) . "\n\n$result</pre><br><b>You will be redirected <a href=\"$returnUrl\">here</a> in $timeout seconds...</b>" );
  }

  public function actiontest_impersonate()
  {
    security_log ( "IMPERSONATION REQUEST: SOURCE=[" . user ()->id . "=" . user ()->name . "]" );
    
    $validFrom = DateTimeEx::now ();
    $validFrom->minute = 0;
    $validFrom->second = 0;
    $validTo = clone $validFrom;
    $validTo->addFromString ( "1 hour" );
    
    $users = User::model ()->findAll ();
    
    $this->render ( 'utilities/test_impersonate', get_defined_vars () );
  }

  public function actionMigrationCreate()
  {
    $req = new Request ();
    
    if (isEmpty ( $req->name ))
    {
      $this->renderText ( "<h2>Create Migration</h2><br />Name with spaces<br /><form><input type=\"text\" name=\"name\" class=\"span5\"/></form>" );
    }
    else
    {
      $name = "m" . DateTimeEx::now ()->toMigrationDateTimeString () . "_" . createVarName ( $req->name );
      $filename = pathCombine ( app ()->basePath, 'migrations', "$name.php" );
      file_put_contents ( $filename, "<?php

      class $name extends MyDbMigration
      {
      public function up()
      {
    }

    public function down()
    {
    return true;
    }
    }
    " );
      $this->redirect ( url ( 'debug/editAsText', array (
          'filename' => $filename 
      ) ) );
    }
  }

  public function actionMigrations()
  {
    $info = DebugHelper::getMigrationsInfo ();
    
    $this->render ( 'migrations/index', array (
        'migrations' => $info->allMigrations,
        'fileMigrations' => $info->fileMigrations,
        'dbMigrations' => $info->dbMigrations 
    ) );
  }

  public function actionLogs()
  {
    $filters = array (
        "*.log",
        "*.txt" 
    );
    
    if (! empty ( $_REQUEST ['filters'] ))
    {
      $filters = explode ( ',', $_REQUEST ['filters'] );
    }
    
    $logs = array ();
    
    // sicurezza
    $security = new CArray ( paramdeep ( 'security' ) );
    $secFileName = $security->logFile;
    if (! empty ( $secFileName ))
    {
      $logItem = new CArray ();
      $logItem->path = realpath ( dirname ( $security->logFile ) );
      $logItem->filename = basename ( $security->logFile );
      $logItem->file = $security->logFile;
      $logItem->levels = $security->logContext;
      
      $logs [] = $logItem;
    }
    
    // yii
    $mainLog = configWeb ( 'components', 'log' );
    if ($mainLog != null)
    {
      $queue = new CQueue ( array (
          $mainLog 
      ) );
      while ( $queue->count () > 0 )
      {
        $log = $queue->dequeue ();
        if ($log != null)
        {
          switch ($log ['class'])
          {
            case 'CLogRouter' :
              foreach ( $log ['routes'] as $route )
                $queue->enqueue ( $route );
              break;
            case 'CFileLogRoute' :
              $path = app ()->runtimePath;
              $filename = "application.log";
              $levels = '';
              
              if (! empty ( $log ['levels'] ))
                $levels = $log ['levels'];
              
              if (! empty ( $log ['logFile'] ))
                $filename = $log ['logFile'];
              
              if (! empty ( $log ['logPath'] ))
                $path = $log ['logPath'];
              
              $file = pathCombine ( $path, $filename );
              
              $logItem = new CArray ();
              $logItem->path = $path;
              $logItem->filename = $filename;
              $logItem->file = $file;
              $logItem->levels = preg_split ( '/[\s,]+/', strtolower ( $levels ), - 1, PREG_SPLIT_NO_EMPTY );
              
              $logs [] = $logItem;
              break;
          }
        }
      }
    }
    
    // kria apache & mysql
    $kriaLogs = array ();
    
    if (dirExists ( DebugHelper::mysql_getPath () ))
      $kriaLogs = array_merge ( $kriaLogs, getFiles ( DebugHelper::mysql_getPath (), "*.log", true ) );
    
    if (dirExists ( DebugHelper::apache_getPath () ))
      $kriaLogs = array_merge ( $kriaLogs, getFiles ( DebugHelper::apache_getPath (), "*.log", true ) );
    
    if (dirExists ( "C:\\KRIA\\Log" ))
      foreach ( $filters as $filter )
        $kriaLogs = array_merge ( $kriaLogs, getFiles ( "C:\\KRIA\\Log", $filter, true ) );
    
    if (dirExists ( "D:\\KRIA\\Log" ))
      foreach ( $filters as $filter )
        $kriaLogs = array_merge ( $kriaLogs, getFiles ( "D:\\KRIA\\Log", $filter, true ) );
    
    foreach ( $kriaLogs as $kl )
    {
      $logItem = new CArray ();
      $logItem->path = dirname ( $kl );
      $logItem->filename = basename ( $kl );
      $logItem->file = $kl;
      $logItem->levels = array (
          basename ( dirname ( $kl ) ) 
      );
      
      $logs [] = $logItem;
    }
    
    // go
    $this->render ( 'logs', array (
        'logs' => $logs,
        'filters' => implode ( ',', $filters ) 
    ) );
  }

  public function actionMysqlProcessList()
  {
    if (! isEmpty ( $_REQUEST ['kill'] ))
    {
      $threadToKill = $_REQUEST ['kill'];
      try
      {
        query ( "KILL QUERY $threadToKill" );
        user ()->setFlash ( 'success', "\"KILL QUERY $threadToKill\" done!" );
      }
      catch ( Exception $e )
      {
        user ()->setFlash ( 'error', "\"KILL QUERY $threadToKill\" failed with error: " . $e->getMessage () );
      }
      try
      {
        query ( "KILL CONNECTION $threadToKill" );
        user ()->setFlash ( 'success', "\"KILL CONNECTION $threadToKill\" done!" );
      }
      catch ( Exception $e )
      {
        user ()->setFlash ( 'error', "\"KILL CONNECTION $threadToKill\" failed with error: " . $e->getMessage () );
      }
    }
    
    $columns = array (
        "Id" => "Id",
        "User" => "User",
        "Host" => "Host",
        "db" => "db",
        "Command" => "Command",
        "Time" => "Time",
        "State" => "State",
        "Info" => "Info",
        "Kill" => "Kill" 
    );
    $originalRows = query ( "SHOW FULL PROCESSLIST", array (), false, false );
    $rows = array ();
    foreach ( $originalRows as $row )
    {
      $row ["Kill"] = "<a href=\"" . url ( 'debug/MysqlProcessList', array (
          'kill' => $row ['Id'] 
      ) ) . "\">Kill</a>";
      $rows [] = $row;
    }
    // logObj($rows);
    $url = url ( 'debug/MysqlProcessList' );
    $title = t ( 'Refresh' );
    $this->renderTable ( t ( "Process List" ), "icon-legal", $columns, $rows, "<h2><a href=\"$url\">$title</a></h2>" );
  }

  public function actionQuery()
  {
    $messages = array ();
    $tablesDict = array ();
    $tables = array ();
    $editable = false;
    
    $db = query ( "SELECT DATABASE() as db FROM DUAL", array (), true )->db;
    foreach ( query ( "SELECT COLUMN_NAME AS CN,TABLE_NAME AS TN FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=:db ORDER BY TABLE_NAME", array (
        ':db' => $db 
    ), false ) as $tb )
    {
      $tablesDict [$tb->TN] [] = $tb->TN [0] . '.' . $tb->CN;
    }
    
    foreach ( $tablesDict as $tableName => $columns )
    {
      $tables [] = "<a href=\"" . url ( 'debug/query', array (
          'query' => 'SELECT' . PHP_EOL . implode ( ", ", $columns ) . PHP_EOL . 'FROM ' . $tableName . ' ' . $tableName [0] . PHP_EOL . 'LIMIT 0' 
      ) ) . "\">" . $tableName . "</a>";
    }
    
    if (isset ( $_REQUEST ['query'] ))
    {
      $editable = $_REQUEST ['editable'] == '1';
      $mustExport = $_REQUEST ['action'] == 'export';
      $sql = $_REQUEST ['query'];
      
      if ($mustExport)
      {
        $at = new DateTimeEx ();
        $results = query ( $sql, array (), false, false );
        $csv = new ECSVExport ( $results );
        $content = $csv->toCSV ();
        prepare_download ( $at->toFilesafeDateTimeString () . '.csv' );
        echo ($content);
        exit ();
      }
      
      $startTime = new DateTimeEx ();
      $results = query ( $sql, array (), false );
      $endTime = new DateTimeEx ();
      
      $messages [] = "START TIME $startTime";
      $messages [] = "END TIME $endTime";
      $messages [] = "RESULTS: " . count ( $results );
    }
    $this->render ( 'query', array (
        'db' => $db,
        'tables' => $tables,
        'sql' => $sql,
        'results' => $results,
        'messages' => $messages,
        'editable' => $editable 
    ) );
  }

  public function actionDisableDebug()
  {
    self::disableDebugMode ();
    $this->redirect ( url ( "/" ) );
  }

  public function actionConsole()
  {
    $consoleLogPath = app ()->runtimePath . DIRECTORY_SEPARATOR . 'console';
    if (! file_exists ( $consoleLogPath ))
      mkdir ( $consoleLogPath );
    
    $consoleLogPathforUser = $consoleLogPath . DIRECTORY_SEPARATOR . user ()->model->username;
    if (! file_exists ( $consoleLogPathforUser ))
      mkdir ( $consoleLogPathforUser );
    
    $cmd = $_REQUEST ['command'];
    
    $shell = isset ( $_REQUEST ['shell'] ) ? $_REQUEST ['shell'] == 1 : false;
    $err2out = isset ( $_REQUEST ['err2out'] ) ? $_REQUEST ['err2out'] == 1 : true;
    
    $output = array ();
    if (empty ( $cmd ))
    {
      $dir = new DirectoryIterator ( $consoleLogPathforUser );
      $last = null;
      foreach ( $dir as $dirdir )
      {
        if ($dir->isFile ())
          $last = $dir->getRealPath ();
      }
      if ($last != null)
        $output [] = file_get_contents ( $last );
    }
    else
    {
      if ($err2out)
        $cmd = "$cmd 2>&1";
      $output [] = "> $cmd";
      $startTime = new DateTimeEx ();
      $output [] = "START TIME $startTime";
      if ($shell)
      {
        $result = shell_exec ( $cmd );
        $output [] = $result;
      }
      else
      {
        exec ( $cmd, $output, $return );
      }
      $endTime = new DateTimeEx ();
      $output [] = "END TIME $endTime";
      $output [] = "OPERATION RESULT " . _2str ( $return );
      
      file_put_contents ( $consoleLogPathforUser . DIRECTORY_SEPARATOR . $startTime->toFilesafeDateTimeString () . ".log", implode ( PHP_EOL, $output ) );
    }
    
    $finalOutput = implode ( PHP_EOL, $output );
    
    $this->render ( 'console', array (
        'output' => $finalOutput,
        'shell' => $shell,
        'err2out' => $err2out 
    ) );
  }

  public function actionEval()
  {
    $as_value = array_get ( $_REQUEST, 'as_value', 0 ) == 1;
    $do_eval = array_get ( $_REQUEST, 'do_eval', 0 ) == 1;
    $code = array_get ( $_REQUEST, 'code' );
    
    if ($do_eval)
    {
      $result = eval ( $code );
      if ($as_value)
        $result = _2str ( $result );
    }
    
    if (empty ( $code ))
      $code = "echo('Hello world!');";
      
      // logObj(get_defined_vars());
    
    $this->render ( 'eval', get_defined_vars () );
  }

  public function actionIndex()
  {
    $this->render ( 'index' );
  }

  public function actionCreate($name, $path, $type, $return = null)
  {
    if (empty ( $return ))
      $return = url ( "debug/fileExplorer" );
    
    $filename = $path . DIRECTORY_SEPARATOR . $name;
    
    if (! empty ( $name ) && file_exists ( $path ) && is_dir ( $path ))
    {
      if ($type == 'file')
      {
        if (file_put_contents ( $filename, '' ) !== false)
          user ()->setFlash ( 'success', t ( 'Created' ) );
        else
          user ()->setFlash ( 'error', t ( 'Create failed' ) );
      }
      else
      {
        if (mkdir ( $filename ) !== false)
          user ()->setFlash ( 'success', t ( 'Created' ) );
        else
          user ()->setFlash ( 'error', t ( 'Create failed' ) );
      }
    }
    else
      user ()->setFlash ( 'notice', t ( 'Path not found' ) );
    
    $this->redirect ( $return );
  }

  public function actionCleanRuntime()
  {
    dirEmpty ( app ()->runtimePath );
    dirEmpty ( app ()->assetManager->basePath );
    sleep ( 1 );
    user ()->setFlash ( 'success', t ( 'Runtime cleaned!' ) );
    $this->redirect ( url ( 'debug' ) );
  }

  public function actionFileExplorer($path = null, $dirSize = null)
  {
    if (! empty ( $dirSize ))
      app ()->session ['debugMode_fileExplorer_getDirSize'] = $dirSize;
    if (empty ( $path ))
      $path = app ()->basePath;
    if (! file_exists ( $path ))
      throw new CHttpException ( 404, t ( 'Path not found' ) );
    $folder = new DirectoryIterator ( $path );
    $this->render ( 'fileExplorer', array (
        'path' => $path,
        'folder' => $folder 
    ) );
  }

  public function actionDeleteDir($path, $empty, $return = null)
  {
    if (empty ( $return ))
      $return = url ( "debug/fileExplorer" );
    
    if (file_exists ( $path ) && is_dir ( $path ))
      if (dirEmpty ( $path, ! $empty ))
        user ()->setFlash ( 'success', t ( 'Directory deleted' ) );
      else
        user ()->setFlash ( 'error', t ( 'Delete failed' ) );
    else
      user ()->setFlash ( 'notice', t ( 'File not found' ) );
    
    $this->redirect ( $return );
  }

  public function actionDeleteFile($filename, $return = null)
  {
    if (empty ( $return ))
      $return = url ( "debug/fileExplorer" );
    
    if (file_exists ( $filename ) && is_file ( $filename ))
      if (unlink ( $filename ))
        user ()->setFlash ( 'success', t ( 'File deleted' ) );
      else
        user ()->setFlash ( 'error', t ( 'Delete failed' ) );
    else
      user ()->setFlash ( 'notice', t ( 'File not found' ) );
    
    $this->redirect ( $return );
  }

  public function actionUnzip($filename, $path, $return = null)
  {
    if (empty ( $return ))
      $return = url ( "debug/fileExplorer" );
    
    if (file_exists ( $filename ) && is_file ( $filename ))
      if (unzip ( $filename ))
        user ()->setFlash ( 'success', t ( 'File unzipped' ) );
      else
        user ()->setFlash ( 'error', t ( 'Unzip failed' ) );
    else
      user ()->setFlash ( 'notice', t ( 'File not found' ) );
    
    $this->redirect ( $return );
  }

  public function actionUpload()
  {
    $upload = $_FILES ['upload'];
    $path = $_REQUEST ['path'];
    $return = $_REQUEST ['return'];
    
    if (empty ( $path ))
      $path = app ()->basePath;
    
    if (empty ( $return ))
      $return = url ( "debug/fileExplorer", array (
          'path' => $path 
      ) );
    
    if (file_exists ( $path ) && is_dir ( $path ))
    {
      if (isset ( $upload ) && file_exists ( $upload ['tmp_name'] ))
      {
        /*
         * $_FILES["file"]["name"] - the name of the uploaded file
         * $_FILES["file"]["type"] - the type of the uploaded file
         * $_FILES["file"]["size"] - the size in bytes of the uploaded file
         * $_FILES["file"]["tmp_name"] - the name of the temporary copy of the file stored on the server
         * $_FILES["file"]["error"] - the error code resulting from the file upload
         */
        $destination = $upload ['name'];
        $destinationName = $destination;
        $destinationCount = 0;
        $destinationPath = $path . DIRECTORY_SEPARATOR . $destinationName;
        while ( file_exists ( $path . DIRECTORY_SEPARATOR . $destinationName ) )
        {
          $destinationName = $destinationCount . "_" . $destination;
          $destinationCount ++;
          $destinationPath = $path . DIRECTORY_SEPARATOR . $destinationName;
        }
        if (move_uploaded_file ( $upload ['tmp_name'], $destinationPath ))
        {
          user ()->setFlash ( 'success', t ( 'Uploaded' ) . ' ' . $destinationPath );
        }
        else
        {
          user ()->setFlash ( 'error', t ( 'Upload failed' ) );
        }
      }
      else
      {
        user ()->setFlash ( 'notice', t ( 'Nothing to upload' ) );
      }
    }
    else
    {
      user ()->setFlash ( 'notice', t ( 'Specify a valid path!' ) );
    }
    
    $this->redirect ( $return );
  }

  public function actionPhpInfo()
  {
    $this->layout = '//layouts/empty';
    phpinfo ();
  }

  public function actionPhpFunctions()
  {
    $this->render ( 'php/functions' );
  }

  public function actionPhpExtensionLoad($name)
  {
    if (DebugHelper::php_addExtension ( $name ))
      $this->actionApache_restart ();
  }

  public function actionPhpExtensionUnload($name)
  {
    if (DebugHelper::php_removeExtension ( $name ))
      $this->actionApache_restart ();
  }

  public function actionPhpExtensionFunctions($name)
  {
    $extInfo = new ReflectionExtension ( $name );
    $columns = array (
        'name' => t ( 'Name' ),
        'type' => t ( 'Type' ) 
    );
    $rows = array ();
    foreach ( $extInfo->getClasses () as $class )
    {
      $rows [] = array (
          'name' => $class->getName (),
          'type' => t ( 'Class' ) 
      );
    }
    foreach ( $extInfo->getFunctions () as $func )
    {
      $rows [] = array (
          'name' => $func->getName (),
          'type' => t ( 'Function' ) 
      );
    }
    $this->renderTable ( t ( "Functions" ), 'icon-code', $columns, $rows );
  }

  public function actionPhpExtensions()
  {
    $extensions = array ();
    
    $loaded = get_loaded_extensions ();
    foreach ( $loaded as $name )
    {
      $ext = new CArray ();
      
      $ext->id = strtolower ( $name );
      $ext->name = $name;
      $ext->filename = "";
      $ext->loaded = true;
      $ext->file = "";
      $ext->info = new ReflectionExtension ( $name );
      
      $extensions [strtolower ( $name )] = $ext;
    }
    
    $path = DebugHelper::php_getExtensionFolderPath ();
    $avaible = array ();
    if (dirExists ( $path ))
    {
      $dlls = getFiles ( $path, "*.dll" );
      foreach ( $dlls as $filename )
      {
        if (fileExists ( $filename ))
        {
          $name = basename ( $filename );
          $name = startsWithGet ( $name, "php_", false, 0, $name );
          $name = endsWithGet ( $name, ".dll", false, 0, $name );
          
          if (array_key_exists ( $name, $extensions ))
          {
            $extensions [strtolower ( $name )]->file = $filename;
            $extensions [strtolower ( $name )]->filename = basename ( $filename );
          }
          else
          {
            $ext = new CArray ();
            
            $ext->id = strtolower ( $name );
            $ext->name = $name;
            $ext->filename = basename ( $filename );
            $ext->loaded = false;
            $ext->file = $filename;
            $ext->info = null;
            
            $extensions [strtolower ( $name )] = $ext;
          }
        }
      }
    }
    
    array_multisort ( array_keys ( $extensions ), $extensions );
    
    $this->render ( 'php/Extensions', array (
        'extensions' => $extensions 
    ) );
  }

  public function actionDownload($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      prepare_download ( basename ( $filename ) );
      readfile ( $filename );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionGetFile($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      prepare_download ( basename ( $filename ) );
      readfile ( $filename );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionViewAsText($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      $this->render ( "viewFileAsText", array (
          'filename' => $filename 
      ) );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionViewAsImage($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      $this->render ( "viewFileAsImage", array (
          'filename' => $filename 
      ) );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionWatchLog($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      $this->render ( "watchLog", array (
          'filename' => $filename 
      ) );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionWatchLogGetTail($filename)
  {
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      $tail = tail ( $filename, 10 * SIZE_KB );
      if ($tail === false)
        throw new CHttpException ( 500, "Cannot find '$filename' tail." );
      echo ($tail);
      app ()->end ();
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionEditAsText($filename, $action = null, $content = null)
  {
    $action = array_get ( $_REQUEST, 'action', $action );
    $content = array_get ( $_REQUEST, 'content', $content );
    
    if (file_exists ( $filename ) && is_file ( $filename ))
    {
      if ($action == 'write')
      {
        if (file_put_contents ( $filename, $content ) !== false)
          user ()->setFlash ( 'success', t ( 'File saved!' ) );
        else
          user ()->setFlash ( 'error', t ( 'File not saved!' ) );
      }
      else
      {
        user ()->setFlash ( 'error', t ( 'Action "' . _2str ( $action ) . '" not found!' ) );
      }
      
      $filecontent = file_get_contents ( $filename );
      $this->render ( "editFile", array (
          'filename' => $filename,
          'filecontent' => $filecontent 
      ) );
    }
    else
      throw new CHttpException ( 404, t ( 'File not found' ) );
  }

  public function actionDynconfig()
  {
    $path = pathCombine ( app ()->basePath, 'config' );
    $file = "debug.php";
    $filename = pathCombine ( $path, $file );
    $req = new Request ();
    $dynconfig = self::getCurrentDynconfig ();
    
    if ($req->SET == "SET")
    {
      $actions = array ();
      $features = array ();
      foreach ( $dynconfig as $dk => $dv )
      {
        if ($req->$dk == 1)
        {
          // enable
          if ($dk == self::DYNCONFIG_DEBUGTOOLBAR)
          {
            $actions [] = array_build_nested ( 'configWeb', 'components', 'log', array (
                'class' => 'CLogRouter',
                'routes' => array (
                    array (
                        'class' => 'ext.yii-debug-toolbar.YiiDebugToolbarRoute',
                        'ipFilters' => array (
                            '127.0.0.1',
                            '192.168.2.24',
                            '192.168.2.200' 
                        ) 
                    ) 
                ) 
            ) );
            $actions [] = array_build_nested ( 'configWeb', 'components', 'db', array (
                'enableParamLogging' => true,
                'enableProfiling' => true 
            ) );
            $features [self::DYNCONFIG_DEBUGTOOLBAR] = true;
          }
          // enable
          if ($dk == self::DYNCONFIG_AUTOENABLE)
          {
            $actions [] = array_build_nested ( 'configWeb', 'params', 'debug', 'autoEnable', true );
            $features [self::DYNCONFIG_AUTOENABLE] = true;
          }
          // enable
          if ($dk == self::DYNCONFIG_YII_DEBUG)
          {
            $actions [] = array_build_nested ( 'yiiDebug', true );
            $features [self::DYNCONFIG_YII_DEBUG] = true;
          }
          // enable
          if ($dk == self::DYNCONFIG_MAINTENANCE_MODE)
          {
            $actions [] = array_build_nested ( 'configWeb', 'params', 'debug', 'maintenance-mode', true );
            $features [self::DYNCONFIG_MAINTENANCE_MODE] = true;
          }
        }
        else
        {
          // disable
        }
      }
      
      if (fileExists ( $filename ))
        unlink ( $filename );
      
      if (count ( $actions ) > 0)
      {
        $features = array (
            self::DYNCONFIG_ROOT => $features 
        );
        
        $finalActions = array ();
        foreach ( $actions as $act )
        {
          $finalActions = array_merge_ex ( $finalActions, $act );
        }
        
        $content = array_merge_ex ( $features, $finalActions );
        
        file_append_line ( $filename, "<?php return " );
        file_append_line ( $filename, _2str ( $content ) );
        file_append_line ( $filename, ";" );
      }
      $this->redirect ( url ( 'debug/dynconfig' ) );
      return;
    }
    
    $dynconfig = self::getCurrentDynconfig ();
    $this->render ( 'utilities/dynconfig', array (
        'dynconfig' => $dynconfig,
        'filename' => $filename 
    ) );
  }

  public function actionUserTrackingDelete($id, $returnUrl = null)
  {
    access_denied_check ( 'user_tracking_delete' );
    
    $model = UserTrackingTable::model ()->findByPk ( $id );
    if ($model === null)
      throw new CHttpException ( 404, Yii::t ( 'app', 'The requested page does not exist.' ) );
    if ($model->delete ())
      user ()->setFlash ( 'success', t ( 'Item deleted: {0}', array (
          '{0}' => $model 
      ) ) );
    else
      user ()->setFlash ( 'error', t ( 'Item NOT deleted: {0}', array (
          '{0}' => $model 
      ) ) );
    if (isEmpty ( $returnUrl ))
      $returnUrl = url ( "debug/UserTrackingIndex" );
    $this->redirect ( $returnUrl );
  }

  /**
   *
   * @return string
   */
  protected function getUserTrackingFolder()
  {
    $esguiFolder = kria_get_esgui_folder ();
    $utFolder = pathCombine ( $esguiFolder, "UserTracking" );
    dirEnsureExists ( $utFolder );
    return $utFolder;
  }

  public function actionUserTrackingArchiveView()
  {
    access_denied_check ( 'user_tracking_archive_view' );
    
    $dir = new DirectoryIterator ( $this->getUserTrackingFolder () );
    $this->render ( 'usertracking/view_archive', get_defined_vars () );
  }

  public function actionUserTrackingArchiveDownload($filename)
  {
    access_denied_check ( 'user_tracking_archive_download' );
    
    $filename = pathCombine ( $this->getUserTrackingFolder (), $filename );
    
    get_file_stream ( $filename );
  }

  public function actionUserTrackingArchiveDelete($filename)
  {
    access_denied_check ( 'user_tracking_archive_delete' );
    
    $filename = pathCombine ( $this->getUserTrackingFolder (), $filename );
    
    if (fileExists ( $filename ) && unlink ( $filename ))
      user ()->setFlash ( 'success', "Archive $filename deleted" );
    else
      user ()->setFlash ( 'error', "Archive $filename NOT deleted" );
    
    $this->redirectTo ( 'debug/UserTrackingArchiveView' );
  }

  protected function doUserTrackingArchive()
  {
    $filename = pathCombine ( $this->getUserTrackingFolder (), "UserTracking_" . DateTimeEx::now ()->toFilesafeDateTimeString () . ".csv" );
    $obj = new stdClass ();
    $obj->rowIndex = 0;
    $obj->ids = array ();
    $reader = queryReader ( "SELECT * FROM user_tracking_table" );
    $filter = function (array $row, $obj)
    {
      if ($obj->rowIndex > 0)
        $obj->ids [] = $row ['id'];
      $obj->rowIndex ++;
      return $row;
    };
    saveCsvFromReader ( $filename, $reader, $filter, $obj );
    if (count ( $obj->ids ) > 0)
    {
      $filenameZip = $filename . ".zip";
      $zipResult = zip_files ( $filenameZip, array (
          $filename 
      ) );
      $criteria = new CDbCriteria ();
      $criteria->addInCondition ( 'id', $obj->ids );
      $deleted = UserTrackingTable::model ()->deleteAll ( $criteria );
    }
    if (fileExists ( $filename ))
      unlink ( $filename );
    return count ( $obj->ids );
  }

  public function actionUserTrackingArchive()
  {
    access_denied_check ( 'user_tracking_archive' );
    
    $count = $this->doUserTrackingArchive ();
    if ($count > 0)
      user ()->setFlash ( 'success', "Saved $count rows a zipped CSV" );
    else
      user ()->setFlash ( 'warning', 'Nothing to archive' );
    
    $this->redirectTo ( 'debug/usertrackingindex' );
  }

  protected function getUserTrakingObjectLink(UserTrackingTable $ut)
  {
    $html = "";
    
    $tables = array ();
    foreach ( yii_getModels () as $modName )
      if (class_exists ( $modName ))
      {
        $class = new ReflectionClass ( $modName );
        $ctor = $class->getConstructor ();
        if ($ctor != null)
        {
          $ctorParams = $ctor->getParameters ();
          if (count ( $ctorParams ) == 1 && $ctorParams [0]->getName () == 'scenario' && ! $class->isAbstract ())
          {
            $item = new $modName ();
            if ($item instanceof ActiveRecord)
              $tables [$item->tableName ()] = $modName;
          }
        }
      }
    
    $modelName = array_get ( $tables, $ut->table_name );
    if (! isEmptyOrWhitespace ( $modelName ))
    {
      $id = eval ( "return {$ut->primary_key};" );
      
      if (! is_array ( $id ))
        $attributes = array (
            $modelName::model ()->getTableSchema ()->primaryKey => $id 
        );
      else
        $attributes = $id;
      
      $attributes2 = array ();
      $names = $modelName::model ()->attributeNames ();
      $namesLower = array_convert ( $names, "strtolower" );
      foreach ( $attributes as $ak => $av )
      {
        $index = array_index_of ( $namesLower, strtolower ( $ak ), - 1 );
        if ($index >= 0)
          $attributes2 [$names [$index]] = $av;
        else
          $attributes2 [$ak] = $av;
      }
      
      $attributes = $attributes2;
      
      $count = $modelName::model ()->countByAttributes ( $attributes );
      if ($count > 0)
      {
        $linkParams = $attributes;
        if (method_exists ( $modelName . 'Controller', 'actionview' ))
        {
          $meth = new ReflectionMethod ( $modelName . 'Controller', 'actionview' );
          $methParams = $meth->getParameters ();
          if (count ( $methParams ) == 1 && ! is_array ( $id ))
            $linkParams = array (
                $methParams [0]->getName () => $id 
            );
          $html = CHtml::link ( "<span class=\"icon-apple\" title=\"View object\"></span>", url ( $modelName . '/view', $linkParams ), array (
              'target' => '_blank' 
          ) );
        }
      }
    }
    
    return $html;
  }

  public function actionUserTrackingView($id)
  {
    access_denied_check ( 'user_tracking_view' );
    $ut = UserTrackingTable::model ()->findByPk ( $id );
    if ($ut == null)
      throw new CHttpException ( 404, "User tracking object $id not found" );
    $this->render ( 'userTracking/view', get_defined_vars () );
  }

  public function actionUserTrackingIndex()
  {
    access_denied_check ( 'user_tracking_view' );
    
    $utmodel = UserTrackingTable::model ();
    $names = $utmodel->attributeNames ();
    
    $sortingOptions = array ();
    $sortingOptions ['NOTSORTED'] = "Not sorted";
    foreach ( $names as $nm )
    {
      $sortingOptions ["$nm ASC"] = "$nm ASC";
      $sortingOptions ["$nm DESC"] = "$nm DESC";
    }
    
    $sorting = array_get ( $_REQUEST, 'sorting', 'NOTSORTED' );
    if ($sorting != 'NOTSORTED')
      $utmodel->search_sorting = $sorting;
    
    foreach ( array_keys ( $_REQUEST ) as $attr )
      if (! isEmpty ( $_REQUEST [$attr] ))
        if ($attr == 'username')
        {
          $targetUserIds = array ();
          foreach ( User::model ()->findAll () as $uobj )
            if (containsStr ( $uobj->getFullName (), $_REQUEST [$attr] ))
              $targetUserIds [] = $uobj->id;
          if (count ( $targetUserIds ) <= 0)
            $utmodel->id_user = - 1;
          else
            $utmodel->id_user = $targetUserIds;
        }
        else if (array_value_exists ( $names, $attr ))
          $utmodel->$attr = $_REQUEST [$attr];
    
    if ($_REQUEST ['submit_action'] == 'Export')
    {
      access_denied_check ( 'user_tracking_export' );
      $reader = queryFromCriteria ( "user_tracking_table", $utmodel->getSearchCriteria () );
      $mem = new stdClass ();
      $mem->rowId = 0;
      $filter = function (array $row, $mem)
      {
        if ($mem->rowId == 0)
        {
          $row ['username'] = 'username';
        }
        else
        {
          $u = User::findById ( $row ['id_user'] );
          if ($u != null)
            $row ['username'] = $u->getFullName ();
          else
            $row ['username'] = null;
        }
        
        $mem->rowId ++;
        
        return $row;
      };
      outputCsvFromReader ( "UserTracking_" . DateTimeEx::now ()->toFilesafeDateTimeString () . ".csv", $reader, $filter, $mem );
    }
    else
    {
      $dataProvider = $utmodel->search ();
      $dataProvider->pagination->pageSize = paramdeep ( 'security', 'user_tracking', 'pagination' );
      
      $this->render ( 'usertracking/index', get_defined_vars () );
    }
  }
}