<?php
/**
 * Wiki farm manager admin plugin
 *
 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author   Etienne MELEARD <etienne.meleard@cru.fr>
 * @desc     Allow farm administration through the DokuWiki admin interface,
 *           handle a farm command from $_REQUEST['farm_cmd'], loads a handler class
 *           form it then process request / display output html
 */

// must be run within Dokuwiki
if(!defined('DOKU_INC')) die();

if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
if(!defined('DOKU_FARM_PLUGIN')) define('DOKU_FARM_PLUGIN', DOKU_PLUGIN.'farm/');

if(!defined('DOKU_FARM_WWW')) define('DOKU_FARM_WWW', 'lib/plugins/farm/');

if(!defined('DOKU_FARMPLUGINLOADED')) define('DOKU_FARMPLUGINLOADED', true);

require_once(DOKU_PLUGIN.'admin.php');

/**
 * Version string, will be used to check whether we need to upgrade the farm or not,
 * it can be in the case of a new installation or if we updated the plugin from
 * plugin manager / fs and the downloaded version is higher than the installed one,
 * in this case we update structure / config if needed.
 */
define('DOKU_FARM_VERSION', '1');

/**
 * All DokuWiki plugins to extend the admin function
 * need to inherit from this class
 */
class admin_plugin_farm extends DokuWiki_Admin_Plugin {
	var $disabled = 0;
	
	var $cmd = '';
	var $opt = array();
	
	var $conf = array();
	
	var $handler = null;
	var $lang = array();
	var $localised = false;
	
	var $errors = array();
	var $success = array();
	
	var $version = null;
	
	function __construct() {
		global $conf;
		
		if(defined('DOKU_IS_FARMER')) $this->getConf();
		
		$this->disabled = (isset($conf['pluginfarm']) && ($conf['pluginfarm'] == 0));
	}
	
	/**
	 * Return some info
	 */
	function getInfo() {
		return array(
			'author' => 'Etienne Meleard',
			'email'  => 'etienne.meleard@cru.fr',
			'date'   => '2009-12-16',
			'name'   => 'Farm Manager',
			'desc'   => 'Manage Wiki farm'.($this->disabled ? ' (disabled)' : ''),
			'url'    => 'http://wiki.splitbrain.org/plugin:farm',
		);
	}
	
	/**
	 * Return prompt for admin menu
	 * @param $l language identifier
	 * @return nothing if not in farmer context, menu title otherwise
	 */
	function getMenuText($l) {
		if(!defined('DOKU_IS_FARMER')) {
			@touch(DOKU_CONF.'local.php');
			return $this->getLang('menu'); // not installed
		}
		if(!DOKU_IS_FARMER) return; // don't display farm management item in the animals' admin page
		if(!$this->disabled) return $this->getLang('menu');
		return '';
	}
	
	/**
	 * Return sort order for position in admin menu
	 * @return integer
	 */
	function getMenuSort() {
		return 20;
	}
	
	/**
	 * Get localized string
	 * @param $code lang string identifier
	 * @param $data string or array used to replace %s occurences in the localized string
	 * @param $opt option to postprocess localized string
	 * @return localized string
	 */
	function getLang($code, $data = null, $opt='') {
		if(!$this->localised) $this->setupLocale();
		if(!isset($this->lang[$code])) return '{'.strtoupper($code).'}';
		$str = $this->lang[$code];
		if(!is_null($data)) if(!is_array($data)) $data = array($data);
		if(is_array($data)) foreach($data as $d) $str = preg_replace('`%s`', $d, $str, 1);
		switch($opt) {
			case 'js': $str = htmlentities(str_replace('\'', '\\\'', $str)); break;
		}
		return $str;
	}
	
	/**
	 * Get farm config
	 * @return array of farm config parameters
	 */
	function getConf() {
		$farmconf = array();
		include DOKU_FARM_PLUGIN.'config.php';
		$this->conf = $farmconf;
		return $this->conf;
	}
	
	/**
	 * Add error to error list
	 * @param $family error familly identifier (lang string identifier)
	 * @param $e error code (lang string identifier) or array containing 'code' => string and 'data => array entries
	 */
	function error($family, $e) {
		if($family == '') $family = 'not_classified_errors';
		if(!isset($this->errors[$family])) $this->errors[$family] = array();
		$this->errors[$family][] = $e;
	}
	
	/**
	 * Print errors
	 */
	function putErrors() {
		if(!count($this->errors)) return;
		foreach($this->errors as $c => $list) {
			ptln('<div class="error">');
			ptln('	'.$this->getLang($c));
			ptln('	<ul>');
			foreach($list as $e) ptln('		<li>'.$this->getLang(is_array($e) ? $e['code'] : $e, is_array($e) ? $e['data'] : null).'</li>');
			ptln('	</ul>');
			ptln('</div>');
		}
	}
	
