<?php

namespace Entity;

/**
 * The class is instantiated and the method validate() is executed in the Entity->check() method.
 *
 */
class Validator_Task extends \App\Entity\Utils\Extension_ValidateDefaultAbstract
{

	/**
	 * Check if the user has access to insert operation
	 */
	protected function isAccessible_insert()
	{
		// current collected messages
		$currMessages = $this->entity->getMessages();

		// check user access
		if (!\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('Modules/TaskManagement/Tasks-insert')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

	}

	/**
	 * Validates the fields for inserting
	 */
	protected function check_insert()
	{
		// get current fields details
		$fields = $this->entity->getFields();

		// current collected messages
		$currMessages = $this->entity->getMessages();

		// entity config
		$entCfg = $this->entity->getCFG();

		// CHECK THAT CATEGORY IS VALID
		if ($fields['idCategory']) {
			$category = \Entity\TaskCategory::select($fields['idCategory']);
			if (!$category->recordExists()) {
				$currMessages->addErrorCode('insert_idCategoryInvalid', 'idCategory');
			}
		}

		// CHECK THAT DEPARTMENT IS VALID
		if ($fields['idDepartment']) {
			$department = \Entity\Department::select($fields['idDepartment']);
			if (!$department->recordExists()) {
				$currMessages->addErrorCode('insert_idDepartmentInvalid', 'idDepartment');
			}
			if ($department->deleted) {
				$currMessages->addErrorCode('insert_idDepartmentDeleted', 'idDepartment');
			}
		}

		// CHECK THAT OFFICE IS VALID
		if ($fields['idOffice']) {
			$office = \Entity\Office::select($fields['idOffice']);
			if (!$office->recordExists()) {
				$currMessages->addErrorCode('insert_idOfficeInvalid', 'idOffice');
			}
			if ($office->deleted) {
				$currMessages->addErrorCode('insert_idOfficeDeleted', 'idOffice');
			}
		}

		// CHECK THAT ASSIGNOR IS VALID
		if ($fields['idAssignorUser']) {
			$assignor = \Entity\User::select($fields['idAssignorUser']);
			if (!$assignor->recordExists()) {
				$currMessages->addErrorCode('insert_idAssignorUserInvalid', 'idAssignorUser');
			}
			if ($assignor->deleted) {
				$currMessages->addErrorCode('insert_idUserDeleted', 'idAssignorUser');
			}
		}

		// CHECK THAT RESPONSIBLE IS VALID
		if ($fields['idResponsibleUser']) {
			$resp = \Entity\User::select($fields['idResponsibleUser']);
			if (!$resp->recordExists()) {
				$currMessages->addErrorCode('insert_idResponsibleUserInvalid', 'idResponsibleUser');
			}
			if ($resp->deleted) {
				$currMessages->addErrorCode('insert_idUserDeleted', 'idResponsibleUser');
			}
		}

		// CHECK THAT OPERATION TYPE IS VALID
		if ($fields['idOperationType']) {
			$type = \Entity\TaskOperationType::select($fields['idOperationType']);
			// check operation type
			if (!$type->recordExists() or $type->deleted) {
				$currMessages->addErrorCode('insert_idOperationTypeInvalid', 'idOperationType');
			}
		}

		// CHECK THAT DEADLINE IS VALID
		if (!($fields['deadline'] instanceof \Engine\DateTime)) {
			throw new \Exception("field 'deadline' should be an \Engine\DateTime object");
		}
		else {
			if (!$fields['deadline']->isValid() || $fields['deadline']->isEmpty()) {
				$currMessages->addWarningCode('insert_deadlineInvalid', 'deadline');
			}
		}


		// CHECK THAT ALERT FIELDS ARE VALID
		if ($fields['noResponsibleNote'] && !in_array($fields['noResponsibleNote'], $entCfg['_special']['eventTypes'])) {
			$currMessages->addErrorCode('insert_eventTypeInvalid', 'noResponsibleNote');
		}
		if ($fields['responsibleInstantNote'] && !in_array($fields['responsibleInstantNote'], $entCfg['_special']['eventTypes'])) {
			$currMessages->addErrorCode('insert_eventTypeInvalid', 'responsibleInstantNote');
		}
		if ($fields['responsibleDeadlineNote'] && !in_array($fields['responsibleDeadlineNote'], $entCfg['_special']['eventTypes'])) {
			$currMessages->addErrorCode('insert_eventTypeInvalid', 'responsibleDeadlineNote');
		}

		// CHECK FILES WITH PATH ///////////////////////////////////////////////////////////////////
		if ($fields['filesWithPath']) {

			$checkFileName = new \App\Utils\RestrictUploadedFile();
			foreach ($fields['filesWithPath'] as $fileName => $filePath) {
				if (!$fileName or !$filePath) {
					$currMessages->addWarningCode('invalidUploadedFile');
				}
				else {
					try {
						$checkFileName->checkFileName($fileName);
					} catch (\App\MessagesException $e) {
						$currMessages->addWarningCode('invalidUploadedFileFormat');
					}
				}
			}
		}
	}

	/**
	 * Check if update can be done
	 */
	protected function isAvailable_update()
	{
		// current entity id
		$currentEntityId = $this->entity->getId();

		// current collected messages
		$currentMessages = $this->entity->getMessages();

		// lock record (if it is the case)
		$task = \Entity\Task::selectForUpdate($currentEntityId);

		if (!$task->recordExists()) {
			$currentMessages->addWarningCode('update_invalidId');
		}
		elseif ($task->deleted) {
			$currentMessages->addWarningCode('update_deleted');
		}
	}

	/**
	 * Validates the fields for updating
	 */
	protected function check_update()
	{
		// get current fields details
		$fields = $this->entity->getFields();

		// current entity id
		$currentEntityId = $this->entity->getId();

		// current collected messages
		$currMessages = $this->entity->getMessages();

		// existing task
		$task = \Entity\Task::selectForUpdate($currentEntityId);

		// modify free perm
		if (isset($fields['free']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskSetAsFree')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify idResponsibleUser perm
		if (isset($fields['idResponsibleUser']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskSetResponsible')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify idAssignorUser perm
		if (isset($fields['idAssignorUser']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskSetAssignor')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify deadline perm
		if (isset($fields['deadline']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskSetDeadline')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify idOffice perm
		if (isset($fields['idOffice']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdateOffice')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify idDepartment perm
		if (isset($fields['idDepartment']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdateDept')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify priority perm
		if (isset($fields['priority']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdatePriority')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify idCategory perm
		if (isset($fields['idCategory']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdateCategory')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify description perm
		if (isset($fields['description']) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdateDescr')) {
			$currMessages->addWarningCode('noAccessToOption');
		}

		// modify pivot/idPivot perm
		if ( (isset($fields['pivot']) || isset($fields['idPivot'])) && !\App\UserAccess\CurrentUserAccessFast::getInstance()->hasAccessToOption('taskUpdateIdPivot')) {
			$currMessages->addWarningCode('noAccessToOption');
		}


		// CHECK THAT CATEGORY IS VALID
		if ($fields['idCategory']) {
			$category = \Entity\TaskCategory::select($fields['idCategory']);
			if (!$category->recordExists()) {
				$currMessages->addErrorCode('update_idCategoryInvalid', 'idCategory');
			}
		}

		// CHECK THAT DEPARTMENT IS VALID
		if ($fields['idDepartment']) {
			$department = \Entity\Department::select($fields['idDepartment']);
			if (!$department->recordExists()) {
				$currMessages->addErrorCode('update_idDepartmentInvalid', 'idDepartment');
			}
			if ($department->deleted) {
				$currMessages->addErrorCode('update_idDepartmentDeleted', 'idDepartment');
			}
		}

		// CHECK THAT OFFICE IS VALID
		if ($fields['idOffice']) {
			$office = \Entity\Office::select($fields['idOffice']);
			if (!$office->recordExists()) {
				$currMessages->addErrorCode('update_idOfficeInvalid', 'idOffice');
			}
			if ($office->deleted) {
				$currMessages->addErrorCode('update_idOfficeDeleted', 'idOffice');
			}
		}

		// CHECK THAT ASSIGNOR IS VALID
		if ($fields['idAssignorUser']) {
			$assignor = \Entity\User::select($fields['idAssignorUser']);
			if (!$assignor->recordExists()) {
				$currMessages->addErrorCode('update_idAssignorUserInvalid', 'idAssignorUser');
			}
			if ($assignor->deleted) {
				$currMessages->addErrorCode('update_idUserDeleted', 'idAssignorUser');
			}
		}

		// CHECK THAT RESPONSIBLE IS VALID
		if ($fields['idResponsibleUser']) {
			$resp = \Entity\User::select($fields['idResponsibleUser']);
			if (!$resp->recordExists()) {
				$currMessages->addErrorCode('update_idResponsibleUserInvalid', 'idResponsibleUser');
			}
			if ($resp->deleted) {
				$currMessages->addErrorCode('update_idUserDeleted', 'idResponsibleUser');
			}
		}

		// DON'T ALOW REMOVING THE RESPONSIBLE IF EXISTING STATUS >= 'pending'
		if ($task->status && !in_array($task->status, ['distributed','notDistributed']) && $task->idResponsibleUser && array_key_exists('idResponsibleUser', $fields) && !$fields['idResponsibleUser']) {
			$currMessages->addErrorCode('update_cannotUnsetResponsible', 'idResponsibleUser');
		}

		// CHECK THAT OPERATION TYPE IS VALID
		if ($fields['idOperationType']) {
			$type = \Entity\TaskOperationType::select($fields['idOperationType']);
			// check operation type
			if (!$type->recordExists() or $type->deleted) {
				$currMessages->addErrorCode('update_idOperationTypeInvalid', 'idOperationType');
			}
		}

		// CHECK THAT DEADLINE IS VALID
		if (!$fields['deadline']->isValid() || $fields['deadline']->isEmpty()) {
			$currMessages->addWarningCode('update_deadlineInvalid', 'deadline');
		}

		// CHECK FILES WITH PATH ///////////////////////////////////////////////////////////////////
		if ($fields['filesWithPath']) {

			$checkFileName = new \App\Utils\RestrictUploadedFile();
			foreach ($fields['filesWithPath'] as $fileName => $filePath) {
				if (!$fileName or !$filePath) {
					$currMessages->addWarningCode('invalidUploadedFile'); // TODO in lang
				}
				else {
					try {
						$checkFileName->checkFileName($fileName);
					} catch (\App\MessagesException $e) {
						$currMessages->addWarningCode('invalidUploadedFileFormat');
					}
				}
			}
		}

	}


	/**
	 * Check if the user has access to delete operation
	 */
	protected function isAccessible_delete()
	{
	}

	/**
	 * Check if the delete operation can be performed
	 */
	protected function isAvailable_delete()
	{
		// current entity id
		$currentEntityId = $this->entity->getId();

		// current collected messages
		$currentMessages = $this->entity->getMessages();

		// check if task is not already deleted
		$task = \Entity\Task::selectForUpdate($currentEntityId);

		if (!$task->recordExists()) {
			$currentMessages->addErrorCode('delete_idInvalid');
		} elseif ($task->deleted) {
			$currentMessages->addWarningCode('delete_deleted');
		}

		// check if task is not already distributed
		if ($task->status!='notDistributed') {
			$currentMessages->addErrorCode('delete_distributed');
		}

	}


	/**
	 * Check if the changeStatus operation can be performed
	 */
	protected function isAvailable_changeStatus()
	{
		// current entity id
		$currentEntityId = $this->entity->getId();

		// current collected messages
		$currentMessages = $this->entity->getMessages();

		$task = \Entity\Task::selectForUpdate($currentEntityId);

		// check if task is not already deleted
		if (!$task->recordExists()) {
			$currentMessages->addErrorCode('changeStatus_idInvalid');
		} elseif ($task->deleted) {
			$currentMessages->addWarningCode('changeStatus_deleted');
		}

		// check that the responsible user is set
		if (!$task->idResponsibleUser) {
			$currentMessages->addErrorCode('changeStatus_responsibleNotSet', 'idResponsibleUser');
		}
	}

	/**
	 * Validates the fields for change status
	 */
	protected function check_changeStatus()
	{
		// get current fields details
		$fields = $this->entity->getFields();

		// current entity id
		$currentEntityId = $this->entity->getId();

		// current collected messages
		$currMessages = $this->entity->getMessages();

		$task = \Entity\Task::selectForUpdate($currentEntityId);

		// check status description length
		if (mb_strlen($fields['statusDescription'])>250) {
			$currMessages->addWarningCode('changeStatus_statusDescr', 'statusDescription', 250);
		}

		// IF RESPONSIBLE IS NOT SET DON'T ALLOW SAVING
		if (!$task->idResponsibleUser) {
			$currMessages->addWarningCode('changeStatus_responsibleNotSet', 'idResponsibleUser');
		}

		// CHECK THAT THE STATUS IS VALID
		if ( !in_array($fields['status'], [/*'notDistributed','distributed',*/'pending','refused','inProgress','onHold','finished']) ) {
			$currMessages->addWarningCode('changeStatus_invalidStatus', 'status');
		}

		// CHECK REASON -------------------------------------------------------------------------------
		if ( in_array($fields['status'], ['refused','onHold']) && !$fields['statusReason'] ) {
			$currMessages->addWarningCode('changeStatus_reasonMissing', 'statusReason');
		}



	}



}
