<?php
/*
Officity - Web application platform - Version 6.0 - 2011-07-05

François Dispaux, Boris Verdeyen, Thomas Hermant,
Jérémie Roy, Grégory Meurice, Abdelila Harbi, 
Marc Mignonsin, Jonathan Sanchez, Julien Gonzalez, Pierre Fouchez

Sushee and Officity is © Copyright 2011 Nectil SA.

`/sushee-source/sushee/private/updateField.inc.php` is part of Officity.

Sushee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Officity and Sushee are distributed in the hope that they will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Sushee. If not, see <http://www.gnu.org/licenses/>.
*/
require_once(dirname(__FILE__).'/../common/nqlOperation.class.php');
require_once(dirname(__FILE__).'/../common/nectil_element.class.php');
require_once(dirname(__FILE__).'/../common/db_manip.class.php');
require_once(dirname(__FILE__).'/../private/update.nql.php');
require_once(dirname(__FILE__).'/../common/translator.class.php');

class sushee_updateField extends NQLOperation{
	
	var $fieldID = false;
	
	function parse(){
		// taking the ID of the field to modify
		// update on fields are only possible with the ID, WHERE is too dangerous, because it could modify too much on the database
		$this->fieldID = $this->firstNode->valueOf('@ID');
		if(!$this->fieldID){
			// trying with a denomination and a module ?
			$denomination = $this->firstNode->valueOf('@denomination');
			$module = $this->firstNode->valueOf('@module');
			if($denomination && $module){
				$db_conn = db_connect();
				$field_row = $db_conn->getRow('SELECT `ID` FROM `fields` WHERE `Denomination`="'.encode_for_db($denomination).'" AND `Module`="'.encode_for_db($module).'"');
				if(!$field_row){
					$this->setError('Field `'.$denomination.'` for module `'.$module.'` doesnt exist');
					return false;
				}else{
					$this->fieldID = $field_row['ID'];
					$this->firstNode->setAttribute('ID',$this->fieldID);
				}
			}else{
				$this->setError('You didnt provide the ID of the field to update (or denomination + module)');
				return false;
			}
			
			
		}
		
		return true;
	}
	