	/**
	 * Add success to success list
	 * @param $s success code (lang string identifier)
	 */
	function success($s) {
		$this->success[] = $s;
	}
	
	/**
	 * Print successes
	 */
	function putSuccess() {
		if(!count($this->success)) return;
		ptln('<div class="success">');
		if(count($this->success) > 1) {
			ptln('	<ul>');
			foreach($this->success as $s) ptln('		<li>'.$this->getLang(is_array($s) ? $s['code'] : $s, is_array($s) ? $s['data'] : null).'</li>');
			ptln('	</ul>');
		}else{
			$s = reset($this->success);
			ptln('	'.$this->getLang(is_array($s) ? $s['code'] : $s, is_array($s) ? $s['data'] : null));
		}
		ptln('</div>');
	}
	
	/**
	 * Returns human readable size
	 * @param $s size as integer
	 * @return human readabe localized size as a string
	 */
	function nicesize($s) {
		$e = '';
		$m = array('k', 'M', 'G', 'T');
		foreach($m as $p) {
			if($s < 1024) break;
			$s /= 1024;
			$e = $p;
		}
		return number_format($s, ($s >= 100 || $e == '') ? 0 : 1).$e.$this->getLang('size_unit');
	}
	
	/**
	 * Print form head
	 * @param $data associative array of hidden fields names and values to be printed in the form
	 */
	function formHead($data = array()) {
		global $ID;
		echo '<form method="post" action="'.wl($ID).'">'."\n";
		echo '	<fieldset class="hidden">'."\n";
		echo '		<input type="hidden" name="do" value="admin" />'."\n";
		echo '		<input type="hidden" name="page" value="farm" />'."\n";
		foreach($data as $k => $v) echo '		<input type="hidden" name="'.$k.'" value="'.$v.'" />'."\n";
		formSecurityToken();
		echo '	</fieldset>'."\n";
	}
	
	/**
	 * Builds a link inside farm manager
	 * @param $cmd farm command
	 * @param $opt associative array of farm options
	 * @return url string
	 */
	function wl($cmd, $opt = array()) {
		global $ID;
		$p = array('do' => 'admin', 'page' => 'farm', 'farm_cmd' => $cmd);
		foreach($opt as $k => $v) $p['farm_opt__'.$k] = $v;
		return wl($ID, $p);
	}
	
	/**
	 * Handle requests
	 */
	function handle() {
		// Do nothing if disabled / not installed
		if($this->disabled) return;
		if(defined('DOKU_IS_FARMER')) if(!DOKU_IS_FARMER) return;
		
		// Enable direct access to language strings
		$this->setupLocale();
		
		// get installed version
		$this->version = @file_exists(DOKU_FARM_PLUGIN.'installed') ? trim(@file_get_contents(DOKU_FARM_PLUGIN.'installed'), "\n") : null;
		if($this->version != DOKU_FARM_VERSION) {
			// set installer class as handler if the farm is not installed
			if(is_null($this->version)) {
				$_REQUEST['farm_cmd'] = 'farminstall';
			}elseif($this->version == '0.99') {
				if($fp = fopen(DOKU_FARM_PLUGIN.'installed', 'w')) {
					fwrite($fp, '1');
					fclose($fp);
					$this->success('install_success');
					$_REQUEST['farm_plugin_cmd'] = 'farmconfig';
				}else $this->error('install_errors', 'install_stepupdate_failure');
			}
			// Add code here to upgrade to other (future) version
		}
		
		// Fetch command from request
		$this->cmd = 'overview';
		$this->opt = array();
		if(isset($_REQUEST['farm_cmd'])) {
			if(is_array($_REQUEST['farm_cmd'])) {
				$this->cmd = key($_REQUEST['farm_cmd']);
				$t = $_REQUEST['farm_cmd'][$this->cmd];
				while(is_array($t)) {
					$k = key($t);
					if(is_array($t[$k])) {
						$v = key($t[$k]);
						$t = $t[$k][$v];
						if(preg_match('`^(true|false)$`i', $v, $m)) {
							$v = (strtolower($m[1]) == 'true');
						}elseif(preg_match('`^([0-9]+)$`', $v, $m)) {
							$v = (int)$m[1];
						}elseif(preg_match('`^([0-9]+\.[0-9]+)$`', $v, $m)) {
							$v = (float)$m[1];
						}
						$this->opt[$k] = $v;
					}else{
						$this->opt[$k] = $t[$k];
						$t = null;
					}
				}
			}else $this->cmd = $_REQUEST['farm_cmd'];
		}
		
		// Fetch arguments from request
		if(isset($_REQUEST['farm_opt']) && !empty($_REQUEST['farm_opt'])) {
			if(is_array($_REQUEST['farm_opt'])) {
				foreach($_REQUEST['farm_opt'] as $k => $v) {
					if(preg_match('`^(true|false)$`i', $v, $m)) {
						$v = (strtolower($m[1]) == 'true');
					}elseif(preg_match('`^([0-9]+)$`', $v, $m)) {
						$v = (int)$m[1];
					}elseif(preg_match('`^([0-9]+\.[0-9]+)$`', $v, $m)) {
						$v = (float)$m[1];
					}
					if(!isset($this->opt[$k])) $this->opt[$k] = $v;
				}
			}else $this->opt[$_REQUEST['farm_opt']] = true;
		}
		
		// Fetch arguments from non array get var
		foreach($_GET as $k => $v) {
			if(preg_match('`^farm_opt__([a-zA-Z0-9_]+)$`', $k, $m)) {
				$this->opt[$m[1]] = $v;
			}
		}
		
		//echo 'REQUEST : '; print_r($_REQUEST);
		//echo '<br />CMD : '; print_r($this->cmd);
		//echo '<br />OPT : '; print_r($this->opt);
		
		// List of allowed commands and their handlers
		$commands = array(
			'farminstall' => 'install',
			'overview' => 'overview',
			'farmconfig' => 'config',
			'soapconfig' => 'soapconfig',
			'virtualhostconfig' => 'virtualhostconfig',
			'animal' => 'animalmanager'
		);
		
		// verify command vars
		if(!isset($commands[$this->cmd])) $this->cmd = 'overview';
		
		// create an object to handle the command, then process request with it
		$file = DOKU_FARM_PLUGIN.$commands[$this->cmd].'.class.php';
		if(@file_exists($file)) {
			include_once $file;
			$class = 'dokuwiki_farm_'.$commands[$this->cmd];
			if(!class_exists($class)) {
				include_once DOKU_FARM_PLUGIN.'overview.class.php';
				$class = 'dokuwiki_farm_overview';
			}
			$this->handler = & new $class($this);
			if($this->handler) $this->handler->process();
		}
	}
	
