<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package clearFusionCMS\module\property
 * @copyright Copyright (c) 2016 - 2017 clearFusionCMS. All rights reserved.
 * @link http://clearfusioncms.com
 */

/**
 * propertyBackendGalleryAction Class
 *
 * Backend controller action for managing property gallery.
 *
 * @package clearFusionCMS\module\property
 */
class propertyBackendGalleryAction extends cfBackendControllerAction {

	/**
	 * Property ID
	 *
	 * @var int
	 */
	protected $propID;

	/**
	 * The name of the property being edited.
	 *
	 * @var string
	 */
	protected $propName;

	/**
	 * Render the gallery tree.
	 *
	 * @param int $id ID of the current image.
	 * @return flWidgetTreeView The built tree.
	 * @throws flDbException
	 */
	protected function renderTree($id) {
		$rootTree = new flWidgetTreeView('cfProperty.property.gallery');

		// Build tree
		$tree = new flWidgetTreeView();
		$results = $this->db->query('SELECT galid,title,imgtype FROM cf_property_gal_' . clearFusionCMS::getSite() . ' WHERE propertyid=? ORDER BY disporder ASC', $this->propID);
		while($row = $results->fetch()) {
			$tree->addNode(new flWidgetTreeLinkNode(($row['imgtype'] == 'floorplan' ? __('(Floorplan) ', 'propertyBackend') : ($row['imgtype'] == 'epc' ? __('(EPC) ', 'propertyBackend') : '')) . $row['title'] . ' [' . $row['galid'] . ']', $this->assemble('property', 'gallery', array($this->propID, 'edit', $row['galid'])), flWidgetTreeNode::NODE, $row['galid']))
				->setLastNodeActive($id == $row['galid']);
		}

		$rootTree->addNode($results->numRows() ? new flWidgetTreeChildNode(__('Property Images', 'propertyBackend'), $tree, null) : new flWidgetTreeNode(__('Property Images', 'propertyBackend'), flWidgetTreeNode::CONTAINER))
			->setAJAXMoveHandler($this->assemble('property', 'gallery', array($this->propID, 'dragdrop', $id ? $id : 0)));

		return $rootTree;
	}

	/**
	 * Render the page.
	 *
	 * @param string $id The current item.
	 * @param string $content The page content.
	 */
	function renderAdminPage($id, $content) {
		$rootTree = $this->renderTree($id);

		// Create the toolbar
		$fam = new flWidgetFloatingActionMenu();
		$fam->setCSS('[[+css]]');

		$fam->addAction('add', __('Add Image', 'propertyBackend'), $this->assemble('property', 'gallery', array($this->propID, 'add')));

		$this->tpl->registerChunk('fam', $fam->render());

		// Render the page
		$this->renderPage(__('Property Images', 'propertyBackend'), $content, $this->renderBlock('', $rootTree->render($this->tpl->getCodeBuffer())));
	}

	/**
	 * Add common parts to the breadcrumb trail.
	 */
	function addBreadcrumbs() {
		$this->breadcrumbTrail->addCrumb(__('Property', 'propertyBackend'), $this->assemble('property', 'properties'));
		$this->propName = $this->db->fetchOne('SELECT title FROM cf_property_' . clearFusionCMS::getSite() . ' WHERE propertyid=?', $this->propID);
		$this->breadcrumbTrail->addCrumb($this->propName, $this->assemble('property', 'edit', array($this->propID)));
		$this->breadcrumbTrail->addCrumb(__('Gallery', 'propertyBackend'), $this->assemble('property', 'gallery', array($this->propID)));
	}

