<?php
class Ftp_PostController extends Library_Controller {
	public function __call($methodName, $args) {
		//nastaveni vychozich dat
		$objectInfo = $this->_parseActionName($methodName);
		
		//kontrola, jeslti byl odeslan objekt s nastavenim
		if (!isset($_REQUEST["ftp"])) {
			//preskoci se na vypis
			$this->_list($objectInfo);
			return;
		}
		
		//kontorla dat a povoleni k pritupu
		$response = new Library_Response();
		$tableProjects = new Application_Model_Projects();
		$useLabel = false;
		$useZip = false;
		
		try {
			//kontorla odeslanych dat
			$data = $_REQUEST["ftp"];
			
			if (!isset($data["host"], $data["username"], $data["password"], $data["remote_path"])) {
				$response->setStatus("DATA_NOT_COMPLETE", 400);
				throw new Zend_Exception("Data sent to server is not complete");
			}
			
			//nacteni projektu
			$project = $tableProjects->find($objectInfo["id"])->current();
			
			if (!$project) {
				//projekt nebyl nalezen
				$response->setStatus("PROJECT_NOT_FOUND", 404);
				throw new Zend_Exception("Project id " . $objectInfo["id"] . " not found");
			}
			
			//kontrola jestli je uzivatel opravnen zobrazit data
			if ($project->user_id != $this->_user->id && $this->_user->id != 1 && !in_array("PROJECT_MANAGER", $this->_user->getRoles())) {
				//zkontroluji se spolupracovnici
				$colabours = $project->findDependentRowset("Application_Model_ProjectsColabours", "project");
				$found = false;
				
				while ($colabour = $colabours->current() && !$found) {
					$found = $colabour->user_id == $this->_user->id;
					$colabours->next();
				}
				
				if (!$found) {
					//uzivatel nebyl nalezen, neni tedy opravnen
					$response->setStatus("NOT_PERMITED", 403);
					throw new Zend_Exception("User id " . $this->_user->id . " is not permited to browse FTP upload logs of project id " . $project->directory_id);
				}
			}
			
			//kontorla jeslti se ma pouzit label
			if (isset($data["use_label"])) {
				if ($data["use_label"]) {
					//pozadavek na pouziti labelu existuje, zkotrnoluje se existence
					$tableLabels = new Application_Model_ProjectsLabels();
					
					$label = $tableLabels->fetchRow(array("directory_id = " . $project->directory_id
						, "id = " . $tableLabels->getAdapter()->quote($data["label_id"])));
					
					if (!$label) {
						//obraz projektu neexistuje
						$response->setStatus("LABEL_NOT_FOUND", 404);
						throw new Zend_Exception("Label id " . $data["label_id"] . " not found in project id " . $project->id);
					}
					
					$useLabel = true;
				}
			}
			
			//konotrla zip komprese
			if (isset($data["use_zip"])) {
				if ($data["use_zip"]) {
					//pozadavek na zip kompresi existuje, zkotrnoluje se DocumentRoot
					if (!isset($data["document_root"], $data["install_path"], $data["target_server"])) {
						$response->setStatus("DOCUMENT_ROOT_NOT_SENT", 400);
						throw new Zend_Exception("Document root not sent");
					}
				
					$useZip = true;
				}
			}
			
			//pripojeni k FTP serveru
			$ftp = ftp_connect($data["host"]);
			
			if (!$ftp) {
				//pripojeni se nezdarilo
				$response->setStatus("FTP_CONNECT_ERROR", 400);
				throw new Zend_Exception("Can't connect to FTP server " . $data["host"]);
			}
			
			if (!ftp_login($ftp, $data["username"], $data["password"])) {
				//autentizace selhala
				$response->setStatus("FTP_AUTH_FAILED", 403);
				throw new Zend_Exception("Authentization on FTP server " . $data["host"] . " failed");
			}
			
			//vnoreni se do vychoziho adredare
			if (!ftp_chdir($ftp, $data["remote_path"])) {
				//nepodarilo se zanorit do slozky
				$response->setStatus("REMOTE_PATH_ERROR", 400);
				throw new Zend_Exception("Error in remote path directory");
			}
		} catch (Zend_Exception $e) {
			$this->_sendToRender($response, $objectInfo["format"], "post");
			return;
		}
		
		//vyhodnoceni typu pozadavku
		if (!$useLabel && !$useZip) {
			//odeslani normalnim zpusobem
			$directory = $project->findParentRow("Application_Model_DocumentsDirectories", "directory");
			$root = new Library_Virtual_Directory($directory);
			$root->loadChildrens();
			
			$this->_uploadNormal($ftp, $root);
		} elseif ($useLabel) {
			//byl vybran obraz
			
			//nacteni a ulozeni dat na lokalni disk
			$content = $label->findDependentRowset("Application_Model_ProjectsLabelsContents", "label")->current();
			
			$zipPath = tempnam(APPLICATION_PATH . "/../tmp/ftp/", "label_");
			file_put_contents($zipPath, $content->content);
			
			//konotrla jeslti se ma pouzit ZIP upload
			if ($useZip) {
				$this->_uploadZip($ftp, $zipPath, $data["document_root"], $data["install_path"], $data["target_server"]);
			} else {
				//vytvoreni adredare pro extrakci ZIP souboru a extrakce
				mkdir($zipPath . "_dir");
				
				$zip = new ZipArchive();
				$zip->open($zipPath);
				
				$zip->extractTo($zipPath . "_dir");
				
				//zjisteni jmena korenoveho adresare a provede se upload na server
				$directory = $project->findParentRow("Application_Model_DocumentsDirectories", "directory");
				
				$this->_uploadFromFileSystem($ftp, $zipPath . "_dir/" . $directory->directory_name);
				
				//odstraneni docasneho adresare
				$this->_removeDir($zipPath . "_dir");
			}
			
			unlink($zipPath);
		} elseif($useZip) {
			//pozadavek na ulozeni aktualni verze za pomoci komprimace
			$directory = $project->findParentRow("Application_Model_DocumentsDirectories", "directory");
			$root = new Library_Virtual_Directory($directory);
			$root->loadChildrens();
			
			//priprava zip
			$zipPath = tempnam(APPLICATION_PATH . "/../tmp/ftp/", "label_");
			$zip = new ZipArchive();
			$zip->open($zipPath);
			
			//vytvoreni zip archivu
			$this->_writeDocuments($root, $zip);
			$zip->close();
			
			//odeslani na server
			$this->_uploadZip($ftp, $zipPath, $data["document_root"], $data["install_path"], $data["target_server"]);
			
			unlink($zipPath);
		}
		
		//zapis do logu
		$tableLogs = new Application_Model_FtpLogs();
		$row = $tableLogs->createRow();
		
		$row->user_id = $this->_user->id;
		$row->project_id = $project->directory_id;
		$row->is_success = 1;
		$row->params = Zend_Json::encode($data);
		
		if ($useLabel) {
			$row->label_id = $label->id;
		}
		
		$row->save();
		
		//zapsani odpovedi
		$response->setOk();
		$this->view->project_id = $project->directory_id;
		
		$this->_sendToRender($response, $objectInfo["format"], "post");
	}
	