	function operate(){
		// first getting back the former field informations in the database, in order to compare with the new one
		$fieldModuleElt = new FieldModuleElement($this->fieldID);
		$fieldModuleElt->loadFields();
		
		// field that is not modifiable: MODULE
		$newModule = $this->firstNode->valueOf('INFO/MODULE');
		if($newModule && $newModule!=$fieldModuleElt->getField('Module')){
			$this->setError('A field cannot be transferred from a module to another, please verify or remove the new MODULE node in your request');
			return false;
		}
		// module from which is the field
		$moduleInfo = moduleInfo($fieldModuleElt->getField('Module'));
		$fieldname = $fieldModuleElt->getField('FieldName');
		$table = $moduleInfo->getTable();
		$DBField = $table->getField($fieldname);
		if(!$DBField){
			$this->setError('Field `'.$fieldname.'` doesnt exist in table `'.$moduleInfo->getTablename().'`');
			return false;
		}
		
		// fields that needs real intervention on the database: Type, SQLType, FieldName, Denomination, DefaultValue
		$infoNode = $this->firstNode->getElement('INFO');
		if(!$infoNode){
			$this->firstNode->appendChild('<INFO/>');
			$infoNode = $this->firstNode->getElement('INFO');
		}
		$newType = $infoNode->valueOf('TYPE');
		$newSQLType = decode_from_xml($infoNode->valueOf('SQLTYPE'));
		$newFieldname = $infoNode->valueOf('FIELDNAME');
		$newDenomination = $infoNode->valueOf('DENOMINATION');
		$newDefaultValue = $infoNode->valueOf('DEFAULTVALUE');
		$newFulltextIndexValue = $infoNode->valueOf('FULLTEXTINDEX');
		$newSignedValue = $infoNode->valueOf('SIGNED');
		$newZerofillValue = $infoNode->valueOf('ZEROFILL');
		$newNullValue = $infoNode->valueOf('NULL');
		
		
		// Type is a virtual type : int, text, boolean, but a text might be represented by different SQL types. Text can be LongText, Varchar(255), etc.
		// SQL Type is the real type used in MySQL: Int(10), Tinyint(1), Varchar(255)
		$sqlchange = false;
		if($newSQLType && $newSQLType!=$DBField->getSQLType()){ // user provided a new SQL type to use
			$DBField->setSQLType($newSQLType);
			
			// new SQL type might imply a new Type
			$newType = $DBField->getType();
			
			// replacing the former Type by the new type in the xml
			$infoNode->modifyOrAppend('TYPE',$newType);
			$sqlchange = true;
		}else if($newType && $newType!=$DBField->getType()){
			$DBField->setType($newType);
			
			// new type implies a new SQL Type
			$newSQLType = $DBField->getSQLType();
			
			// replacing the former SQL Type by the new sql type in the xml
			$infoNode->modifyOrAppend('SQLTYPE',$newSQLType);
			$sqlchange = true;
		}
		
		if($newFieldname && $newFieldname!=$DBField->getName()){
			$DBField->setName($newFieldname);
			
			// fieldname is the real name of the field and denomination is its name in NQL(in uppercase)
			$newDenomination = $DBField->getNQLName();
			$infoNode->modifyOrAppend('DENOMINATION',$newDenomination);
			$sqlchange = true;
		}else if($newDenomination && strtoupper($newDenomination)!=$DBField->getNQLName()){
			
			// if denomination has changed, we assume the user wanted to change the fieldname
			$DBField->setName($newDenomination);
			$newFieldname = $DBField->getName();
			
			// replacing in request by the official NQL name (user may have given it as lowercase)
			$newDenomination = $DBField->getNQLName();
			$denominationNode = $this->firstNode->getElement('INFO/DENOMINATION');
			$denominationNode->setValue($newDenomination);
			
			$infoNode->modifyOrAppend('FIELDNAME',$newFieldname);
			$sqlchange = true;
			
		}else if($newDenomination && $newDenomination===strtolower($DBField->getNQLName())){ // if newDenomination is lowercase in request, not allowing to insert it like this in database
			$denominationNode = $this->firstNode->getElement('INFO/DENOMINATION');
			$denominationNode->setValue(strtoupper($newDenomination));
		}
		
		if($newDefaultValue!==false && $newDefaultValue!=$DBField->getDefaultValue()){
			$DBField->setDefaultValue($newDefaultValue);
			$sqlchange = true;
		}
		
		if($newFulltextIndexValue!==false && $newFulltextIndexValue != $DBField->isFulltextIndexed()){
			if($DBField->isFulltextIndexable() && $newFulltextIndexValue){
				$DBField->enableFulltextIndex(1);
			}else{
				if($newFulltextIndexValue){ // means its not full indexable and we should warn the user
					$this->setError('Field with type `'.$DBField->getType().'` cannot use a fulltext index');
					return false;
				}else{
					$DBField->enableFulltextIndex(0);
					$infoNode->modifyOrAppend('FULLTEXTINDEX',0);
				}
				
			}
			$sqlchange = true;
		}
		
		if($newNullValue!==false && $newNullValue != $DBField->isNULLEnabled()){
			$DBField->enableNULL($newNullValue);
			$sqlchange = true;
		}
		
		if($newSignedValue!==false && $newSignedValue != $DBField->isSigned()){
			$DBField->enableSigned($newSignedValue);
			$sqlchange = true;
		}
		
		if($newZerofillValue!==false && $newZerofillValue != $DBField->isZeroFillEnabled()){
			// certain types of fields (text) cannot be zerofilled
			if($DBField->isZeroFillable() && $newZerofillValue){
				$DBField->enableZeroFill(1);
				// a zerofilled field cannot be signed
				if($DBField->isSigned()){
					$DBField->enableSigned(false);
					$infoNode->modifyOrAppend('SIGNED',0);
				}
			}else{
				if($newZerofillValue){// means its not zerofillable and we should warn the user
					$this->setError('Field with type `'.$DBField->getType().'` cannot be zerofilled');
					return false;
				}else{
					$DBField->enableZeroFill(0);
					$infoNode->modifyOrAppend('ZEROFILL',0);
				}
				
			}
			$sqlchange = true;
		}
		
		// completing with the decomposition of the sqltype in two parts
		$infoNode->modifyOrAppend('DBTYPE',$DBField->getDBType($DBField->getSQLType()));
		$infoNode->modifyOrAppend('OPTION',$DBField->getOption($DBField->getSQLType()));
		
		if($sqlchange){
			// applying changes
			$res = $DBField->update();
			if(!$res){
				$this->setError($DBField->getError());
				return false;
			}
		}
		
		
		if($this->firstNode->getAttribute('translate')=='true'){
			// composing a fieldname in fluid english in order to translate
			$readablefieldname = $DBField->getReadableName();
			
			// calling a translator to fill the descriptions
			$desc = '<DESCRIPTION languageID="eng"><TITLE>'.encode_to_xml($readablefieldname).'</TITLE></DESCRIPTION>';
			
			$translator = new sushee_translator();
			
			/**
			 * If not null it means that we don't need the classic languages but only those given
			 * 
			 * @var 	string		valid language ID optionally separated by commas
			 * @author	Julien
			 */
			$translateTo   = $this->firstNode->getAttribute('translateTo');						
			
			/**
			 * If not null the translation will be put there
			 * 
			 * Ex: translate 'first name' to french but put it in shared.
			 * 			 
			 * @author	Julien
			 */
			$translateTarget = $this->firstNode->getAttribute('translateTarget');
			

			if ($translateTo){
				$lgs         = array();
				$translateTo = explode(',', $translateTo);
				
				if ($translateTarget){//if set then we just take the first language defined in translateTo
					$lgs[] = new Sushee_Language($translateTo[0]);
				} else {
					foreach ($translateTo as $languageID){
						$lgs[] = new Sushee_Language($languageID);
					}	
					
				}							
			} else {
				$lgs = $translator->getClassicLanguages();	
			}
			
			
			$translator->setOriginLanguage('eng');
			
			foreach($lgs as $lg){
				$translator->setTargetLanguage($lg);
				$translation = $translator->execute($readablefieldname);
				if($translation){
					/**
					 * @author	Julien
					 */
					$lgID = ($translateTarget) ? $translateTarget : $lg->getID();
					//commented by Julien
					//$desc.='<DESCRIPTION languageID="'.$lg->getID().'"><TITLE>'.encode_to_xml($translation).'</TITLE></DESCRIPTION>';
					$desc.='<DESCRIPTION languageID="'.$lgID.'"><TITLE>'.encode_to_xml($translation).'</TITLE></DESCRIPTION>';
				}
			}
			// saving the descriptions
			$this->firstNode->appendChild('<DESCRIPTIONS>'.$desc.'</DESCRIPTIONS>');
		}
		
		// letting the usual update in NQL do its job
		$update = new UpdateElement($this->getName(),$this->operationNode);
		$update->execute();
		$this->setMsg($update->getMsg());
		
		// forcing the session to reload the definition of the module to be synchronised with the changes made
		$moduleInfo->clearInSession();
		
		return true;
	}
	
}


?>