	/**
	 * Process the request
	 */
	function process() {
		$this->testPermission('cfProperty.properties');

		$currid = '';
		$content = '';
		$msg = $this->session->flashGet('cfManagerOpSuccess', '');

		// Build routes
		$homeRoute = new flRouterRoute(':propID', array(), array('propID' => '\d+'));
		$addRoute = new flRouterRoute(':propID/add', array(), array('propID' => '\d+'));
		$editRoute = new flRouterRoute(':propID/edit/:id', array(), array('propID' => '\d+', 'id' => '\d+'));
		$deleteRoute = new flRouterRoute(':propID/delete/:id', array(), array('propID' => '\d+', 'id' => '\d+'));
		$dropRoute = new flRouterRoute(':propID/dragdrop/:id', array(), array('propID' => '\d+', 'id' => '\d+'));

		// If home
		if($params = $homeRoute->match($this->request->getParam('*', array()))) {
			$this->propID = $params['propID'];
			$this->addBreadcrumbs();
			if(($content = $this->lockObject('property', $params['propID'])) === true)
				$content = '';
		}
		// If drag n drop
		else if($params = $dropRoute->match($this->request->getParam('*', array()))) {
			$this->propID = $params['propID'];

			$result = array(
				'success' => true,
				'msg' => '',
				'dismiss' => __('Dismiss', 'cfBackend'),
				'tree' => ''
			);

			$position = $this->request->getPost('position', '');
			$moving = $this->request->getPost('moving', '');
			$target = $this->request->getPost('target', '');

			if(!preg_match('/^-?[01]$/', $position) || !preg_match('/^\d+$/', $moving) || !preg_match('/^\d+$/', $target)) {
				$result['success'] = false;
				$result['msg'] = __('Internal failure, please try again.', 'cfBackend');
			}

			if($result['success']) {

				$moveNode = $this->db->fetchOne('SELECT disporder FROM cf_property_gal_' . clearFusionCMS::getSite() . ' WHERE propertyid=? && galid=?', $this->propID, $moving);
				$targetNode = $this->db->fetchOne('SELECT disporder FROM cf_property_gal_' . clearFusionCMS::getSite() . ' WHERE propertyid=? && galid=?', $this->propID, $target);

				// Move before
				if($position == -1) {
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=disporder+1 WHERE propertyid=? && disporder>=?', $this->propID, $targetNode);
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=? WHERE galid=?', $targetNode, $moving);
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=disporder-1 WHERE propertyid=? && disporder>?', $this->propID, $moveNode);
				}
				// After
				else {
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=disporder+1 WHERE propertyid=? && disporder>?', $this->propID, $targetNode);
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=? WHERE galid=?', $targetNode + 1, $moving);
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=disporder-1 WHERE propertyid=? && disporder>?', $this->propID, $moveNode);
				}

				$result['msg'] = __('The gallery display order has been updated.', 'storeBackend');
				$this->cache->flush();
			}

			// Rebuild the tree
			$rootTree = $this->renderTree($params['id']);
			$result['tree'] = $rootTree->render(null, true);

			// Send AJAX response
			$this->response->setContentType('application/json')
				->noCache()
				->setBody(json_encode($result))
				->sendResponse();
			die;
		}
		// If adding
		else if($params = $addRoute->match($this->request->getParam('*', array()))) {
			$this->propID = $params['propID'];
			$this->addBreadcrumbs();

			if(($content = $this->lockObject('property', $params['propID'])) === true) {
				$form = new flForm($this->request, 'addimageform', $this->assemble('property', 'gallery', array($this->propID, 'add')), true);
				$form->setCSS('metaSSubmit');

				$title = new flFormElementText($form, 'title');
				$title->setLabel(__('Image Title', 'propertyBackend'))
					->setRequired()
					->addValidator(new flFormValidatorRequired())
					->addValidator(new flFormValidatorMaxLength(255));

				$imgFile = new flFormElementFile($form, 'image');
				$imgFile->setLabel(__('Image', 'propertyBackend'))
					->setCSS('primary')
					->setRequired();

				$imgURI = new flFormElementUri($form, 'imguri');
				$imgURI->setLabel(__('Or Location to Download Image From', 'propertyBackend'));

				$imgtype = new flFormElementSelect($form, 'imgtype', null, array(
					'normal' => __('Property Image', 'propertyBackend'),
					'floorplan' => __('Floorplan Image', 'propertyBackend'),
					'epc' => __('EPC Image', 'propertyBackend')
				));
				$imgtype->setLabel(__('Use As:', 'propertyBackend'));

				$submit = new flFormElementSubmit($form, 'addimg');
				$submit->setCaption(__('Add Image', 'propertyBackend'))->setCSS('primary');

				$form->groupElements('leftcolimg', array($title, $imgtype))
					->groupElements('rightcolimg', array($imgFile, $imgURI))
					->groupElements('submit', array($submit), new flFormDecoratorList(new flFormDecoratorDl()));

				$form->focusElement($title);

				// Capture ctrl+s for save, implement select all/none, check user really wants to leave page
				$this->tpl->getCodeBuffer()->bufferHeadJS('system/app/js/cfMetaS.js');
				$this->confirmLeavePage();

				if($form->isSubmitted() && $form->isValid()) {
					$fileCfg = clearFusionCMS::getSiteConfig('cfSystemFileStore');

					// If upload file given
					$ext = '';
					if($imgFile->fileUploaded()) {
						try {
							$img = new flImage($imgFile->getTmpFileName());
							switch($img->getType()) {
								case IMAGETYPE_GIF: $ext = '.gif'; break;
								case IMAGETYPE_JPEG: $ext = '.jpg'; break;
								case IMAGETYPE_PNG: $ext = '.png'; break;
							}
						} catch(flException $e) { }
					}
					// Else if download file give
					else if($imgURI->getValue() != '') {

						// Get the image from a remote source
						$http = new flHttpClient($imgURI->getValue());
						if($http->sendRequest() && $http->getResponseCode() == 200) {
							// Save the file data
							$tmpFile = tempnam($fileCfg->privateStorage, 'store');
							@file_put_contents($tmpFile, $http->getBody());
							unset($http); // Release the object & memory

							try {
								$img = new flImage($tmpFile);
								switch($img->getType()) {
									case IMAGETYPE_GIF: $ext = '.gif'; break;
									case IMAGETYPE_JPEG: $ext = '.jpg'; break;
									case IMAGETYPE_PNG: $ext = '.png'; break;
								}
							} catch(flException $e) {
								@unlink($tmpFile);
							}
						}
					}

					// Create
					if(!empty($ext) && $this->db->insert('cf_property_gal_' . clearFusionCMS::getSite(), array(
						'propertyid' => $this->propID,
						'title' => $title->getValue(),
						'fileext' => $ext,
						'disporder' => $this->db->fetchOne('SELECT MAX(disporder) FROM cf_property_gal_' . clearFusionCMS::getSite() . ' WHERE propertyid=?', $this->propID) + 1,
						'imgtype' => $imgtype->getValue()
					))) {
						$currid = $this->db->insertID();
						propertyAudit::createGallery($currid, $this->propName, $title->getValue());

						// If upload file given
						if($imgFile->fileUploaded())
							$imgFile->moveTo($fileCfg->privateStorage . $this->getFilename($currid, $ext));
						// Else download file
						else
							rename($tmpFile, $fileCfg->privateStorage . $this->getFilename($currid, $ext));

						$this->cache->flush();
						$this->session->flashSet('cfManagerOpSuccess', $this->alertMessage('Success', __('The new image has been added.', 'propertyBackend')));
						$this->response->redirectTo($this->assemble('property', 'gallery', array($this->propID, 'edit', $currid), true));
					}
					else {
						if(isset($tmpFile))
							@unlink($tmpFile);
						$msg = $this->alertMessage('Error', __('Unable to create the new image, please make sure that you are using a PNG, GIF or JPEG file for the image and try again.', 'propertyBackend'));
					}
				}

				$content = $this->renderBlock(__('Add Image', 'propertyBackend'), $form->render($this->tpl->getCodeBuffer()), '', $msg);
			}
		}
		// If editing
		else if($params = $editRoute->match($this->request->getParam('*', array()))) {
			$this->propID = $params['propID'];
			$currid = $params['id'];
			$this->addBreadcrumbs();

			if(($content = $this->lockObject('property', $params['propID'])) === true) {
				$data = $this->db->fetchRow('SELECT * FROM cf_property_gal_' . clearFusionCMS::getSite() .' WHERE galid=?', $currid);

				$form = new flForm($this->request, 'editimageform', $this->assemble('property', 'gallery', array($this->propID, 'edit', $currid)), true);
				$form->setCSS('metaSSubmit');

				$title = new flFormElementText($form, 'title', $data['title']);
				$title->setLabel(__('Image Title', 'propertyBackend'))
					->setRequired()
					->addValidator(new flFormValidatorRequired())
					->addValidator(new flFormValidatorMaxLength(255));

				$imgPane = new flFormElementPane($form, 'imgthumb', '<img src="' . $this->assemble('property', 'thumbnail', array($this->propID, $currid)) . '" />');
				$imgPane->setLabel(__('The Current Image', 'propertyBackend'));

				$imgFile = new flFormElementFile($form, 'image');
				$imgFile->setLabel(__('Image', 'propertyBackend'))->setCSS('primary');

				$imgURI = new flFormElementUri($form, 'imguri');
				$imgURI->setLabel(__('Or Location to Download Image From', 'propertyBackend'));

				$imgtype = new flFormElementSelect($form, 'imgtype', $data['imgtype'], array(
					'normal' => __('Property Image', 'propertyBackend'),
					'floorplan' => __('Floorplan Image', 'propertyBackend'),
					'epc' => __('EPC Image', 'propertyBackend')
				));
				$imgtype->setLabel(__('Use As:', 'propertyBackend'));

				$submit = new flFormElementSubmit($form, 'updatefield');
				$submit->setCaption(__('Update Image', 'propertyBackend'))->setCSS('primary');

				$delete = new flFormElementSubmit($form, 'deletefield');
				$delete->setCaption(__('Delete Image', 'propertyBackend'))
					->setCSS('danger');

				$form->groupElements('leftcolimg', array($title, $imgtype))
					->groupElements('rightcolimg', array($imgPane, $imgFile, $imgURI))
					->groupElements('submit', array($submit, $delete), new flFormDecoratorList(new flFormDecoratorDl()));

				$form->focusElement($title);

				// Capture ctrl+s for save, implement select all/none, check user really wants to leave page
				$this->tpl->getCodeBuffer()->bufferHeadJS('system/app/js/cfMetaS.js');
				$this->confirmLeavePage();

				if($form->isSubmitted() && $form->isValid()) {
					if($delete->getValue())
						$this->response->redirectTo($this->assemble('property', 'gallery', array($this->propID, 'delete', $currid), true));

					$fileCfg = clearFusionCMS::getSiteConfig('cfSystemFileStore');
					$d = array(
						'title' => $title->getValue(),
						'imgtype' => $imgtype->getValue()
					);

					// If upload file given
					$ext = '';
					if($imgFile->fileUploaded()) {
						try {
							$img = new flImage($imgFile->getTmpFileName());
							switch($img->getType()) {
								case IMAGETYPE_GIF: $ext = '.gif'; break;
								case IMAGETYPE_JPEG: $ext = '.jpg'; break;
								case IMAGETYPE_PNG: $ext = '.png'; break;
							}
							$d['fileext'] = $ext;
						} catch(flException $e) { }
					}
					// Else if download file give
					else if($imgURI->getValue() != '') {

						// Get the image from a remote source
						$http = new flHttpClient($imgURI->getValue());
						if($http->sendRequest() && $http->getResponseCode() == 200) {
							// Save the file data
							$tmpFile = tempnam($fileCfg->privateStorage, 'store');
							@file_put_contents($tmpFile, $http->getBody());
							unset($http); // Release the object & memory

							try {
								$img = new flImage($tmpFile);
								switch($img->getType()) {
									case IMAGETYPE_GIF: $ext = '.gif'; break;
									case IMAGETYPE_JPEG: $ext = '.jpg'; break;
									case IMAGETYPE_PNG: $ext = '.png'; break;
								}
								$d['fileext'] = $ext;
							} catch(flException $e) {
								@unlink($tmpFile);
							}
						}
					}

					// Update
					if($this->db->update('cf_property_gal_' . clearFusionCMS::getSite(), $d, 'galid=?', $currid)) {
						propertyAudit::updateGallery($currid, $this->propName, $title->getValue(), $data);

						// if new file given
						if(!empty($ext)) {
							// If upload file given
							if($imgFile->fileUploaded())
								$imgFile->moveTo($fileCfg->privateStorage . $this->getFilename($currid, $ext));
							// Else download file
							else
								@rename($tmpFile, $fileCfg->privateStorage . $this->getFilename($currid, $ext));

							// Purge the caches
							$prodinfo = $this->db->fetchRow('SELECT catid,slug FROM cf_property_' . clearFusionCMS::getSite() . ' WHERE propertyid=?', $this->propID);
							$content = new cfContent($this->db, clearFusionCMS::getSite());
							if(!empty($ext) && ($container = $content->getContainer('property.region.' . $prodinfo['regionid']))) {
								$route = $content->getContainerRoute($container, "image/:size/:slug/$currid", array(), array(), $ext);

								clearFusionCMS::getEventManager()->notify(new flEvent('system.cachePurge', array('files' => array(
									$route->assemble(array('size' => 'o', 'slug' => $prodinfo['slug'])),
									$route->assemble(array('size' => 't', 'slug' => $prodinfo['slug'])),
									$route->assemble(array('size' => 's', 'slug' => $prodinfo['slug'])),
									$route->assemble(array('size' => 'm', 'slug' => $prodinfo['slug'])),
									$route->assemble(array('size' => 'l', 'slug' => $prodinfo['slug']))
								))));
							}
						}

						$this->cache->flush();

						$this->session->flashSet('cfManagerOpSuccess', $this->alertMessage('Success', __('The image has been updated.', 'propertyBackend')));
						$this->response->redirectTo($this->assemble('property', 'gallery', array($this->propID, 'edit', $currid), true));
					}
					else {
						if(isset($tmpFile))
							@unlink($tmpFile);
						$msg = $this->alertMessage('Error', __('Unable to update the image, please make sure that you are using a PNG, GIF or JPEG file for the image and try again.', 'propertyBackend'));
					}
				}

				$content = $this->renderBlock(sprintf(__('Edit Image: %s', 'propertyBackend'), $data['title']), $form->render($this->tpl->getCodeBuffer()), '', $msg);
			}
		}

		// If deleting
		else if($params = $deleteRoute->match($this->request->getParam('*', array()))) {
			$this->propID = $params['propID'];
			$currid = $params['id'];
			$this->addBreadcrumbs();
			$this->breadcrumbTrail->addCrumb(__('Delete Image', 'propertyBackend'), $this->assemble('property', 'gallery', array($this->propID, 'delete', $currid)));

			if(($content = $this->lockObject('property', $params['propID'])) === true) {
				$data = $this->db->fetchRow('SELECT title,fileext,disporder,imgtype FROM cf_property_gal_' . clearFusionCMS::getSite() .' WHERE galid=?', $currid);

				$form = new flForm($this->request, 'delimageform', $this->assemble('property', 'gallery', array($this->propID, 'delete', $currid)), true);

				$title = new flFormElementText($form, 'title', $data['title']);
				$title->setLabel(__('Image Title', 'propertyBackend'))
					->setDisabled()
					->setReadonly();

				$imgPane = new flFormElementPane($form, 'imgthumb', '<img src="' . $this->assemble('property', 'thumbnail', array($this->propID, $currid)) . '" />');
				$imgPane->setLabel(__('The Current Image', 'propertyBackend'));

				$delSubmit = new flFormElementSubmit($form, 'deleteimage');
				$delSubmit->setCaption(__('Permanently Delete The Image', 'propertyBackend'))
					->setCSS('danger')
					->setDescription($this->alertMessage('Warning', __('This action cannot be undone.', 'propertyBackend')));

				if($form->isSubmitted() && $form->isValid()) {
					propertyAudit::deleteGallery($currid, $this->propName, $data);

					$this->db->delete('cf_property_gal_' . clearFusionCMS::getSite(), 'galid=?', $currid);
					$this->db->query('UPDATE cf_property_gal_' . clearFusionCMS::getSite() . ' SET disporder=disporder-1 WHERE propertyid=? && disporder>?', $this->propID, $data['disporder']);
					$this->getFilename($currid, $data['fileext']);
					$this->cache->flush();
					$this->response->redirectTo($this->assemble('property', 'gallery', array($this->propID), true));
				}

				$content = $this->renderBlock(sprintf(__('Delete Image: %s', 'storeBackend'), $data['title']), $form->render($this->tpl->getCodeBuffer()), '', $msg);
			}
		}
		else
			$this->response->redirectTo($this->assemble('', 'dashboard'));

		$this->renderAdminPage($currid, $content);
	}

	/**
	 * Get the filename to store an image under.
	 *
	 * Folders are created if required and old images are removed.
	 *
	 * @param int $id The ID of the gallery item.
	 * @param string $ext The file extension.
	 * @return bool|string The filename to use or false if failed.
	 */
	protected function getFilename($id, $ext) {
		// Calculate the storage path and file name
		$idHash = md5($this->propID);
		$cfg = clearFusionCMS::getSiteConfig('cfSystemFileStore');
		$path = '/property/' . clearFusionCMS::getSite() . '/' . $idHash[0] . '/' . $idHash[1] . '/';
		$file = $path . $this->propID . '-' . $id . $ext;

		// Create the folder if not already present
		if(!is_writable($cfg->privateStorage . $path)) {
			if(!@mkdir($cfg->privateStorage . $path, 0777, true))
				return false;
		}

		// Remove the old file if any
		foreach(glob($cfg->privateStorage . $path . $this->propID . '-' . $id . '.*') as $f)
			@unlink($f);

		foreach(glob($cfg->privateStorage . $path . $this->propID . '-' . $id . '_*.*') as $f)
			@unlink($f);

		return $file;
	}
}