	protected function _list($objectInfo) {
		//kontrla dat
		$response = new Library_Response();
		$tableProjects = new Application_Model_Projects();
		
		try {
			//nacteni projektu
			$project = $tableProjects->find($objectInfo["id"])->current();
			
			if (!$project) {
				//projekt nebyl nalezen
				$response->setStatus("PROJECT_NOT_FOUND", 404);
				throw new Zend_Exception("Project id " . $objectInfo["id"] . " not found");
			}
			
			//kontrola jestli je uzivatel opravnen zobrazit data
			if ($project->user_id != $this->_user->id && $this->_user->id != 1 && !in_array("PROJECT_MANAGER", $this->_user->getRoles())) {
				//zkontroluji se spolupracovnici
				$colabours = $project->findDependentRowset("Application_Model_ProjectsColabours", "project");
				$found = false;
				
				while ($colabour = $colabours->current() && !$found) {
					$found = $colabour->user_id == $this->_user->id;
					$colabours->next();
				}
				
				if (!$found) {
					//uzivatel nebyl nalezen, neni tedy opravnen
					$response->setStatus("NOT_PERMITED", 403);
					throw new Zend_Exception("User id " . $this->_user->id . " is not permited to browse FTP upload logs of project id " . $project->directory_id);
				}
			}
		} catch (Zend_Exception $e) {
			$this->_sendToRender($response, $objectInfo["format"], "list");
			return;
		}
		
		//nacteni logu
		$logs = $project->findDependentRowset("Application_Model_FtpLogs", "project");
		
		$response["log"] = $logs;
		$response->setOk();
		
		$this->view->project = $project;
		
		$this->_sendToRender($response, $objectInfo["format"], "list");
	}
	
