<?php
/**
 * Wiki farm manager
 *
 * @license  GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author   Etienne MELEARD <etienne.meleard@cru.fr>
 * @desc     Process and renders farm config related requests
 */
// 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_FARMPLUGINLOADED')) define('DOKU_FARMPLUGINLOADED', true);

require_once DOKU_FARM_PLUGIN.'animal.class.php';

class dokuwiki_farm_config {
	var $data = array();
	var $manager = null;
	var $errors = array();
	private $ref = array();
	private $conf = array();
	
	/**
	 * @param $manager object that must handle error(), success(), nicesize(), getLang() ... calls
	 */
	function __construct($manager) {
		$this->manager = & $manager;
		$farmconf = array();
		include DOKU_FARM_PLUGIN.'config.php';
		$this->data = $farmconf;
	}
	
	/**
	 * Process requests
	 */
	function process() {
		if(isset($this->manager->opt['save'])) {
			// Security check
			if(!checkSecurityToken()) {
				$this->manager->error('system_errors', 'system_badtoken_failure');
				return;
			}
			if(!$this->save()) {
				$this->manager->error('config_errors', 'config_save_failure');
				return;
			}
		}
	}
	
	/**
	 * Renders
	 */
	function html() {
		ptln('<div class="farm_cmd_title">'.$this->manager->getLang('config_title').'</div>');
		ptln('<div class="farm_cmd_info">'.$this->manager->getLang('config_info').'</div>');
		$this->form();
	}
	
	/**
	 * Tells whether a configuration parameter is editable
	 * @param $f parameter identifier
	 * @return boolean
	 */
	function allowed($f) {
		if(
			$f == 'farmwebroot' ||
			$f == 'farmfsroot' ||
			$f == 'farmer' ||
			$f == 'barn'
		) return false;
		return true;
	}
	
	/**
	 * Outputs a form to edit the farm configuration
	 */
	function form($install = false) {
		$cnf = array();
		foreach(explode("\n", @file_get_contents(DOKU_FARM_PLUGIN.'config.php')) as $l) {
			if(preg_match('`^\$farmconf\[[\'"]([a-z0-9_-]+)[\'"]\]\s*=\s*([^;]+);$`i', trim($l), $m)) {
				$id = trim($m[1]);
				if(!$this->allowed($id)) continue;
				$d = trim($m[2]);
				if(preg_match('`^[\'"].*[\'"]$`', $d)) $d = substr($d, 1, -1);
				if(in_array(strtolower($d), array('true', 'false'))) $d = (strtolower($d) == 'true');
				$cnf[$id] = $d;
			}
		}

		$this->manager->formHead(array('farm_cmd' => 'farmconfig'));
		foreach($cnf as $id => $d) {
			ptln('	<fieldset>');
			$l = '		'.$this->manager->getLang('config_field_name_'.$id).' : ';
			if(is_bool($d)) {
				$l .= '<input type="checkbox" name="config_field_'.$id.'"';
				if($d) $l .= ' checked="checked"';
				$l .= '/>';
			}else{
				$l .= '<input type="text" name="config_field_'.$id.'" value="'.$d.'"/>';
			}
			ptln($l.'<br />');
			ptln('<small>'.$this->manager->getLang('config_field_desc_'.$id).'</small>');
			ptln('	</fieldset>');
		}
		
		ptln('	<fieldset class="save">');
		ptln('		<input type="submit" class="button" name="farm_opt[save]" value="'.$this->manager->getLang('btn_save').'" />');
		ptln('	</fieldset>');
		ptln('</form>');
	}
	
