<?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
 */

/**
 * propertyBackendTypeAction Class
 *
 * Backend controller action for managing types of properties.
 *
 * @package clearFusionCMS\module\property
 */
class propertyBackendTypeAction extends cfBackendControllerAction {

	/**
	 * Access to categories.
	 *
	 * @var propertyTypes
	 */
	protected $types;

	/**
	 * Constructor.
	 *
	 * @param flController $controller The controller object.
	 */
	function __construct(flController $controller) {
		parent::__construct($controller);

		$this->types = new propertyTypes($this->db);
	}

	/**
	 * Build the category tree.
	 *
	 * @param int $active The active node.
	 * @return flWidgetTreeView The tree widget.
	 */
	protected function buildTree($active) {
		$rootTree = new flWidgetTreeView('cfProperty.type.tree');

		// Build tree
		$tree = new flWidgetTreeView();
		$results = $this->types->getChildren(0, array('typeid', 'title'));
		foreach($results as $row) {
			$tree->addNode(new flWidgetTreeLinkNode("$row[title] [$row[typeid]]", $this->assemble('property', 'type', array('edit', $row['typeid'])), flWidgetTreeNode::NODE, $row['typeid']))
				->setLastNodeActive($active == $row['typeid']);
		}

		$rootTree->addNode(count($results) ? new flWidgetTreeChildNode(__('Types', 'propertyBackend'), $tree, null) : new flWidgetTreeNode(__('Types', 'propertyBackend'), flWidgetTreeNode::CONTAINER))
			->setAJAXMoveHandler($this->assemble('property', 'type', array('dragdrop', $active ? $active : 0)));

		return $rootTree;
	}

