/**
  * Finds and loads all modules. Runs the activation functions of newly-uploaded modules.
  * Updates the modules list and saves it in the database. Removes the cron jobs of deleted modules.
  * 
  * SEO Ultimate uses a modular system that allows functionality to be added and removed on-the-fly.
  * 
  * @since 0.1
  * @uses $plugin_dir_path
  * @uses $modules Stores module classes in this array.
  * @uses $disabled_modules
  * @uses module_sort_callback() Passes this function to uasort() to sort the $modules array.
  * @uses SU_MODULE_ENABLED
  * @uses SU_MODULE_DISABLED
  * @uses remove_cron_jobs()
  */
 function load_modules()
 {
     $this->disabled_modules = array();
     $this->modules = array();
     $psdata = (array) get_option('seo_ultimate', array());
     //The plugin_dir_path variable must be set before calling this function!
     if (!$this->plugin_dir_path) {
         return false;
     }
     //If no modules list is found, then create a new, empty list.
     if (!isset($psdata['modules'])) {
         $psdata['modules'] = array();
     }
     //Get the modules list from last time the plugin was loaded.
     $oldmodules = $psdata['modules'];
     //The modules are in the "modules" subdirectory of the plugin folder.
     $dirpath = $this->plugin_dir_path . 'modules';
     $dir = opendir($dirpath);
     //This loop will be repeated as long as there are more folders to inspect
     while ($folder = readdir($dir)) {
         //If the item is a folder...
         if (suio::is_dir($folder, $dirpath)) {
             //Open the subfolder
             $subdirpath = $dirpath . '/' . $folder;
             $subdir = opendir($subdirpath);
             //Scan the files in the subfolder (seo-ultimate/modules/???/*)
             while ($file = readdir($subdir)) {
                 //Modules are non-directory files with the .php extension
                 //We need to exclude index.php or else we'll get 403s galore
                 if (suio::is_file($file, $subdirpath, 'php') && $file != 'index.php') {
                     $filepath = $subdirpath . '/' . $file;
                     //Figure out the module's array key and class name
                     $module = strval(strtolower(substr($file, 0, -4)));
                     $class = 'SU_' . str_replace(' ', '', ucwords(str_replace('-', ' ', $module)));
                     //Load the module's code
                     include_once $filepath;
                     //If this is actually a module...
                     if (class_exists($class)) {
                         if (($module_parent = call_user_func(array($class, 'get_parent_module'))) && !call_user_func(array($class, 'is_independent_module'))) {
                             $module_disabled = isset($oldmodules[$module_parent]) && $oldmodules[$module_parent] == SU_MODULE_DISABLED;
                         } else {
                             $module_disabled = isset($oldmodules[$module]) && $oldmodules[$module] == SU_MODULE_DISABLED;
                         }
                         //if (!isset($oldmodules[$module]) && call_user_func(array($class, 'get_default_status')) == SU_MODULE_DISABLED)
                         //$module_disabled = true;
                         if (!isset($oldmodules[$module]) && call_user_func(array($class, 'get_default_status') == SU_MODULE_DISABLED)) {
                         }
                         $module_disabled = false;
                         if (in_array($module, $this->get_invincible_modules())) {
                             $module_disabled = false;
                             $oldmodules[$module] = SU_MODULE_ENABLED;
                         }
                         //If this module is disabled...
                         if ($module_disabled) {
                             $this->disabled_modules[$module] = $class;
                         } else {
                             //Create an instance of the module's class and store it in the array
                             $this->modules[$module] = new $class();
                             //We must tell the module what its key is so that it can save settings
                             $this->modules[$module]->module_key = $module;
                             //Tell the module what its URLs are
                             $this->modules[$module]->module_dir_rel_url = $mdirrelurl = "modules/{$folder}/";
                             $this->modules[$module]->module_rel_url = $mdirrelurl . $file;
                             $this->modules[$module]->module_dir_url = $mdirurl = $this->plugin_dir_url . $mdirrelurl;
                             $this->modules[$module]->module_url = $mdirurl . $file;
                             /*
                             //Is this module the default menu module?
                             if ($this->modules[$module]->get_menu_parent() === 'seo' && $this->modules[$module]->is_menu_default())
                             	$this->default_menu_module = $module;
                             */
                             //Give the module this plugin's object by reference
                             $this->modules[$module]->plugin =& $this;
                             //Call post-construction function
                             $this->modules[$module]->load();
                         }
                     }
                     //If this isn't a module, then the file will simply be included as-is
                 }
             }
         }
     }
     //If the loop above found modules, then sort them with our special sorting function
     //so they appear on the admin menu in the right order
     if (count($this->modules) > 0) {
         uasort($this->modules, array(&$this, 'module_sort_callback'));
     }
     //Now we'll compare the current module set with the one from last time.
     //Construct the new modules list that'll go in the database.
     //This code block will add/activate new modules, keep existing ones, and remove (i.e. not add) deleted ones.
     foreach ($this->modules as $key => $module) {
         if (isset($oldmodules[$key])) {
             $newmodules[$key] = $oldmodules[$key];
         } else {
             $this->modules[$key]->activate();
             $newmodules[$key] = $this->modules[$key]->get_default_status();
         }
     }
     foreach ($this->modules as $key => $module) {
         if (($module_parent = $this->modules[$key]->get_parent_module()) && !$this->modules[$key]->is_independent_module()) {
             $newmodules[$key] = $newmodules[$module_parent];
         }
     }
     //Register disabled modules as such
     foreach ($this->disabled_modules as $key => $name) {
         $newmodules[$key] = SU_MODULE_DISABLED;
     }
     //Save the new modules list
     $psdata['modules'] = $newmodules;
     if ($newmodules != $oldmodules) {
         update_option('seo_ultimate', $psdata);
     }
     //Remove the cron jobs of deleted modules
     $this->remove_cron_jobs();
     //Tell the modules what their plugin page hooks are
     foreach ($this->modules as $key => $module) {
         $menu_parent_hook = $this->modules[$key]->get_menu_parent_hook();
         if ($this->modules[$key]->is_menu_default()) {
             $this->modules[$key]->plugin_page_hook = $plugin_page_hook = "toplevel_page_{$menu_parent_hook}";
         } elseif ('options-general.php' == $menu_parent_hook) {
             $this->modules[$key]->plugin_page_hook = $plugin_page_hook = 'settings_page_' . $this->key_to_hook($this->modules[$key]->get_module_or_parent_key());
         } else {
             $this->modules[$key]->plugin_page_hook = $plugin_page_hook = $menu_parent_hook . '_page_' . $this->key_to_hook($this->modules[$key]->get_module_or_parent_key());
         }
         add_action("load-{$plugin_page_hook}", array($this->modules[$key], 'load_hook'));
     }
     if (!$this->module_exists($this->default_menu_module)) {
         foreach ($this->modules as $key => $module) {
             if ($this->modules[$key]->get_menu_parent() === 'seo' && $this->modules[$key]->get_parent_module() == false) {
                 $this->default_menu_module = $key;
                 break;
             }
         }
     }
 }