<?php
require_once(dirname(__FILE__) . '/../base.inc.php');

/***********************************

 menu class

 how to use:

1. instantiate object
2. add section
3. build/add link to section
4. add other links to section, using search terms
5. add spacer to section
6. add raw section
7. print specified page

1. $me = new menu();
2. $me->add_section('A title', 'page-A', 'a');
3. $me->add_link(menu::build_link('link a', 'href a', 'class a', 'id a', 'icon a'), 'a');
4. $me->add_link(menu_link('link b', 'href b', 'class b', 'id b', 'icon b'), 'a', 'before:id a');
5. $me->add_link_spacer('a', 'before:id a');
6. $me->add_raw_section('a', 'b', '<span class="taco"></span>');
7. $me->print_menu('page-A');

***********************************/

/**
 * menu class
 */
class menu {

	public $sections;

	/**
	 * new menu() = instantiate menu object
	 */
	public function __construct() {

		$this->sections = array();
	}

	/**
	 * $menu->print_menu() - print (echo) the menus for specified page
	 * @param string $page - which page to print (correspends to section['page'] in sections array)
	 * @param string $section_id - if specified, then only print this section of the specified page
	 */
	public function print_menu($page, $section_id = null) {

	    $menu_collapse_options = get_user_meta('menu_collapse_options');
	    if ($menu_collapse_options !== null)
	        $menu_collapse_options = unpack_array($menu_collapse_options);
	    else
	    	$menu_collapse_options = array();

		foreach($this->sections as $this_section_id => $this_section) {
			if ($this_section['page'] == $page) {

				if ($section_id !== null && $section_id != $this_section['id'])
					continue;

				$collapsed = false;

				if (isset($menu_collapse_options[$this_section['id']]))
					$collapsed = true;

				echo menu::div_menu_section($this_section, $collapsed, is_null($section_id));
			}
		}
	}

	/**
	 * menu::div_menu_section() - return array converted to html for a specified section
	 * @param string $section - an array element of sections array to build html for
	 * @param bool $collapsed - is the section collapsed or not?
	 * @param bool $include_menu_section_div - shall we include the wrapping menu section div? default is true
	 * @return string - the built html for specified section
	 */
	public static function div_menu_section($section, $collapsed, $include_menu_section_div = true) {

		$t = "\t";
		$n = "\n";

		$id = 		empty($section['id']) 		? "" : $section['id'];
		$class = 	empty($section['class']) 	? "" : $section['class'];
		$content = 	empty($section['content']) 	? "" : $section['content'];
		$title = 	empty($section['title']) 	? "" : $section['title'];

		$div = "";

		// if this is a raw html section, we handle it a bit different
		if ($section['raw']) {

			// this literally is just a raw div with some content. nothing fancy
			$div = '<div id="' . $id . '" class="' . $class . '" >' . $content . '</div>';

		} else {

			// if our class doesn't specify menusection, then we need to add it!
			$class = trim(strpos($class, 'menusection') !== false ? $class : 'menusection ' . $class);

			if ($collapsed)
				$class .= ' menusection-collapsed';

			$links = "";
			if (isset($section['links']) && is_array($section['links'])) {
				foreach($section['links'] as $this_link_id => $this_link) {

					// spacers are special, just print and move on in the loop
					if (isset($this_link['spacer'])) {

						$links .= $t . $t . $t . '<li class="menulinkspacer"></li>' . $n;
						continue;
					}

					$link_id = 		empty($this_link['id']) 	? "" : $this_link['id'];
					$link_class = 	empty($this_link['class']) 	? "" : $this_link['class'];
					$link_href = 	empty($this_link['href']) 	? "" : $this_link['href'];
					$link_title = 	empty($this_link['title']) 	? "" : $this_link['title'];
					$link_icon = 	empty($this_link['icon']) 	? "" : '<i class="fa fa-fw ' . $this_link['icon'] . '"></i> ';
					$link_raw =		empty($this_link['raw'])	? "" : trim($this_link['raw']) . ' ';

					$link_target = 'target="maincontentframe"';
					if (!empty($this_link['target'])) {
						$link_target = 'target="' . $this_link['target'] . '"';
					}

					$link_class = trim(strpos($link_class, 'menulink') !== false ? $link_class : 'menulink ' . $link_class);

					$links .= 
						$t . $t . $t . '<li id="' . $link_id . '" class="' . $link_class . '">' . $n .
						$t . $t . $t . $t . '<a href="' . $link_href . '" ' . $link_raw . ' ' . $link_target . '>' . $n .
						$t . $t . $t . $t . $t . $link_icon .
						$t . $t . $t . $t . $t . $link_title . $n .
						$t . $t . $t . $t . '</a>' . $n .
						$t . $t . $t . '</li>' . $n;
				}
			}

			//id="' . $id . '" 
			$icon = "fa-chevron-down";

			if ($collapsed)
				$icon = 'fa-chevron-up';

			$icon_text = "Collapse menu section";
			$div = 
				$t . $t . '<div class="menusectiontitle" data-id="' . $id .'"><i class="fa ' . $icon . '" title="' . $icon_text . '"></i>&nbsp;' . $title . '</div>' . $n .
				$t . $t . '<ul class="menusection">' . $n .
				$links . $n .
				$t . $t . '</ul>' . $n;

			if (!empty($include_menu_section_div)) {

				$div = 
					$t . '<div class="' . $class . '">' . $n .
					$div .
					$t . '</div>' . $n;
			}
		}

		return $div;
	}

