<?php
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'admin.php');

/**
 * All DokuWiki plugins to extend the admin function
 * need to inherit from this class
 */
class admin_plugin_translator extends DokuWiki_Admin_Plugin {

	var $_auth = null;        	// auth object
	var $functions = null;		// Helper
	var $revertableUpload = array();

	/**
	 * Constructor
	 */
	function admin_plugin_translator(){
		global $auth;

		if (!isset($auth)) {
			$this->disabled = $this->lang['noauth'];
		} else if (!$auth->canDo('getUsers')) {
			$this->disabled = $this->lang['nosupport'];
		} else {

			// we're good to go
			$this->_auth = & $auth;
		}
		
		if ( ! $this->_setup() ) return false;
		if ( !$this->functions->checkDatabase() ) {
			$this->functions = null;
			return false;
		}
	}

	/**
	 * return some info
	 */
	function getInfo(){
		return array_merge(confToHash(dirname(__FILE__).'/info.txt'), array(
				'name' => 'Translator (Admin Component)',
		));
	}

	/**
	 * return sort order for position in admin menu
	 */
	function getMenuSort() {
		return 100;
	}

	function forAdminOnly(){
		return false;
	}

	/**
	 * handle user request
	 */
	function handle() {

		if (is_null($this->_auth)) return false;

		// extract the command and any specific parameters
		// submit button name is of the form - fn[cmd][param(s)]
		$fn   = $_REQUEST['fn'];

		if (is_array($fn)) {
			$cmd = key($fn);
			$param = is_array($fn[$cmd]) ? key($fn[$cmd]) : null;
		} else {
			$cmd = $fn;
			$param = null;
		}

		switch($cmd){
			case "set_user"    			: $this->_setUser($_REQUEST['user']); break;
			case "createcategories"		: $this->_createCategory($_REQUEST['CategoryName'], $_REQUEST['FileName']); break;
			case "updatecategories"    	: $this->_deleteCategory($_REQUEST['deletecategory']); break;
			case "uploadmaster"			: $this->_handleUploadedFiles($_REQUEST['Category'], $_REQUEST['Version'], $_FILES['File']); break;
			case "deletemaster"			: $this->_handleDeleteMaster($_REQUEST['deletemaster']); break;
			case "deleteuser"			: $this->_handleDeleteUser($_REQUEST['deleteuser'], $_REQUEST['manageUser']); break;
		}

		$this->functions->_handleRequest($fn);
	}

	/**
	 * output appropriate html
	 */
	function html() {
		global $ID, $conf;

		if(is_null($this->_auth)) {
			print $this->lang['badauth'];
			return false;
		}

		print $this->locale_xhtml('intro');
		print '<div id="translator">';

		if ( $_REQUEST['manageUser'] ) {
			// Display Categories of User
			$this->_userCategoryManager($_REQUEST['manageUser']);
		} else {
			// Set User Languages
			$this->_userRightsForm();

			// Manager Categories
			$this->_categoryManager();

			// Import Master and Languages
			$this->_importManager();

			// Export MAnager
			$this->functions->_exportManager($this);

			// Delete Master Languages
			$this->_deleteMasterLanguageManager();
		}
		print '</div>';
	}

	function _importManager() {

		$categories = array_keys($this->functions->_getCategories());
		if ( count($categories) == 0 ) return;

		$form = $this->_startFieldSet($this->getLang('ImportMasterLanguage'), 'translator_master_import', 'multipart/form-data');

		$form->addElement(form_makeListboxField('Category', $categories, $_REQUEST['Category'], 'Select the Category:'));
		$form->addElement(form_makeTag('br'));
		$form->addElement(form_makeTextField('Version', $_REQUEST['Version'], 'Product Version:'));
		$form->addElement(form_makeTag('br'));
		$form->addElement(form_makeFileField('File[]', 'Upload File:', null, null, array('multiple' => 'true')));
		$form->addElement(form_makeTag('br'));
		$form->addElement(form_makeField('submit', 'fn[uploadmaster]', 'Upload', ''));

		$this->_finishFieldset($form);

		$this->functions->_revertManager($this, $this->revertableUpload);
	}