	/**
	 * Render the page.
	 *
	 * @param string $id The current item.
	 * @param string $content The page content.
	 */
	function renderAdminPage($id, $content) {

		// Create the tree
		$rootTree = $this->buildTree($id);

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

		$fam->addAction('add', __('Add Type', 'propertyBackend'), $this->assemble('property', 'type', array('add')));

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

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

	/**
	 * Process the request
	 */
	function process() {
		$this->testPermission('cfProperty.types');
		$this->breadcrumbTrail->addCrumb(__('Types', 'propertyBackend'), $this->assemble('property', 'type'));

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

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

		// If adding
		if($params = $addRoute->match($this->request->getParam('*', array()))) {
			$this->breadcrumbTrail->addCrumb(__('Add Type', 'propertyBackend'), $this->assemble('property', 'type', array('add')));

			$form = new flForm($this->request, 'addtypeform', $this->assemble('property', 'type', array('add')), true);
			$form->setCSS('metaSSubmit');

			$name = new flFormElementText($form, 'title');
			$name->setLabel(__('Property Type', 'propertyBackend'))
				->setRequired()
				->addValidator(new flFormValidatorRequired());

			$submit = new flFormElementSubmit($form, 'add');
			$submit->setCaption(__('Create Type', 'propertyBackend'))->setCSS('primary');

			$form->groupElements('fullcolinfo', array($name))
				->groupElements('submit', array($submit), new flFormDecoratorList(new flFormDecoratorDl()));

			$form->focusElement($name);

			// 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()) {

				// Create
				if($id = $this->types->insertNode(0, flDbNestedSet::UNDER, array(
					'title' => $name->getValue()
				))) {
					propertyAudit::createType($id, $name->getValue());
					$this->cache->flush();

					$this->session->flashSet('cfManagerOpSuccess', $this->alertMessage('Success', __('The new property type has been created.', 'propertyBackend')));
					$this->response->redirectTo($this->assemble('property', 'type', array('edit', $id), true));
				}
				else
					$msg = $this->alertMessage('Error', __('Unable to create the new property type, please try again.', 'propertyBackend'));
			}

			$content = $this->renderBlock(__('Add Property Type', 'propertyBackend'), $form->render($this->tpl->getCodeBuffer()), '', $msg);
		}
		// If editing
		else if($params = $editRoute->match($this->request->getParam('*', array()))) {
			$currid = $params['id'];
			$this->breadcrumbTrail->addCrumb(__('Edit Type', 'propertyBackend'), $this->assemble('property', 'type', array('edit', $currid)));

			if(($content = $this->lockObject('property.type', $currid)) === true) {
				$data = $this->types->getNodeData($currid, array('title'));

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

				$name = new flFormElementText($form, 'title', $data['title']);
				$name->setLabel(__('Property Type', 'propertyBackend'))
					->setRequired()
					->addValidator(new flFormValidatorRequired());

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

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

				$form->groupElements('fullcolinfo', array($name))
					->groupElements('submit', array($submit, $delete), new flFormDecoratorList(new flFormDecoratorDl()));

				$form->focusElement($name);

				// 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', 'type', array('delete', $currid), true));

					// Update the zone
					if($this->types->updateNodeData($currid, array(
						'title' => $name->getValue()
					))) {
						propertyAudit::updateType($currid, $name->getValue(), $data);
						$this->cache->flush();

						$this->session->flashSet('cfManagerOpSuccess', $this->alertMessage('Success', __('The property type has been updated.', 'propertyBackend')));
						$this->response->redirectTo($this->assemble('property', 'type', array('edit', $currid), true));
					}
					else
						$msg = $this->alertMessage('Error', __('Unable to update the property type.', 'propertyBackend'));
				}

				$content = $this->renderBlock(sprintf(__('Edit Property Type: %s', 'propertyBackend'), $data['title']), $form->render($this->tpl->getCodeBuffer()), '', $msg);
			}
		}
		// If deleting
		else if($params = $deleteRoute->match($this->request->getParam('*', array()))) {
			$currid = $params['id'];
			$this->breadcrumbTrail->addCrumb(__('Delete Type', 'propertyBackend'), $this->assemble('property', 'type', array('delete', $currid)));

			if(($content = $this->lockObject('property.type', $currid)) === true) {
				$data = $this->types->getNodeData($currid, array('title'));

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

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

				$delSubmit = new flFormElementSubmit($form, 'delete');
				$delSubmit->setCaption(__('Permanently Delete The Type', 'propertyBackend'))
					->setCSS('danger')
					->setDescription($this->alertMessage('Warning', __('This action cannot be undone and may affect the ability to locate properties.', 'propertyBackend')));

				if($form->isSubmitted() && $form->isValid()) {
					propertyAudit::deleteType($currid, $data);
					$this->types->deleteNode($currid);
					$this->db->query('UPDATE cf_property_' . clearFusionCMS::getSite() . ' SET typeid=0 WHERE ctypeid=?', $currid);
					$this->cache->flush();
					$this->response->redirectTo($this->assemble('property', 'type', array(), true));
				}

				$content = $this->renderBlock(sprintf(__('Delete Property Type: %s', 'propertyBackend'), $data['title']), $form->render($this->tpl->getCodeBuffer()), '', $msg);
			}
		}
		// If drag n drop
		else if($params = $dragRoute->match($this->request->getParam('*', array()))) {
			$active = $params['id'];

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

			if(!$this->user->hasPermission('cfProperty.types')) {
				$result['success'] = false;
				$result['msg'] = __('Internal failure, please try again.', 'cfBackend');
				$active = '-1';
			}

			$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']) {
				if($this->types->moveNode($moving, $target, $position == 0 ? propertyRegions::AFTER : ($position == -1 ? propertyRegions::BEFORE : propertyRegions::AFTER))) {
					$result['msg'] = __('The type has been moved to the new location.', 'propertyBackend');
					$this->cache->flush();
					propertyAudit::moveType($moving, $this->db->fetchOne('SELECT title FROM cf_property_type_' . clearFusionCMS::getSite() . ' WHERE typeid=?', $moving));
				}
				else {
					$result['msg'] = __('Unable to move this type to the selected location, please try again.', 'propertyBackend');
					$result['success'] = false;
				}
			}

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

			// Send AJAX response
			$this->response->setContentType('application/json')
				->noCache()
				->setBody(json_encode($result))
				->sendResponse();
			die;
		}

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