<?php

/**
 * Description of SuperTool
 * @author Arkadiusz Rychlik <a.rychlik at eppe.com.pl>
 */
class Rtn_Module_Tool {

	/**
	 * Dodaje moduł do aplikacji
	 * @param type $params
	 * @throws Rtn_Exception_Module
	 */
	static function install($params) {
		$name = array_shift($params);
		$replace = array_shift($params) === 'replace';

		$tool = new Rtn_Module_Tool($name);

		if (!$tool->exists()) {
			Rtn_Cli::writeln(__('Module `:module` does not exist!', array(':module' => $name)));
			exit;
		}

		$tool->installMod($replace);
	}
	
	static function create($params) {
		$name = array_shift($params);
		$replace = array_shift($params) === 'replace';

		$tool = new Rtn_Module_Tool($name);

		$tool->createMod($replace);
	}

	protected $installPath;
	protected $mainPath;
	protected $name;

	public function __construct($moduleName) {
		$this->name = $moduleName;

		$this->mainPath = LIBRARY_PATH . 'Main/' . $moduleName . '/';
		$this->installPath = MODULES_PATH . $moduleName . '/';
	}

	/**
	 * Czy moduł istnieje w Main?
	 * @return type
	 */
	public function exists() {
		return file_exists($this->mainPath);
	}

	/**
	 * Instaluje moduł w Application
	 */
	public function installMod($replace) {
		Rtn_Cli::writeln("Install module: {$this->name}");
		if ($replace) {
			Rtn_Cli::writeln("Replace module: {$this->name}");
			Rtn_Filesystem::delTree($this->installPath);
		}

		if (!$this->prepareInstallPath($this->installPath)) {
			Rtn_Cli::writeln(__('Module `:module` already installed', array(':module' => $this->name)));
			exit;
		}

		$this->copyFiles();
		$this->copyClasses($this->mainPath . 'classes/');

		Rtn_Cli::writeln('Done!');
	}
	
	public function createMod($replace) {
		Rtn_Cli::writeln("Create module: {$this->name}");
		if ($replace) {
			Rtn_Cli::writeln("Replace module: {$this->name}");
			Rtn_Filesystem::delTree($this->installPath);
		}

		if (!$this->prepareInstallPath($this->installPath)) {
			Rtn_Cli::writeln(__('Module `:module` already installed', array(':module' => $this->name)));
			exit;
		}

		$this->createDirs();
		$this->createFiles();

		Rtn_Cli::writeln('Done!');
	}
	
	/**
	 * Kopiuje rekurencyjnie wszystkie klasy z Main do Application
	 * @param type $initialPath
	 */
	public function copyClasses($initialPath) {
		foreach (new RecursiveDirectoryIterator($initialPath, FilesystemIterator::SKIP_DOTS) as $node) {
			$pathName = $node->getPathname();
			if (strpos($pathName, '.svn') !== FALSE) {
				continue;
			}
			if ($node->isDir()) {
				$this->copyClasses($pathName);
			}
			else {
				Rtn_Cli::writeln("Render class: {$this->_className($pathName)}");
				$this->_copyClass($pathName);
			}
		}
	}

	public function createFiles() {
		$files = [
			'configs/module.ini' => null,
			'classes/Bootstrap.php' => null,
			'classes/Module/Module.php' => null,
			'classes/Module/Acl.php' => null,
			'classes/Module/Initer.php' => null,
			'classes/Module/Menu.php' => null,
			'classes/Module/Route.php' => null,
			'classes/Module/Initer/Acl.php' => null,
			'classes/Module/Initer/DB.php' => null,
		];
		
		$data = new stdClass();
		$data->moduleName = $this->name;
		
		foreach($files as $filename=>$dummy){
			$file = $this->installPath.$filename;
			file_put_contents($file, Rtn_Module_Tool_Filecreator::create($filename, $data));
		}
	}
	
	/**
	 * Kopiuje pojedynczą klasę do application
	 * @param type $pathName
	 */
	protected function _copyClass($pathName) {
		file_put_contents($this->_prepareDestPath($pathName), $this->_renderClass($this->_className($pathName)));
	}

