<?php
class pjApp
{
	protected $config = array();
	
	public function __construct($config=array())
	{
		$this->setConfig($config);
	}
	
	protected function load()
	{
		if (!pjUtil::isXHR())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing HTTP headers.'));
		}
		
		if (!pjUtil::isGet())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Invalid request.'));
		}
		
		$filter = NULL;
		if (isset($_GET['q']) && !empty($_GET['q']))
		{
			$filter = $_GET['q'];
		}
		
		$thumbs_data = array();
		pjUtil::readDir($thumbs_data, $this->config['fu_relative_path'].$this->config['fu_thumbs_folder'], $filter);
		
		$source_data = array();
		pjUtil::readDir($source_data, $this->config['fu_relative_path'].$this->config['fu_source_folder'], $filter);
		
		header("X-FileUploader-Cnt: " . count($source_data));
		
		$this->render('load_files', array(
			'config' => $this->config,
			'thumbs_data' => $thumbs_data,
			'source_data' => $source_data,
		));
	}
	
	protected function delete()
	{
		if (!pjUtil::isXHR())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing HTTP headers.'));
		}
		
		if (!pjUtil::isPost())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Invalid request.'));
		}
		
		if (!$this->config['fu_allow_delete'])
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Operation is not allowed.'));
		}
		
		if (!(isset($_POST['name']) && !empty($_POST['name'])))
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 104, 'text' => 'Missing, empty or invalid form data.'));
		}
		
		$name = basename($_POST['name']);
		
		$files = array(
			$this->config['fu_source_path'] . $name,
			$this->config['fu_thumbs_path'] . $name,
		);
		
		$i = 0;
		foreach ($files as $filename)
		{
			if (!is_file($filename))
			{
				continue;
			}
			
			if (@unlink($filename))
			{
				$i += 1;
			}
		}
		
		if (!$i)
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 150, 'text' => 'Missing, empty or invalid form data.'));
		}
		
		pjUtil::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'File has been deleted.'));
	}
	
	protected function truncate()
	{
		if (!pjUtil::isXHR())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing HTTP headers.'));
		}
		
		if (!pjUtil::isPost())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Invalid request.'));
		}
		
		if (!$this->config['fu_allow_truncate'])
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Operation is not allowed.'));
		}
		
		$source_data = array();
		pjUtil::readDir($source_data, $this->config['fu_source_path']);
		$source_data = array_values($source_data);
		
		$thumbs_data = array();
		pjUtil::readDir($thumbs_data, $this->config['fu_thumbs_path']);
		$thumbs_data = array_values($thumbs_data);
		
		$files = array_merge($source_data, $thumbs_data);
		$i = 0;
		foreach ($files as $filename)
		{
			if (!is_file($filename))
			{
				continue;
			}
			
			if (@unlink($filename))
			{
				$i += 1;
			}
		}
		
		if (!$i)
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 104, 'text' => 'No file deleted.'));
		}
		
		pjUtil::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'All files has been deleted.'));
	}
	
	protected function download()
	{
		if (!pjUtil::isPost())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Invalid request.'));
		}
		
		if (!$this->config['fu_allow_download'])
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'Operation is not allowed.'));
		}
		
		if (!(isset($_POST['name']) && !empty($_POST['name'])))
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Missing, empty or invalid form data.'));
		}
		
		$filename = $this->config['fu_source_path'] . basename($_POST['name']);
		
		if (!is_file($filename))
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'File not found.'));
		}
		
		$mimetype = pjUtil::getMimeType($filename);
		
		pjUtil::chunckedDownload($filename, $mimetype);
	}
	
	protected function upload()
	{
		if (!pjUtil::isXHR())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing HTTP headers.'));
		}
		
		if (!$this->config['fu_allow_upload'])
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'Operation is not allowed.'));
		}
		
		if (pjUtil::isGet())
		{
			$this->render('upload', array(
				'config' => $this->config,
				'have_allowed' => $this->getAllowedTypes() || $this->getAllowedExt() ? 1 : 0,
			));
			return;
		}
		
		if (!pjUtil::isPost())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Invalid request.'));
		}
		
		if (!(isset($_FILES['userfile']) && !empty($_FILES['userfile'])))
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Missing, empty or invalid form data.'));
		}
		
		$files = array();
		if ($this->config['fu_multiple_upload'] && !pjUtil::isSafari())
		{
			foreach (array_keys($_FILES['userfile']['tmp_name']) as $i)
			{
				$files[] = array(
					'tmp_name' => $_FILES['userfile']['tmp_name'][$i],
					'name' => $_FILES['userfile']['name'][$i],
					'type' => $_FILES['userfile']['type'][$i],
					'error' => $_FILES['userfile']['error'][$i],
					'size' => $_FILES['userfile']['size'][$i],
				);
			}
		} else {
			$files[] = $_FILES['userfile'];
		}
		
		$allowedTypes = $this->getAllowedTypes();
		$allowedExt = $this->getAllowedExt();
		
		if (!$allowedTypes && !$allowedExt)
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 160, 'text' => 'No files allowed to upload.'));
		}
		
		foreach ($files as $i => $userfile)
		{
			# Upload
			$mimetype = pjUtil::getMimeType($userfile['tmp_name']);
			$is_image = $mimetype !== false && stripos($mimetype, 'image/') === 0;
			
			if ($is_image)
			{
				$upload = new pjImage();
			} else {
				$upload = new pjUpload();
			}
			
			if ($allowedTypes)
			{
				$upload->setAllowedTypes($allowedTypes);
			}
			if ($allowedExt)
			{
				$upload->setAllowedExt($allowedExt);
			}
			
			if (!$upload->load($userfile))
			{
				pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 161, 'text' => $upload->getError()));
			}
			
			$basename = basename(urldecode($userfile['name']));
			
			$source_filename = $this->name($this->config['fu_source_path'] . $basename);
			if (!$upload->save($source_filename))
			{
				pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 162, 'text' => $upload->getError()));
			}
			
			if ($is_image)
			{
				# Create thumb
				$thumb_filename = $this->name($this->config['fu_thumbs_path'] . $basename);
				
				$upload->loadImage($source_filename);
				$upload->thumbnail($this->config['fu_thumbs_width'], $this->config['fu_thumbs_height']);
				$upload->saveImage($thumb_filename);
				$upload->unloadImage();
			}
		}
		
		pjUtil::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'File has been uploaded.'));
	}
	
	protected function rename()
	{
		if (!pjUtil::isXHR())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 100, 'text' => 'Missing HTTP headers.'));
		}
		
		if (!pjUtil::isPost())
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 101, 'text' => 'Invalid request.'));
		}
		
		if (!$this->config['fu_allow_rename'])
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 102, 'text' => 'Operation is not allowed.'));
		}
		
		if (!(isset($_POST['from'], $_POST['to']) && !empty($_POST['from']) && !empty($_POST['to'])))
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 103, 'text' => 'Missing, empty or invalid form data.'));
		}
		
		if ($_POST['from'] == $_POST['to'])
		{
			pjUtil::jsonResponse(array('status' => 'OK', 'code' => 201, 'text' => 'File has been renamed.'));
		}

		$paths = array(
			$this->config['fu_source_path'],
			$this->config['fu_thumbs_path'],
		);
		
		$i = 0;
		foreach ($paths as $path)
		{
			$oldname = $path . basename(urldecode($_POST['from']));
			if (!is_file($oldname))
			{
				continue;
			}
			
			$newname = $path . basename(urldecode($_POST['to']));
			if (is_file($newname))
			{
				pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 104, 'text' => 'File name already exist.'));
			}
			
			if (rename($oldname, $newname))
			{
				$i++;
			}
		}
		
		if (!$i)
		{
			pjUtil::jsonResponse(array('status' => 'ERR', 'code' => 105, 'text' => 'File has not been renamed.'));
		}
		
		pjUtil::jsonResponse(array('status' => 'OK', 'code' => 200, 'text' => 'File has been renamed.'));
	}
	
	protected function name($filename, $i = 0)
	{
		if (!is_file($filename))
		{
			return $filename;
		}
		
		$name = basename($filename);
		$path = substr($filename, 0, strrpos($filename, '/'));
		
		$ext = pjUtil::getFileExtension($name);
		$name_only = substr($name, 0, -(strlen($ext) + 1));
		
		$i++;
		
		if (preg_match('/\(\d+\)$/', $name_only))
		{
			$name_only = preg_replace('/\(\d+\)$/', "($i)", $name_only);
		} else {
			$name_only = sprintf("%s (%u)", $name_only, $i);
		}
		
		$new_name = sprintf("%s/%s.%s", $path, $name_only, $ext);
		
		return $this->name($new_name, $i);
	}
	
	protected function index()
	{
		$is_safari = pjUtil::isSafari() ? 1 : 0;
		
		$this->render('index', array(
			'config' => $this->config,
			'is_safari' => $is_safari,
			'have_allowed' => $this->getAllowedTypes() || $this->getAllowedExt() ? 1 : 0,
		));
	}
	
	protected function render($view, $vars=array())
	{
		$filename = sprintf("%s/../views/%s.php", dirname(__FILE__), $view);
		if (is_file($filename))
		{
			if (is_array($vars) && $vars)
			{
				extract($vars);
			}
			
			include $filename;
		}
	}
	
	protected function getAllowedTypes()
	{
		$allowedTypes = array();
		if (is_array($this->config['fu_accept_files']) && !empty($this->config['fu_accept_files']))
		{
			foreach ($this->config['fu_accept_files'] as $accept)
			{
				if (strpos($accept, '/') !== false)
				{
					$allowedTypes[] = strtolower($accept);
				}
			}
		}
		
		return $allowedTypes;
	}
	
	protected function getAllowedExt()
	{
		$allowedExt = array();
		if (is_array($this->config['fu_accept_files']) && !empty($this->config['fu_accept_files']))
		{
			foreach ($this->config['fu_accept_files'] as $accept)
			{
				if (strpos($accept, '.') === 0)
				{
					$allowedExt[] = strtolower(substr($accept, 1));
				}
			}
		}
		
		return $allowedExt;
	}
	
	public function run()
	{
		if (isset($_GET['action']) && !empty($_GET['action']))
		{
			switch ($_GET['action'])
			{
				case 'load':
					$this->load();
					break;
				case 'delete':
					$this->delete();
					break;
				case 'download':
					$this->download();
					break;
				case 'rename':
					$this->rename();
					break;
				case 'truncate':
					$this->truncate();
					break;
				case 'upload':
					$this->upload();
					break;
				default:
					header('HTTP/1.1 404 Not Found');
			}
		} else {
			$this->index();
		}
	}

	public function getConfig()
	{
		return $this->config;
	}
	
	public function setConfig($config)
	{
		if (is_array($config))
		{
			$this->config = $config;
		}
		
		return $this;
	}
}