<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Ajax extends MY_Controller
{
	public function __construct()
	{
		parent::__construct();

		$this->load->library("DataTables");
		$this->current_user = get_user();
		$this->sql_details = array('user' => $this->db->username,
		                           'pass' => $this->db->password,
		                           'db'   => $this->db->database,
		                           'host' => $this->db->hostname);
	}

	/**
	 * IMPORTANT: This function does not use the typical Ajax search mechanism that all other functions use in order to populate Data Tables.
	 * This function is for providing data to the search field.
	 */
	public function search($q)
	{
		$this->admin_login_required();

		$results = array("Pages" => array(),
		                 "Documents" => array(),
		                 "Existing Modules" => array(),
		                 "Create New Module" => array(),
		                 "Menu Links" => array(),
		                 "Portfolio Items" => array(),
		                 "Testimonials" => array(),
		                 "Events" => array(),
		                 "Users" => array());

		$this->load->model(array("page", "user", "module", "moduleinstance", "menuitem", "event", "document"));

		if($this->current_user->has(ACTION_PAGES))
		{
			$pages = $this->page->search($q, MainFrame::active_site_id(), Mainframe::user());
			$count = 0;

			foreach($pages as $page)
			{
				$results["Pages"][$count]["url"]	= "/admin/page/" . $page->page_id;
				$results["Pages"][$count]["onclick"] = "";
				$results["Pages"][$count]["text"]	= truncate($page->title, 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_DOCUMENTS))
		{
			$documents = $this->document->search($q, Mainframe::user());
			$count = 0;

			foreach($documents as $document)
			{
				$results["Documents"][$count]["url"]		= "/admin/document/" . $document->document_id;
				$results["Documents"][$count]["onclick"] 	= "";
				$results["Documents"][$count]["text"]		= truncate($document->title, 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_MENUS))
		{
			$links = $this->menuitem->search($q, Mainframe::user());
			$count = 0;

			foreach($links as $link)
			{
				$results["Menu Links"][$count]["url"]	= "/admin/menuitem/" . $link->menu_id . "/" . $link->menu_item_id;
				$results["Menu Links"][$count]["onclick"] = "";
				$results["Menu Links"][$count]["text"]	= truncate($link->title, 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_MODULES))
		{
			$modules = $this->module->search($q);
			$count = 0;

			foreach($modules as $module)
			{
				$results["Create New Module"][$count]["url"]	= "/admin/module/" . $module->module_id . "/0";
				$results["Create New Module"][$count]["onclick"] = "";
				$results["Create New Module"][$count]["text"]	= truncate($module->name, 50);

				$count++;
			}

			$modules = $this->moduleinstance->search($q, Mainframe::user());
			$count = 0;

			foreach($modules as $module)
			{
				$results["Existing Modules"][$count]["url"]	= "/admin/module/" . $module->module_id . "/" . $module->module_instance_id;
				$results["Existing Modules"][$count]["onclick"] = "";
				$results["Existing Modules"][$count]["text"]	= truncate($module->tag . " (" . $module->name . ")", 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_PORTFOLIO))
		{
			$portfolios = $this->portfolio->search($q);
			$count = 0;

			foreach($portfolios as $portfolio)
			{
				$results["Portfolio Items"][$count]["url"]	= "/admin/portfolio/" . $portfolio->portfolio_id;
				$results["Portfolio Items"][$count]["onclick"] = "";
				$results["Portfolio Items"][$count]["text"]	= truncate($portfolio->client_name, 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_EVENTS))
		{
			$events = $this->event->search($q);
			$count = 0;

			foreach($events as $event)
			{
				$results["Events"][$count]["url"]	= "/admin/event/" . $event->event_id;
				$results["Events"][$count]["onclick"] = "";
				$results["Events"][$count]["text"]	= truncate($event->headline, 50);

				$count++;
			}
		}

		if($this->current_user->has(ACTION_USERS))
		{
			$users = $this->user->search($q);
			$count = 0;

			foreach($users as $tmp_user)
			{
				$results["Users"][$count]["url"]	= "/admin/user/" . $tmp_user->user_id;
				$results["Users"][$count]["onclick"] = "";
				$results["Users"][$count]["text"]	= truncate($tmp_user->fname . " " . $tmp_user->lname . " (" . $tmp_user->username . ")", 50);

				$count++;
			}
		}

		// Look for any hooks that add additional items to our search results.
		$files = scandir(APPLICATION_PATH . "/hooks");

		foreach($files as $file)
		{
			if(preg_match('/^search_.*\.php$/', $file))
			{
				require_once(APPLICATION_PATH . "/hooks/$file");
				//We know there will be a function by the same name as the file. ie: search_custom()
				$file = str_replace(".php", "", $file);
				$more_results = $file($q);

				if(is_array($more_results))
				{
					// Merge and put the custom results above the default NCMS results.
					$results = array_merge($more_results, $results);
				}
			}
		}

		$this->spit_json($results);
		die();
	}

	private function _get_dirs($directory, $subdirectories=true)
	{
		$files 					= scandir($directory);
		$image_dirs 			= array();
		$count 					= 1;

		$image_dirs[0] 			= new StdClass();
		$image_dirs[0]->text 	= str_replace(ABSOLUTE_PATH . "/", "", $directory);
		$image_dirs[0]->value 	= str_replace(ABSOLUTE_PATH . "/", "", $directory);

		foreach($files as $file)
		{
			if(is_dir("$directory/$file") && $file != "." && $file != "..")
			{
				if($subdirectories)
				{
					$new_image_dirs 			= $this->_get_dirs("$directory/$file", $subdirectories);
					$image_dirs 				= array_merge($image_dirs, $new_image_dirs);
				}
				else
				{
					$nice_dir 		   			= str_replace(ABSOLUTE_PATH . "/", "", "$directory/$file");
					$image_dirs[$count] 	   	= new StdClass();
					$image_dirs[$count]->text  	= $nice_dir;
					$image_dirs[$count]->value 	= $nice_dir;
				}
				$count++;
			}
		}

		usort($image_dirs, "sort_dirs_array");
		return $image_dirs;
	}

	public function get_image_dirs_array($subdirectories=true)
	{
		$this->admin_login_required();
		$dirs = $this->_get_dirs(ABSOLUTE_PATH . "/images", $subdirectories);

		$this->spit_json($dirs);
	}

	public function get_video_dirs_array($subdirectories=true)
	{
		$this->admin_login_required();
		$dirs = $this->_get_dirs(ABSOLUTE_PATH . "/videos", $subdirectories);

		$this->spit_json($dirs);
	}

	public function get_video_files_array($subdirectories=true)
	{
		$this->admin_login_required();

		$directory 		= ABSOLUTE_PATH . "/videos/";
		$files 			= scandir($directory);
		$videos 		= array();
		$count 			= 0;
		$videos_temp 	= array();

		foreach($files as $file)
		{
			$file_no_ext = substr($file, 0, strripos($file, "."));

			if(is_file("$directory/$file") && preg_match('/\.(mp4|webm|ogv)/i', $file))
			{
				$videos_temp[$count] = "$file_no_ext";
				$count++;
			}
		}

		$videos_temp = array_unique($videos_temp);

		$count = 0;
		foreach($videos_temp as $video)
		{
			$videos[$count] = new StdClass();
			$videos[$count]->text = $video;
			$videos[$count]->value = $video;
			$count++;
		}

		$this->spit_json($videos);
	}

	public function get_roles_array()
	{
		$this->admin_login_required();

		$this->load->model("acl_role");
		$list = $this->acl_role->get();
		$roles = array();
		$count = 0;

		foreach($list as $l)
		{
			$roles[$count] = new StdClass();
			$roles[$count]->text 		= $l->role;
			$roles[$count]->value 		= $l->acl_role_id;
			$roles[$count]->role 		= $l->role;
			$roles[$count]->acl_role_id = $l->acl_role_id;
			$count++;
		}

		$this->spit_json($roles, true);
	}

	public function get_categories_array()
	{
		$this->admin_login_required();

		$this->load->model("category");
		$list = $this->category->LoadBySiteID(Mainframe::active_site_id());
		$categories = array();
		$count = 0;

		foreach($list as $l)
		{
			$categories[$count] = new StdClass();
			$categories[$count]->text = $l->name;
			$categories[$count]->value = $l->category_id;
			$count++;
		}

		$this->spit_json($categories, true);
	}

	public function get_tags_array()
	{
		$this->admin_login_required();

		$this->load->model("page_tag");
		$list = $this->page_tag->get();
		$tags = array();
		$count = 0;

		foreach($list as $t)
		{
			$tags[$count] = new StdClass();
			$tags[$count]->text = $t->tag;
			$tags[$count]->value = $t->tag_id;
			$count++;
		}

		$this->spit_json($tags, true);
	}

	public function get_menus_array()
	{
		$this->admin_login_required();

		$this->load->model("menu");
		$list = $this->menu->LoadBySiteID(Mainframe::active_site_id());
		$menus = array();
		$count = 0;

		foreach($list as $l)
		{
			$menus[$count] = new StdClass();
			$menus[$count]->text = $l->name;
			$menus[$count]->value = $l->menu_id;
			$count++;
		}

		$this->spit_json($menus, true);
	}

	public function get_pages_array()
	{
		$this->admin_login_required();

		$this->load->model("page");
		$list = $this->page->LoadBySiteID(Mainframe::active_site_id(), Mainframe::user());
		$pages = array();
		$count = 0;

		foreach($list as $l)
		{
			$pages[$count] 			= new StdClass();
			$pages[$count]->text 	= $l->title;
			$pages[$count]->value 	= $l->page_id;
			$pages[$count]->url 	= $l->url;
			$count++;
		}

		$this->spit_json($pages, true);
	}

	/**
	 * Functions for loading table data via AJAX.
	 *
	 * Note: the last select column always contains the ID.
	 * This is because we use that to generate the edit/delete buttons during load.
	 * Also note: the "match_columns" must appear in the same order as you display them in the table or sorting won't work!
	 * Any additional fields you want searchable, add them after the displayed fields.
	 */

	public function get($model_name)
	{
		$this->admin_login_required();
		$this->simple($model_name);
	}

	protected function simple($model_name, $columns=array())
	{
		$this->admin_login_required();

		// If the model is in a subdirectory, grab the class name from that.
		$class_name = basename($model_name);
		$this->load->model($model_name);
		$class 		= new $class_name();
		$table 		= $class::DB_TABLE;
		$primaryKey = $class::DB_TABLE_PK;

		// If the user has not specifically requested columns, we'll give them everything.
		if(count($columns) == 0)
		{
			$query 	= $this->db->query("DESCRIBE `" . $table . "`");

			foreach($query->result() as $field)
	        {
	        	// Map the primary key to DT_RowId
	        	if(strtoupper($field->Key) == "PRI")
	        	{
	        		$columns[] = array('db' => $field->Field, 'dt' => 'DT_RowId');
	        	}
	        	// Map each field to DataTables by its field name.
	        	$columns[] = array('db' => $field->Field, 'dt' => $field->Field);
	        }
	    }

	    $key = "sql:" . sha1($table . "-" . $primaryKey . "-" . print_r($columns, true) . "-" . print_r($this->input->get(), true));

	    if(($data = $this->cache->get($key)) === false)
		{
			$data = DataTables::simple($this->input->get(), $this->sql_details, $table, $primaryKey, $columns);
			$this->cache->save($key, $data, 86400);
		}

		$this->spit_json($data, true);
	}

	protected function complex($model_name, $inner_query, $columns=array())
	{
		$this->admin_login_required();

		// If the model is in a subdirectory, grab the class name from that.
		$class_name = basename($model_name);
		$this->load->model($model_name);
		$class 		= new $class_name();
		$table 		= $class::DB_TABLE;
		$primaryKey = $class::DB_TABLE_PK;

		// If the user has not specifically requested columns, we'll give them everything.
		if(count($columns) == 0)
		{
			$query 		= $this->db->query("SELECT * FROM (" . $inner_query . ") AS x LIMIT 1");
			// Map the primary key to DT_RowId
	        $columns[] 	= array('db' => $primaryKey, 'dt' => 'DT_RowId');

			foreach($query->result() as $row)
	        {
	        	// Map each field to DataTables by its field name.
	        	foreach($row as $key=>$value)
	        	{
					$columns[] = array('db' => $key, 'dt' => $key);
	        	}
	        }
	    }

	    $key = "sql:" . sha1($inner_query . "-" . $primaryKey . "-" . print_r($columns, true) . "-" . print_r($this->input->get(), true));

	    if(($data = $this->cache->get($key)) === false)
		{
			$data = DataTables::complex($this->input->get(), $this->sql_details, $inner_query, $primaryKey, $columns);
			$this->cache->save($key, $data, 86400);
		}

		$this->spit_json($data, true);
	}

	public function get_documents()
	{
		$site_id = Mainframe::active_site_id();
		$sql = "SELECT d.*, c.`name` AS category_name
				FROM `document` AS d
				INNER JOIN `acl` AS a USING(document_id)
				LEFT JOIN `categories` AS c ON d.`category_id`=c.`category_id`
				WHERE d.site_id='" . $this->db->escape_str($site_id) . "' AND a.write=1 AND a.acl_role_id IN(" . implode(",", Mainframe::user()->roles) . ")
				GROUP BY d.document_id";

		$this->complex("document", $sql);
	}

	public function get_404s()
	{
		$sql = "SELECT l.*, IF(r.redirect_id IS NULL, 0, 1) AS fixed
				FROM 404log AS l
				LEFT JOIN redirects AS r ON l.url=r.old_url";

		$this->complex("four_oh_four", $sql);
	}

	public function get_domains()
	{
		$sql = "SELECT d.*, s.name AS site_name
				FROM domains AS d
				INNER JOIN sites AS s ON d.site_id=s.site_id";
		$this->complex("domain", $sql);
	}

	public function get_sites()
	{
		$sql = "SELECT s.site_id, s.`name`, t.`name` AS template_name
				FROM sites AS s INNER JOIN templates AS t ON s.template_id=t.template_id";
		$this->complex("site", $sql);
	}

	public function get_categories()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT c.*, s.name AS site_name
						FROM categories AS c
						INNER JOIN sites AS s ON c.site_id=s.site_id
						WHERE c.site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("category", $sql);
	}

	public function get_pages()
	{
		$content_type_id = $this->input->get("content_type_id");
		$category_id     = $this->input->get("category_id");

		$site_id = Mainframe::active_site_id();
		$sql 		= "SELECT p.page_id, p.title, p.url, p.created, p.modified, c.name AS category_name, t.content_type,
						GROUP_CONCAT(cv.`value`) AS search_data
						FROM pages AS p
						INNER JOIN `acl` AS a USING(page_id)
						LEFT JOIN categories AS c ON p.category_id=c.category_id
						LEFT JOIN content_types AS t USING(content_type_id)
						LEFT JOIN content_values AS cv USING(page_id)
						WHERE p.site_id='" . $this->db->escape_str($site_id) . "' AND a.write=1 AND a.acl_role_id IN(" . implode(",", Mainframe::user()->roles) . ") " .
						($content_type_id ? " AND p.content_type_id='" . $content_type_id . "' " : "") .
						($category_id ? " AND p.category_id='" . $category_id . "' " : "") .
						" GROUP BY p.page_id";

		// Add a searchable hidden column to the table
		$_GET["columns"][] = array("data" => "search_data", "name" => "", "searchable" => true, "orderable" => false, "search" => array("value" => "", "regex" => false));

		$this->complex("page", $sql);
	}

	public function get_redirects()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT r.redirect_id, r.old_url, IF(p.page_id IS NULL, r.new_url, p.url) AS new_url
						FROM redirects AS r
						LEFT JOIN pages AS p USING(page_id)
						WHERE r.site_id='" . $this->db->escape_str($site_id) . "'
						GROUP BY r.redirect_id";
		$this->complex("redirect", $sql);
	}

	public function get_modules()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT mi.module_instance_id, mi.tag, mi.position, mi.published,
						m.module_id AS module_id, mi.module_instance_id AS instance_id,
						CONCAT(mi.tag, ' (', m.`name`, ')') AS display_name
						FROM module_instances AS mi
						INNER JOIN `acl` AS a USING(module_instance_id)
						INNER JOIN modules AS m ON mi.module_id=m.module_id
						WHERE mi.site_id='" . $this->db->escape_str($site_id) . "' AND a.write=1 AND a.acl_role_id IN(" . implode(",", Mainframe::user()->roles) . ")
						GROUP BY mi.module_instance_id";
		$this->complex("moduleinstance", $sql);
	}

	public function get_menus()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT * FROM menus WHERE site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("menu", $sql);
	}

	public function get_roles()
	{
		$sql = "SELECT r.*, GROUP_CONCAT(a.`action` ORDER BY a.`action` SEPARATOR '<br>') AS `actions`
				FROM acl_role AS r
				LEFT JOIN acl_role_action AS ra USING(acl_role_id)
				LEFT JOIN acl_action AS a USING(acl_action_id)
				GROUP BY r.acl_role_id";
		$this->complex("acl_role", $sql);
	}

	public function get_events()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT * FROM events WHERE site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("event", $sql);
	}

	public function get_event_forms()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT f.*, e.headline
						FROM events_forms AS f
						INNER JOIN events AS e ON f.event_id=e.event_id
						WHERE e.site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("event_form", $sql);
	}

	public function get_directory_categories()
	{
		$site_id = Mainframe::active_site_id();
		$this->complex("directory_category", "SELECT * FROM directory_categories WHERE site_id='" . $this->db->escape_str($site_id) . "'");
	}

	public function get_directory_companies()
	{
		$site_id = Mainframe::active_site_id();
		$this->complex("directory_company", "SELECT * FROM directory_companies WHERE site_id='" . $this->db->escape_str($site_id) . "'");
	}

	function get_appointments_for_module()
	{
		$start 	= date("Y-m-d", strtotime(preg_replace('/ \(.*\)$/', '', $this->input->get_post("start"))));
		$end 	= date("Y-m-d", strtotime(preg_replace('/ \(.*\)$/', '', $this->input->get_post("end"))));
		$duration 	= $this->input->get_post("duration");
		$slots 	= $this->input->get_post("slots");

		$sql = "SELECT * FROM booking_appointments WHERE appointment_date >= '$start 00:00:00'
													AND  appointment_date <= '$end 23:59:59'";

		$result = $this->db->query($sql);

		$totals = array();

		foreach($result->result() as $row)
		{
			$date = date("Y-m-d", strtotime($row->appointment_date));
			$totals[$date]++;
		}

		//mail("brian@nerivon.com", "TESTING", print_r($result, true));
		?>
		<events>
			<?php
			foreach($result->result() as $row)
			{
				?>
				<event title="Booked" start="<?php echo $row->appointment_date?>" end="<?php echo date("Y-m-d H:i:s", strtotime("$row->appointment_date +$duration minutes"));?>" allDay="false" />
			<?php
			}
			?>
		</events>
		<?php
	}

	function get_events_for_module()
	{
		$start 		= date("Y-m-d", strtotime(preg_replace('/ \(.*\)$/', '', $this->input->get_post("start"))));
		$end 		= date("Y-m-d", strtotime(preg_replace('/ \(.*\)$/', '', $this->input->get_post("end"))));
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT * FROM events WHERE site_id=? AND event_date >= ? AND event_date <= ?";
		$result 	= $this->db->query($sql, array($site_id, "$start 00:00:00", "$end 23:59:59"));
		?>
		<events>
			<?php
			foreach($result->result() as $row)
			{
				?>
				<event title="<?php echo(addslashes(htmlentities($row->headline))); ?>" description="<?php echo(addslashes(htmlentities($row->description))); ?>" start="<?php echo(date('Y-m-d H:i', strtotime($row->event_date . ' ' . $row->time_start)));?>" end="<?php echo(date('Y-m-d H:i', strtotime($row->event_date . ' ' . $row->time_end)));?>" allDay="<?php echo($row->all_day ? 'true' : 'false'); ?>" />
				<?php
			}
			?>
		</events>
		<?php
	}

	public function get_module_settings($id)
	{
		$this->admin_login_required();

		if($id == 0)
		{
			$this->spit_json(array());
			return;
		}

		$this->load->model(array("module", "moduleinstance", "modulesetting"));

		$instance = new ModuleInstance();
		$instance->load($id);

		require_once(ABSOLUTE_PATH . "/modules/" . $instance->file_name . "/" . $instance->file_name . ".php");
		$m = new $instance->class_name();

		// Get module settings for this module and any children it may have.
		if(count($m->children()))
		{
			$settings = array();
			$settings[] = $this->modulesetting->load_by_instance_id($id);

			foreach($m->children() as $child)
			{
				$settings[] = $this->modulesetting->load_by_instance_id($child);
			}
		}
		else
		{
			$settings = $this->modulesetting->load_by_instance_id($id);
		}

		$this->spit_json($settings, true);
	}

	public function get_page_settings($id)
	{
		$this->admin_login_required();

		if($id == 0)
		{
			$this->spit_json(array());
			return;
		}

		$this->load->model(array("page", "content_value"));

		$p = new Page();
		$p->load($id);

		$this->spit_json($p->fields, true);
	}

	public function get_content_types()
	{
		$this->admin_login_required();

		$this->complex("content_type", "SELECT content_type_id, filename, page_info, sort,
		               					CONCAT(LPAD(`sort`, 2, 0), ': ', content_type) AS content_type
		               					FROM content_types");
	}

	public function get_content_types_array()
	{
		$this->admin_login_required();

		$this->load->model("content_type");
		$list = $this->content_type->get();
		$types = array();
		$count = 0;

		foreach($list as $l)
		{
			$types[$count] = new StdClass();
			$types[$count]->text = $l->content_type;
			$types[$count]->value = $l->content_type_id;
			$count++;
		}

		$this->spit_json($types, true);
	}

	public function get_documents_array()
	{
		$this->admin_login_required();

		$this->load->model("document");
		$list = $this->document->LoadBySiteID(Mainframe::active_site_id(), get_user());
		$documents = array();
		$count = 0;

		foreach($list as $l)
		{
			$documents[$count] = new StdClass();
			$documents[$count]->text = $l->title;
			$documents[$count]->value = $l->document_id;
			$count++;
		}

		$this->spit_json($documents, true);
	}

	public function get_popular_image_size($category_id=null)
	{
		$this->admin_login_required();

		$sql = "SELECT width, height, CONCAT(width, 'x', height) AS wh, COUNT(*) AS total, c.name
				FROM pages AS p
				LEFT JOIN categories AS c USING(category_id)
				INNER JOIN(
					SELECT `value` AS width, page_id
					FROM content_values AS v
					WHERE `key`='image_width'
				) AS w USING(page_id)
				INNER JOIN(
					SELECT `value` AS height, page_id
					FROM content_values AS v
					WHERE `key`='image_height'
				) AS h USING(page_id)
				" . ($category_id ? " WHERE c.category_id='" . $category_id . "'" : "") . "
				GROUP BY c.category_id, wh
				ORDER BY total DESC
				LIMIT 1";

		$query = $this->db->query($sql);

		if($query->num_rows())
		{
			$this->spit_json($query->row(), true);
		}
		else
		{
			$this->spit_json(new StdClass());
		}
	}

	/**
	 * SHOP FUNCTIONS
	 */
	public function get_shop_orders()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT o.order_id, o.order_date, o.customer_name, o.order_total, s.order_status_name, o.paid
						FROM shop_orders AS o
						INNER JOIN shop_order_status AS s ON o.order_status_id=s.order_status_id
						INNER JOIN shop_payment_gateways AS pay ON o.payment_gateway_id=pay.payment_gateway_id
						INNER JOIN shop_shipping_gateways AS ship ON o.shipping_gateway_id=ship.shipping_gateway_id
						WHERE o.site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("shop/shop_order", $sql);
	}

	public function get_shop_payment_gateways()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT *
						FROM shop_payment_gateways
						WHERE site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("shop/shop_payment_gateway", $sql);
	}

	public function get_shop_shipping_gateways()
	{
		$site_id 	= Mainframe::active_site_id();
		$sql 		= "SELECT *
						FROM shop_shipping_gateways
						WHERE site_id='" . $this->db->escape_str($site_id) . "'";
		$this->complex("shop/shop_shipping_gateway", $sql);
	}

	/**
	 * END SHOP FUNCTIONS
	 */

	public function get_icons()
	{
		$this->admin_login_required();

		$list 	= get_icons();
		$icons 	= array();
		$count 	= 0;

		foreach($list as $l)
		{
			$icons[$count] 			= new StdClass();
			$icons[$count]->text 	= $l;
			$icons[$count]->value 	= $l;
			$count++;
		}

		$this->spit_json($icons, true);
	}

	/**
	 * Convert the passed content to JSON and send it to the browser.
	 *
	 * @access protected
	 * @param mixed $content
	 * @return void
	 */
	protected function spit_json($content, $JSON_NUMERIC_CHECK=false)
	{
		header('Content-type: application/json');

		if($JSON_NUMERIC_CHECK)
		{
			echo json_encode( $content, JSON_NUMERIC_CHECK );
		}
		else
		{
			echo json_encode( $content );
		}
	}

	/**
	 * Generic function to get data from the database based on the columns and table requested.
	 *
	 * @access protected
	 * @param array Database fields to return.
	 * @param string Database primary key field name.
	 * @param string Database table name.
	 * @param (optional) string Group by field name.
	 * @param (optional) string Where clause to prepend the built in where conditions.
	 * @return void
	 */
	protected function get_data($match_columns, $select_columns, $sIndexColumn, $sTable, $sGroupBy="", $initialWhere="", $initialWhereAndOr="AND")
	{
		error_reporting(0);
		login_required();

		header('Content-type: application/json');

		/*
		 * Script:    DataTables server-side script for PHP and MySQL
		 * Copyright: 2010 - Allan Jardine
		 * License:   GPL v2 or BSD (3-point)
		 */

		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		 * Easy set variables
		 */

		/* Array of database columns which should be read and sent back to DataTables. Use a space where
		 * you want to insert a non-database field (for example a counter or static image)
		 */
		//$match_columns = array( 'engine', 'browser', 'platform', 'version', 'grade' );

		/* Indexed column (used for fast and accurate table cardinality) */
		//$sIndexColumn = "id";

		/* DB table to use */
		//$sTable = "ajax";

		/*
		 * Paging
		 */
		//$iDisplayStart = $this->input->get('iDisplayStart', 0);
		//$iDisplayLength = $this->input->get('iDisplayLength', 10);

		$sLimit = "LIMIT ".$this->db->escape( intval($this->input->get('iDisplayStart')) ).", ".$this->db->escape( intval($this->input->get('iDisplayLength')) );

		/*
		 * Ordering
		 */
		$sOrder = "";

		if ( is_numeric($this->input->get('iSortCol_0')) )
		{
			$sOrder = "ORDER BY  ";
			for ( $i=0 ; $i<intval( $this->input->get('iSortingCols') ) ; $i++ )
			{
				if ( $this->input->get( 'bSortable_'.intval($this->input->get('iSortCol_'.$i)) ) == "true" )
				{
					$sOrder .= $match_columns[ intval( $this->input->get('iSortCol_'.$i) ) ]."
					 	" . ($this->input->get('sSortDir_'.$i) == "asc" ? "asc" : "desc") . ", ";
				}
			}

			$sOrder = substr_replace( $sOrder, "", -2 );
			if ( $sOrder == "ORDER BY" )
			{
				$sOrder = "";
			}
		}


		/*
		 * Filtering
		 * NOTE this does not match the built-in DataTables filtering which does it
		 * word by word on any field. It's possible to do here, but concerned about efficiency
		 * on very large tables, and MySQL's regex functionality is very limited
		 */
		$sWhere = "";
		if ( $this->input->get('sSearch') != "" || $initialWhere)
		{
			$keywords = explode("|", $this->input->get('sSearch'));

			$sWhere = "WHERE (" . ($initialWhere ? "(" . $initialWhere . ") " . $initialWhereAndOr . " " : "");

			foreach($keywords as $keyword)
			{
				$sWhere .= "(";

				for ( $i=0 ; $i<count($match_columns) ; $i++ )
				{
					$sWhere .= $match_columns[$i]." LIKE '%" . $this->db->escape_like_str(trim($keyword)) . "%' OR ";
				}

				$sWhere = substr_replace( $sWhere, "", -3 );
				$sWhere .= ") AND ";
			}
			$sWhere = substr_replace( $sWhere, "", -4 );
			$sWhere .= ')';
		}
		//mail("brian@chowns.ca", "TEST", $sWhere);

		/* Individual column filtering */
		for ( $i=0 ; $i<count($match_columns) ; $i++ )
		{
			if ( $this->input->get('bSearchable_'.$i) == "true" && $this->input->get('sSearch_'.$i) != '' )
			{
				$keywords = explode("|", $this->input->get('sSearch_'.$i));

				foreach($keywords as $keyword)
				{
					if ( $sWhere == "" )
					{
						$sWhere = "WHERE ";
					}
					else
					{
						$sWhere .= " " . $initialWhereAndOr . " ";
					}
					$sWhere .= $match_columns[$i]." LIKE '%" . $this->db->escape_like_str($keyword) . "%'";
				}
			}
		}

		$sQuery = "
			SELECT SQL_CALC_FOUND_ROWS $select_columns
			FROM   $sTable
			$sWhere
			" . ($sGroupBy ? " GROUP BY $sGroupBy " : "") . "
			$sOrder
			$sLimit
		";

		$rResult = $this->db->query( $sQuery );

		/* Data set length after filtering */
		$sQuery = "
			SELECT FOUND_ROWS() AS `total`
		";
		$rResultFilterTotal = $this->db->query( $sQuery );
		$aResultFilterTotal = $rResultFilterTotal->result_array();
		$aResultFilterTotal = $rResultFilterTotal->row();
		$iFilteredTotal = $aResultFilterTotal->total;

		/* Total data set length */
		$sQuery = "
			SELECT COUNT(".$sIndexColumn.") AS `total`
			FROM   $sTable
		";

		$rResultTotal = $this->db->query( $sQuery );
		$aResultTotal = $rResultTotal->result_array();
		$aResultTotal = $rResultTotal->row();
		$iTotal = $aResultTotal->total;


		/*
		 * Output
		 */
		$output = array(
			"sEcho" => intval($this->input->get('sEcho')),
			"iTotalRecords" => $iTotal,
			"iTotalDisplayRecords" => $iFilteredTotal,
			"aaData" => array()
		);

		//while ( $aRow = mysql_fetch_array( $rResult ) )
		foreach($rResult->result_array() as $row)
		{
			//for security reasons, lets not transmit any passwords over the wire
			//man in the middle could sniff this if SSL is not used
			if(isset($row["password"]))
			{
				$row["password"] = "";
			}

			$output['aaData'][] = $row;
		}


		echo json_encode( $output );
	}

	/**
	 * Generic function to get any model and load all elements with LoadTokens().
	 * The only difference between this and get_all() is that this is guaranteed to return `id` and `name` for each element.
	 * It also accepts a single parameter $q for filtering results.
	 */
	public function get_tokens($model)
	{
		$this->load->model($model);

		if(method_exists($this->{$model}, "LoadTokens"))
		{
			$objects = $this->{$model}->LoadTokens($this->input->get("q"));

			http_response_code(200);
			echo json_encode($objects);
		}
		else
		{
			http_response_code(400);
			die();
		}
	}
}