	/**
	 * uploaduje soubory na FTP server pojednom z vertualniho adresare
	 * @param resource $ftp zdroj pripojeni k FTP serveru
	 * @param Library_Virtual_Directory $directory korenovy adredar projektu
	 */
	protected function _uploadNormal($ftp, Library_Virtual_Directory $directory) {
		$directory->sendToFtp($ftp);
	}
	
	/**
	 * odeslen soubory na FTP server pojednom z fyzickeho adresare
	 * @param resource $ftp zdroj pripojeni k FTP serveru
	 * @param string $path cesta k vychozimu adredari
	 */
	protected function _uploadFromFileSystem($ftp, $path) {
		//nacteni a naparsovani vypisu objektu na strane serveru
		$rawList = ftp_rawlist($ftp, ".");
		$nList = ftp_nlist($ftp, ".");
		
		//priprava seznamu souboru a adredaru
		$dirList = array();
		$fileList = array();
		
		$maxI = count($rawList);
		
		for ($i = 0; $i < $maxI; $i++) {
			//kontorla jeslti je objekt adresarem nebo souborem
			if ($rawList[$i][0] == "d") {
				//objekt je adredarem
				$dirList[] = $nList[$i];
			} else {
				//objekt je souborem
				$fileList[$i] = $nList[$i];
			}
		}
		
		//nacteni a vyhodnoceni objketu na lokalnim systemu
		$dir = dir($path);
		
		if (!$dir) {
			return false;
		}
		
		$localDirs = array();
		$localFiles = array();
		
		while ($name = $dir->read()) {
			//preskoceni . a ..
			if ($name == "." || $name == "..") {
				continue;
			}
			
			//vyhodnoceni typu
			if (is_file($path . "/" . $name)) {
				$localFiles[] = $name;
			} else {
				$localDirs[] = $name;
			}
		}
		
		//zapsani dokumentu
		/* @var $document Library_Virtual_Document */
		foreach ($localFiles as $name) {
			//odeslani souboru na server
			ftp_put($ftp, $name, $path . "/" . $name, FTP_BINARY);
		}
		
		//konotrla existence potrebnych adredaru
		/* @var $directory Library_Virtual_Directory */
		foreach ($localDirs as $name) {
			//konotrla jestli adredar existuje
			if (!in_array($name, $dirList)) {
				//adresar neexistuje, musi se vytvorit
				ftp_mkdir($ftp, $name);
			}
			
			//vstup do adresare na FTP a ulozeni lokalniho adresare
			ftp_chdir($ftp, $name);
			
			$this->_uploadFromFileSystem($ftp, $path . "/" . $name);
			
			//vystup z adresare
			ftp_chdir($ftp, "..");
		}
	}
	