	function _deleteMasterLanguageManager() {

		$categories = $this->functions->_getCategories();
		if ( count($categories) == 0 ) return;
		$nothingToDo = true;

		$form = $this->_startFieldSet($this->getLang('RemoveMasterLanguage'), 'translator_master_remove');

		foreach ( $categories as $name => $category ) {
			$formCategories[] = $name;
			foreach ( $this->functions->_getAvailableVersions($category['CategoryID']) as $Version ) {
				$nothingToDo = false;
				$form->addElement(form_makeCheckboxField("deletemaster[$name][$Version]", 1, $name . " ($Version)", null));
				$form->addElement(form_makeTag('br'));
			}
		}

		$form->addElement(form_makeField('submit', 'fn[deletemaster]', 'Delete', ''));

		if ( ! $nothingToDo )
		$this->_finishFieldset($form);
	}

	/*
	 * Print the Manager for Categories
	 */
	function _categoryManager() {

		$categories = $this->functions->_getCategories();

		if ( count($categories) > 0 ) {

			$form = $this->_startFieldSet($this->getLang('CategoryManager'), 'translator_categories');

			foreach( $categories as $name => $data ) {
				$form->addElement(form_makeCheckboxField("deletecategory[{$data['CategoryID']}]", 1, $name . " ({$data['FileName']})", null));
				$form->addElement(form_makeTag('br'));
			}

			$form->addElement(form_makeField('submit', 'fn[updatecategories]', $this->getLang('Delete'), ''));
			$this->_finishFieldset($form);
		}


		$form = $this->_startFieldSet($this->getLang('AddCategory'), 'translator_new_categories');

		$form->addElement(form_makeTextField('CategoryName', $_REQUEST['CategoryName'], $this->getLang('Category') . ':', 'CategoryName', null));
		$form->addElement(form_makeTag('br'));
		$form->addElement(form_makeTextField('FileName', $_REQUEST['FileName'], $this->getLang('CategoryFileName') . ':', 'FileName', null));
		$form->addElement(form_makeTag('br'));

		$form->addElement(form_makeField('submit', 'fn[createcategories]', $this->getLang('Create'), ''));
		$this->_finishFieldset($form);

	}

	/*
	 * Print the User Rights formula with update button for Languages
	 */
	function _userRightsForm() {

		// System User List
		$user_list = $this->_getUserLanguages();

		$form = $this->_startFieldSet($this->getLang('UserManager'), 'translator_users');
		foreach ( $user_list as $user => $values ) {

			$lang = $values['Lang'];
			$form->addElement(form_makeTextField("user[$user]", $lang, tpl_link(wl($ID, array('do' => 'admin', 'page' => 'translator', 'manageUser' => $user ), true), $user, null, true) . ':', $user, null));
			$form->addElement(form_makeTag('br'));

		}

		$form->addElement(form_makeField('submit', 'fn[set_user]', $this->getLang('Update'), ''));
		$this->_finishFieldset($form);
	}

	/*
	 * Fieldsets for the admin page
	 */
	function _startFieldSet($name, $hid='translator', $formType=null) {
		global $ID;

		$form = new Doku_Form($hid, wl($ID), 'post', $formType);
		$form->addHidden('do', 'admin');
		$form->addHidden('page', 'translator');
		$form->startFieldset( $name );

		return $form;
	}

	function _getUserLanguages() {
		$user_list = $this->_auth->retrieveUsers();
		$this->functions->database->prepare("SELECT User, Lang FROM tblUserRights;");
		$this->functions->database->execute();

		if ( $this->functions->database->num_rows() != 0 ) {

			$data = array(); $this->functions->database->bind_assoc($data);
			while ( $this->functions->database->fetch() ) {
				$user_list[$data['User']]['Lang'] = $data['Lang'];
			}
		}

		return $user_list;
	}

	function _finishFieldset($form=null) {
		if ( empty($form) ) return;

		$form->endFieldset();
		$form->printForm();
	}

