<?php
namespace App\Mvc\Controller\Window\PaginatedListing;

/**
 * The class extends listing abstract to create a "standard module" by adding insert, update and delete options.
 *
 * Use for standard modules, where entities are not available
 * Support:
 * 	- insert
 * 	- edit
 * 	- delete
 * 	- listing
 *
 * @author Gabriel
 */
abstract class PaginatedListing extends \App\Mvc\Controller\Window\PaginatedListing\ListingAbstract
{

	/**
	 * The submit button name for insert/update.
	 * @var String
	 */
	protected $formSubmitButtonName='save';

	/**
	 * The id of the new inserting record.
	 * @var Int|String
	 */
	protected $insertIdRecord = null;

	/**
	 * The id of the new inserting record.
	 * @var Int|String
	 */
	protected $updateIdRecord = null;


	/**
	 * (non-PHPdoc)
	 * @see \App\Mvc\Controller\Window\PaginatedListing\PaginatedListing::initialize()
	 */
	protected function initialize()
	{
		parent::initialize();

		$this->actionsCfg['insert'] = [ 'checkOption' => true, ];
		$this->actionsCfg['update'] = [ 'checkOption' => true, ];
		$this->actionsCfg['delete'] = [ 'checkOption' => true, ];
	}


	/**
	 * The "insert" action.
	 * @return String - the output of "insert" action.
	 */
	protected function actionInsert($R)
	{

		$msgs = \App\MessagesCollector::create();

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			$formData=$this->insert_getDefaultFormData($R);
		} else {
			$formData=$R;
		}

		// execute the model (and collect the output)
		$modelOutput = null;
		if ($R[$this->formSubmitButtonName]) {
			$modelOutput = $this->insert_doInsert($formData, $msgs);
			// check that insert id record is set if the model outputs true
			if ($modelOutput and !$this->insertIdRecord) {
				throw new \Exception('The `insertIdRecord` class attribute is not set although the model returned `true`.');
			}
		}

		// instantiate the view
		$view = $this->buildViewObjectFromCurrentModuleForAction($this->getAction());

		return $this->insert_returnResponse($view, $formData, $modelOutput, $msgs);
	}

	/**
	 * Sets the type of return response
	 * @param \App\Mvc\ViewAbstract $view
	 * @param array $formData
	 * @param boolean $modelOutput
	 * @param \App\MessagesCollector $msgs
	 * @return \Engine\Mvc\Response\Html
	 */
	protected function insert_returnResponse(\App\Mvc\ViewAbstract $view, array $formData, $modelOutput, \App\MessagesCollector $msgs)
	{
		// send data to the view
		$view->addInput('formData', $formData);
		if ($modelOutput) {
			$view->setClosePopup(true);
		}
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);
		$view->addInput('idRecord', $this->insertIdRecord);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}


	/**
	 * Returns an array of default values for insert form.
	 * @return Array
	 */
	protected function insert_getDefaultFormData($R)
	{
		return [];
	}


	/**
	 * The "update" action.
	 * @return String - the output of "update" action.
	 */
	protected function actionUpdate($R)
	{

		$msgs = \App\MessagesCollector::create();

		$this->updateIdRecord = $R['id'];

		// get form data for this operation
		if (!$R[$this->formSubmitButtonName]) {
			$formData = $this->update_getDefaultFormData($this->updateIdRecord);
			if ($formData!==null) {
				$formData['id']=$this->updateIdRecord;
			}
		} else {
			$formData=$R;
		}

		// execute the model (and collect the output)
		$modelOutput = null;
		if ($R[$this->formSubmitButtonName]) {
			$modelOutput = $this->update_doUpdate($formData, $msgs);
		}

		// instantiate the view
		$view = $this->buildViewObjectFromCurrentModuleForAction($this->getAction());

		// send data to the view
		$view->addInput('formData', $formData);
		if ($modelOutput) {
			$view->setClosePopup(true);
		}
		$view->getMessagesCollector()->appendMessages($msgs);
		$view->addInput('formSubmitButtonName', $this->formSubmitButtonName);
		$view->addInput('idRecord', $this->updateIdRecord);

		// render the view
		return new \Engine\Mvc\Response\Html($view->render());
	}


	/**
	 * The method executes the deletion of the selected records (this will be used for single row delete also).
	 * @param array $recordsIds
	 * @param \App\MessagesCollector $msgs
	 * @param array $R
	 */
	protected function bulkActionDelete(array $recordsIds, \App\MessagesCollector $msgs, $R)
	{

		// executes the actual deletion
		$this->delete_doDelete($recordsIds, $msgs, $R);

		// group success messages (count success messages grouped by text)
		$successTexts = [];
		foreach($msgs->getMessages() as $msg) {
			if ($msg->getType()=='success') {
				$successTexts[$msg->getText()]++;
			}
		}
		// if all success messages have the same messages (and there are more than one) - group the message
		if (count($successTexts)==1 and current($successTexts)>1) {
			$msgs->removeSuccess();
			$msgs->addSuccess(sprintf($this->globalLang['stdModule']['recordsSuccessfullyDeleted'], current($successTexts)));
		}
	}


	/**
	 * Does the actual "insert" operation upon form submit.
	 */
	abstract protected function insert_doInsert($formData, \App\MessagesCollector $msgs);


	/**
	 * Returns an array of default values for "update" form - usually the data is taken from database.
	 * @return Array
	 */
	abstract protected function update_getDefaultFormData($idEntity);

	/**
	 * Does the actual "update" operation upon form submit.
	 */
	abstract protected function update_doUpdate($formData, \App\MessagesCollector $msgs);


	/**
	 * Does the actual deletion of multiple records.  In case of any type of message - the
	 */
	abstract protected function delete_doDelete(array $recordsIds, \App\MessagesCollector $msgs, array $R) ;

}