	protected function _uploadZip($ftp, $zipPath, $documentRoot, $installPath, $domain) {
		$documentRoot = trim($documentRoot, "/");
		$domain = trim($domain, "/");
		
		if ($documentRoot) {
			$documentRoot . "/";
		}
		
		//odeslani ZIP archivu 
		ftp_put($ftp, $documentRoot . "projectComprimed.zip", $zipPath, FTP_BINARY);
		ftp_chmod($ftp, 0666, $documentRoot . "projectComprimed.zip");
		
		//odeslani instalacniho skriptu
		ftp_put($ftp, $documentRoot . "projectComprimed.php", APPLICATION_PATH . "/objects/ftp/install.php", FTP_ASCII);
		ftp_chmod($ftp, 0666, $documentRoot . "projectComprimed.php");
		
		//spusteni instalacniho skruptu
		$fp = fopen($domain . "/projectComprimed.php?install_path=" . urldecode($installPath), "r");
	}
	
	/**
	 * rekurzivne smaze adresar z fyzickeho disku
	 * @param string $path cesta k adredari
	 */
	protected function _removeDir($path) {
		//vytvoreni instance adredare
		$dir = dir($path);
		
		while ($filename = $dir->read()) {
			//konotrla . a ..
			if ($filename == "." || $filename == "..") {
				continue;
			}
			
			//kontrola typu objektu
			if (is_file($path . "/" . $filename)) {
				//objekt je soubor
				unlink($path . "/" . $filename);
			} else {
				$this->_removeDir($path . "/" . $filename);
			}
		}
		
		rmdir($path);
	}
	
	/**
	 * zabali aktualni stav projektu do ZIP archivu a vraci cestu k tomuto archivu
	 * @param Library_Virtual_Directory $directory vychozi adresar
	 * @return string
	 */
	protected function _createArchive(Zend_Db_Table_Row_Abstract $directory) {
		//nacteni struktury
		$root = new Library_Virtual_Directory($directory);
		$root->loadChildrens();
		
		//vytvoreni zip archivu
		$zipName = tempnam(APPLICATION_PATH . "/../tmp/project/", "project_");
		
		$zip = new ZipArchive();
		$zip->open($zipName, ZipArchive::CREATE);
		
		//prochazeni struktury a zapis dokumentu
		$hashList = array();
		$this->_writeDocuments($root, $zip, $hashList);
		
		//vytvoreni a zapsani indexu souboru
		$index = array();
		
		foreach ($hashList as $path => $uuid) {
			$index[] = "$path $uuid";
		}
		
		//vygenerovani timestampu
		$timestamp = new Zend_Date();
		
		//vegenerovani formatu
		$format = Zend_Date::YEAR . "-" . Zend_Date::MONTH . "-" . Zend_Date::DAY . " " . Zend_Date::HOUR . ":" . Zend_Date::DAY . ":" . Zend_Date::SECOND;
		
		//zapsani do zipu
		$zip->addFromString(".project-" . $project->directory_id, $timestamp->get($format) . "\n" . implode("\n", $index));
		
		$zip->close();
		
		return $zipName;
	}
	
	/**
	 * zapise dokumenty do ZIP archivu
	 * @param Library_Virtual_Directory $directory reprezentace virtualniho adredare v pameti
	 * @param ZipArchive $zip objekt ZIPu
	 */
	protected function _writeDocuments(Library_Virtual_Directory $directory, ZipArchive $zip) {
		//vytvoreni adredare
		$zip->addEmptyDir($directory->getPath());
		
		//vytvoreni podadredsaru
		$directories = $directory->getDirs();
		
		foreach ($directories as $dir) {
			$this->_writeDocuments($dir, $zip);
		}
		
		//zapsani dokumentu
		$documents = $directory->getDocuments();
		
		foreach ($documents as $document) {
			$document->addToArchive($zip);
		}
	}
}