	function _setUser($users=array()) {

		if ( empty($users) || !is_array($users)) { return false; }
		foreach ( $users as $user => $lang ) {

			$user = trim($user);
			if ( empty($user) ) continue;

			$lang = trim($lang);
			if ( empty($lang) )	{
				$this->functions->database->prepare("DELETE FROM tblUserRights WHERE User=?;");
				$this->functions->database->execute($user);
				continue;
			}

			$lang = preg_replace("/[,;\s]/", "|", $lang);
			$lang = preg_replace("/\|+/", "|", $lang);

			$this->functions->database->prepare("SELECT * FROM tblUserRights WHERE User=?;");
			$this->functions->database->execute($user);
			if ( $this->functions->database->num_rows() > 0 )
			$this->functions->database->prepare("UPDATE tblUserRights SET Lang=? WHERE User=?;");
			else
			$this->functions->database->prepare("INSERT INTO tblUserRights (Lang, User) VALUES(?, ?);");

			$this->functions->database->execute($lang, $user);
		}
	}

	function _createCategory($categoryName, $fileName) {
		if ( empty($categoryName) ) {
			msg($this->getLang('CategoryNameMissing'), -1);
			return false;
		}

		if ( empty($fileName) ) {
			msg($this->getLang('FileNameMissing'), -1);
			return false;
		}

		$this->functions->database->prepare("SELECT * FROM tblCategory WHERE Name=?;");
		$this->functions->database->execute($categoryName);
		if ( $this->functions->database->num_rows() > 0 ) {
			msg($this->getLang('CategoryExists'), -1);
			return false;
		}


		$this->functions->database->prepare("INSERT INTO tblCategory (Name, FileName) VALUES (?,?);");
		$this->functions->database->execute($categoryName, $fileName);
	}

	/*
	 * Remove Categories
	 */
	function _deleteCategory($category=array()) {

		if ( empty($category) || !is_array($category)) { return false; }

		foreach ( $category as $name => $value ) {

			$name = trim($name);
			if ( empty($name) ) continue;

			$value = trim($value);
			if ( empty($value) ) {
				continue;
			}

			$this->functions->database->prepare("DELETE FROM tblCategory WHERE CategoryID=?;");
			$this->functions->database->execute($name);
			$this->_handleDeleteFiles($name, "%", true);
		}
	}

	/*
	 * Reorders the uplaoded Files to insert the master language first
	 * It also checks and rejects wrong file formats.
	 */
	function _handleUploadedFiles($category, $version, $FILES) {

		list($CategoryID, $CategoryRegex)  = $this->functions->_getCategoryFromName($category);

		$orderedFiles = array();
		for ( $i=0; $i<count($FILES['name']); $i++ ) {

			$FILE = array(
							'name' => $FILES['name'][$i],
							'tmp_name' => $FILES['tmp_name'][$i],
							'current_date_time' => date('Y-m-d H:i:s')
			);

			// check uploaded FileName to match on the selected Category
			$matches = array();
			if ( !preg_match("/$CategoryRegex/", $FILE['name'], $matches) ) {
				msg($this->functions->_messageReplacer('MasterFileNotInFormat', array($FILE['name'], $CategoryRegex)), -1);
				return;
			}

			// Cleanup the Language and set default Language if needed.
			$FILE['lang'] = preg_replace("/^_?(.*?)_?$/", "$1", $matches[1]);

			// Set Default Language and put in front of all others in ordered list
			if ( empty($FILE['lang']) ) {

				// Need a version here!
				if ( empty($version) ) {
					msg($this->getLang('VersionNeeded'), -1);
					return;
				}

				$FILE['lang'] = $this->getConf('default_language');
				array_unshift($orderedFiles, $FILE);

				continue;
			}

			$orderedFiles[] = $FILE;
		}

		foreach ( $orderedFiles as $file ) {
			$status = $this->_importLanguage($file, $CategoryID, $version);

			// Should be reverted
			if ( $status === false ) {
				$this->revertableUpload[] = $file;
			}
		}

	}

	/*
	 * Delete Master Languages
	 */
	function _handleDeleteMaster($deleteMaster) {
		foreach( $deleteMaster as $key => $versions) {
			foreach ( array_keys($versions) as $version ) {
				$this->_handleDeleteFiles($key, $version);
			}
		}
	}

