/**
  * Various module interactions
  * 	
  * Actions:
  *  list - Lists installed modules
  *  list-remote - Lists available modules
  *    --server=nthalk.com
  *  install - installs a remote package
  *    --dir=app/modules
  *    --server=nthalk.com
  *    --as-git-submodule
  *    --as-git-repo
  *	uninstall - removes a module
  */
 public function modules($like = array(), $options = array())
 {
     $action = array_shift($like);
     if (isset($options['server'])) {
         $server = $options['server'];
     } else {
         $server = 'nthalk.com';
     }
     if ($action == 'uninstall') {
         $module = array_shift($like);
         $module_dir = Framework::moduleInstalled($module);
         if (!$module_dir) {
             $this->write("Module does not appear to be installed: {$module}\n");
             return;
         }
         $this->write("Uninstalling: {$module}\n");
         $this->write("Running uninstall scripts...\n");
         if (method_exists($module, 'uninstall')) {
             if (!call_user_func(array($module, 'uninstall')) || isset($options['force'])) {
                 $this->write("Uninstaller failed... Please inspect {$module}::uninstall() before completely removing or supply --force\n");
                 return;
             }
         }
         $this->write("Removing submodule from app/.git cache...\n");
         $cmd = 'git rm --cached ' . $module_dir;
         //$this->write($cmd . "\n");
         $cmd_p = popen($cmd, 'r');
         $this->write(fread($cmd_p, 10000) . "\n");
         $dir = SERVER_APP_DIR;
         $git_submodules_file = $dir . '/.gitmodules';
         if (file_exists($git_submodules_file)) {
             $git_submodules = file_get_contents($git_submodules_file);
             $match = "/\\[submodule.*{$module}\"\\]\\s+path.*\\s+url.*\\s?/";
             if (preg_match($match, $git_submodules)) {
                 $git_submodules_new = preg_replace($match, '', $git_submodules);
                 $git_submodules_new = preg_replace("/\n+/", "\n", $git_submodules_new);
                 $this->write("Removing submodule from submodules...\n");
                 //$this->write($git_submodules_new . "\n");
                 file_put_contents($git_submodules_file, $git_submodules_new);
             }
         }
         $git_conf_file = $dir . '/.git/config';
         if (file_exists($git_conf_file)) {
             $git_conf = file_get_contents($git_conf_file);
             $match = "/\\[submodule.*{$module}\"\\](\\s+path.*|\\s+url.*)+?\\s?/";
             if (preg_match($match, $git_conf)) {
                 $git_conf_new = preg_replace($match, '', $git_conf);
                 $git_conf_new = preg_replace("/\n+/", "\n", $git_conf_new);
                 $this->write("Removing submodule from config...\n");
                 //$this->write($git_conf_new . "\n");
                 file_put_contents($git_conf_file, $git_conf_new);
             }
         }
         $this->write("Removing submodule from file system...\n");
         $cmd = 'rm -rf ' . $module_dir;
         //$this->write($cmd . "\n");
         $cmd_p = popen($cmd, 'r');
         $this->write(fread($cmd_p, 10000) . "\n");
         $this->write("Done. It is up to you to commit this change into your app repo...\n");
     } else {
         if ($action == 'list') {
             $this->write("Currently installed modules:\n\n");
             foreach (Framework::moduleList(array_shift($like)) as $module) {
                 $this->write(' ' . $module . ' -' . $this->getDocumentation(new ReflectionClass($module)));
             }
             $this->write("\n");
         } else {
             if ($action == 'list-remote') {
                 $content = file_get_contents("http://{$server}/Packages");
                 $packages = json_decode($content);
                 if (!is_array($packages)) {
                     $this->write('Error retrieving data from module server: ' . $server . "\n");
                 } else {
                     foreach ($packages as $package) {
                         $this->write($package->name . " - " . $package->version . "\n");
                     }
                 }
             } else {
                 if ($action == 'install') {
                     if (realpath(getcwd()) !== SERVER_APP_DIR) {
                         $this->write("fatal: You must install modules from the root of your app dir ( " . SERVER_APP_DIR . " )\n");
                         return;
                     }
                     $content = file_get_contents("http://{$server}/Packages");
                     $packages = json_decode($content);
                     if (!is_array($packages)) {
                         $this->write('Error retrieving data from module server: ' . $server . "\n");
                         exit - 1;
                     } else {
                         $what = array_shift($like);
                     }
                     foreach ($packages as $package) {
                         if ($package->name == $what) {
                             // Define the dir
                             $dir = SERVER_EXT_DIR;
                             if (!file_exists($dir)) {
                                 $dir_parts = explode('/', $dir);
                                 $curr_dir = '';
                                 do {
                                     $curr_dir .= '/' . array_shift($dir_parts);
                                     if (!file_exists($curr_dir)) {
                                         mkdir($curr_dir);
                                     }
                                 } while (!file_exists($dir));
                             }
                             // If app is git repo
                             $app_is_git = file_exists(SERVER_APP_DIR . '/.git');
                             // Install directory
                             $dir .= '/modules/';
                             if (!file_exists($dir)) {
                                 mkdir($dir);
                             }
                             $dir .= $package->name;
                             $dir = substr($dir, strlen(SERVER_APP_DIR) + 1);
                             if (isset($options['as-git-submodule'])) {
                                 if (!$app_is_git) {
                                     $this->write('fatal: app is not a git repo. Please run `git init` within ' . SERVER_APP_DIR . "\n");
                                     exit - 1;
                                 }
                                 $cmd = 'git submodule add ' . $package->git_url . ' ' . $dir;
                             } else {
                                 $cmd = 'git clone --depth 0 ' . $package->git_url . ' ' . $dir;
                             }
                             $this->write("Retrieving package {$what}...\t");
                             $this->write("\ncmd: {$cmd}\n");
                             if (shell_exec($cmd)) {
                                 if (!isset($options['as-git-repo']) && !isset($options['as-git-submodule'])) {
                                     if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                                         exec("rd /s {$dir}/.git");
                                     } else {
                                         if (!$app_is_git) {
                                             $this->write('warning: app is not a git repo. Installing modules this way may pollute the framework and prevent you from having your application as a standalone repository. Please run `git init` within app to avoid this warning.' . "\n");
                                         }
                                         exec("rm -rf {$dir}/.git");
                                     }
                                 }
                                 $this->write("[Success]\n");
                                 // If the module has a configuration function, run that on install
                                 if (method_exists($what, 'setup')) {
                                     call_user_func_array(array($what, 'setup'), array($this->out_stream, $this->in_stream));
                                 }
                                 $this->write("Package installed!\n");
                                 exit;
                             } else {
                                 exit - 1;
                             }
                         }
                     }
                     $this->write('Package: ' . json_encode($what) . ' not found.' . "\n");
                 } else {
                     $this->write("Usage: nth action [ARGS] [[--option=setting]]\n\n");
                     $this->write($this->getDocumentation(new ReflectionMethod($this, __FUNCTION__), true));
                 }
             }
         }
     }
 }