/**
  * Imports a set XMLArchive
  *
  * @access	public
  * @param	string		XMLArchive content to import
  * @param	int 		[ Skin set parent. If omitted, it will be made a root skin ]
  * @param	string		[ Images directory to use. If omitted, default skin's image dir is used ]
  * @param	string		[ Name of skin to create. If omitted, name from skin set is used ]
  * @return	mixed		bool, or number of items added
  */
 public function importSetXMLArchive($content, $parentID = 0, $imageDir = '', $setName = '')
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $templates = array();
     $csss = array();
     $groups = array();
     $defaultSkin = array();
     $return = array('replacements' => 0, 'css' => 0, 'templates' => 0);
     //-----------------------------------------
     // Got anything?
     //-----------------------------------------
     if (!strstr($content, "<xmlarchive")) {
         $this->_addErrorMessage("The content was not a valid XMLArchive");
         return FALSE;
     }
     //-----------------------------------------
     // Make admin group list
     //-----------------------------------------
     foreach ($this->caches['group_cache'] as $id => $data) {
         if ($data['g_access_cp']) {
             $groups[] = $id;
         }
     }
     //-----------------------------------------
     // Grab the XMLArchive class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
     $xmlArchive = new classXMLArchive();
     $xmlArchive->readXML($content);
     if (!$xmlArchive->countFileArray()) {
         $this->_addErrorMessage("The XMLArchive is empty");
         return FALSE;
     }
     //-----------------------------------------
     // Gather data
     //-----------------------------------------
     /* Info */
     $infoXml = $xmlArchive->getFile('info.xml');
     if (!$infoXml) {
         $this->_addErrorMessage("The info.xml file is empty or was not included");
         return FALSE;
     }
     $info = $this->parseInfoXML($infoXml);
     /* Replacements */
     $replacements = $this->parseReplacementsXML($xmlArchive->getFile('replacements.xml'));
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'templates' && $fileData['content']) {
             $templates[str_replace('.xml', '', $fileData['filename'])] = $this->parseTemplatesXML($fileData['content']);
         }
     }
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'css') {
             $csss[str_replace('.xml', '', $fileData['filename'])] = $this->parseCSSXML($fileData['content']);
         }
     }
     if (!is_array($info)) {
         $this->_addErrorMessage("The XMLArchive does not contain an info.xml file");
         return FALSE;
     }
     $info['set_output_format'] = $info['set_output_format'] ? $info['set_output_format'] : 'html';
     //-----------------------------------------
     // Find default skin
     //-----------------------------------------
     foreach ($this->registry->output->allSkins as $id => $data) {
         if ($data['set_is_default'] and $data['set_output_format'] == $info['set_output_format']) {
             $defaultSkin = $data;
             break;
         }
     }
     //-----------------------------------------
     // Build Set Array
     //-----------------------------------------
     $newSet = array('set_name' => $setName ? $setName : $info['set_name'] . ' (Import)', 'set_key' => '', 'set_parent_id' => $parentID, 'set_permissions' => implode(",", $groups), 'set_is_default' => 0, 'set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_image_dir' => $imageDir ? $imageDir : $defaultSkin['set_image_dir'], 'set_emo_dir' => $defaultSkin['set_emo_dir'], 'set_css_inline' => 0, 'set_output_format' => $info['set_output_format'], 'set_css_groups' => '', 'set_hide_from_list' => 1, 'set_updated' => time());
     //-----------------------------------------
     // Insert...
     //-----------------------------------------
     $this->DB->insert('skin_collections', $newSet);
     $setID = $this->DB->getInsertId();
     /* Rebuild trees */
     $this->rebuildTreeInformation($setID);
     /* Now re-load to fetch the tree information */
     $newSet = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_id=' . $setID));
     /* Add to allSkins array for caching functions below */
     $newSet['_parentTree'] = unserialize($newSet['set_parent_array']);
     $newSet['_childTree'] = unserialize($newSet['set_child_array']);
     $newSet['_userAgents'] = unserialize($newSet['set_locked_uagent']);
     $newSet['_cssGroupsArray'] = unserialize($newSet['set_css_groups']);
     $this->registry->output->allSkins[$setID] = $newSet;
     //-----------------------------------------
     // Replacements...
     //-----------------------------------------
     if (is_array($replacements)) {
         foreach ($replacements as $replacement) {
             if ($replacement['replacement_key']) {
                 $return['replacements']++;
                 $this->DB->insert('skin_replacements', array('replacement_key' => $replacement['replacement_key'], 'replacement_content' => $replacement['replacement_content'], 'replacement_set_id' => $setID, 'replacement_added_to' => $setID));
             }
         }
     }
     //-----------------------------------------
     // CSS...
     //-----------------------------------------
     /* Fetch master CSS */
     $_MASTER = $this->fetchCSS(0);
     $apps = new IPSApplicationsIterator();
     if (is_array($csss)) {
         foreach ($apps as $app) {
             $appDir = $apps->fetchAppDir();
             if (isset($csss[$appDir]) && is_array($csss[$appDir])) {
                 foreach ($csss[$appDir] as $css) {
                     if ($css['css_group']) {
                         $return['css']++;
                         $this->DB->insert('skin_css', array('css_group' => $css['css_group'], 'css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app' => $css['css_app'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_set_id' => $setID, 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID));
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Templates - only import apps we have...
     //-----------------------------------------
     /* Fetch all master items */
     $_MASTER = $this->fetchTemplates(0, 'allNoContent');
     $apps = new IPSApplicationsIterator();
     if (is_array($templates)) {
         foreach ($apps as $app) {
             $appDir = $apps->fetchAppDir();
             if (array_key_exists($appDir, $templates)) {
                 foreach ($templates[$appDir] as $template) {
                     if ($template['template_group'] and $template['template_name']) {
                         /* Figure out if this is added by a user or not */
                         $isAdded = (is_array($_MASTER[$template['template_group']][strtolower($template['template_name'])]) and !$_MASTER[$template['template_group']][strtolower($template['template_name'])]['template_user_added']) ? 0 : 1;
                         $return['templates']++;
                         $this->DB->insert('skin_templates', array('template_set_id' => $setID, 'template_group' => $template['template_group'], 'template_content' => $template['template_content'], 'template_name' => $template['template_name'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'], 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID));
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Re-cache
     //-----------------------------------------
     $this->rebuildReplacementsCache($setID);
     $this->rebuildCSS($setID);
     $this->rebuildPHPTemplates($setID);
     $this->rebuildSkinSetsCache();
     //-----------------------------------------
     // Done....
     //-----------------------------------------
     return $return;
 }
 /**
  * Imports a set XMLArchive
  *
  * @access	public
  * @param	string		XMLArchive content to import
  * @param	int 		[ Skin set parent. If omitted, it will be made a root skin ]
  * @param	string		[ Images directory to use. If omitted, default skin's image dir is used ]
  * @param	string		[ Name of skin to create. If omitted, name from skin set is used ]
  * @param	bool		[ Whether or not we are attempting to upgrade an existing skin ]
  * @return	mixed		bool, or number of items added
  */
 public function importSetXMLArchive($content, $parentID = 0, $imageDir = '', $setName = '', $upgrading = FALSE)
 {
     //-----------------------------------------
     // INIT
     //-----------------------------------------
     $templates = array();
     $csss = array();
     $groups = array();
     $defaultSkin = array();
     $return = array('replacements' => 0, 'css' => 0, 'templates' => 0, 'upgrade' => FALSE);
     //-----------------------------------------
     // Got anything?
     //-----------------------------------------
     if (!strstr($content, "<xmlarchive")) {
         $this->_addErrorMessage($this->lang->words['invalidxmlarchivei']);
         return FALSE;
     }
     //-----------------------------------------
     // Make admin group list
     //-----------------------------------------
     foreach ($this->caches['group_cache'] as $id => $data) {
         if ($data['g_access_cp']) {
             $groups[] = $id;
         }
     }
     //-----------------------------------------
     // Grab the XMLArchive class
     //-----------------------------------------
     require_once IPS_KERNEL_PATH . 'classXMLArchive.php';
     /*noLibHook*/
     $xmlArchive = new classXMLArchive();
     $xmlArchive->readXML($content);
     if (!$xmlArchive->countFileArray()) {
         $this->_addErrorMessage($this->lang->words['emptyxmlarchivei']);
         return FALSE;
     }
     //-----------------------------------------
     // Gather data
     //-----------------------------------------
     /* Info */
     $infoXml = $xmlArchive->getFile('info.xml');
     if (!$infoXml) {
         $this->_addErrorMessage($this->lang->words['noinfoxml']);
         return FALSE;
     }
     $info = $this->parseInfoXML($infoXml);
     /* Are we attempting to upgrade? */
     $setID = 0;
     $doUpgrade = FALSE;
     $new_items = array('replacements' => array(), 'css' => array(), 'templates' => array());
     if ($info['set_key'] && $upgrading) {
         foreach ($this->caches['skinsets'] as $set_id => $set_data) {
             if ($set_data['set_key'] == $info['set_key']) {
                 $setID = $set_id;
                 $doUpgrade = TRUE;
                 $return['upgrade'] = TRUE;
                 break;
             }
         }
     }
     /* Replacements */
     $replacements = $this->parseReplacementsXML($xmlArchive->getFile('replacements.xml'));
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'templates' && $fileData['content']) {
             $templates[str_replace('.xml', '', $fileData['filename'])] = $this->parseTemplatesXML($fileData['content']);
         }
     }
     /* Templates */
     foreach ($xmlArchive->asArray() as $path => $fileData) {
         if ($fileData['path'] == 'css') {
             $csss[str_replace('.xml', '', $fileData['filename'])] = $this->parseCSSXML($fileData['content']);
         }
     }
     if (!is_array($info)) {
         $this->_addErrorMessage($this->lang->words['noinfoxml']);
         return FALSE;
     }
     $info['set_output_format'] = $info['set_output_format'] ? $info['set_output_format'] : 'html';
     //-----------------------------------------
     // Find default skin
     //-----------------------------------------
     foreach ($this->registry->output->allSkins as $id => $data) {
         if ($data['set_is_default'] and $data['set_output_format'] == $info['set_output_format']) {
             $defaultSkin = $data;
             break;
         }
     }
     /* Make sure key in unique */
     $test = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_key=\'' . $this->DB->addSlashes($info['set_key']) . '\' AND set_id != ' . intval($setID)));
     if ($test['set_id']) {
         $info['set_key'] .= '_' . time();
     }
     //-----------------------------------------
     // Build Set Array
     //-----------------------------------------
     $newSet = array('set_name' => $setName ? $setName : $info['set_name'] . ' (Import)', 'set_key' => $info['set_key'], 'set_parent_id' => $parentID, 'set_permissions' => implode(",", $groups), 'set_is_default' => 0, 'set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_image_dir' => $imageDir ? $imageDir : $defaultSkin['set_image_dir'], 'set_emo_dir' => $defaultSkin['set_emo_dir'], 'set_css_inline' => 1, 'set_output_format' => $info['set_output_format'], 'set_css_groups' => '', 'set_hide_from_list' => 1, 'set_order' => intval($this->fetchHighestSetPosition()) + 1, 'set_master_key' => isset($info['set_master_key']) ? $info['set_master_key'] : 'root', 'set_updated' => time());
     if ($setID) {
         //-----------------------------------------
         // Update...
         //-----------------------------------------
         $this->DB->update('skin_collections', array('set_author_name' => $info['set_author_name'], 'set_author_url' => $info['set_author_url'], 'set_updated' => time()), 'set_id=' . $setID);
     } else {
         //-----------------------------------------
         // Insert...
         //-----------------------------------------
         $this->DB->insert('skin_collections', $newSet);
         $setID = $this->DB->getInsertId();
     }
     /* Rebuild trees */
     $this->rebuildTreeInformation($setID);
     /* Now re-load to fetch the tree information */
     $newSet = $this->DB->buildAndFetch(array('select' => '*', 'from' => 'skin_collections', 'where' => 'set_id=' . $setID));
     /* Add to allSkins array for caching functions below */
     $newSet['_parentTree'] = unserialize($newSet['set_parent_array']);
     $newSet['_childTree'] = unserialize($newSet['set_child_array']);
     $newSet['_userAgents'] = unserialize($newSet['set_locked_uagent']);
     $newSet['_cssGroupsArray'] = unserialize($newSet['set_css_groups']);
     $this->registry->output->allSkins[$setID] = $newSet;
     //-----------------------------------------
     // Replacements...
     //-----------------------------------------
     if (is_array($replacements)) {
         foreach ($replacements as $replacement) {
             if ($replacement['replacement_key']) {
                 $return['replacements']++;
                 $existing_id = 0;
                 /* Check if we need to update or insert */
                 if ($doUpgrade) {
                     $exists = $this->DB->buildAndFetch(array('select' => 'replacement_id', 'from' => 'skin_replacements', 'where' => "replacement_key='{$replacement['replacement_key']}' AND replacement_set_id={$setID} AND replacement_added_to={$setID}"));
                     $existing_id = $exists['replacement_id'];
                 }
                 if ($existing_id) {
                     $new_items['replacements'][] = $existing_id;
                     $this->DB->update('skin_replacements', array('replacement_content' => $replacement['replacement_content']), "replacement_id=" . $existing_id);
                 } else {
                     $this->DB->insert('skin_replacements', array('replacement_key' => $replacement['replacement_key'], 'replacement_content' => $replacement['replacement_content'], 'replacement_set_id' => $setID, 'replacement_added_to' => $setID));
                 }
             }
         }
     }
     //-----------------------------------------
     // CSS...
     //-----------------------------------------
     /* Fetch master CSS */
     $_MASTER = $this->fetchCSS(0);
     if (is_array($csss)) {
         foreach (ipsRegistry::$applications as $appDir => $data) {
             if (isset($csss[$appDir]) && is_array($csss[$appDir])) {
                 foreach ($csss[$appDir] as $css) {
                     if ($css['css_group']) {
                         $return['css']++;
                         $existing_id = 0;
                         /* Check if we need to update or insert */
                         if ($doUpgrade) {
                             $exists = $this->DB->buildAndFetch(array('select' => 'css_id', 'from' => 'skin_css', 'where' => "css_group='{$css['css_group']}' AND css_app='{$css['css_app']}' AND css_set_id={$setID}"));
                             $existing_id = $exists['css_id'];
                         }
                         if ($existing_id) {
                             $new_items['css'][] = $existing_id;
                             $this->DB->update('skin_css', array('css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID), "css_id=" . $existing_id);
                         } else {
                             $this->DB->insert('skin_css', array('css_group' => $css['css_group'], 'css_content' => $css['css_content'], 'css_position' => $css['css_position'], 'css_attributes' => $css['css_attributes'], 'css_app' => $css['css_app'], 'css_app_hide' => $css['css_app_hide'], 'css_modules' => str_replace(' ', '', $css['css_modules']), 'css_updated' => time(), 'css_set_id' => $setID, 'css_added_to' => isset($_MASTER[$css['css_group']]) ? 0 : $setID));
                         }
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // Templates - only import apps we have...
     //-----------------------------------------
     /* Fetch all master items */
     $_MASTER = $this->fetchTemplates(0, 'allNoContent');
     if (is_array($templates)) {
         foreach (ipsRegistry::$applications as $appDir => $data) {
             if (array_key_exists($appDir, $templates)) {
                 foreach ($templates[$appDir] as $template) {
                     if ($template['template_group'] and $template['template_name']) {
                         /* Figure out if this is added by a user or not */
                         $isAdded = (is_array($_MASTER[$template['template_group']][strtolower($template['template_name'])]) and !$_MASTER[$template['template_group']][strtolower($template['template_name'])]['template_user_added']) ? 0 : 1;
                         $return['templates']++;
                         $existing_id = 0;
                         /* Check if we need to update or insert */
                         if ($doUpgrade) {
                             $exists = $this->DB->buildAndFetch(array('select' => 'template_id', 'from' => 'skin_templates', 'where' => "template_set_id={$setID} AND template_group='{$template['template_group']}' AND template_name='{$template['template_name']}'"));
                             $existing_id = $exists['template_id'];
                         }
                         if ($existing_id) {
                             $new_items['templates'][] = $existing_id;
                             $this->DB->update('skin_templates', array('template_content' => $template['template_content'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'] ? $template['template_updated'] : IPS_UNIX_TIME_NOW, 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID), "template_id=" . $existing_id);
                         } else {
                             $this->DB->insert('skin_templates', array('template_set_id' => $setID, 'template_group' => $template['template_group'], 'template_content' => $template['template_content'], 'template_name' => $template['template_name'], 'template_data' => $template['template_data'], 'template_updated' => $template['template_updated'] ? $template['template_updated'] : IPS_UNIX_TIME_NOW, 'template_removable' => 1, 'template_user_edited' => 1, 'template_user_added' => $isAdded, 'template_added_to' => $setID));
                         }
                     }
                 }
             }
         }
     }
     //-----------------------------------------
     // If upgrading, and there are items from an old
     // skin not in the new one, delete the old elements
     // This probably won't ever come up, but I'm anal retentive :P
     //-----------------------------------------
     if ($doUpgrade) {
         if (count($new_items['replacements'])) {
             $this->DB->delete('skin_replacements', "replacement_set_id={$setID} AND replacement_id NOT IN (" . implode(',', $new_items['replacements']) . ")");
         }
         if (count($new_items['css'])) {
             $this->DB->delete('skin_css', "css_set_id={$setID} AND css_id NOT IN (" . implode(',', $new_items['css']) . ")");
         }
         if (count($new_items['templates'])) {
             $this->DB->delete('skin_templates', "template_set_id={$setID} AND template_id NOT IN (" . implode(',', $new_items['templates']) . ")");
         }
     }
     //-----------------------------------------
     // Re-cache
     //-----------------------------------------
     $this->rebuildReplacementsCache($setID);
     $this->rebuildCSS($setID);
     $this->rebuildPHPTemplates($setID);
     $this->rebuildSkinSetsCache();
     //-----------------------------------------
     // Done....
     //-----------------------------------------
     return $return;
 }