	/**
	 * $menu->check_if_section_exists_by_id() - check if a section exists by id (section[id])
	 * @param string $id - the id to check against
	 * @return mixed - false if not found, otherwise the array key of the sections array where this section exists at
	 */
	public function check_if_section_exists_by_id($id) {

		$section_id = false;

		// find the section (by id)
		foreach($this->sections as $this_section_id => $this_section) {
			if ($this_section['id'] == $id) {

				$section_id = $this_section_id;
			}
		}

		return $section_id;
	}

	/**
	 * $menu->add_section() - add a section to the sections array of this object
	 * @param string $page - the page for which this section should be displayed for
	 * @param string $title - the title of the section [the text that will appear]
	 * @param string $id - the html id you wish to give to this section
	 * @param string $class - any additional html classes you wish to give to this section, menu_section will be added regardless of whether or not you specify it
	 */
	public function add_section($page, $title, $id, $class = '') {

		if (!$this->check_if_section_exists_by_id($id)) {
			
			$section = array();

			$section['id'] = $id;
			$section['page'] = $page;
			$section['title'] = $title;
			$section['raw'] = false;

			if (!empty($class))
				$section['class'] = $class;

			$this->sections[] = $section;
		}
	}

	/**
	 * $menu->add_raw_section() - add some html to be injected into the sections array for a specified page
	 * @param string $page - the page for which this section should be displayed for
	 * @param string $id - the html id you wish to give to this section
	 * @param string $content - the actual html you're injecting. will be wrapped in a div with the id and classes specified
	 * @param string $class - any additional html classes you wish to give to this section, menu_section will be added regardless of whether or not you specify it	 
	 */
	public function add_raw_section($page, $id, $content, $class = '') {

		if (!$this->check_if_section_exists_by_id($id)) {
		
			$section = array();

			$section['id'] = $id;
			$section['page'] = $page;
			$section['content'] = $content;
			$section['raw'] = true;

			if (!empty($class))
				$section['class'] = $class;

			$this->sections[] = $section;
		}
	}

	/**
	 * $menu->add_link_spacer() - add a spacer to a section
	 * @param string $search_section_id - the section to add a link spacer to (found with $menu->check_if_section_exists_by_id())
	 * @param mixed $terms - the terms with which to determine where in the list it is added. terms are the same here as in $menu->add_link()
	 */
	public function add_link_spacer($search_section_id, $terms = null) {

		$this->add_link(array('spacer' => true), $search_section_id, $terms);
	}