	/**
	 * Saves the farm configuration
	 * @return success as boolean
	 */
	function save() {
		$this->conf = explode("\n", @file_get_contents(DOKU_FARM_PLUGIN.'config.php'));
		if(!count($this->conf)) return false;
		
		for($i=0; $i<count($this->conf); $i++) {
			if(preg_match('`^\$farmconf\[[\'"]([a-z0-9_-]+)[\'"]\]\s*=\s*([^;]+);$`i', trim($this->conf[$i]), $m)) {
				$id = trim($m[1]);
				$this->ref[$id] = $i;
			}
		}
		
		foreach($this->ref as $id => $n) {
			if(!$this->allowed($id)) continue;
			if(preg_match('`^\$farmconf\[[\'"]([a-z0-9_-]+)[\'"]\]\s*=\s*([^;]+);$`i', trim($this->conf[$n]), $m)) {
				$d = trim($m[2]);
				if(preg_match('`^[\'"].*[\'"]$`', $d)) $d = substr($d, 1, -1);
				if(in_array(strtolower($d), array('true', 'false'))) {
					$d = (strtolower($d) == 'true');
					if($this->triggerChange($id, $d, isset($_POST['config_field_'.$id]))) $this->conf[$n] = '$farmconf[\''.$id.'\'] = '.(isset($_POST['config_field_'.$id]) ? 'true' : 'false').';';
				}elseif(preg_match('`^[0-9]+(\s*[+/*-]\s*[0-9]+)*$`', $d)) {
					if(!isset($_POST['config_field_'.$id])) continue;
					$fb = create_function('', 'try{ return '.$d.'; }catch(Exception $e) { return null; }');
					$fa = create_function('', 'try{ return '.(!empty($_POST['config_field_'.$id]) ? $_POST['config_field_'.$id] : '0').'; }catch(Exception $e) { return 0; }');
					if(is_null($fa())) continue;
					if($this->triggerChange($id, $fb(), $fa())) $this->conf[$n] = '$farmconf[\''.$id.'\'] = '.$_POST['config_field_'.$id].';';
				}else{
					if(!isset($_POST['config_field_'.$id])) continue;
					if($this->triggerChange($id, $d, $_POST['config_field_'.$id])) $this->conf[$n] = '$farmconf[\''.$id.'\'] = \''.str_replace('\'', '\\\'', $_POST['config_field_'.$id]).'\';';
				}
			}
		}
		if($fp = fopen(DOKU_FARM_PLUGIN.'config.php', 'w')) {
			fwrite($fp, implode("\n", $this->conf));
			fclose($fp);
			return true;
		}else return false;
	}
	
	/**
	 * Copy .htaccess replacing some tags
	 * @param $src source file
	 * @param $dest destination file
	 */
	function copyHtaccess($src, $dest, $more = array()) {
		$c = @file_get_contents($src);
		if(!$c) return false;
		
		$farm = $this->manager->conf['farmwebroot'];
		if(preg_match('`^([^:]+://)?([^/]+)?/?(.*)$`i', $farm, $m)) $farm = $m[3];
		if(substr($farm, -1) != '/') $farm .= '/';
		$c = str_replace('{farm}', $farm, $c);
		$c = str_replace('{farmer}', $this->manager->conf['farmer'], $c);
		$c = str_replace('{barn}', $this->manager->conf['barn'], $c);
		
		foreach($more as $k => $v) $c = str_replace('{'.$k.'}', $v, $c);
		
		$fp = fopen($dest, 'w');
		if(!$fp) return false;
		fwrite($fp, $c);
		fclose($fp);
		return true;
	}
	
