<?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/app/app-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_AppProcessor extends AbstractFactoryProcessor
	{
		/* PREPROCESSOR : CREATION  */
		
		public function preCreate($data)
		{	
			// 1st: retrieve editor and app folder
			if (($clean_result = $this->getCleanEditorAndAppFolders($data, $editor_folder_name, $app_folder_name)) !== true)
			{
				return $clean_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');
				$app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$app_folder_name;
				
				$app_folder = new KernelFolder($app_folder_path);
				if ($app_folder->exists())
				{
					return new SusheeProcessorException('Folder '.$app_folder_path.' already exists!');
				}
				
				$package_path = '/'.$env_folder_name.'/system/packages/application';
				$package_folder = new KernelFolder($package_path);
				if (!$package_folder->exists())
				{
					return new SusheeProcessorException('Package folder '.$package_path.' not found!');
				}
			}
			
			// 3rd: create folders
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				$package_path = '/'.$env_folder_name.'/system/packages/application';
				$package_folder = new KernelFolder($package_path);
				
				$dest_path = '/'.$env_folder_name.'/'.$editor_folder_name;
				if (!$package_folder->copy($dest_path))
				{
					return new SusheeProcessorException('Error copying package folder to '.$dest_path.'!');
				}
				
				$new_folder_path = $dest_path.'/application';
				$new_folder = new KernelFolder($new_folder_path);
				if (!$new_folder->rename($app_folder_name))
				{
					return new SusheeProcessorException('Error renaming package folder '.$new_folder_path.' to '.$app_folder_name.'!');
				}
				
				// update app config file
				if (($update_result = $this->updateAppConfigFile($env_folder_name, $editor_folder_name, $app_folder_name, $data->getValue('Denomination'))) !== true)
				{
					return $update_result;
				}
			}
						
			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}		
			
			$paths = array(ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/'.$app_folder_name.'/');
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/CREATECOMMAND'), $paths, 'Create');
			
			return new SusheeProcessorMessage($return_message);
		}
		
		public function postCreate($data)
		{
			// create and add app key to visitor's keyring
			$visitor = new OfficityUser();
			$visitor_ID = $visitor->getID();
			if (empty($visitor_ID))
			{
				return new SusheeProcessorException('Cannot retrieve visitor ID!');
			}
			
			$nql = new Sushee_Shell(false);
			$nql->addCommand('
				<UPDATE>
					<KEYRING>
						<WHERE>
							<DEPENDENCIES>
								<DEPENDENCY type="keyringUsers">
									<CONTACT ID="'.$visitor_ID.'" />
								</DEPENDENCY>
							</DEPENDENCIES>
						</WHERE>
						<DEPENDENCIES>
							<DEPENDENCY type="keyringAppKeys" operation="append">
								<APPLICATIONKEY>
									<INFO>
										<DENOMINATION>Access to '.$data->getValue('Denomination').'</DENOMINATION>
										<APPLICATIONTOID>'.$data->getID().'</APPLICATIONTOID>
									</INFO>
								</APPLICATIONKEY>
							</DEPENDENCY>
						</DEPENDENCIES>
					</KEYRING>
				</UPDATE>
			');
			$nql->execute();
			
			$message = $nql->valueOf('/RESPONSE/MESSAGE[@msgType!=0]');
			if (!empty($message))
			{
				return new SusheeProcessorException("Error adding application key to visitor's keyring: ".$message);
			}
		}
		
		public function preUpdate($data)
		{
			// 1st: retrieve editor and app folder
			if (($clean_result = $this->getCleanEditorAndAppFolders($data, $editor_folder_name, $new_app_folder_name)) !== true)
			{
				return $clean_result;
			}
			
			// 2nd: folder change?
			if ($data->getFormerValue('URL') != $new_app_folder_name)
			{
				return $this->folderChange($data, $editor_folder_name, $new_app_folder_name);
			}	

			// 3rd: denomination change?
			$new_app_denom = $data->getValue('Denomination');
			if ($data->getFormerValue('Denomination') != $new_app_denom)
			{
				return $this->denominationChange($editor_folder_name, $new_app_folder_name, $new_app_denom);
			}	
			
			return new SusheeProcessorMessage('Update processed');
		}
		
		public function preDelete($data)
		{
			// 1st: retrieve editor and app folder
			if (($clean_result = $this->getCleanEditorAndAppFolders($data, $editor_folder_name, $app_folder_name)) !== true)
			{
				return $clean_result;
			}
			
			// 2nd: folders deletion
			$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');
				$app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$app_folder_name;
				
				$app_folder = new KernelFolder($app_folder_path);
				if ($app_folder->exists())
				{
					$app_folder->delete();
					if ($app_folder->exists())
					{
						return new SusheeProcessorException('Error deleting folder '.$app_folder_path.'!');
					}
				}
			}
			
			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}		
			
			$editor_folder = ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/';
			$paths = array($editor_folder.$app_folder_name.'/');
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/DELETECOMMAND'), $paths, 'Delete');
			
			return new SusheeProcessorMessage($return_message);
		}
		
		public function postDelete($data)
		{
			// 1st: remove app key from visitor's keyring
			$visitor = new OfficityUser();
			$visitor_ID = $visitor->getID();
			if (empty($visitor_ID))
			{
				return new SusheeProcessorException('Cannot retrieve visitor ID!');
			}
			
			// retrieve appkey ID
			$nql = new Sushee_Shell(false);
			$nql->addCommand('
				<SEARCH>
					<APPLICATIONKEY>
						<INFO>
							<APPLICATIONTOID>'.$data->getID().'</APPLICATIONTOID>
						</INFO>
					</APPLICATIONKEY>
					<RETURN>
						<NOTHING />
					</RETURN>
				</SEARCH>
			');
			$nql->execute();
			$appkey_ID = $nql->valueOf('/RESPONSE/RESULTS/APPLICATIONKEY/@ID');
			if (empty($appkey_ID))
			{
				return new SusheeProcessorMessage("No application key to remove from visitor's keyring!");
			}
			
			$nql->addCommand('
				<UPDATE>
					<KEYRING>
						<WHERE>
							<DEPENDENCIES>
								<DEPENDENCY type="keyringUsers">
									<CONTACT ID="'.$visitor_ID.'" />
								</DEPENDENCY>
							</DEPENDENCIES>
						</WHERE>
						<DEPENDENCIES>
							<DEPENDENCY type="keyringAppKeys" operation="remove">
								<APPLICATIONKEY ID="'.$appkey_ID.'" />
							</DEPENDENCY>
						</DEPENDENCIES>
					</KEYRING>
				</UPDATE>
			');
			$nql->execute();
			
			$message = $nql->valueOf('/RESPONSE/MESSAGE[@msgType!=0]');
			if (!empty($message))
			{
				return new SusheeProcessorException("Error removing application key from visitor's keyring: ".$message);
			}
			
			// 2nd: delete appkey
			$nql->addCommand('
				<KILL>
					<APPLICATIONKEY ID="'.$appkey_ID.'" />
				</KILL>
			');
			$nql->execute();
			
			$message = $nql->valueOf('/RESPONSE/MESSAGE[@msgType!=0]');
			if (!empty($message))
			{
				return new SusheeProcessorException("Error deleteing application key: ".$message);
			}
		}
		
		// ...
		protected function getCleanEditorAndAppFolders($data, &$editor_folder_name, &$app_folder_name)
		{
			// 1st: clean editor folder
			$editor_ID = $data->getElementNode()->valueOf('DEPENDENCIES/DEPENDENCY[@type="officity:appNamespaces"]/NAMESPACE/@ID');
			if (empty($editor_ID))
			{			
				$nql = new Sushee_Shell(false);
				$nql->addCommand('
					<SEARCH>
						<NAMESPACE>
							<DEPENDENCIES>
								<DEPENDENCY type="officity:namespaceApps">
									<APP ID="'.$data->getID().'" />
								</DEPENDENCY>
							</DEPENDENCIES>
						</NAMESPACE>
						<RETURN>
							<NOTHING />
						</RETURN>
					</SEARCH>
				');
				$nql->execute();			
				$editor_ID = $nql->valueOf('/RESPONSE/RESULTS/NAMESPACE/@ID');
			}			
			if (empty($editor_ID))
			{
				return new SusheeProcessorException('Cannot retrieve editor ID!');
			}

			$editor_folder_name = $this->getEditorFolder($editor_ID);
			if (empty($editor_folder_name))
			{
				return new SusheeProcessorException('Cannot retrieve editor folder!');
			}
			if (($clean_result = $this->cleanFolderName($editor_folder_name)) !== true)
			{
				return $clean_result;
			}
			
			// 2nd: clean folder name
			$app_folder_name = $data->getValue('URL');
			if (($clean_result = $this->cleanFolderName($app_folder_name)) !== true)
			{
				return $clean_result;
			}
			
			// update data...
			$data->setValue('URL', $app_folder_name);
			
			return true;
		}
		
		// ...
		protected function folderChange($data, $editor_folder_name, $new_app_folder_name)
		{
			// 1st: check envs
			$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');
				$former_app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$data->getFormerValue('URL');
			
				$former_app_folder = new KernelFolder($former_app_folder_path);
				if (!$former_app_folder->exists())
				{
					return new SusheeProcessorException('Folder '.$former_app_folder_path.' does not exist!');
				}
				
				$new_app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$new_app_folder_name;
				
				$new_app_folder = new KernelFolder($new_app_folder_path);
				if ($new_app_folder->exists())
				{
					return new SusheeProcessorException('Folder '.$new_app_folder_path.' already exists!');
				}
			}
			
			// 2nd: update app in all published environments
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				$former_app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$data->getFormerValue('URL');
			
				$former_app_folder = new KernelFolder($former_app_folder_path);
				if (!$former_app_folder->rename($new_app_folder_name))
				{
					return new SusheeProcessorException('Error renaming folder '.$former_app_folder_path.' to '.$new_app_folder_name.'!');
				}
				
				// update app config file
				if (($update_result = $this->updateAppConfigFile($env_folder_name, $editor_folder_name, $new_app_folder_name, $data->getValue('Denomination'))) !== true)
				{
					return $update_result;
				}
			}

			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}		
			
			$paths = array(
				'old_path' => ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/'.$data->getFormerValue('URL').'/',
				'new_path' => ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/'.$new_app_folder_name.'/'
			);
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/RENAMECOMMAND'), $paths, 'Rename');
			
			return new SusheeProcessorMessage($return_message);
		}
		
		// ...
		protected function denominationChange($editor_folder_name, $app_folder_name, $new_app_denom)
		{
			// 1st: check envs
			$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');
				$app_folder_path = '/'.$env_folder_name.'/'.$editor_folder_name.'/'.$app_folder_name;
			
				$app_folder = new KernelFolder($app_folder_path);
				if (!$app_folder->exists())
				{
					return new SusheeProcessorException('Folder '.$app_folder_path.' does not exist!');
				}
			}
			
			// 2nd: update app denom in all published environments
			foreach ($env_elements as $env)
			{
				$env_folder_name = $env->valueOf('INFO/FOLDER');
				
				// update app config file
				if (($update_result = $this->updateAppConfigFile($env_folder_name, $editor_folder_name, $app_folder_name, $new_app_denom)) !== true)
				{
					return $update_result;
				}
			}	

			/* execute server commands */
			
			if (($dev_env = $this->getDevEnvironment()) == false)
			{
				return new SusheeProcessorMessage('Development environment not published. No server commands executed.');
			}

			$paths = array(ROOT_PATH.$dev_env->valueOf('INFO/FOLDER').'/'.$editor_folder_name.'/'.$app_folder_name.'/config/');
			$return_message = $this->execServerCommands($dev_env->valueOf('INFO/UPDATECOMMAND'), $paths, 'Update');
			
			return new SusheeProcessorMessage($return_message);
		}
		
		// ...
		protected function updateAppConfigFile($env_folder, $editor_folder, $app_folder, $app_name)
		{
			$php_file_name = 'app.config.php';
			$php_file_path = $env_folder.'/'.$editor_folder.'/'.$app_folder.'/config/'.$php_file_name;
			
			$config_script = "<?php".PHP_EOL.
								chr(9)."/* file automatically generated by the system on ".date('d-m-Y @ H:i:s').' */'.PHP_EOL.
								chr(9)."define(".PHP_EOL.
								chr(9).chr(9)."'APP_NAME',".PHP_EOL.
								chr(9).chr(9)."'$app_name'".PHP_EOL.
								chr(9).");".PHP_EOL.
								chr(9)."define(".PHP_EOL.
								chr(9).chr(9)."'APP_FOLDER',".PHP_EOL.
								chr(9).chr(9)."'$app_folder'".PHP_EOL.
								chr(9).");".PHP_EOL.
								"?>";
			
			$php_file = new KernelFile($php_file_path);
			$php_file->save($config_script);
			if (!$php_file->exists())
			{
				return new SusheeProcessorException('Error updating application config file : '.$php_file_path.' has not been created!');
			}
			
			return true;
		}
	}
?>