	/**
	 * $menu->add_link() - add a link to a section
	 * @param array $link - the link to add, preferrably built with menu::build_link() or menu_link()
	 * @param string $search_section_id - the section to add a link to (found with $menu->check_if_section_exists_by_id())
	 * @param mixed $terms - the terms with which to determine where in the list it is added. terms are the same here as in $menu->add_link()
	 *                     - string examples: 'before:link_id','before:link_title' <- will go before link_id/link_title
	 *					   -                  'after:link_id','after:link_id' <- will go after link_id/link_title
	 *                     -                  'before' <- will go at the beginning of the section
	 *					   - array examples: array('before' => link_id) , array('before' => link_title), etc.
	 *					   - if blank, then it will simply be appended to the end of the section links
	 */
	public function add_link($link, $search_section_id, $terms = null) {

		$section_id = $this->check_if_section_exists_by_id($search_section_id);

		if ($section_id !== false) {

			$search_link_id = null;
			$search_type = null;
			$search_term = null;

			if (empty($this->sections[$section_id]['links'])) {

				$this->sections[$section_id]['links'] = array();
			}

			// find the link in question
			if (!empty($terms)) {

				// since terms can be a string or an array, we just need to figure out which one to use!
				if (is_string($terms)) {

					$search_terms = explode(':', $terms);
					$search_terms_count = count($search_terms);

					if ($search_terms_count == 1) {

						$search_type = 'before';

					} else if ($search_terms_count > 1) {

						$search_type = strtolower($search_terms[0]);
						$search_term = $search_terms[1];
					}
				}

				// now lets pull our search info if we specified term as an array
				if (is_array($terms)) {

					if (array_key_exists('after', $terms)) {
						$search_type = 'after';
						$search_term = $terms['after'];
					}

					if (array_key_exists('before', $terms)) {
						$search_type = 'before';
						$search_term = $terms['after'];
					}

					if (in_array('before', $terms)) {
						$search_type = 'before';
					}
				}

				// now find the link we reference in our search term if we have one
				if ($search_term) {

					foreach ($this->sections[$section_id]['links'] as $this_link_id => $this_link) {

						// we look for the search term in the link id and title
						if ((!empty($this_link['id']) && $search_term == $this_link['id']) || (!empty($this_link['title']) && $search_term == $this_link['title'])) {

							$search_link_id = $this_link_id;
							break;
						}
					}
				}
			}

			// if terms is empty or there was no search_link_id found, just add it to the list of links and return
			if (empty($terms) || $search_link_id === null) {

				$this->sections[$section_id]['links'][] = $link;
				return;
			}

			// if we're adding the link after the one we found, just increment the key id by 1
			if ($search_type == 'after') {

				$search_link_id += 1;

			// but if we have only the type of before and no term, that means we want it at the beginning
			} else if ($search_type == 'before') {
				if (!$search_term) {

					$search_link_id = 0;
				}
			}

			array_splice($this->sections[$section_id]['links'], $search_link_id, 0, array($link));
		}
	}

	/**
	 * menu::build_link() - build a link array from string arguments
	 * @param string $title - the text to be displayed for this link
	 * @param string $href - the href for this link
	 * @param string $class - any additional class to append to the <li> this link is wrapped in (menu_section_link is appended regardless)
	 * @param string $id - the id to be given to the <li> this link is wrapped in
	 * @param string $icon - an icon, if any to be displayed by the link
	 * @param string $raw - any raw html to be included within the <a> tag
	 */
	public static function build_link($title = '', $href = '', $class = '', $id = '', $icon = '', $target = '', $raw = '') {

		$link = array();

		if (!empty($title))
			$link['title'] = $title;

		if (!empty($href))
			$link['href'] = $href;

		if (!empty($class))
			$link['class'] = $class;

		if (!empty($id))
			$link['id'] = $id;

		if (!empty($icon))
			$link['icon'] = $icon;

		if (!empty($raw))
			$link['raw'] = $raw;

		if (!empty($target))
			$link['target'] = $target;

		return $link;
	}
}

/**
 * menu_link() - synonym for menu::build_link()
 * @param string $title - the text to be displayed for this link
 * @param string $href - the href for this link
 * @param string $class - any additional class to append to the <li> this link is wrapped in (menu_section_link is appended regardless)
 * @param string $id - the id to be given to the <li> this link is wrapped in
 * @param string $icon - an icon, if any to be displayed by the link
 * @param string $raw - any raw html to be included within the <a> tag
 */
function menu_link($title = '', $href = '', $class = '', $id = '', $icon = '', $target = '', $raw = '') {
	return menu::build_link($title, $href, $class, $id, $icon, $target, $raw);
}
