/**
  * Prepare a menu item to be converted to the WordPress format and added to the current
  * WordPress admin menu. This function applies menu defaults and templates, calls filters
  * that allow other components to tweak the menu, decides on what capability/-ies to use,
  * and so on.
  *
  * Caution: The filters called by this function may cause side-effects. Specifically, the Pro-only feature
  * for displaying menu pages in a frame does this. See wsMenuEditorExtras::create_framed_menu().
  * Therefore, it is not safe to call this function more than once for the same item.
  *
  * @param array $item Menu item in the internal format.
  * @param string $item_type Either 'menu' or 'submenu'.
  * @param string $parent Optional. The parent of this sub-menu item. An empty string for top-level menus.
  * @return array Menu item in the internal format.
  */
 private function prepare_for_output($item, $item_type = 'menu', $parent = '')
 {
     // Special case : plugin pages that have been moved from a sub-menu to a different
     // menu or the top level. We'll need to adjust the file field to point to the correct URL.
     // This is required because WP identifies plugin pages using *both* the plugin file
     // and the parent file.
     if ($item['template_id'] !== '' && !$item['separator']) {
         $template = $this->item_templates[$item['template_id']];
         if ($template['defaults']['is_plugin_page']) {
             $default_parent = $template['defaults']['parent'];
             if ($parent != $default_parent) {
                 $item['file'] = $template['defaults']['url'];
             }
         }
     }
     //Give each unclickable item a unique URL.
     if ($item['template_id'] === ameMenuItem::unclickableTemplateId) {
         static $unclickableCounter = 0;
         $unclickableCounter++;
         $unclickableUrl = '#' . ameMenuItem::unclickableTemplateClass . '-' . $unclickableCounter;
         $item['file'] = $item['url'] = $unclickableUrl;
         //The item must have the special "unclickable" class even if the user overrides the class.
         $cssClass = ameMenuItem::get($item, 'css_class', '');
         if (strpos($cssClass, ameMenuItem::unclickableTemplateClass) === false) {
             $item['css_class'] = ameMenuItem::unclickableTemplateClass . ' ' . $cssClass;
         }
     }
     //Menus that have both a custom icon URL and a "menu-icon-*" class will get two overlapping icons.
     //Fix this by automatically removing the class. The user can set a custom class attr. to override.
     $hasCustomIconUrl = !ameMenuItem::is_default($item, 'icon_url');
     $hasIcon = !in_array(ameMenuItem::get($item, 'icon_url'), array('', 'none', 'div'));
     if (ameMenuItem::is_default($item, 'css_class') && $hasCustomIconUrl && $hasIcon) {
         $new_classes = preg_replace('@\\bmenu-icon-[^\\s]+\\b@', '', $item['defaults']['css_class']);
         if ($new_classes !== $item['defaults']['css_class']) {
             $item['css_class'] = $new_classes;
         }
     }
     //Apply defaults & filters
     $item = ameMenuItem::apply_defaults($item);
     $item = ameMenuItem::apply_filters($item, $item_type, $parent);
     //may cause side-effects
     $item = $this->set_final_menu_capability($item);
     if (!$this->options['security_logging_enabled']) {
         unset($item['access_check_log']);
         //Throw away the log to conserve memory.
     }
     $this->add_access_lookup($item, $item_type);
     //Menus without a custom icon image should have it set to "none" (or "div" in older WP versions).
     //See /wp-admin/menu-header.php for details on how this works.
     if ($item['icon_url'] === '') {
         $item['icon_url'] = 'none';
     }
     //Submenus must not have the "menu-top" class(-es). In WP versions that support submenu CSS classes,
     //it can break menu display.
     if (!empty($item['css_class']) && $item_type === 'submenu') {
         $item['css_class'] = preg_replace('@\\bmenu-top(?:-[\\w\\-]+)?\\b@', '', $item['css_class']);
     } elseif ($item_type === 'menu' && !$item['separator'] && !preg_match('@\\bmenu-top\\b@', $item['css_class'])) {
         //Top-level menus should always have the "menu-top" class.
         $item['css_class'] = 'menu-top ' . $item['css_class'];
     }
     //Add submenu icons if necessary.
     if ($item_type === 'submenu' && $hasIcon) {
         $item = apply_filters('admin_menu_editor-submenu_with_icon', $item, $hasCustomIconUrl);
     }
     //Used later to determine the current page based on URL.
     if (empty($item['url'])) {
         $original_parent = !empty($item['defaults']['parent']) ? $item['defaults']['parent'] : $parent;
         $item['url'] = ameMenuItem::generate_url($item['file'], $original_parent);
     }
     //Convert relative URls to fully qualified ones. This prevents problems with WordPress
     //incorrectly converting "index.php?page=xyz" to, say, "tools.php?page=index.php?page=xyz"
     //if the menu item was moved from "Dashboard" to "Tools".
     $itemFile = ameMenuItem::remove_query_from($item['file']);
     $shouldMakeAbsolute = strpos($item['file'], '://') === false && substr($item['file'], 0, 1) != '/' && $itemFile == 'index.php' && strpos($item['file'], '?') !== false;
     if ($shouldMakeAbsolute) {
         $item['file'] = admin_url($item['url']);
     }
     //WPML support: Use translated menu titles where available.
     if (!$item['separator'] && function_exists('icl_t')) {
         $item['menu_title'] = icl_t(self::WPML_CONTEXT, $this->get_wpml_name_for($item, 'menu_title'), $item['menu_title']);
     }
     return $item;
 }
 /**
  * Convert internal menu representation to the form used by WP.
  * 
  * Note : While this function doesn't cause any side effects of its own, 
  * it executes several filters that may modify global state. Specifically,
  * IFrame-handling callbacks in 'extras.php' may insert items into the 
  * global $menu and $submenu arrays.
  *
  * @param array $tree
  * @return array $menu and $submenu
  */
 function tree2wp($tree)
 {
     $menu = array();
     $submenu = array();
     $title_lookup = array();
     //Sort the menu by position
     uasort($tree, array(&$this, 'compare_position'));
     //Prepare the top menu
     $first_nonseparator_found = false;
     foreach ($tree as $topmenu) {
         //Skip missing menus, unless they're user-created and thus might point to a non-standard file
         $custom = $this->get_menu_field($topmenu, 'custom', false);
         if (!empty($topmenu['missing']) && !$custom) {
             continue;
         }
         //Skip leading menu separators. Fixes a superfluous separator showing up
         //in WP 3.0 (multisite mode) when there's a custom menu and the current user
         //can't access its first item ("Super Admin").
         if (!empty($topmenu['separator']) && !$first_nonseparator_found) {
             continue;
         }
         $first_nonseparator_found = true;
         //Menus that have both a custom icon URL and a "menu-icon-*" class will get two overlapping icons.
         //Fix this by automatically removing the class. The user can set a custom class attr. to override.
         if (ameMenuItem::is_default($topmenu, 'css_class') && !ameMenuItem::is_default($topmenu, 'icon_url') && !in_array($topmenu['icon_url'], array('', 'none', 'div'))) {
             $new_classes = preg_replace('@\\bmenu-icon-[^\\s]+\\b@', '', $topmenu['defaults']['css_class']);
             if ($new_classes !== $topmenu['defaults']['css_class']) {
                 $topmenu['css_class'] = $new_classes;
             }
         }
         //Apply defaults & filters
         $topmenu = $this->apply_defaults($topmenu);
         $topmenu = $this->apply_menu_filters($topmenu, 'menu');
         //Skip hidden entries
         if (!empty($topmenu['hidden'])) {
             continue;
         }
         //Build the menu structure that WP expects
         $menu[] = array($topmenu['menu_title'], $topmenu['access_level'], $topmenu['file'], $topmenu['page_title'], $topmenu['css_class'], $topmenu['hookname'], $topmenu['icon_url']);
         //Prepare the submenu of this menu
         if (!empty($topmenu['items'])) {
             $items = $topmenu['items'];
             //Sort by position
             uasort($items, array(&$this, 'compare_position'));
             foreach ($items as $item) {
                 //Skip missing items, unless they're user-created
                 $custom = $this->get_menu_field($item, 'custom', false);
                 if (!empty($item['missing']) && !$custom) {
                     continue;
                 }
                 //Special case : plugin pages that have been moved to a different menu.
                 //If the file field hasn't already been modified, we'll need to adjust it
                 //to point to the old parent. This is required because WP identifies
                 //plugin pages using *both* the plugin file and the parent file.
                 if ($this->get_menu_field($item, 'is_plugin_page', false) && $item['file'] === null) {
                     $default_parent = '';
                     if (isset($item['defaults']) && isset($item['defaults']['parent'])) {
                         $default_parent = $item['defaults']['parent'];
                     }
                     if ($topmenu['file'] != $default_parent) {
                         $item['file'] = $default_parent . '?page=' . $item['defaults']['file'];
                     }
                 }
                 $item = $this->apply_defaults($item);
                 $item = $this->apply_menu_filters($item, 'submenu', $topmenu['file']);
                 //Skip hidden items
                 if (!empty($item['hidden'])) {
                     continue;
                 }
                 $submenu[$topmenu['file']][] = array($item['menu_title'], $item['access_level'], $item['file'], $item['page_title']);
                 //Make a note of the page's correct title so we can fix it later
                 //if necessary.
                 $title_lookup[$item['file']] = $item['menu_title'];
             }
         }
     }
     return array($menu, $submenu, $title_lookup);
 }