<?php
namespace App\ExportData\Output;

abstract class DbEntityAbstract
{
	/**
	 * Stores the export data xml object
	 * @var \SimpleXMLElement
	 */
	protected $xml = NULL;

	/**
	 * Stores the current entity database table name
	 * @var String
	 */
	protected $dbTableName = NULL;

	/**
	 * Stores the operation of current entity(insert/update/delete)
	 * @var String
	 */
	public $operation = NULL;

	/**
	 * Stores the primary key name used for update and delete operation
	 * @var String
	 */
	protected $primaryKeyName = NULL;

	/**
	 * Stores the primary key value
	 * @var String
	 */
	protected $primaryKeyValue = NULL;

	/**
	 * Array of all the fields of the current entity operation(insert/update/delete)
	 * @var array
	 */
	protected $fields = [];

	/**
	 * Default class construct
	 * @param \SimpleXMLElement $xml
	 */
	public function __construct(\SimpleXMLElement $xml)
	{
		$this->xml = $xml;

		// associate the table
		$this->setTableName();

		// associate the primary key name
		$this->setPrimaryKeyName();

		// associate the primary key value
		$this->setPrimaryKeyValue();
	}

	/**
	 * Sets the $this->dbTableName - the database table name used for the current entity.
	 */
	abstract protected function setTableName();

	/**
	 * The method is used in concrete classes to set primary key name.
	 */
	abstract protected function setPrimaryKeyName();

	/**
	 * The method is used in concrete classes to set primary key value.
	 */
	abstract protected function setPrimaryKeyValue();

	/**
	 * The method is used in concrete classes to add fields to the $this->fields array.
	 */
	abstract public function populate();

	/**
	 * Returns the database table name
	 * @return string
	 */
	public function getDbTableName()
	{
		return $this->dbTableName;
	}

	/**
	 * Returns the entity operation
	 * @return string
	 */
	public function getOperation()
	{
		return $this->operation;
	}

	/**
	 * Returns the primary key name
	 * @return string
	 */
	public function getPrimaryKeyName()
	{
		return $this->primaryKeyName;
	}

	/**
	 * Returns the primary key value
	 * @return string
	 */
	public function getPrimaryKeyValue()
	{
		return $this->primaryKeyValue;
	}

	/**
	 * Returns the entity fields
	 * @return Array
	 */
	public function getFields()
	{
		return $this->fields;
	}

	/**
	 * Validate entity
	 * @throws \App\MessagesException
	 */
	public function validate()
	{
		$msgs = new \App\MessagesCollector();

		// check if table is set
		if ($this->dbTableName == NULL) {
			throw new \App\MessagesException($msgs->addError(sprintf('The flag `dbTableName` is not set for class `%s`', get_called_class())));
		}

		// check if operation is set
		if ($this->operation == NULL) {
			throw new \App\MessagesException($msgs->addError(sprintf('The operation must be set as insert/update/delete for class `%s`', get_called_class())));
		}

		// validate operation
		if (!in_array($this->operation, ['insert', 'update', 'delete'])) {
			throw new \App\MessagesException($msgs->addError(sprintf("The operation `%s` is not valid for class `%s`", $this->operation, get_called_class())));
		}

		// validate id entity
		if (($this->operation == 'update' or $this->operation == 'delete') and (!$this->primaryKeyName or !$this->primaryKeyValue)) {
			throw new \App\MessagesException($msgs->addError(sprintf("The primary key value and primary key name must be set for operation `%s` for class `%s`", $this->operation, get_called_class())));
		}

		// validate data
		if (($this->operation == 'insert' or $this->operation == 'update') and !$this->fields) {
			throw new \App\MessagesException($msgs->addError(sprintf("The array with fields must be set for operation `%s` for class `%s`", $this->operation, get_called_class())));
		}

		// validate data
		$this->validateFields($msgs);
		if ($msgs->hasErrorOrWarning()) {
			throw new \App\MessagesException($msgs);
		}
	}

	/**
	 * Validate fields
	 * @param \App\MessagesCollector $msgs
	 */
	abstract protected function validateFields(\App\MessagesCollector $msgs);

}
