<?php

	/*
	*	Gekko - Open Source Web Development Framework
	*	------------------------------------------------------------------------
	*	Copyright (C) 2004-2005, J. Carlos Nieto <xiam@users.sourceforge.net>
	*	This program is Free Software.
	*
	*	@package	Gekko
	*	@license	http://www.gnu.org/copyleft/gpl.html GNU/GPL License 2.0
	*	@author		J. Carlos Nieto <xiam@users.sf.net>
	*	@version	CVS: $Id:$
	*	@link		http://www.gekkoware.org
	*/

	if (!defined("IN-GEKKO")) die("Get a life!");

	/*
		Template markers.
		Open templates/default/main/index.tpl ans search for
		V_DOC_$markername
	*/
	// Encloses subtitle
	define("SUBTITLE_EL", ":: ");
	define("SUBTITLE_ER", "");

	// Encloses maintitle
	define("TITLE_EL", "");
	define("TITLE_ER", "");

	// Title separator (title [separator] website name)
	define("TITLE_SEPARATOR", " | ");

	$htdoc_attach_markers = Array("HEAD", "FOOTER", "TITLE");
	foreach ($htdoc_attach_markers as $marker) {
		$GLOBALS["L"]["V_DOC_{$marker}"] = "";
	}

	function htdoc_attach($tag, $value) {
		$GLOBALS["L"]["V_DOC_{$tag}"] .= "$value\n";
	}
	function title_attach($title, $type = 0) {
		switch ($type) {
			case 1:
				// main title
				htdoc_attach("TITLE", TITLE_EL.$title.TITLE_ER);
			break;
			default:
				// subtitle
				htdoc_attach("TITLE", SUBTITLE_EL.$title.SUBTITLE_ER);
			break;
		}
		return true;
	}

	function user_env_vars($data) {
		$env = Array (
			// <a href="%index%/some/relative/link"> useful since we're using relative paths
			//"index" => rtrim(_l("C_SITE.URL"), "/")
			"index" => rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/")
		);
		foreach ($env as $p => $r) {
			$pattern[] = "/%$p%/";
			$replace[] = $r;
		}
		$data = preg_replace($pattern, $replace, $data);
		return $data;
	}

	function preg_escape($str) {
		$pat = array("/\(/", "/\)/");
		$rep = array("\(", "\)");
		return preg_replace($pat, $rep, $str);
	}

	// ANTIBOT
	function jsobfuscate($string) {
		// Obfuscates a single string for use as Javascript code.
		// The main pourpose for doing this is to avoid lowlife people
		// that create simple spam spiders to be attacking our website.
		// Commonly, those spiders doesn't evaluate javascript (they don't
		// need to do such a thing), so I think this is simple and useful
		// method to keep those annoying spiders out from our website.
		$len = strlen($string);
		$mod = Array();
		$i = 0;
		while ($i < $len) {
			$o = rand(1, $len - $i);
			$part = substr($string, $i, $o);

			switch (rand(0, 2)) {
				case 0:
					$mod[] = "\"".$part."\"";
				break;
				case 1:
					$buff = "";
					for ($j = 0; $j < strlen($part); $j++) {
						$buff .= "%".dechex(ord(substr($part, $j, 1)));
					}
					$mod[] = "unescape(\"$buff\")";
				break;
				case 2:
					switch (rand(0, 7)) {
						case 0: $cmp = "<"; break;
						case 1: $cmp = ">"; break;
						case 2: $cmp = "&&"; break;
						case 3: $cmp = "=="; break;
						case 4: $cmp = "!="; break;
						case 5: $cmp = "||"; break;
						case 6: $cmp = "<="; break;
						case 7: $cmp = ">="; break;
					}
					$buff = Array();
					for ($j = 0; $j < strlen($part); $j++) {
						$eval = "(".rand(0, 10).$cmp.rand(0, 10).")";
						eval("\$val = $eval;");
						$t = substr($part, $j, 1);
						$f = dechex(rand(0,16));
						$buff[] = "($eval?\"".($val ? $t : $f)."\":\"".($val ? $f : $t)."\")";
					}
					$mod[] = implode("+", $buff);
				break;
			}
			$i += $o;
		}
		return implode("+", $mod);
	}

	function html_split_attributes($tag) {
		preg_match_all("/([a-z]*)\=\"(.*?)\"/i", " $tag ", $m);
		$attr = Array();
		foreach ($m[1] as $i => $n) {
			$attr[$n] = $m[2][$i];
		}
		return $attr;
	}

	function preg_pos($text, $pattern) {
		preg_match($pattern, $text, $buff);
		if (isset($buff[0])) {
			return strpos($text, $buff[0]);
		} else {
			return false;
		}
	}

	/*
		TEMPLATE ENGINE

	*/
	define ("BLOCK_HIDE_FLAG", '1');

	// Gekko Template Engine
	Class gtEngine {

		var $tpldir;
		var $gzip_output;
		var $buff;
		function gtEngine($gzip = false) {
			$this->tpldir = GEKKO_ROOT."templates/default/";
			return true;
		}
		/*
			eval_code(statement);

			Returns true or false after evaluating statement

			eval_code("if (1 == 1)"); // returns true
			eval_code("if (1 > 1)"); // returns false

			When no statement is provided returns true.

			You can also use variables like $VAR if VAR is a key in
			$vars array.
		*/
		function eval_code($code, $vars = Array()) {
			if ($code) {
				// pattern
				preg_match("/(\w*)\s*(.*)/", $code, $cpat);
				array_shift($cpat);
				list($code, $eval) = $cpat;

				// replacing $variable with $vars[variable] unless it were an array
				$eval = preg_replace("/\\\$([A-Za-z0-9\.\-\_]*)/e", "(array_key_exists(\"\\1\", \$vars) && !is_array(\$vars[\"\\1\"])) ? (\$vars[\"\\1\"] ? \"\\\\\$vars[\\\"\\1\\\"]\" : 0) : 0", $eval);

				switch ($code) {
					// if statement
					case "if":
						eval("\$return = $eval ? 1 : 0;");
					break;
					default:
						trigger_error("Unknown statement: $code.", E_USER_ERROR);
					break;
				}
				return $return;
			} else {
				// no statament was provided
				return true;
			}
		}
		/*
			split_blocks();

			Splits template buffer into an array of blocks:

			$buff example:

			...some code...
			<!--{bgn: BLOCKNAME}-->
				...
				Block content
				<!--{bgn: BLOCK2 #if (1==1)#}-->
					Block with conditional statement
				<!--{end: BLOCK2}-->
				...
			<!--{end: BLOCKNAME}-->
			...some code...
		*/

		function split_blocks($buff) {

			$ret = Array();

			if (is_array($buff)) $buff = $buff["CORE"];

			// locating block tags
			preg_match_all("/<!--{bgn: (\w*)\s*?(#(.*?)#)*?}-->/", $buff, $bpat);

			$ret["CORE"] = $buff;

			foreach ($bpat[1] as $i => $block_name) {
				// matching the whole block and its content
				preg_match("/".preg_escape($bpat[0][$i])."(.*?)<!--{end: $block_name}-->/s", $ret["CORE"], $block);

				if (isset($block[0])) {
					// array keys for blocks must be uppercase
					$block_name = strtoupper($block_name);

					// evaluating block condition (if any)
					$eval = isset($bpat[3][$i]) ? $this->eval_code($bpat[3][$i]) : 1;

					// replacing whole block with {%block_name} if condition eq true
					$ret["CORE"] = str_replace($block[0], ($eval) ? "{%".$block_name."}" : "", $ret["CORE"]);

					if ($eval) {
						// adding block buffer to a new array key and starts
						// again with block content (for nested blocks)
						$ret[$block_name] = $this->split_blocks($block[1]);
					}
				}
			}
			return $ret;
		}

		function escape($v) {
			$v = str_replace("\\", "\\\\", $v);
			$v = str_replace("{", "\\{", $v);
			$v = str_replace("}", "\\}", $v);
			return $v;
		}
		function unescape($v) {
			$v = str_replace("\\{", "{", $v);
			$v = str_replace("\\}", "}", $v);
			$v = str_replace("\\\\", "\\", $v);
			return $v;
		}
		/*
			conditional_block(template_buffer, array variables)

			Returns a modified version of template_buffer by
			evaluating conditional blocks:

				<!--if (1 == 2)-->
					Show some code
				<!--endif-->

			You can, also, use variables passed to $vars array.
			To display the blocm below, $vars["my_variable"] must
			be 2;

				<!--if ($my_variable == 2)-->
					Show some code
					<!--if (1==2)-->
						This is false.
					<!--endif-->
				<!--endif-->

			Note that there is no spaces in <!--endif--> tag, it must
			be wrote "as is".
		*/
		function conditional_block($buff, $vars) {
			// <!--if(statement)-->code to show, if true<!--endif-->
			while ((!isset($ifpat) || $ifpat) && preg_match("/(<!--(if\s*?\(.*?\))-->)(.*?)$/s", $buff, $ifpat)) {
				// searching the deepest "if" nested statement
				while ($ifpat && ($s = preg_pos($ifpat[3], "/<!--if\s*?(.*?)-->/")) < ($e = preg_pos($ifpat[3], "/<!--endif-->/")) && $s) {
					preg_match("/(<!--(if\s*?\(.*?\))-->)(.*?)$/s", $ifpat[3], $ifpat);
				}
				// evaluating condition
				list($whole, $init_tag, $condition, $block) = $ifpat;
				$block = substr($block, 0, $e);
				$whole = substr($whole, 0, strlen($block)+strlen($init_tag)+12);
				$buff = str_replace($whole, $this->eval_code($condition, $vars) ? $block : "", $buff);
			}
			return $buff;
		}
		/*
			replace_vars(array vars, data);

			Replaces {VARIABLE_NAME} in $data by $vars["VARIABLE_NAME"]

			Returns modified data.
		*/
		function replace_vars($vars, $data) {
			return preg_replace("/{(.*?)}/e", "(array_key_exists(\"\\1\", \$vars) && (!is_array(\$vars[\"\\1\"])) ? \$this->escape(\$vars[\"\\1\"]) : \"{\\1}\")", $data);
		}
		/*
			parse_plain(&$buff, array &$vars, bool &$dinamic);

			Compiles a template buffer in plain mode ($data must
			not be passed as an array). Executes all conditional
			blocks (when $dinamic is true), performs variable
			replacement...
		*/
		function parse_plain(&$buff, &$vars, &$dinamic) {
			if ($dinamic) {
				$buff = $this->conditional_block($buff, $vars);
				$buff = $buff;
			}
			$buff = $this->replace_vars($vars, $buff);
		}
		/*
			parse_dinamic(&$buff, array &$vars, bool $dinamic);

			Compiles a template block array or a plain template
			buffer executing conditional blocks and performs
			variable replacement in recursive mode.
		*/
		function parse_dinamic(&$buff, &$vars, $dinamic = false) {
			foreach ($buff as $key => $data) {
				if (is_array($data)) {
					$this->parse_dinamic($buff[$key], $vars, $dinamic);
				} else {
					$this->parse_plain($buff[$key], $vars, $dinamic);
				}
			}
		}
		/*
			parse (buff, array vars, bool dinamic);

			Compiles and returns the given template buffer, that
			could be a block array or a plain string.

			Please refer ro parse_dinamic and parse_plain functions
		*/
		function parse($buff, $vars, $dinamic = false) {
			if (is_array($buff)) {
				$this->parse_dinamic($buff, $vars, $dinamic);
			} else {
				$this->parse_plain($buff, $vars, $dinamic);
			}
			return $buff;
		}
		/*
			load(filename, bool lang, bool dinamic);

			Reads a template file into memory.
			Returns the loaded buffer

			Templates are stored by default in ./templates/default
			You must either specify an absolute path (beginning with "/") or
			a relative one (relative to $this->tpldir)

			When $lang is true, after loading this block it will be parsed
			agains Gekko language variables.
		*/
		function load($tpl_file, $lang = true, $dynamic = false) {
			$tpl_file = (substr($tpl_file, 0, 1) == "/") ? $tpl_file : $this->tpldir.$tpl_file;
			if (file_exists($tpl_file)) {
				$buff = fileread($tpl_file);
				$buff = $this->split_blocks($buff);
				if ($lang) {
					$buff = $this->parse($buff, $GLOBALS["L"], $dynamic);
				}
			} else {
				trigger_error("Cannot load template: $tpl_file", E_USER_ERROR);
			}
			return $buff;
		}
		/*
			tar(blocks buffer);

			Performs the last step on template compilation, this function
			converts from a block buffer to a single string and returns it.
		*/
		function tar(&$buff) {
			if (is_array($buff)) {
				if (count($buff)) {
					preg_match_all("/{%(.*?)}/", $buff["CORE"], $matches);
					foreach ($matches[0] as $i => $void) {
						$buff["CORE"] = str_replace($matches[0][$i], $this->tar($buff[$matches[1][$i]]), $buff["CORE"]);
					}
				}
				return $buff["CORE"];
			} else {
				return $buff;
			}
		}
		/*
			make(template buffer);

			Returns a compiled and "ready-to-output" version of the given
			template buffer.
		*/
		function make(&$buff) {
			return $this->unescape($this->tar($buff));
		}
		/*
			output(template buffer, bool fix_code);

			Outputs the compiled template buffer to user's
			browser and can perform some code improvements
			when fix_code is 1.
		*/
		function output($buff = null, $fixes = true) {

			if (!$buff) $buff = $this->buff;

			$buff = $this->make($buff);

			// code fixes
			if ($fixes) {
				// enviromental variables
				$buff = user_env_vars($buff);

				// replacing absolute uris with relative ones
				$buff = str_replace(_l("C_SITE.URL"), _l("C_SITE.REL_URL"), $buff);

				/*
					I'd write a decent plugin system... later now I want to sleep 
				*/
				$plugins = listdir(GEKKO_ROOT."lib/plugins");
				foreach ($plugins as $plugin) {
					include_once GEKKO_ROOT."lib/plugins/$plugin";
					$plugin_call = substr($plugin, 0, -4)."_output";
					$plugin_call($buff);
				}

			}
			echo $buff;
		}
	}

	Class BlockWidget {

		var $widget_template;
		var $widget_variable = Array();
		var $gte;

		var $icondir;
		var $cache;
		var $blocks = Array();
		var $bvars = Array();

		/*
			BlockWidget(template, array initialization variables)
			Can load a template file using initialization variables.

			Please refer to $this->load(); function.
		*/
		function BlockWidget ($template = null, $initvars = null) {
			$this->gte = new gtEngine();
			if ($template)
				$this->load($template, $initvars);
			return true;
		}
		function block($block, $set = null, $buff = false) {
			$path = explode(".", $block);
			$block = &$this->blocks;
			foreach ($path as $p) {
				$block = &$block[$p];
			}
			$k = ($buff) ? "BUFF" : "CORE";
			$p = &$block[$k];
			if ($set !== null) $p = rtrim($set);
			return $p;
		}
		function hideBlock($block) {
			$this->block($block, BLOCK_HIDE_FLAG, true);
		}
		/*
			load (template file, initizalization vars);

			Loads into cache the given template file using
			initialization variables.
		*/
		function load ($template = null, $initvars = null) {
			if ($this->cache) {

				// we don't need to reload this file.
				$this->widget_template = $this->cache;

			} else {

				// loading file using gtEngine
				$buff = $GLOBALS["T"]->Load($template, true);

				if ($initvars)
					$buff = $GLOBALS["T"]->Parse($buff, $initvars);

				// setting up template
				if (is_array($buff)) {
					$this->widget_template = $buff["CORE"];
					unset($buff["CORE"]);
					foreach ($buff as $block => $content) {
						$this->blocks[$block] = $content;
						$this->bvars[$block] = Array();
					}
				} else {
					$this->widget_template = $buff;
				}
			}
		}
		/*
			vren (old name, nre name, [block]);

			Renames a template variable for the given block or in the
			main buffer when $block argument is null
		*/
		function vren($old_name, $new_name, $block = null) {
			if ($block) {
				$this->block($block, str_replace("{".$this->vkey($old_name)."}", "{".$this->vkey($new_name)."}", $this->block($block)));
			} else {
				$this->widget_template = str_replace("{".$this->vkey($old_name)."}", "{".$this->vkey($new_name)."}", $this->widget_template);
			}
		}
		/*
			insert (where, template file, [initialization variables], [block]);

			Replaces $where variable with a (non-compiled) template buffer.

			Since this template buffer is not compiled you can insert templates
			that uses blocks.
		*/
		function insert ($where, $template, $initvars = false, $block = null) {
			$where = "{".$this->vkey($where)."}";

			// loading template
			$tmp = $GLOBALS["T"]->load($template, 1);

			if ($initvars)
				$tmp = $GLOBALS["T"]->parse($tmp, $initvars, true);

			if (is_array($tmp)) {
				// inserting a block buffer
				if ($block) {
					$this->block($block, str_replace($where, $tmp["CORE"], $this->block($block)));
				} else {
					$this->widget_template = str_replace($where, $tmp["CORE"], $this->widget_template);
				}
				unset($tmp["CORE"]);
				foreach ($tmp as $block => $content) {
					$this->blocks[$block] = $content;
				}
			} else {
				// inserting a plain template buffer
				if ($block) {
					$this->block($block, str_replace($where, $tmp, $this->block($block)));
				} else {
					$this->widget_template = str_replace($where, $tmp, $this->widget_template);
				}
			}
			return true;
		}
		/*
			saveBuff(block, clean variables)

			Compiles and appends the given block to its corresponding
			output buffer
		*/
		function saveBuff ($block, $clearvars = true) {
			// appending block to its buffer, removing leading spaces
			$buff = $this->block($block, null, true).$this->make($block);
			$buff = rtrim($buff);

			$this->block($block, rtrim($buff), 1);
			if ($clearvars)
				$this->bvars[$block] = Array();
		}
		/*
			mkblocks (block name, [bool core]);

			Converts the given block into a plain string. Useful when
			compiling blocks.
		*/
		function mkblocks($block, $core = false) {
			$buff = Array();
			if (isset($block["CORE"])) {
				if (isset($block["BUFF"]) && $block["BUFF"] && !$core) {
					// hidden blocks
					$buff["CORE"] = ($block["BUFF"] == BLOCK_HIDE_FLAG) ? "": $block["BUFF"];
				} else {
					$buff["CORE"] = $block["CORE"];
				}
			}
			unset($block["CORE"], $block["BUFF"]);
			foreach ($block as $key => $val) {
				// isn't a pretty recursion?
				$buff[$key] = $this->mkblocks($block[$key]);
			}
			return $buff;
		}
		/*
			make ([block], [bool is_core], [exclude list]);

			Compiles the given block (if any), or the whole block
			buffer (if no block is given).
		*/
		function make ($block = null, $core = false, $exclude = array()) {
			$buff = "";
			if ($block) {
				// simple block compilation
				$buff = $this->blocks;
				$path = explode(".", $block);

				foreach ($path as $p)
					$buff = $buff[$p];

				$buff = $GLOBALS["T"]->make($b = $this->mkblocks($buff, 1));
				$buff = $GLOBALS["T"]->parse($buff, isset($this->bvars[$block]) ? $this->bvars[$block] : array(), true);
			} else {
				if (count($this->blocks)) {

					$buff = Array();

					$buff["CORE"] = $GLOBALS["T"]->parse($this->widget_template, $this->widget_variable, true);

					$blocks = $this->mkblocks($this->blocks);

					$buff = array_merge($buff, $blocks);

					$buff = $GLOBALS["T"]->make($buff);

				} else {
					$buff = $GLOBALS["T"]->parse($this->widget_template, $this->widget_variable, true);
				}
			}
			return $buff;
		}

		// returns template variable name
		function vkey ($vname) { return "V_".strtoupper($vname); }

		// gets $what variable from $block
		function get ($what, $block = null) {
			if ($block) {
				return ($b = $this->bvars[$block][$this->vkey($what)]) ? $b : "{E_UNDEFINED}";
			} else {
				return ($b = $this->widget_variable[$this->vkey($what)]) ? $b : "{E_UNDEFINED}";
			}
		}

		// sets $what variable in $block buffer
		function set ($what, $value, $block = null) {
			if ($block) {
				if (!isset($this->bvars[$block])) $this->bvars[$block] = array();
				$this->bvars[$block][$this->vkey($what)] = $value;
			} else {
				$this->widget_variable[$this->vkey($what)] = $value;
			}
			return true;
		}

		// clears $what variable in $block buffer
		function clear ($what, $block = null) {
			if ($block) {
				$this->bvars[$block][$this->vkey($what)] = null;
			} else {
				$this->widget_variable[$this->vkey($what)] = null;
			}
		}

		// sets an array of variables in $block
		function set_arr ($vars, $block = null, $destroy = true) {
			foreach ($vars as $key => $val) {
				$this->set($key, $val, $block);
			}
			return true;
		}
		/*
			reset([block], [bool keep buffer]);

			An attemp to revert a block to its original status (before
			any work with it)
		*/
		function reset ($block = null, $keep_buffer = false) {
			if ($block) {
				$this->bvars[$block] = array();
				// cleaning buffer
				if (!$keep_buffer) $this->block($block, " ", true);
				// reverting to original
				$this->block($block, $this->block($block));
			} else {
				// using cache
				$this->widget_template = $this->cache;
			}
		}

		// saves main buffer into cache
		function save () {
			$this->cache = $this->widget_template;
		}
	}

	Class ContentBlock extends BlockWidget {
		function ContentBlock ($class = "ContentBlock", $source = "main/ContentBlock.tpl") {
			$this->widget_variable = Array (
				"V_BLOCK_ICON" => mkIcon("block.png", 16),
				"V_BLOCK_TITLE" => "New Block",
				"V_BLOCK_CONTENT" => "Block Content",
				"V_BLOCK_CLASS" => $class
			);
			$this->load($source);
		}
	}

	Class Panel {
		var $icons = Array();
		var $icon = "panel";
		var $title = "New Panel";
		var $isize = 48;
		function Panel($title, $icon = "panel", $size = "48") {
			$this->isize = $size;
			$this->icon = $icon;
			$this->title = $title;
			$this->icons[""] = Array();
		}
		function AddIcon($icon, $category = null) {
			if (!isset($this->icons[urlencode($category)])) $this->icons[$category] = Array();
			$this->icons[urlencode($category)][] = $icon;
		}
		function Icon($icon, $href, $text) {
			return mkLink($href, mkIcon($icon, $this->isize)."<br />$text");
		}
		function make() {
			$tpl = new ContentBlock();
			$tpl->insert("BLOCK_CONTENT", "main/Panel.tpl");
			$tpl->set_arr (
				Array (
					"BLOCK_TITLE" => $this->title,
					"BLOCK_ICON" => mkIcon($this->icon, 16)
				)
			);
			foreach ($this->icons as $key => $icons) {
				if (count($icons)) {
					$tpl->reset("CATEGORY.ICON");
					foreach ($icons as $icon) {
						$tpl->set_arr(
							Array("ICON" => $icon), "CATEGORY.ICON"
						);
						$tpl->saveBuff("CATEGORY.ICON");
					}
					$tpl->set_arr (
						Array ("CATEGORY" => urldecode($key)), "CATEGORY"
					);
					$tpl->saveBuff("CATEGORY");
				}
			}
			return $tpl->make();
		}
	}

	Class buttonBox {
		var $buff;
		var $buttons = Array();
		function add($href, $text, $icon = false, $confirm = false, $style = null) {
			$this->buttons[] = mkLink($href, $text, $icon, $confirm, $style);
		}
		function make() {
			return '<div class="buttons">'.trim(implode(" | ", $this->buttons)).'</div>';
		}
	}

	/*
		mkLink(String Link, String Link Text);

		- if $href has someword:// link is displayed 'as is'
		- when $href has / at it's beginning (commonly used for
		module actions), this only adds the proper relative file
		path to make it work
		- when $href has not a / at it's beginning, in addition
		to relative file path its adding /index.php/ to work like
		a link to other page
	*/
	function mkLink($href, $text, $icon = false, $confirm = false, $style = null) {

		$href = preg_match("/\w*:\/\//i", $href) ? $href : $GLOBALS["L"]["C_SITE.REL_URL"].htmlspecialchars($href);

		if ($confirm) $href = 'javascript:confirmAction(\''.$href.'\', \''.$text.'\')';

		switch ($style) {
			case "icon":
				return '<a href="'.$href.'" title="'.$text.'">'.mkIcon($icon, 16).'</a>';
			break;
			default:
				return '<a href="'.$href.'">'.($icon ? mkIcon($icon, 16)." " : "").$text.'</a>';
			break;
		}
	}

	/*
		checks if this is a relative or external link
		returns the correct href format
	*/
	function rel_link($href) {
		if (!preg_match("/([a-z0-9]*):\/\/.*/i", $href)) {
			if (substr($href, 0, 1) == "/") {
				$href = _l("C_SITE.URL").substr($href, 1);
			} else {
				$href = _l("C_SITE.REL_URL").$href;
			}
		}
		return $href;
	}

	function safeURL($url) {
		if (preg_match("/([a-zA-Z]*):.*/", $url, $m)) {
			$proto = strtolower($m[1]);
			switch ($proto) {
				// this protocols in a user submitted link doesn't seems to be friendly
				case "javascript": $url = null; break;
				case "vbs": $url = null; break;
			}
		}
		if (!isset($proto) || !$proto) {
			if (preg_match("/^[a-zA-Z0-9\.\-\_]*@[a-zA-Z0-9\.\-\_]*\.[a-z]*$/", $url, $m)) {
				$url = "mailto:".$url;
			} else {
				$url = "http://$url";
			}
		}
		return $url;
	}
	/*
		safeLink(url to check, [url text]);
		Returns a safe <a href=""></a> tag by identifying undesired
		protocols such as javascript:someLeetFunction();
	*/
	function safeLink($url, $text = null) {
		return (($href = safeURL($url)) == true) ? "<a href=\"$href\">".($text?$text:$href)."</a>" : $text;
	}

	// mkIconChooser(icon size, [default icon], [obj id]);
	function mkIconChooser($size, $default = "default.png", $id = "imgIcon") {
		switch ($size) {
			case "16":
				return '<img id="'.$id.'" src="'.fetchIcon($default, 16).'" width="16" height="16" alt="icon" /><input readonly="readonly" onclick="iconChooser(\''.$id.'\', this, 16)" class="text" type="text" name="icon" size="15" value="'.$default.'" />';
			break;
			case "48":
				return '<img id="'.$id.'" src="'.fetchIcon($default, 48).'" width="48" height="48" alt="icon" /><br /><input readonly="readonly" onclick="iconChooser(\''.$id.'\', this, 48)" class="text" type="text" name="icon" size="12" value="'.$default.'" />';
			break;
		}
	}

	// returns a link for the specified icon
	function fetchIcon($icon, $size, $relpath = null) {
		$icondir = "media/icons/"._l("C_SITE.ICONTHEME")."/{$size}/";
		if (file_exists(GEKKO_ROOT.$icon)) {
			$icon = _l("C_SITE.URL").$icon;
		} elseif (file_exists(GEKKO_ROOT.$icondir.$icon)) {
			$icon = ($relpath ? $relpath : _l("C_SITE.REL_URL").$icondir).$icon;
		} else {
			$icon = ($relpath ? $relpath : _l("C_SITE.REL_URL").$icondir)."default.png";
		}
		return $icon;
	}

	// mkIcon(icon name, icon size, html style, relative path);
	function mkIcon($icon, $size, $style = null, $relpath = null) {
		return '<img src="'.fetchIcon($icon, $size, $relpath).'" width="'.$size.'" height="'.$size.'" alt="'.basename($icon).'"'.($style ? ' style="'.$style.'"' : '').' />';
	}

	// mkSelect(array options, selected option index, html object name, html attributes)
	function mkSelect($options, $selected = null, $name = null, $attributes = null) {
		$buff = null;
		foreach ($options as $value => $option) {
			$buff .= '<option value="'.$value.'"'.(($selected && $selected == $value) ? ' selected="selected" class="selected"' : "").'>'.$option.'</option>';
		}
		return $name ? '<select name="'.$name.'"'.($attributes ? " $attributes" : "").'>'.$buff.'</select>' : $buff;
	}

	// mkButtonDisplay(Array buttons);
	function mkButtonDisplay($buttons, $style = null) {
		switch ($style) {
			case "iconbox":
				return '<div class="buttons">'.trim(implode(" ", $buttons)).'</div>';
			break;
			default:
				return '<div class="buttons">'.trim(implode(" | ", $buttons)).'</div>';
			break;
		}
	}

	// mkcheckBox(obj name, descriptive text, [bool checked], [value]);
	function mkCheckBox($name, $text, $checked = false, $value = "1") {
		return '<span><input type="checkbox" name="'.$name.'" value="'.$value.'"'.($checked ? ' checked="checked"' : '').' /> '.$text.'</span>';
	}

	// mkRadio(obj name, descripive text, [bool checked], [value]);
	function mkRadio($name, $text, $checked = false, $value = "1") {
		return '<span><input type="radio" name="'.$name.'" value="'.$value.'"'.($checked ? ' checked="checked"' : '').' /> '.$text.'</span>';
	}

	// mkInputBox(obj name, [input value]);
	function mkInputBox($name, $value = "") {
		return '<input class="text" type="text" name="'.$name.'" value="'.$value.'" />';
	}

	// mkTag(obj name, array attributes, [bool single close]);
	function mkTag($name, $attrib = null, $single = false) {
		$html = Array();
		foreach ($attrib as $attr => $val) $html[] = "$attr=\"$val\"";
		$html = trim(implode(" ", $html));
		$html = "<$name $html".($single ? " />" : "></$name>");
		return $html;
	}

	// mkDateSelect(obj name, [selected date string (yyyymmdd)])
	function mkDateSelect($name, $selected = null) {

		$days = Array();
		for ($i = 1; $i <= 31; $i++) { $days[$i] = $i; }
		$months = Array();
		for ($i = 1; $i <= 12; $i++) { $months[$i] = strftime("%B", mktime(0,0,0,$i,1,date("Y"))); }
		$years = Array();
		for ($i = (date("Y")-50); $i <= date("Y"); $i++) { $years[$i] = $i; }

		if (strpos($selected, " ")) {
			preg_match("/(\d*)\-(\d*)-(\d*)\s(\d*):(\d*):(\d*)/", $selected, $m);
			list($selected,$y,$m,$d,$h,$i,$s) = $m;
		} else {
			$d = intval(substr($selected, 6, 2));
			$m = intval(substr($selected, 4, 2));
			$y = substr($selected, 0, 4);
		}

		$return = Array();
		$return[] = mkSelect($days, intval($d), $name."[d]");
		$return[] = mkSelect($months, intval($m), $name."[m]");
		$return[] = mkSelect($years, intval($y), $name."[y]");

		return implode("/", $return);
	}

	// mkLetter(array (module, template letter), [array variables])
	function mkLetter($tpl, $vars = Array()) {
		$tpl = explode("/", $tpl);
		$tpl = GEKKO_ROOT."modules/{$tpl[0]}/lang/"._l("C_SITE.LANG")."/{$tpl[1]}.letter";
		$obj = new BlockWidget($tpl);
		$obj->set_arr($vars);
		return $obj->make();
	}

	// booleanStatus([bool enable], [obj name]);
	function booleanStatus($opt = 1, $name = "status") {
		return mkSelect(Array(_l("L_DISABLED"), _l("L_ENABLED")), $opt, $name);
	}

	// mkAuthSelect([default auth string], [obj name])
	function mkAuthSelect($value = "*", $name = "auth_access") {
		return '<input class="text" type="text" readonly="readonly" onclick="groupChooser(this, true)" name="'.$name.'" value="'.$value.'" />';
	}

	// sw_class(foo integer);
	function sw_class(&$i) { return "sw_class_".($i = (($i) ? --$i : ++$i)); }

	/*
		mkPager (total pages, current page, url, amplitude)
		url = http://myscript/content?page=%p
		Where "%p" is our page variable
	*/
	function mkPager($total, $current, $link, $amp=3) {
		// returns a pretty xhtml formated pager
		$pager = "";
		if ($current <= 0) $current = 1;

		if ($total > 1) {
			for ($i = $current+$amp*-1; $i <= $current+$amp && $i <= $total; $i++) {
				if ($i > 0)
					$pager .= ($current == $i) ? "<b>[$i]</b>": mkLink(str_replace("%p", $i, $link), "[$i]");
			}
			if ($current-$amp > 0) {
				if ($current-$amp > 2)
					$pager = "...".$pager;
				if ($current-$amp > 1)
					$pager = mkLink(str_replace("%p", 1, $link), "[1]").$pager;
				$pager = "<b>".mkLink(str_replace("%p", $current-1, $link), "&laquo;")."</b> ".$pager;
			}
			if ($total >= $i && $current+1 <= $total) {
				if ($total != $i)
					$pager .= "...";
				$pager .= mkLink(str_replace("%p", $total, $link), "[$total]")."</b>";

				$pager .= " <b>".mkLink(str_replace("%p", $current+1, $link), "&raquo;")."</b>";
			}
			return '<div class="pager"><b>'._l("L_PAGES").'</b>: '.$pager.'</div>';
		}
	}

	/*
		fetchIcons(size, [iconset]);
		Will fetch and return an array of the found icons.
	*/
	function fetchIcons($size, $iconset = "default") {
		$icondir = GEKKO_ROOT."media/icons/$iconset/$size";
		$r = Array();
		if (file_exists($icondir) || ($icondir = GEKKO_ROOT."media/icons/default/$size")) {
			$dh = opendir($icondir);
			while (($f = readdir($dh)) !== false) {
				if ($f != "." && $f != "..") {
					$e = file_extension($f);
					// accepted extensions
					if ($e == "png" || $e == "gif" || $e == "jpg") {
						$r[] = $f;
					}
				}
			}
			closedir($dh);
		} else {
			trigger_error("Couldn't locate iconset.", E_USER_ERROR);
		}
		return $r;
	}

	function draw_message($type, $message, $custom_icon = "") {
		switch ($type) {
			case "success": $class = "info"; $icon = "ok.png"; break;
			case "info": $class = "info"; $icon = "info.png"; break;
			case "warning": $class = "error"; $icon = "warning.png"; break;
			case "error": $class = "error"; $icon = "error.png"; break;
			default: $class = $type; $icon = $type.".png"; break;
		}
		return "<div class=\"$class\"><table style=\"padding:3;margin:0;\"><tr><td>".mkIcon($custom_icon ? $custom_icon : $icon, 48)."</td><td>$message</td></tr></table></div>\n";
	}

	$L["B_SUBMIT"] = "<button type=\"submit\">".mkIcon("submit.png", 16)." "._l("L_SUBMIT")."</button>";
	$L["B_RESET"] = "<button type=\"reset\">".mkIcon("reset.png", 16)." "._l("L_RESET")."</button>";

	// Generic template engine
	$T = new gtEngine();
?>