	/**
	 * Output appropriate html
	 */
	function html() {
		global $ID;
		
		// Do nothing if disabled / not installed
		if($this->disabled) return;
		if(defined('DOKU_IS_FARMER')) if(!DOKU_IS_FARMER) return;
		
		// Enable direct access to language strings
		$this->setupLocale();
		
		ptln('<div id="farm__manager">');
		ptln('	<div class="farm_title">'.$this->getLang('menu').'</div>');
		
		// Farm menu
		if($this->cmd != 'farminstall') {
			ptln('	<div class="farm_commands">');
			ptln('		<a '.($this->cmd == 'overview' ? 'class="current_cmd"' : '').' href="'.$this->wl('overview').'"><img src="'.DOKU_FARM_WWW.'images/home.png" alt="overview" /> '.$this->getLang('overview_title').'</a>');
			if($this->cmd == 'animal' && isset($this->opt['aid'])) ptln('		<a class="current_cmd" href="'.$this->wl('animal', array('aid' => $this->opt['aid'])).'"><img src="'.DOKU_FARM_WWW.'images/aconf.png" alt="animal settings" /> '.$this->getLang('animal_title', array($this->opt['aid'])).'</a>');
			ptln('		<a '.($this->cmd == 'animal' && isset($this->opt['new']) ? 'class="current_cmd"' : '').' href="'.$this->wl('animal', array('new' => 1)).'"><img src="'.DOKU_FARM_WWW.'images/add.png" alt="add animal" /> '.$this->getLang('animal_new_title').'</a>');
			ptln('		<a '.($this->cmd == 'farmconfig' ? 'class="current_cmd"' : '').' href="'.$this->wl('farmconfig').'"><img src="'.DOKU_FARM_WWW.'images/configure.png" alt="config" /> '.$this->getLang('config_title').'</a>');
			if($this->conf['enablesoap']) ptln('		<a '.($this->cmd == 'soapconfig' ? 'class="current_cmd"' : '').' href="'.$this->wl('soapconfig').'"><img src="'.DOKU_FARM_WWW.'images/soap.png" alt="soap config" /> '.$this->getLang('soapconfig_title').'</a>');
			if($this->conf['virtual']) ptln('		<a '.($this->cmd == 'virtualhostconfig' ? 'class="current_cmd"' : '').' href="'.$this->wl('virtualhostconfig').'"><img src="'.DOKU_FARM_WWW.'images/virtualhost.png" alt="virtualhost config" /> '.$this->getLang('virtualhostconfig_title').'</a>');
			ptln('	</div>');
		}
		
		// Call handler renderer, prints errors / successes if needed
		ptln('	<div class="farm_cmd farm_cmd_'.$this->cmd.'_class">');
		if(!$this->handler) $this->error('system_errors', array('code' => 'system_nohandler_failure', 'data' => array($this->cmd)));
		if($this->handler) if(method_exists($this->handler, 'htmlheader')) $this->handler->htmlheader();
		$this->putErrors();
		$this->putSuccess();
		if($this->handler) $this->handler->html();
		ptln('	</div>');
		ptln('</div><!-- #farm__manager -->');
	}
}

?>
