<?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/shared/module/module-processors.class.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__).'/../../../sushee/shared/class/AbstractFactoryProcessor.class.php');
	
	/* *** */
	
	class Sushee_ModuleProcessor extends AbstractFactoryProcessor
	{
		/* PREPROCESSOR : CREATION, FILES GENERATIONS */
		
		public function genFiles($data)
		{	
			// 1st: retrieve editor and module folder
			$editor_folder_name = $editor_url = $module_folder_name = '';
			if (($get_folders_result = $this->getCleanFolders($data, $editor_folder_name, $editor_url, $module_folder_name)) !== true)
			{
				return $get_folders_result;
			}
						
			// 2nd: check environments/packages
			$env_elements = $this->getPublishedEnvironments();
			if (empty($env_elements))
			{
				return new SusheeProcessorException('Cannot retrieve published environments!');
			}
			
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				$module_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/shared/'.$module_folder_name;
				
				$module_folder = new KernelFolder($module_folder_path);
				if ($module_folder->exists())
				{
					return new SusheeProcessorException('Folder '.$module_folder_path.' already exists!');
				}
				
				$package_path = '/'.$env_folder_name.'/system/packages/module-objects';
				$package_folder = new KernelFolder($package_path);
				if (!$package_folder->exists())
				{
					return new SusheeProcessorException('Package folder '.$package_path.' not found!');
				}
			}
			
			// 3rd: create folders/generate module files
			$module_filenames = array(
				'module.class.php'				=> $module_folder_name.'.class.php',	  	
				'module-op.class.php'			=> $module_folder_name.'-op.class.php',
				'module-processors.class.php'	=> $module_folder_name.'-processors.class.php',
				'module.definitions.xsl'		=> $module_folder_name.'.definitions.xsl'
			);
			
			$files_created = array();
			
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				$package_path = '/'.$env_folder_name.'/system/packages/module-objects';
				$package_folder = new KernelFolder($package_path);
				
				$shared_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/shared';
				if (!$package_folder->copy($shared_path))
				{
					return new SusheeProcessorException('Error copying package folder to '.$shared_path.'!');
				}
				
				$new_folder_path = $shared_path.'/module-objects';
				$new_folder = new KernelFolder($new_folder_path);
				if (!$new_folder->rename($module_folder_name))
				{
					return new SusheeProcessorException('Error renaming package folder '.$new_folder_path.' to '.$module_folder_name.'!');
				}
				
				// generate each module file : class, operations class, processor class, XSL definitions
				foreach ($module_filenames as $tpl_filename => $module_filename)
				{
					$tpl_path = $new_folder->getCompletePath().$tpl_filename;
					$tpl_file = new KernelFile($tpl_path);
					if (!$tpl_file->rename($module_filename))
					{
						return new SusheeProcessorException('Error renaming template file '.$tpl_path.' to '.$module_filename.'!');
					}
					
					$MODULE = strtoupper($module_folder_name);
					$NAMESPACE = strtoupper($editor_folder_name);
					$NSMODULE = ($NAMESPACE == 'SUSHEE') ? $MODULE : $NAMESPACE.':'.$MODULE;
					
					$new_content = $tpl_file->toString();
					$new_content = str_replace('%Module%',			ucfirst($module_folder_name), 		$new_content);
					$new_content = str_replace('%MODULE%',			$MODULE, 							$new_content);
					$new_content = str_replace('%module%',			strtolower($module_folder_name),	$new_content);
					$new_content = str_replace('%NSMODULE%',		$NSMODULE, 							$new_content);
					$new_content = str_replace('%Namespace%', 		ucfirst($editor_folder_name),		$new_content);
					$new_content = str_replace('%NAMESPACE%',		$NAMESPACE, 						$new_content);
					$new_content = str_replace('%namespace%',		strtolower($editor_folder_name), 	$new_content);
					$new_content = str_replace('%namespaceurl%',	$editor_url, 						$new_content);
					
					$tpl_file->save($new_content);
				}	
				
				// rename files and generate classes etc.
				if (($update_result = $this->add2SharedConfigFiles($shared_path, $module_folder_name)) !== true)
				{
					return $update_result;
				}
			}
			
			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}		
			
			$dev_shared_folder = ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/shared/';
			$paths = array($dev_shared_folder.$module_folder_name.'/');
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/CREATECOMMAND'), $paths, 'Create');
			
			$paths = array(
				$dev_shared_folder.'shared.elements.classes.php',
				$dev_shared_folder.'shared.elements.definitions.xsl'
			);
			$return_message .= $this->execServerCommands($dev_env->valueOf('INFO/UPDATECOMMAND'), $paths, 'Update');
			
			return new SusheeProcessorMessage($return_message);
		}
		
		/* POSTPROCESSOR : CREATE SEARCH CONFIG + DEFAULT FILTER + REPORTS */
		public function createDefaultResources($data)
		{
			$nql = new Sushee_Shell(false);
			
			$denomination = $data->getValue('Denomination');
			
	    	// search config
	    	$nql->addCommand('
	    		<CREATE>
	    			<OFFICITY:SEARCHCONFIG>
	    				<INFO>
	    					<MODULE>'.$denomination.'</MODULE>
	    					<DEFAULT>1</DEFAULT>
	    					<CONFIGXML>
		    					<MODULE>'.$denomination.'</MODULE>
		    					<MODULEDESC>'.$denomination.'</MODULEDESC>
								<DEFAULTFIELD>ID</DEFAULTFIELD>
								<DEFAULTOPERATOR>=</DEFAULTOPERATOR>
								<DEFAULTOPERANDS/>
	    					</CONFIGXML>
	    				</INFO>
	    			</OFFICITY:SEARCHCONFIG>
	    		</CREATE>
	    	');	
			
	    	// filter
	    	$nql->addCommand('
	    		<CREATE>
	    			<OFFICITY:FILTER>
	    				<INFO>
	    					<MODULE>'.$denomination.'</MODULE>
	    					<DEFAULT>1</DEFAULT>
	    					<OWNERID>0</OWNERID>
	    					<DENOMINATION>Default '.$denomination.' display</DENOMINATION>
	    					<ISQUERY>0</ISQUERY>
	    					<ISDISPLAY>1</ISDISPLAY>
	    					<COUNT>0</COUNT>
	    					<SEARCH>0</SEARCH>
	    					<DISPLAYXML>
								<RETURN>
									<INFO><ID order="1" /></INFO>
								</RETURN>
								<SORT select="INFO/ID" order="descending" />
								<PAGINATE display="100" page="1" />
	    					</DISPLAYXML>
	    				</INFO>
	    			</OFFICITY:FILTER>
	    		</CREATE>
	    	');	
			
	    	// PDF report
	    	$nql->addCommand('
	    		<CREATE>
	    			<OFFICITY:REPORT>
	    				<INFO>
	    					<MODULE>'.$denomination.'</MODULE>
	    					<MODEL>1</MODEL>
	    					<OWNERID>0</OWNERID>
	    					<TYPE>pdf</TYPE>
	    					<FORMAT>A4</FORMAT>
	    					<ORIENTATION>portrait</ORIENTATION>
	    					<APPLY>search</APPLY>
	    					<TITLE>Basic report</TITLE>
	    					<DISPLAYXML>
								<RETURN>
									<INFO>
										<ID order="1" />
									</INFO>
								</RETURN>
								<SORT select="INFO/ID" order="descending" />
								<PAGINATE display="100" page="1" />
	    					</DISPLAYXML>
	    				</INFO>
	    			</OFFICITY:REPORT>
	    		</CREATE>
	    	');	
	    	
	    	// CSV export
	    	$nql->addCommand('
	    		<CREATE>
	    			<OFFICITY:REPORT>
	    				<INFO>
	    					<MODULE>'.$denomination.'</MODULE>
	    					<MODEL>1</MODEL>
	    					<OWNERID>0</OWNERID>
	    					<TYPE>csv</TYPE>
	    					<FORMAT>A4</FORMAT>
	    					<ORIENTATION>portrait</ORIENTATION>
	    					<APPLY>search</APPLY>
	    					<TITLE>Export</TITLE>
	    					<DISPLAYXML>
								<RETURN>
									<INFO>
										<ID order="1" />
									</INFO>
								</RETURN>
								<SORT select="INFO/ID" order="descending" />
								<PAGINATE display="100" page="1" />
	    					</DISPLAYXML>
	    				</INFO>
	    			</OFFICITY:REPORT>
	    		</CREATE>
	    	');	
	    	
	    	$nql->addCommand('
	    		<CREATE>
	    			<OFFICITY:REPORT>
	    				<INFO>
	    					<MODULE>'.$denomination.'</MODULE>
	    					<MODEL>1</MODEL>
	    					<OWNERID>0</OWNERID>
	    					<TYPE>csv</TYPE>
	    					<FORMAT>A4</FORMAT>
	    					<ORIENTATION>portrait</ORIENTATION>
	    					<APPLY>all</APPLY>
	    					<TITLE>Extended export</TITLE>
	    					<TEMPLATE>csv/generic-csv-export-alt.xsl</TEMPLATE>
	    					<DISPLAYXML>
								<RETURN>
									<INFO>
										<ID order="1" />
									</INFO>
								</RETURN>
								<SORT select="INFO/ID" order="descending" />
								<PAGINATE display="100" page="1" />
	    					</DISPLAYXML>
	    				</INFO>
	    			</OFFICITY:REPORT>
	    		</CREATE>
	    	');	
	    	$nql->execute();
	    	
			return new SusheeProcessorMessage('Default search config, filter and reports created.');
		}
		
		/* PREPROCESSOR : DELETE, FILES DELETION */
		
		public function deleteFiles($data)
		{	 
            // 1st. get editor folder + module folder
            $nql = new Sushee_Shell(false);
            $nql->addCommand('
            	<GET>
            		<MODULE ID="'.$data->getID().'" />
				  	<RETURN depth="2">
						<INFO>
							<DENOMINATION />
						</INFO>
						<DEPENDENCIES>
							<DEPENDENCY type="officity:moduleNamespaces">
								<INFO>
									<NAMESPACE />
								</INFO>
							</DEPENDENCY>
						</DEPENDENCIES>
					</RETURN>
            	</GET>
            ');
            $nql->execute();
            
            $module_folder_name = $nql->valueOf('/RESPONSE/RESULTS/MODULE/INFO/DENOMINATION');
            $editor_folder_name = $nql->valueOf('/RESPONSE/RESULTS/MODULE/DEPENDENCIES/DEPENDENCY[@type="officity:moduleNamespaces"]/NAMESPACE/INFO/NAMESPACE');

            $denom_slices = explode(':', $module_folder_name);
			if ($denom_slices[0] != $module_folder_name)
			{
				$module_folder_name = $denom_slices[1];
			}
			
			if (empty($editor_folder_name))
			{
				return new SusheeProcessorException('Cannot retrieve editor folder!');
			}
			if (empty($module_folder_name))
			{
				return new SusheeProcessorException('Cannot retrieve module folder!');
			}
			
			// 2nd. delete files
			$env_elements = $this->getPublishedEnvironments();
			if (empty($env_elements))
			{
				return new SusheeProcessorException('Cannot retrieve published environments!');
			}	
			
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				$shared_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/shared';
				$module_folder_path = $shared_path.'/'.$module_folder_name;
				
				$module_folder = new KernelFolder($module_folder_path);
				if ($module_folder->exists())
				{
					$module_folder->delete();
					if ($module_folder->exists())
					{
						return new SusheeProcessorException('Error deleting folder '.$module_folder_path.'!');
					}
				}
				
				// ...
				if (($update_result = $this->removeFromSharedConfigFiles($shared_path, $module_folder_name)) !== true)
				{
					return $update_result;
				}
			}
			
			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}	
					
			$dev_shared_folder = ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/shared/';
			$paths = array($dev_shared_folder.$module_folder_name.'/');
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/DELETECOMMAND'), $paths, 'Delete');
			
			$paths = array(
				$dev_shared_folder.'shared.elements.classes.php',
				$dev_shared_folder.'shared.elements.definitions.xsl'
			);
			$return_message .= $this->execServerCommands($dev_env->valueOf('INFO/UPDATECOMMAND'), $paths, 'Update');
			
			return new SusheeProcessorMessage($return_message);
		}
			
		public function deleteDefaultResources($data)
		{
			$nql = new Sushee_Shell(false);
			
			$denomination = $data->getValue('Denomination');
			
	    	// search config
	    	$nql->addCommand('
	    		<KILL>
	    			<OFFICITY:SEARCHCONFIG>
	    				<WHERE>
		    				<INFO>
		    					<MODULE>'.$denomination.'</MODULE>
		    				</INFO>
	    				</WHERE>
	    			</OFFICITY:SEARCHCONFIG>
	    		</KILL>
	    	');	
	    	// search config
	    	$nql->addCommand('
	    		<KILL>
	    			<OFFICITY:FILTER>
	    				<WHERE>
		    				<INFO>
		    					<MODULE>'.$denomination.'</MODULE>
		    				</INFO>
	    				</WHERE>
	    			</OFFICITY:FILTER>
	    		</KILL>
	    	');	
			
	    	// reports
	    	$nql->addCommand('
	    		<KILL>
	    			<OFFICITY:REPORT>
		    			<WHERE>
		    				<INFO>
		    					<MODULE>'.$denomination.'</MODULE>
		    					<MODEL>1</MODEL>
		    					<OWNERID>0</OWNERID>
		    				</INFO>
	    				</WHERE>
	    			</OFFICITY:REPORT>
	    		</KILL>
	    	');	
	    	$nql->execute();
	    	
			return new SusheeProcessorMessage('Default search config, filter and reports deleted.');
		}			
						
		// ...
		protected function add2SharedConfigFiles($shared_path, $module_folder_name)
		{
			// 1st. classes importer file
			$class_file_path = $shared_path.'/shared.elements.classes.php';
			$class_file = new KernelFile($class_file_path);
			$content = $class_file->toString();
			$include_string = "require_once(dirname(__FILE__).'/$module_folder_name/$module_folder_name.class.php');";
			if (strpos($content, $include_string) === false)
			{
				$string_2_append = '';
				//$string_2_append = chr(9).'// '.$module_folder_name.': system update on '.date('d-m-Y @ H:i:s').PHP_EOL;
				$string_2_append .= chr(9).$include_string.PHP_EOL;
				$string_2_append .= chr(9)."require_once(dirname(__FILE__).'/$module_folder_name/$module_folder_name-op.class.php');".PHP_EOL;
				$string_2_append .= '?>';
				$new_content = str_replace('?>', $string_2_append, $content);
				/*if (!*/$class_file->save($new_content);/*)
				{*/
					//return new SusheeProcessorException('Error updating shared config file '.$class_file_path.'!');
				/*}*/
			}
			
			// 2nd. xsl definitions importer file
			$xsl_file_path = $shared_path.'/shared.elements.definitions.xsl';
			$xsl_file = new KernelFile($xsl_file_path);
			$content = $xsl_file->toString();
			$include_string = '<xsl:import href="'.$module_folder_name.'/'.$module_folder_name.'.definitions.xsl"/>';
			if (strpos($content, $include_string) === false)
			{			
				$string_2_append = '';	
				//$string_2_append = chr(9).'<!-- '.$module_folder_name.': system update on '.date('d-m-Y @ H:i:s').' -->'.PHP_EOL;
				$string_2_append .= chr(9).$include_string.PHP_EOL;
				$string_2_append .= '</xsl:stylesheet>';
				$new_content = str_replace('</xsl:stylesheet>', $string_2_append, $content);
				/*if (!*/$xsl_file->save($new_content);/*)
				{*/
					//return new SusheeProcessorException('Error updating shared config file '.$class_file_path.'!');
				/*}*/
			}
			
			return true;
		}
		
		// ...
		protected function removeFromSharedConfigFiles($shared_path, $module_folder_name)
		{
			// 1st. classes importer file
			$class_file_path = $shared_path.'/shared.elements.classes.php';
			$class_file = new KernelFile($class_file_path);
			$content = $class_file->toString();
			$new_content = str_replace("require_once(dirname(__FILE__).'/$module_folder_name/$module_folder_name.class.php');", '', $content);
			$new_content = str_replace("require_once(dirname(__FILE__).'/$module_folder_name/$module_folder_name-op.class.php');", '', $new_content);
			/*if (!*/$class_file->save($new_content);/*)
			{*/
				//return new SusheeProcessorException('Error updating shared config file '.$class_file_path.'!');
			/*}*/
			
			// 2nd. xsl definitions importer file
			$xsl_file_path = $shared_path.'/shared.elements.definitions.xsl';
			$xsl_file = new KernelFile($xsl_file_path);
			$content = $xsl_file->toString();
			$new_content = str_replace('<xsl:import href="'.$module_folder_name.'/'.$module_folder_name.'.definitions.xsl"/>', '', $content);
			/*if (!*/$xsl_file->save($new_content);/*)
			{*/
				//return new SusheeProcessorException('Error updating shared config file '.$class_file_path.'!');
			/*}*/
			
			return true;
		}
		
		// ...
		protected function getCleanFolders($data, &$editor_folder_name, &$editor_url, &$module_folder_name)
		{
			// check for namespace
		    $denom_slices = explode(':', $data->getValue('Denomination'));
		    if (count($denom_slices) > 2)
		    {
		    	return new SusheeProcessorException('Module denomination '.$data->getValue('Denomination').' is invalid!');
		    }
		    
			if (isset($denom_slices[1]))
			{
				$editor_folder_name = strtolower($denom_slices[0]);
				$module_folder_name = strtolower($denom_slices[1]);
			}
			else
			{
				$editor_folder_name = 'sushee'; // default
				$module_folder_name = strtolower($denom_slices[0]);
			}
					
			if (($is_clean_result = $this->isCleanFolderName($module_folder_name)) !== true)
			{
				return $is_clean_result;
			}
			
			// namespace in dependency?
			$editor_ID = $data->getElementNode()->valueOf('DEPENDENCIES/DEPENDENCY[@type="officity:moduleNamespaces"]/NAMESPACE/@ID');
			if (!empty($editor_ID))
			{			
				$editor = $this->getEditor($editor_ID);
			}
			else
			{
				$shell = new Sushee_Shell();
				$shell->addCommand('
					<SEARCH>
						<NAMESPACE namespace="'.$editor_folder_name.'" />
						<RETURN>
							<INFO>
								<URL/>
							</INFO>
						</RETURN>
					</SEARCH>
				');
				// xml_out($shell->getQuery());
				$shell->execute();
				$editor = $shell->getElement('/RESPONSE/RESULTS/NAMESPACE');
			}
			if($editor===false){
				return new SusheeProcessorException('Cannot retrieve editor (ID='.$editor_ID.')!');
			}

			$editor_url = $editor->valueOf('INFO/URL');

			if(!$data->getElementNode()->getElement('DEPENDENCIES/DEPENDENCY[@type="officity:moduleNamespaces"]')){
				$data->getElementNode()->appendChild('
				<DEPENDENCIES>
					<DEPENDENCY type="officity:moduleNamespaces">
						<NAMESPACE ID="'.$editor->valueOf('@ID').'"/>
					</DEPENDENCY>
				</DEPENDENCIES>
				');
			}
			return true;
		}
		
		// ...
		protected function isCleanFolderName($denomination)
		{
			$clean_folder_name = $denomination;
			$clean_folder_name = trim($clean_folder_name, '/');
			$clean_folder_name = removeaccents($clean_folder_name);
			$clean_folder_name = strtolower($clean_folder_name);
			$clean_folder_name = preg_replace('/[^a-z0-9_\-]/', '_', $clean_folder_name);
			if ($denomination != $clean_folder_name)
			{
				return new SusheeProcessorException('Module denomination '.$denomination.' is invalid! Only alphanumeric lower-case chars (a-z, 0-9), underscore (_) or hyphen (-) are authorized.');
			}
			return true;
		}
	}
?>