	/*
	 * Cycle through Users to be deleted
	 */
	function _handleDeleteUser($deleteUserLanguage, $User) {

		$removed = 0;
		$removeUserKeys = array();

		foreach( $deleteUserLanguage as $Category => $versions) {
			if ( !empty($Category) ) {
				list($CategoryID, $FileName) = $this->functions->_getCategoryFromName($Category);
			}

			foreach ( $versions as $version => $date ) {
				if ( !is_array($date) ) {
					$this->_getTranslastionsForUser($removeUserKeys, $User, $CategoryID, $version);
					continue;
				}

				foreach( $date as $dateEntry => $Lang ) {
					if ( !is_array($Lang) ) {
						continue;
					}

					foreach ( array_keys($Lang) as $Language ) {
						$this->_getTranslastionsForUser($removeUserKeys, $User, $CategoryID, $version, $dateEntry, $Language);
					}
				}
			}
		}

		$this->functions->database->prepare("DELETE FROM tblTranslation WHERE KeyID=? AND User=? AND Lang=?;");
		foreach( $removeUserKeys as $Entry) {
			list($KeyID, $Lang) = $Entry;
			$this->functions->database->execute($KeyID, $User, $Lang);
			$removed += $this->functions->database->num_rows();
		}

		msg($this->functions->_messageReplacer('RemovedUserEntries', array($removed, $User)));
	}

	function _getTranslastionsForUser(&$removeUserKeys, $User, $CategoryID=null, $Version=null, $Date=null, $Lang=null) {

		$ADDITIONAL = "";
		$EXECUTE = array($User);

		// If Date is set, check for that one too
		if ( !empty($Date) ) {
			$ADDITIONAL .= " AND Date=?";
			$EXECUTE[] = $Date;
		}

		// If Date is set, check for that one too
		if ( !empty($CategoryID) ) {
			$ADDITIONAL .= " AND CategoryID=?";
			$EXECUTE[] = $CategoryID;
		}

		// If Date is set, check for that one too
		if ( !empty($Version) ) {
			$ADDITIONAL .= " AND Version=?";
			$EXECUTE[] = $Version;
		}

		// If Date is set, check for that one too
		if ( !empty($Lang) ) {
			$ADDITIONAL .= " AND Lang=?";
			$EXECUTE[] = $Lang;
		}

		$this->functions->database->prepare("SELECT tblTranslation.KeyID FROM tblTranslation INNER JOIN tblMaster ON tblTranslation.KeyID = tblMaster.KeyID WHERE User=? $ADDITIONAL;");

		$this->functions->database->execute($EXECUTE);
		$data = array(); $this->functions->database->bind_assoc($data);
		while ( $this->functions->database->fetch() ) {
			$removeUserKeys[] = array($data['KeyID'],$Lang);
		}
	}

	function _handleDeleteFiles($Category, $Version, $isID=false, $User=null) {

		if ( $isID) {
			$CategoryID = $Category;
			$Category = array_shift(array_keys($this->functions->_getCategories($CategoryID, true)));
		} else {
			list($CategoryID, $FileName) = $this->functions->_getCategoryFromName($Category);
		}

		$ADDITIONAL = "";
		$EXECUTE = array($CategoryID, $Version);

		if ( !empty($User) ) {
			$ADDITIONAL .= " AND User=?";
			$EXECUTE[] = $User;
		}

		$this->functions->database->prepare("DELETE FROM tblMaster WHERE CategoryID=? AND Version LIKE ? $ADDITIONAL");
		$this->functions->database->execute($EXECUTE);
		if ( $this->functions->database->num_rows() > 0 ) {
			if ( $Version == '%' ) { $Version = 'any version'; }
			msg($this->functions->_messageReplacer('RemovedEntries', array($this->functions->database->num_rows(), $Category, $Version)));
		}
	}

