<?php

class DebugHelper
{

  public static function getTableSize($table, $database = null)
  {
    if ($database == null)
      $database = getDbName ();
    $size = query ( "SELECT (data_length + index_length) as size FROM information_schema.TABLES WHERE table_name=:t AND table_schema=:d", array (
        ':t' => $table,
        ':d' => $database 
    ), false, false );
    if ($size != null)
      if (is_array ( $size ))
      {
        $size = array_first ( $size );
        if ($size != null && is_array ( $size ))
          return $size ['size'];
      }
    return 0;
  }

  /**
   *
   * @param boolean $x64
   *          default=false
   * @return multitype:DotNetFramework
   */
  public static function getDotNetFrameworks($x64 = false)
  {
    $frameworks = array ();
    $frameworksFolder = "C:\Windows\Microsoft.NET\Framework";
    if ($x64)
      $frameworksFolder .= "64";
    if (dirExists ( $frameworksFolder ))
    {
      $frameworksFolders = getDirectories ( $frameworksFolder, "v*", false );
      foreach ( $frameworksFolders as $ff )
      {
        $version = basename ( $ff );
        $frameworks [$version] = new DotNetFramework ( $ff );
      }
    }
    return $frameworks;
  }

  /**
   *
   * @return string[]
   */
  public static function getARModels()
  {
    $files = getFiles ( pathCombine ( app ()->basePath, 'models' ), "*.php" );
    $models = array ();
    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 ))
        {
          $models [] = $model;
        }
      }
    }
    return $models;
  }

  public static function getSystemTools()
  {
    $system32 = "C:\\Windows\\System32";
    $toolNames = array (
        "sc",
        "tasklist",
        "tskill",
        "taskkill",
        "cmd",
        "shutdown",
        "schtasks" 
    );
    $tools = array ();
    foreach ( $toolNames as $name )
    {
      $path = pathCombine ( $system32, $name . ".exe" );
      if (fileExists ( $path ))
        $tools [strtolower ( $name )] = $path;
    }
    return $tools;
  }

  public static function toolExists($tool)
  {
    $tools = self::getSystemTools ();
    $tool = strtolower ( $tool );
    return ! isEmpty ( $tools [$tool] );
  }

  public static function createScheduledTaskPerMinute($name, $command)
  {
    /*
     * SCHTASKS /Create /RU "" /SC MINUTE /TN "prova" /TR "calc.exe"
     */
  }

  /**
   *
   * @return ScheduledTask[]
   */
  public static function getScheduledTasks()
  {
    $tools = self::getSystemTools ();
    // logObj($tools);
    $services = array ();
    if (! isEmpty ( $tools ['schtasks'] ))
    {
      $output = shell_exec ( "\"$tools[schtasks]\" /query /v /fo csv 2>&1" );
      $output = explode_ex ( array (
          "\n",
          "\r" 
      ), $output );
      if (count ( $output ) > 0)
      {
        $index = 0;
        $columns = null;
        $tasks = array ();
        foreach ( $output as $line )
        {
          if (! isEmpty ( trim ( $line ) ))
          {
            $values = str_getcsv ( $line ); // ,";","\"","\\");
            if ($index == 0)
            {
              $columns = $values;
            }
            else
            {
              $tasks [] = new ScheduledTask ( $values, $columns );
            }
            
            $index ++;
          }
        }
        return $tasks;
      }
      else
        Yii::log ( "getScheduledTasks :: no output from 'schtasks'", CLogger::LEVEL_WARNING );
    }
    else
      Yii::log ( "getScheduledTasks :: tool 'schtasks' not found", CLogger::LEVEL_WARNING );
    return null;
  }

  /**
   *
   * @return string|false
   */
  public static function killProcess($pidOrName)
  {
    $tools = self::getSystemTools ();
    if (! isEmpty ( $tools ['tskill'] ))
    {
      return shell_exec ( "\"$tools[tskill]\" \"$pidOrName\" 2>&1" );
    }
    
    return false;
  }

  /**
   *
   * @return ProcessesInfo
   */
  public static function getProcesses()
  {
    $tools = self::getSystemTools ();
    // logObj($tools);
    $services = array ();
    if (! isEmpty ( $tools ['tasklist'] ))
    {
      $output = shell_exec ( "\"$tools[tasklist]\" /V /FO CSV 2>&1" );
      $output = explode_ex ( array (
          "\n",
          "\r" 
      ), $output );
      if (count ( $output ) > 0)
      {
        $container = new ProcessesInfo ();
        $index = 0;
        foreach ( $output as $line )
        {
          if (! isEmpty ( trim ( $line ) ))
          {
            $values = str_getcsv ( $line ); // ,";","\"","\\");
            if ($index == 0)
            {
              $container->columns = $values;
            }
            else
            {
              $container->processes [] = $values;
              $container->infos [] = new ProcessInfo ( $values, $columns );
            }
            
            $index ++;
          }
        }
        return $container;
      }
      else
        Yii::log ( "getProcesses :: no output from 'tasklist'", CLogger::LEVEL_WARNING );
    }
    else
      Yii::log ( "getProcesses :: tool 'tasklist' not found", CLogger::LEVEL_WARNING );
    return null;
  }

  public static function php_getExePath()
  {
    $path = "C:\\php\\php.exe";
    if (fileExists ( $path ))
      return $path;
    return null;
  }

  public static function php_getBaseFolderPath()
  {
    $path = self::php_getExePath ();
    if (fileExists ( $path ))
      return dirname ( $path );
    return null;
  }

  public static function php_getIniPath()
  {
    $phpIni = php_ini_loaded_file ();
    if (fileExists ( $phpIni ))
      return $phpIni;
    $phpIni = get_cfg_var ( 'cfg_file_path' );
    if (fileExists ( $phpIni ))
      return $phpIni;
    return null;
  }

  public static function php_addExtension($name)
  {
    $iniPath = DebugHelper::php_getIniPath ();
    if (fileExists ( $iniPath ))
    {
      $ini = ini_file_to_array ( $iniPath );
      
      $phpSection = $ini ['PHP']; // get_first_not_empty($ini['PHP'],$ini['php'],$ini['Php']);
      if (isEmpty ( $phpSection ))
        $phpSection = array ();
      
      $extensions = $phpSection ['extension']; // get_first_not_empty($ini['extension'],$ini['extensions']);
      if (isEmpty ( $extensions ))
        $extensions = array ();
      if (! is_array ( $extensions ))
        $extensions = array (
            $extensions 
        );
      
      if (array_value_exists ( $extensions, $name ))
        return true;
      $extensions [] = $name;
      $extensions = array_sort ( $extensions );
      $phpSection ['extension'] = $extensions;
      $ini ['PHP'] = $phpSection;
      
      $iniName = basename ( $iniPath );
      $iniDir = dirname ( $iniPath );
      $bckIni = pathCombine ( $iniDir, "bck_" . DateTimeEx::now ()->toFilesafeDateTimeString () . "_" . $iniName );
      if (copy ( $iniPath, $bckIni ))
      {
        return ini_file_from_array ( $ini, $iniPath );
      }
    }
    return false;
  }

  public static function php_removeExtension($name)
  {
    $iniPath = DebugHelper::php_getIniPath ();
    if (fileExists ( $iniPath ))
    {
      $ini = ini_file_to_array ( $iniPath );
      
      $phpSection = $ini ['PHP']; // get_first_not_empty($ini['PHP'],$ini['php'],$ini['Php']);
      if (isEmpty ( $phpSection ))
        $phpSection = array ();
      
      $extensions = $phpSection ['extension']; // get_first_not_empty($ini['extension'],$ini['extensions']);
      if (isEmpty ( $extensions ))
        $extensions = array ();
      if (! is_array ( $extensions ))
        $extensions = array (
            $extensions 
        );
      
      if (! array_value_exists ( $extensions, $name ))
        return true;
      
      unset ( $extensions [$name] );
      
      $extensions = array_sort ( $extensions );
      $phpSection ['extension'] = $extensions;
      $ini ['PHP'] = $phpSection;
      
      $iniName = basename ( $iniPath );
      $iniDir = dirname ( $iniPath );
      $bckIni = pathCombine ( $iniDir, "bck_" . DateTimeEx::now ()->toFilesafeDateTimeString () . "_" . $iniName );
      if (copy ( $iniPath, $bckIni ))
      {
        return ini_file_from_array ( $ini, $iniPath );
      }
    }
    return false;
  }

  public static function php_getIniExtensions()
  {
    $ini = DebugHelper::php_getIniPath ();
    $extensions = array ();
    if (fileExists ( $ini ))
    {
      $data = file_get_contents ( $ini );
      $lines = explode ( PHP_EOL, $data );
      $lineIndex = 0;
      foreach ( $lines as $line )
      {
        $line = trim ( $line );
        $name = startsWithGet ( $line, "extension=", false, 0, startsWithGet ( $line, ";extension=", false, 0, null ) );
        
        if (! isEmpty ( $name ))
        {
          $ext = new CArray ();
          
          $ext->id = strtolower ( $name );
          $ext->name = $name;
          $ext->loaded = ! startsWith ( $line, ";" );
          $ext->line = $lineIndex;
          
          $extensions [$ext->id] = $ext;
        }
        
        $lineIndex ++;
      }
    }
    return $extensions;
  }

  public static function php_getExtensionFolderPath()
  {
    $path = self::php_getBaseFolderPath ();
    if (dirExists ( $path ))
    {
      $path = pathCombine ( $path, 'ext' );
      if (dirExists ( $path ))
        return $path;
    }
    return null;
  }

  public static function getServices()
  {
    $tools = self::getSystemTools ();
    // logObj($tools);
    $services = array ();
    if (! isEmpty ( $tools ['sc'] ))
    {
      $output = shell_exec ( "\"$tools[sc]\" query 2>&1" );
      $lines = explode_ex ( array (
          "\n",
          "\r" 
      ), $output );
      // logObj(count($lines));
      foreach ( $lines as $line )
      {
        $line = trim ( $line );
        $serviceName = startsWithGet ( $line, "SERVICE_NAME: " );
        if (! isEmpty ( $serviceName ))
        {
          $services [] = $serviceName;
        }
      }
    }
    else
      Yii::log ( "getServices :: tool 'sc' not found", CLogger::LEVEL_WARNING );
    return $services;
  }

  /**
   *
   * @return ServiceInfo[]
   */
  public static function getServicesEx()
  {
    $tools = self::getSystemTools ();
    // logObj($tools);
    $services = array ();
    if (! isEmpty ( $tools ['sc'] ))
    {
      $output = shell_exec ( "\"$tools[sc]\" queryex 2>&1" );
      $lines = explode_ex ( array (
          "\n",
          "\r" 
      ), $output );
      // logObj(count($lines));
      $currentService = null;
      foreach ( $lines as $line )
      {
        $line = trim ( $line );
        $serviceName = startsWithGet ( $line, "SERVICE_NAME: " );
        if (! isEmpty ( $serviceName ))
        {
          if ($currentService != null)
            $services [] = $currentService;
          $currentService = new ServiceInfo ( $serviceName );
        }
        else
        {
          if ($currentService != null)
          {
            $value = startsWithGet ( $line, "DISPLAY_NAME: " );
            if (! isEmpty ( $value ))
              $currentService->description = $value;
            else
            {
              $value = startsWithGet ( $line, "TYPE               : " );
              if (! isEmpty ( $value ))
                $currentService->type = $value;
              else
              {
                $value = startsWithGet ( $line, "STATE              : " );
                if (! isEmpty ( $value ))
                  $currentService->state = $value;
                else
                {
                  $value = startsWithGet ( $line, "WIN32_EXIT_CODE    : " );
                  if (! isEmpty ( $value ))
                    $currentService->win32ExitCode = $value;
                  else
                  {
                    $value = startsWithGet ( $line, "SERVICE_EXIT_CODE  : " );
                    if (! isEmpty ( $value ))
                      $currentService->serviceExitCode = $value;
                    else
                    {
                      $value = startsWithGet ( $line, "CHECKPOINT         : " );
                      if (! isEmpty ( $value ))
                        $currentService->checkpoint = $value;
                      else
                      {
                        $value = startsWithGet ( $line, "WAIT_HINT          : " );
                        if (! isEmpty ( $value ))
                          $currentService->waithint = $value;
                        else
                        {
                          $value = startsWithGet ( $line, "PID                : " );
                          if (! isEmpty ( $value ))
                            $currentService->pid = $value;
                          else
                          {
                            $value = startsWithGet ( $line, "FLAGS              : " );
                            if (! isEmpty ( $value ))
                              $currentService->flags = $value;
                            else
                            {
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    else
      Yii::log ( "getServicesEx :: tool 'sc' not found", CLogger::LEVEL_WARNING );
    return $services;
  }

  public static function getProgramFilesArray()
  {
    return array (
        getenv ( "ProgramFiles" ),
        "C:\\Programmi",
        "C:\\Program Files (x86)",
        "C:\\Program Files",
        "c:\\Bitnami\\wampstack-5.5.30-0\\" 
    );
  }

  public static function getProgramFilesPath()
  {
    $programFilesArray = self::getProgramFilesArray ();
    foreach ( $programFilesArray as $path )
      if (dirExists ( $path ))
        return $path;
    return null;
  }

  /**
   * ******************************
   */
  /* APACHE */
  /**
   * ******************************
   */
  public static function apache_getPath()
  {
    $programFilesArray = self::getProgramFilesArray ();
    foreach ( $programFilesArray as $programFiles )
      if (dirExists ( $programFiles ))
      {
        foreach ( getDirectories ( $programFiles ) as $dir )
        {
          if (containsStr ( $dir, "apache" ))
          {
            if (dirExists ( $dir ))
            {
              $bin = array_first ( getDirectories ( $dir, "bin", true ) );
              if (! isEmpty ( $bin ))
              {
                return dirname ( $bin );
              }
            }
          }
        }
      }
    return null;
  }

  public static function apache_getServicesName()
  {
    $services = self::getServices ();
    $apacheServiceName = array ();
    foreach ( $services as $svc )
    {
      if (containsStr ( $svc, "apache", true ))
      {
        $apacheServiceName [] = $svc;
      }
    }
    return implode ( " - ", $apacheServiceName );
  }

  public static function apache_getServiceName()
  {
    $apaches = self::apache_getServicesName ();
    return count ( $apaches ) > 1 ? $apaches : array_first ( $apaches );
  }

  public static function apache_canRestart()
  {
    $apache = self::apache_getServiceName ();
    return ! isEmpty ( $apache );
  }

  public static function apache_restart()
  {
    $restartBat = pathCombine ( app ()->runtimePath, "restart_apache.bat" );
    $apache = self::apache_getServiceName ();
    file_append_line ( $restartBat, "net stop $apache", true );
    file_append_line ( $restartBat, "net start $apache" );
    shell_exec ( "\"$restartBat\"" );
  }

  public static function apache_getConfigPath()
  {
    $path = self::apache_getPath ();
    if (dirExists ( $path ))
    {
      $filename = pathCombine ( $path, "conf", "httpd.conf" );
      if (fileExists ( $filename ))
        return $filename;
    }
    return null;
  }

  /**
   * ******************************
   */
  /* MYSQL */
  /**
   * ******************************
   */
  public static function mysql_getPath()
  {
    $mysqlPath = "D:\\MYSQL\\";
    if (dirExists ( $mysqlPath ))
      return $mysqlPath;
    return null;
  }

  public static function mysql_getServiceName()
  {
    $services = self::getServices ();
    $apacheServiceName = array ();
    foreach ( $services as $svc )
    {
      if (containsStr ( $svc, "mysql", true ))
      {
        $apacheServiceName [] = $svc;
      }
    }
    return implode ( " - ", $apacheServiceName );
  }

  public static function mysql_restart()
  {
    $restartBat = pathCombine ( app ()->runtimePath, "restart_mysql.bat" );
    $mysql = self::mysql_getServiceName ();
    file_append_line ( $restartBat, "net stop $mysql", true );
    file_append_line ( $restartBat, "net start $mysql" );
    shell_exec ( "\"$restartBat\"" );
  }

  public static function mysql_getConfigPath()
  {
    $path = self::mysql_getPath ();
    if (! isEmpty ( $path ))
    {
      $filename = pathCombine ( $path, "my.ini" );
      if (fileExists ( $filename ))
        return $filename;
    }
    return null;
  }

  /**
   *
   * @return MigrationsInfo
   */
  public static function getMigrationsInfo()
  {
    $dbMigrations = Migration::model ()->findAll ( array (
        'order' => 'version DESC' 
    ) );
    $dbMigrations = array_remap ( $dbMigrations, function ($k, $v)
    {
      $key = strtolower ( $v->version );
      return $key;
    } );
    
    foreach ( $dbMigrations as $dbmk => $dbmv )
      if (! array_value_exists ( $allMigrations, $dbmk ))
        $allMigrations [] = $dbmk;
    
    $allMigrations = array ();
    
    $migDir = new DirectoryIterator ( pathCombine ( app ()->basePath, 'migrations' ) );
    $fileMigrations = array ();
    foreach ( $migDir as $migFile )
    {
      if ($migFile->isFile ())
      {
        $ext = $migFile->getExtension ();
        if (strtoupper ( $ext ) == "PHP")
        {
          $fm = new CArray ();
          $filename = $migFile->getFilename ();
          $migrationName = strtolower ( substr ( $filename, 0, strlen ( $filename ) - 4 ) );
          
          if (! array_value_exists ( $allMigrations, $migrationName ))
            $allMigrations [] = $migrationName;
          
          $applied = array_key_exists ( $migrationName, $dbMigrations );
          
          $fm->filename = $migFile->getFilename ();
          $fm->name = $migrationName;
          $fm->path = $migFile->getRealPath ();
          $fm->dir = $migFile->getPath ();
          $fm->applied = $applied;
          
          $fm->model = $applied ? $dbMigrations [$migrationName] : null;
          
          $fileMigrations [$migrationName] = $fm;
        }
      }
    }
    
    $allMigrations = array_sort ( $allMigrations, null, false, true );
    
    $info = new MigrationsInfo ();
    
    $info->allMigrations = $allMigrations;
    $info->dbMigrations = $dbMigrations;
    $info->fileMigrations = $fileMigrations;
    
    return $info;
  }
}

class ScheduledTask
{

  public $rawData;

  public $columns;

  /*
   * [0=Nome host]
   * [1=Nome operazione]
   * [2=Prossima esecuzione]
   * [3=Stato]
   * [4=Ultima esecuzione]
   * [5=Ultimo esito]
   * [6=Autore]
   * [7=Pianificazione]
   * [8=Operazione da eseguire]
   * [9=Avvia in]
   * [10=Commento]
   * [11=Stato operazione pianificata]
   * [12=Tipo di pianificazione]
   * [13=Ora di avvio]
   * [14=Data di avvio]
   * [15=Data di fine]
   * [16=giorni]
   * [17=mesi]
   * [18=Esegui come utente]
   * [19=Elimina l'operazione se non ripianificata]
   * [20=Interrompi l'operazione se è in esecuzione da X ore e X minuti]
   * [21=Ripeti: Ogni] [22=Ripeti: Fino a: Ora]
   * [23=Ripeti: Fino a: Durata]
   * [24=Ripeti: Interrompi se ancora in esecuzione]
   * [25=Tempo di inattività]
   * [26=Risparmio energia]
   */
  public function __construct($rd = array(), $cols = array())
  {
    $this->rawData = $rd;
    $this->columns = $cols;
  }

  public function getName()
  {
    return $this->rawData [1];
  }

  public function getNextRun()
  {
    return $this->rawData [2];
  }

  public function getCommand()
  {
    return $this->rawData [8];
  }

  public function getLastRun()
  {
    return $this->rawData [4];
  }

  public function getEnabled()
  {
    return $this->rawData [11];
  }
}

class ProcessesInfo
{

  /**
   *
   * @var array
   */
  public $processes = array ();

  /**
   *
   * @var string[]
   */
  public $columns = array ();

  /**
   *
   * @var ProcessInfo[]
   */
  public $infos = array ();
}

class ServiceInfo
{

  public $name;

  public $description;

  public $type;

  public $state;

  public $win32ExitCode;

  public $serviceExitCode;

  public $checkpoint;

  public $waithint;

  public $pid;

  public $flags;

  public function __construct($nm)
  {
    $this->name = $nm;
  }

  public function __toString()
  {
    return $this->name;
  }

  public function toArray()
  {
    return array (
        $this->name,
        $this->description,
        $this->type,
        $this->state,
        $this->win32ExitCode,
        $this->serviceExitCode,
        $this->checkpoint,
        $this->waithint,
        $this->pid,
        $this->flags 
    );
  }
}

class ProcessInfo
{

  public $rawData;

  public $columns;

  /*
   * 0=>"Name",
   * 1=>"PID",
   * 2=>"Session name",
   * 3=>"Session #",
   * 4=>"Memory",
   * 5=>"Status",
   * 6=>"User",
   * 7=>"CPU time",
   * 8=>"Window title",
   */
  public function __construct($rd = array(), $cols = array())
  {
    $this->rawData = $rd;
    $this->columns = $cols;
  }

  public function getName()
  {
    return $this->rawData [0];
  }

  public function getPid()
  {
    return $this->rawData [1];
  }
}

class MigrationsInfo
{

  public $dbMigrations = array ();

  public $fileMigrations = array ();

  public $allMigrations = array ();
}