	/**
	 * Konwertuje ścieżkę źródłową na docelową. Tworzy katalog pod ścieżką docelową.
	 * @param type $pathName
	 * @return type
	 */
	protected function _prepareDestPath($pathName) {
		$destPathName = str_replace($this->mainPath, $this->installPath, $pathName);
		$dir = pathinfo($destPathName, PATHINFO_DIRNAME);
		if (!file_exists($dir)) {
			mkdir($dir, 0775, true);
		}
		return $destPathName;
	}

	/**
	 * Renderuje ciało klasy do użycia w application
	 * @param type $className
	 * @return type
	 */
	protected function _renderClass($className) {
		$date = date('Y-m-d H:i:s');
		$body = <<<EOF
<?php
/**
 * Generated: {$date}
 * @author Rtn_Module_Tool
 */
class $className extends Main_$className {
\t
}
EOF;
		return $body;
	}

	/**
	 * Zwraca nazwę klasy na podstawie ścieżki
	 * @param type $pathName
	 * @return string
	 */
	protected function _className($pathName) {
		$ph1 = str_replace($this->mainPath . 'classes/', '', $pathName);
		$ph2 = substr_replace($ph1, '', -4);
		$ph3 = str_replace('/', '_', $ph2);
		$ph4 = $this->name . '_' . $ph3;
		return $ph4;
	}

	/**
	 * Kopiuje pliki nie będące klasami
	 */
	public function copyFiles() {
		$dirs_to_copy = array(
			'configs',
			'resources',
			'views'
		);

		foreach ($dirs_to_copy as $source) {
			Rtn_Cli::writeln("Copy dir: $source");
			$this->_copyDir($this->mainPath . $source, $this->installPath.$source);
		}
	}

	public function createDirs() {
		$dirs_to_create = array(
			'classes' => ['Controller'=>null,'Form'=>null,'Jqgrid'=>null,'Model'=>null,'Module'=>['Initer'=>null]],
			'configs' => null,
			'resources' => null,
			'views' => ['helpers'=>null,'scripts'=>null]
		);

		foreach ($dirs_to_create as $dir=>$subdirs) {
			$this->_createDir($this->installPath.$dir,$subdirs);
		}
	}

	/**
	 * Kopiuje katalog
	 * @param type $source
	 * @param type $dest
	 * @param type $excludeSvnFolders
	 * @return boolean
	 * @throws Rtn_Exception_Module
	 */
	protected function _copyDir($source, $dest, $excludeSvnFolders = true) {
		$sourceHandle = opendir($source);

		if (!$sourceHandle) {
			throw new Rtn_Exception_Module(__('Failed to copy directory: failed to open source `:source`', array(':source', $source)));
		}

		while ($file = readdir($sourceHandle)) {
			if ($file == '.' || $file == '..') {
				continue;
			}
			if ($excludeSvnFolders && $file == '.svn') {
				continue;
			}
			if (is_dir($source . '/' . $file)) {
				if (!file_exists($dest . '/' . $file)) {
					mkdir($dest . '/' . $file, 0775, true);
				}
				$this->_copyDir($source . '/' . $file, $dest . '/' . $file, $excludeSvnFolders);
			}
			else {
				if(!file_exists($dest)){
					mkdir($dest, 0775, true);
				}
				copy($source . '/' . $file, $dest . '/' . $file);
			}
		}

		return true;
	}

	protected function _createDir($dir,$subdirs) {
		Rtn_Cli::writeln("Create dir: $dir");
		if (!file_exists($dir)) {
			mkdir($dir, 0775);
			if(is_array($subdirs)){
				foreach($subdirs as $_dir=>$_subdirs){
					$this->_createDir($dir.'/'.$_dir, $_subdirs);
				}
			}
		}

		return true;
	}

	/**
	 * Przogotowuje katalog w którym zainstalowany zostanie moduł
	 * @param type $path
	 * @return boolean
	 */
	public function prepareInstallPath($path) {
		if (!file_exists($path)) {
			mkdir($path, 0775);
			return true;
		}
	}

}