	function _importLanguage($file, $CategoryID, $version) {

		$FileName = $file['name'];
		$Lang = $file['lang'];
		$currentDateTime = $file['current_date_time'];
		$isMasterLang = $Lang == $this->getConf('default_language');

		$finalStatus = array(
								'KeysNotInMaster' => array(),
								'KeysMatchingExisting' => array(),
								'CountOfKeys' => 0,
								'CountOfToBeReverted' => 0,
		);

		// Get Content of uploaded temp file
		$FileContent = file($file['tmp_name']);
		@unlink($file['tmp_name']);

		if ( $isMasterLang ) {
			// Clean Up Current Category and Version Entries
			$this->functions->database->prepare("DELETE FROM tblMaster WHERE CategoryID=? AND Version=?;");
			$this->functions->database->execute($CategoryID, $version);
		}
		
		$FileContent = preg_grep("/^\s*?(#|\/\/)/", $FileContent, PREG_GREP_INVERT);
		
		$translation = array();

		// Cycle through the Lines and add them into the MasterDB
		foreach ( $FileContent as $line ) {
			// No Comments.
//			if ( preg_match("/^\s*?(#|\/\/)/", $line) ) {
//				continue;
//			}

			list($key, $value) = explode("=", $line, 2);
			$key = trim($key);
			$value = trim($value);
			
			if ( empty($key) || empty($value) ) {
				continue;
			}
		    
			$translation[$key] = $value;
		}
		
		unset($FileContent);

		
        if ( $isMasterLang ) {
            // Create Master Entry and finish this entry
            $this->functions->_createMasterTableEntry($translation, $CategoryID, $version, $finalStatus);
        } else {

		    // Bottleneck 1
		    $this->functions->_checkForMasterKeyIDs($translation, $finalStatus, $CategoryID);
            $this->functions->_insertTranslationArray($translation, $finalStatus, $Lang, $currentDateTime);
		}

		return $this->functions->_statusResult($finalStatus, $Lang, $FileName);
	}

	function _printBackToAdmin() {
		return '<div class="clearer">&nbsp;</div>' . tpl_link(wl($ID, array('do' => 'admin', 'page' => 'translator', ), true), $this->getLang('backToFirstPage'), null, true);
	}

