type = $type;
  }
  /**
   * Set the id
   * @chainable
   */
  public function id($id) {
    $this->id = $id;
    return $this;
  }
  /**
   * Set the label
   * @chainable
   */
  public function label($label) {
    $this->label = $label;
    return $this;
  }
  /**
   * Set the url
   * @chainable
   */
  public function url($url) {
    $this->url = $url;
    return $this;
  }
  /**
   * Set the css id
   * @chainable
   */
  public function css_id($css_id) {
    $this->css_id = $css_id;
    return $this;
  }
  /**
   * Set the css class
   * @chainable
   */
  public function css_class($css_class) {
    $this->css_class = $css_class;
    return $this;
  }
}
/**
 * Menu element that provides a link to a new page.
 */
class Menu_Element_Link extends Menu_Element {
  public function __toString() {
    if (isset($this->css_id) && !empty($this->css_id)) {
      $css_id = " id=\"$this->css_id\"";
    } else {
      $css_id = "";
    }
    if (isset($this->css_class) && !empty($this->css_class)) {
      $css_class = " $this->css_class";
    } else {
      $css_class = "";
    }
    return "
";
  }
}
/**
 * Menu element that provides a pop-up dialog
 */
class Menu_Element_Dialog extends Menu_Element {
  public function __toString() {
    if (isset($this->css_id) && !empty($this->css_id)) {
      $css_id = " id=\"$this->css_id\"";
    } else {
      $css_id = "";
    }
    if (isset($this->css_class) && !empty($this->css_class)) {
      $css_class = " $this->css_class";
    } else {
      $css_class = "";
    }
    return "";
  }
}
/**
 * Root menu or submenu
 */
class Menu_Core extends Menu_Element {
  public $elements;
  public $is_root = false;
  /**
   * Return an instance of a Menu_Element
   * @chainable
   */
  public static function factory($type) {
    switch($type) {
    case "link":
      return new Menu_Element_Link($type);
    case "dialog":
      return new Menu_Element_Dialog($type);
    case "root":
      $menu = new Menu("root");
      $menu->css_class("gMenu");
      return $menu;
    case "submenu":
      return new Menu("submenu");
    default:
      throw Exception("@todo UNKNOWN_MENU_TYPE");
    }
  }
  public function compact() {
    foreach ($this->elements as $target_id => $element) {
      if ($element->type == "submenu") {
        if (empty($element->elements)) {
          $this->remove($target_id);
        } else {
          $element->compact();
        }
      }
    }
    return $this;
  }
  public function __construct($type) {
    parent::__construct($type);
    $this->elements = array();
    $this->is_root = $type == "root";
  }
  /**
   * Add a new element to this menu
   */
  public function append($menu_element) {
    $this->elements[$menu_element->id] = $menu_element;
    return $this;
  }
  /**
   * Add a new element to this menu
   */
  public function add_after($target_id, $new_menu_element) {
    $copy = array();
    foreach ($this->elements as $id => $menu_element) {
      $copy[$id] = $menu_element;
      if ($id == $target_id) {
        $copy[$new_menu_element->id] = $new_menu_element;
      }
    }
    $this->elements = $copy;
    return $this;
  }
  /**
   * Remove an element from the menu
   */
  public function remove($target_id) {
    unset($this->elements[$target_id]);
  }
  /**
   * Retrieve a Menu_Element by id
   */
  public function get($id) {
    if (array_key_exists($id, $this->elements)) {
      return $this->elements[$id];
    }
    return null;
  }
  public function __toString() {
    $html = $this->is_root ? "css_class\">" :
      "- label\">$this->label";
    $html .= implode("\n", $this->elements);
    $html .= $this->is_root ? " " : "
";
    return $html;
  }
}