	/**
	 * Handles some specific parameters changes
	 * @param $id parameter identifier
	 * @param $before value before change
	 * @param $after value after change
	 * @return boolean telling wheter the change is acepted or not
	 */
	function triggerChange($id, $before, $after) {
		if($after === $before) return true;
		
		if($id == 'farmrewrite') {
			if($after) {
				if(realpath($this->manager->conf['farmfsroot'].$this->manager->conf['barn']) == realpath($this->manager->conf['farmfsroot'])) return true;

				if($this->copyHtaccess(DOKU_FARM_PLUGIN.'install/farm.htaccess', $this->manager->conf['farmfsroot'].'.htaccess')) {
					if($this->triggerChange('userewrite', false, true)) {
						$_POST['config_field_userewrite'] = 1; // to keep integrity
						$this->conf[$this->ref['userewrite']] = '$farmconf[\'userewrite\'] = true;';
						return true;
					}
					return false;
				}else{
					$this->manager->error('config_errors', 'config_createfarmrewritefile_failure');
					return false;
				}
			}elseif(@file_exists($this->manager->conf['farmfsroot'].'.htaccess')) {
				if(realpath($this->manager->conf['farmfsroot'].$this->manager->conf['barn']) == realpath($this->manager->conf['farmfsroot'])) return true;
				if(!unlink($this->manager->conf['farmfsroot'].'.htaccess')) {
					$this->manager->error('config_errors', 'config_deletefarmrewritefile_failure');
					return false;
				}
			}
			return true;
		}
		
		if($id == 'userewrite') {
			if($after) {
				$src = (realpath($this->manager->conf['farmfsroot'].$this->manager->conf['barn']) != realpath($this->manager->conf['farmfsroot'])) ? 'barn.htaccess' : 'barnatroot.htaccess';
				if($this->copyHtaccess(DOKU_FARM_PLUGIN.'install/'.$src, $this->manager->conf['farmfsroot'].$this->manager->conf['barn'].'.htaccess')) {
					return true;
				}else{
					$this->manager->error('config_errors', 'config_createrewritefile_failure');
					return false;
				}
			}else{
				if(@file_exists($this->manager->conf['farmfsroot'].'.htaccess')) {
					if(!unlink($this->manager->conf['farmfsroot'].'.htaccess')) {
						$this->manager->error('config_errors', 'config_deletefarmrewritefile_failure');
					}else{
						$_POST['config_field_farmrewrite'] = 0; // to keep integrity
						$this->conf[$this->ref['barnrewrite']] = '$farmconf[\'farmrewrite\'] = false;';
					}
				}
				if(@file_exists($this->manager->conf['farmfsroot'].$this->manager->conf['barn'].'.htaccess')) {
					if(!unlink($this->manager->conf['farmfsroot'].$this->manager->conf['barn'].'.htaccess')) {
						$this->manager->error('config_errors', 'config_deleterewritefile_failure');
						return false;
					}
				}
				return true;
			}
		}
		
		if($id == 'virtual') {
			if($after) {
				if(!@file_exists(DOKU_FARM_PLUGIN.'virtual_hosts.php')) {
					if(!copy(DOKU_FARM_PLUGIN.'install/virtual_hosts.php', DOKU_FARM_PLUGIN.'virtual_hosts.php')) {
						$this->manager->error('config_errors', 'config_copyvirtualhostfile_failure');
						return false;
					}
				}
				
				if(!$this->copyHtaccess(DOKU_FARM_PLUGIN.'install/virtual.htaccess', $this->manager->conf['farmfsroot'].'.htaccess', array('farmerhost' => $this->manager->conf['farmerhost']))) {
					$this->manager->error('config_errors', 'config_createrewritefile_failure');
					return false;
				}
			}else{
				if($this->manager->conf['userewrite']) {
					if($this->triggerChange('userewrite', false, true)) {
						$_POST['config_field_userewrite'] = 1; // to keep integrity
						$this->conf[$this->ref['userewrite']] = '$farmconf[\'userewrite\'] = true;';
					}
				}
				if($this->manager->conf['farmrewrite']) {
					if($this->triggerChange('farmrewrite', false, true)) {
						$_POST['config_field_farmrewrite'] = 1; // to keep integrity
						$this->conf[$this->ref['farmrewrite']] = '$farmconf[\'farmrewrite\'] = true;';
					}
				}
			}
			$this->manager->conf['virtual'] = $after;
			return true;
		}
		
		if($id == 'farmerhost') {
			if(!$this->manager->conf['virtual']) return true;
			if($this->copyHtaccess(DOKU_FARM_PLUGIN.'install/virtual.htaccess', $this->manager->conf['farmfsroot'].'.htaccess', array('farmerhost' => $after))) {
				return true;
			}else{
				$this->manager->error('config_errors', 'config_createrewritefile_failure');
				return false;
			}
		}
		
		if($id == 'animaltemplate') {
			if(!dokuwiki_farm_animal::exists($after)) {
				$this->manager->error('config_errors', 'animal_unknownanimal_failure');
				return false;
			}else return true;
		}
		
		if($id == 'enablesoap') {
			if($after) {
				if(!@file_exists($this->manager->conf['farmfsroot'].'farm.wsdl')) {
					$wsdl = @file_get_contents(DOKU_FARM_PLUGIN.'install/wsdl.base');
					if(!$wsdl) {
						$this->manager->error('config_errors', 'config_createwsdl_failure');
						return false;
					}
					$file = $this->manager->conf['farmwebroot'].'farm.wsdl';
					$wsdl = str_replace('{wsdl}', $file, $wsdl);
					$wsdl = str_replace('{location}', $this->manager->conf['farmwebroot'].$this->manager->conf['farmer'].'lib/plugins/farm/soapserver.php', $wsdl);
					if($fp = fopen($this->manager->conf['farmfsroot'].'farm.wsdl', 'w')) {
						fwrite($fp, $wsdl);
						fclose($fp);
					}else{
						$this->manager->error('config_errors', 'config_createwsdl_failure');
						return false;
					}
				}
				
				if(!@file_exists(DOKU_FARM_PLUGIN.'trusted_apps.php')) {
					if(!copy(DOKU_FARM_PLUGIN.'install/trusted_apps.php', DOKU_FARM_PLUGIN.'trusted_apps.php')) {
						$this->manager->error('config_errors', 'config_copytrustedappsfile_failure');
						return false;
					}
				}
			}else{
				if(@file_exists($this->manager->conf['farmfsroot'].'farm.wsdl')) {
					if(!unlink($this->manager->conf['farmfsroot'].'farm.wsdl')) {
						$this->manager->error('config_errors', 'config_deletewsdl_failure');
						return false;
					}
				}
			}
			$this->manager->conf['enablesoap'] = $after;
			return true;
		}
		
		return true;
	}
}
?>
