<?php

class Atmail_Files_Adapter_FileSystem extends Atmail_Files_Adapter_Abstract {
	
	protected $_userData;
	public $_storageDir;
	
	function __construct($account) 
	{
		
		parent::__construct($account);
		// Find the users storageDir
		$this->_userData = users::getAllUserData($account);
		if( $this->_userData['Users']['MailDir'] == '' || $this->_userData['Users']['MailDir'] == null || strlen($this->_userData['Users']['MailDir']) < 3 )
			$this->_storageDir = users::generateMailDir($account, APP_ROOT . "webstorageroot" . DIRECTORY_SEPARATOR);
		else
			$this->_storageDir = rtrim($this->_userData['Users']['MailDir'], '/') . "/webfiles" . DIRECTORY_SEPARATOR;
		
		if($this->_storageDir != '' && !is_dir($this->_storageDir))
			mkdir($this->_storageDir); //TODO: handle errors
			
	}
	
	public function delete($path) 
	{
		
		$fullPath = $this->getFullPath($path);
		if (is_dir($fullPath)) 
		{
			
			// Recursively deleting
			foreach(scandir($fullPath) as $subNode) 
			{
				
				if ($subNode === '.' || $subNode === '..')
					continue;
				$this->delete($path . '/' . $subNode);
				
			}
			@rmdir($fullPath);
		
		}
		else
		{
		
			$this->deleteComment($path);
			@unlink($fullPath);
		
		}
		return 1;
		
	}
	
	public function createDirectory($path) {
		$fullPath = $this->getFullPath($path);
		@mkdir($fullPath);
	}
	
	public function createFile($path, $stream) {
		$content_sizeKB = round($_SERVER['CONTENT_LENGTH']/1024, 0);
		list($currentQuotaKB, $totalQuotaKB) = Atmail_Quota::getTotalQuota(array(Atmail_Quota::TYPE => Atmail_Quota::TYPE_IMAP));
		$newTotalStorageUsedKB = $content_sizeKB+$currentQuotaKB;

		if($totalQuotaKB && $newTotalStorageUsedKB > $totalQuotaKB)
		{
			throw new Atmail_Exception('Upload file exceeds the quota limit and process is canceled! Please check your quota!');
		}

		if (!is_resource($stream)) {
			throw new Atmail_Exception('The stream argument must be a readable file stream');
		}
		
		$fullPath = $this->getFullPath($path);
		@file_put_contents($fullPath, $stream);
	}
	
	
	public function getFile($path) {
	
		$fullPath = $this->getFullPath($path);
		return fopen($fullPath, 'r');
		
	}
	
	public function rename($oldFile, $newFile) {
		
		$fullPath1 = realpath( $this->getFullPath($oldFile) );
		$fullPath2 = $this->getFullPath($newFile);
		
		@rename($fullPath1, $fullPath2);
		
		// Now get the new location on disk
		$fullPath2 = realpath($fullPath2);
		
		// Update any associated comments to the new filename
		$this->updateComment($fullPath1, $fullPath2);
		
		return true;
	}

	public function getFileInfo($path) {
		
	 	$fullPath = $this->getFullPath($path);
		
		if(!is_dir($fullPath) && !is_file($fullPath))
			return;
			
		$result = new Atmail_Files_FileObject();
		$result->path = $path;
					
		$result->size = filesize($fullPath);
		$result->accessed = fileatime($fullPath);
		$result->modified = filemtime($fullPath);
		$result->fileName = basename($path);
		$result->getContentType();
		$result->getIconName();

		if (is_dir($fullPath)) {
			$result->type = self::TYPE_DIR;
		} else {
			$result->type = self::TYPE_FILE;
		}
		
		return $result;
		
	}
	
	public function getFiles($path, $type = self::TYPE_ALL, $recursive = false, $search = false) {
		
		$fullPath = $this->getFullPath($path);

		$result = array();
		foreach(scandir($fullPath) as $fileName) {
		
			if ($fileName === '.' || $fileName === '..')
				continue;
				
			if (is_file($fullPath . '/' . $fileName) && (!($type & self::TYPE_FILE))) {
				continue;
			}
			
			// If a search is specfied, does it match?
			if(!empty($search) && !preg_match("/" . $search . "/i", $fileName)) {
				continue;				
			}

            $newResult = null;

			if (!(is_dir($fullPath . '/' . $fileName) && (!($type & self::TYPE_DIR)))) {
				$newResult = $this->getFileInfo($path . '/' . $fileName);
			}
			
			if ($recursive && is_dir($fullPath . '/' . $fileName)) {
				if(!($type & self::TYPE_DIR))
				{
					$newFiles = $this->getFiles($path . '/' . $fileName, $type, $recursive, $search);
					
					$result = array_merge($result, $newFiles);
				}
				else
				{
					$newResult->children = $this->getFiles($path . '/' . $fileName, $type, $recursive, $search);
				}
			}
			if($newResult != null)
			{
				$result[]=$newResult;
				$newResult = null;
			}
		}
		
		return $result;
		
	}
	
	public function getFullPath($path) 
	{

		
		$path = trim($path, DIRECTORY_SEPARATOR);
		// TODO: security check here to see if users are not escaping the storageDir
		if(file_exists(rtrim($this->_storageDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $path))
			$newDir = realpath(rtrim($this->_storageDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $path);
		else 
			$newDir = rtrim($this->_storageDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $path;
		
		foreach(explode('/', $path) as $part) 
		{

			if ($part === '.' || $part === '..') 
				throw new Atmail_Exception('Security violation');

		}

		// todo : add 'chroot' style support
		// restrict to users directory only.
		// todo : audit all function leverage getFullPath.

		return $newDir;
		
	}
	
}