	function _userCategoryManager($user) {
		global $conf;

		$this->functions->database->prepare("SELECT tblCategory.CategoryID, tblCategory.Name FROM (tblTranslation INNER JOIN tblMaster ON tblMaster.KeyID=tblTranslation.KeyID) INNER JOIN tblCategory ON tblCategory.CategoryID=tblMaster.CategoryID WHERE tblTranslation.User=? GROUP BY tblMaster.CategoryID");
		$this->functions->database->execute($user);

		if ( $this->functions->database->num_rows() == 0 ) {
			print $this->getLang('UserHasNoTranslations');
			print $this->_printBackToAdmin();
			return;
		}

		$categories=array(); $data=array(); $this->functions->database->bind_assoc($data);
		while ( $this->functions->database->fetch()) {
			$categories[$data['Name']] = $data['CategoryID'];
		}

		$form = $this->_startFieldSet($this->functions->_messageReplacer('RemoveUserLanguage', $user), 'translator_user_language_remove');
		$form->addHidden("manageUser", $user);

		$form->addElement(form_makeOpenTag("table", array('class' => 'translation_table')));
		$form->addElement(form_makeOpenTag("tr"));
		$form->addElement(form_makeOpenTag("th")); $form->addElement($this->getLang('Category')); $form->addElement(form_makeCloseTag("th"));
		$form->addElement(form_makeOpenTag("th")); $form->addElement($this->getLang('Version')); $form->addElement(form_makeCloseTag("th"));
		$form->addElement(form_makeOpenTag("th")); $form->addElement($this->getLang('AmountOfValues')); $form->addElement(form_makeCloseTag("th"));
		$form->addElement(form_makeCloseTag("tr"));

		$formByDate = $this->_startFieldSet($this->functions->_messageReplacer('RemoveUserLanguageByDate', $user), 'translator_user_language_date_remove');
		$formByDate->addHidden("manageUser", $user);

		$formByDate->addElement(form_makeOpenTag("table", array('class' => 'translation_table')));
		$formByDate->addElement(form_makeOpenTag("tr"));
		$formByDate->addElement(form_makeOpenTag("th")); $formByDate->addElement($this->getLang('Date')); $formByDate->addElement(form_makeCloseTag("th"));
		$formByDate->addElement(form_makeOpenTag("th")); $formByDate->addElement($this->getLang('Language')); $formByDate->addElement(form_makeCloseTag("th"));
		$formByDate->addElement(form_makeOpenTag("th")); $formByDate->addElement($this->getLang('AmountOfValues')); $formByDate->addElement(form_makeCloseTag("th"));
		$formByDate->addElement(form_makeCloseTag("tr"));

		$onclick = array(	'onclick' => 'var elem=getElementsByClass("edit", this.parentNode); elem[0].firstChild.checked=(elem[0].firstChild.checked ? false : true);',);

		foreach ( $categories as $Name => $CategoryID ) {

			$this->functions->database->prepare("SELECT Version, COUNT(tblTranslation.KeyID) as Amount FROM tblTranslation INNER JOIN tblMaster ON tblMaster.KeyID=tblTranslation.KeyID WHERE tblTranslation.User=? AND CategoryID=? GROUP BY Version;");
			$this->functions->database->execute($user, $CategoryID);

			$data=array(); $this->functions->database->bind_assoc($data);
			while ( $this->functions->database->fetch()) {
				$form->addElement(form_makeOpenTag("tr"));
				$form->addElement(form_makeOpenTag("td", $onclick)); $form->addElement($Name); $form->addElement(form_makeCloseTag("td"));
				$form->addElement(form_makeOpenTag("td", $onclick)); $form->addElement($data['Version']); $form->addElement(form_makeCloseTag("td"));
				$form->addElement(form_makeOpenTag("td", $onclick)); $form->addElement($data['Amount']); $form->addElement(form_makeCloseTag("td"));
				$form->addElement(form_makeOpenTag("td"));
				$form->addElement(form_makeCheckboxField("deleteuser[$Name][{$data['Version']}]", 1, '', '', 'edit'));
				$form->addElement(form_makeCloseTag("td"));
				$form->addElement(form_makeCloseTag("tr"));
			}
		}

		$this->functions->database->prepare("SELECT Date, Lang, COUNT(tblTranslation.KeyID) as Amount FROM tblTranslation WHERE tblTranslation.User=? GROUP BY Date ORDER By Date DESC;");
		$this->functions->database->execute($user);

		$data=array(); $this->functions->database->bind_assoc($data);
		while ( $this->functions->database->fetch()) {
			$formByDate->addElement(form_makeOpenTag("tr"));
			$formByDate->addElement(form_makeOpenTag("td", $onclick)); $formByDate->addElement(strftime($conf['dformat'], strtotime($data['Date']))); $formByDate->addElement(form_makeCloseTag("td"));
			$formByDate->addElement(form_makeOpenTag("td", $onclick)); $formByDate->addElement($data['Lang']); $formByDate->addElement(form_makeCloseTag("td"));
			$formByDate->addElement(form_makeOpenTag("td", $onclick)); $formByDate->addElement($data['Amount']); $formByDate->addElement(form_makeCloseTag("td"));
			$formByDate->addElement(form_makeOpenTag("td"));
			$formByDate->addElement(form_makeCheckboxField("deleteuser[][][{$data['Date']}][{$data['Lang']}]", 1, '', '', 'edit'));
			$formByDate->addElement(form_makeCloseTag("td"));
			$formByDate->addElement(form_makeCloseTag("tr"));
		}

		$form->addElement(form_makeCloseTag("table"));
		$form->addElement(form_makeField('submit', 'fn[deleteuser]', 'Delete', ''));
		$form->addElement(form_makeTag('br'));

		$formByDate->addElement(form_makeCloseTag("table"));
		$formByDate->addElement(form_makeField('submit', 'fn[deleteuser]', 'Delete', ''));
		$formByDate->addElement(form_makeTag('br'));
			
		$this->_finishFieldset($form);
		$this->_finishFieldset($formByDate);
		print $this->_printBackToAdmin();
	}

	function _setup() {
		if ( !$this->functions =& plugin_load('helper', 'translator') ) {
			msg($this->lang['helpermissing'], -1);
			return false;
		}

		// check Database
		return $this->functions->init_database(true);
	}
}
//Setup VIM: ex: et ts=4 enc=utf-8 :