<?php
/**
 * List repository
 *
 * @author Lucas Dantas <lucas@caju.nu>
 * @package classes
 * @subpackage list
 * @version 1.0
 * @since 2018/04/09 19:25
 */
Class ListRepositoryDBR{

	/**
	 * Connection's object
	 *
	 * @access private
	 * @var PDO
	 */
	private $connection;

	/**
	 * Showing or not the exception
	 *
	 * @access private
	 * @var boolean
	 */
	public $exception	= true;

	/**
	 * Instance
	 *
	 * @access private
	 * @static
	 * @var ListRepositoryDBR
	 */
	private static $instance = [];

	/**
	 * Class constructor
	 *
	 * @access public
	 * @param string $type Type
	 * @uses ConnectionDBR::getInstance Defining the instance
	 */
	public function __construct( $type ){

		$this->connection	= ConnectionDBR::getInstance()->getConnection();
		$this->type			= $type;

	}

	/**
	 * Getting the instance
	 *
	 * @access public
	 * @param string $type Type
	 * @return ConnectionDBR
	 */
	public static function getInstance( $type ){

		//Checking
		if( !array_key_exists( $type, self::$instance ) )
			//Defining
			self::$instance[ $type ]	= new self( $type );

		//Returning
		return self::$instance[ $type ];

	}

	/**
	 * Listing by destination
	 *
	 * @access public
	 * @param integer $destination Destination
	 * @param string $complement Complement
	 * @param array $params Params
	 * @throws Exception
	 * @return mixed
	 */
	public function listByDestination( $destination, $complement = null, $params = [] ){

		try{

			//Preparing
			$resource	= $this->connection->prepare( 'SELECT DISTINCT(R.email) AS email FROM recipient R INNER JOIN recipient_company RC ON (R.id = RC.recipient) INNER JOIN recipient_destination RD ON (R.id = RD.recipient) WHERE RD.destination = :destination ' . $complement );

			//Checking
			if( count( $params ) > 0 )
				//Listing
				foreach( $params as $field => $configuration )
					//Defining
					$resource->bindValue( $field, $configuration[ 'value' ], $configuration[ 'type' ] );

			//Defining
			$resource->bindValue( ':destination', $destination, PDO::PARAM_INT );

			//Executing
			$resource->execute();

			//Defining
			$records	= $resource->fetchAll( PDO::FETCH_OBJ );

			//Checking
			if( count( $records ) > 0 ){

				//Listring
				foreach( $records as $record )
					//Defining
					$array[]	= $record;

				//Returning
				return $array;

			}else
				//Returning
				return null;

		}catch( PDOException $e ){

			//Throwing the exception
			throw new Exception( 'Ocorreu um erro durante a listagem dos contatos por destino. Por favor, tente novamente mais tarde.' );

		}

	}

	/**
	 * Listing
	 *
	 * @access public
	 * @param string $complement Complement
	 * @param array $params PArams
	 * @throws Exception
	 * @return stdclass[]
	 */
	public function list( $complement = null, $params = [] ){

		try{

			//Checking
			switch( $this->type ){

				//Product's category
				case 'product-category':

					//Defining
					$sql	= 'SELECT * FROM product_category TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Product
				case 'product':

					//Defining
					$sql	= 'SELECT * FROM product TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Service
				case 'service':

					//Defining
					$sql	= 'SELECT * FROM service TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Customer
				case 'customer':

					//Defining
					$sql	= 'SELECT * FROM customer TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//News
				case 'news':

					//Defining
					$sql	= 'SELECT TBL.* FROM news TBL WHERE date(date) <= NOW() ' . $complement;

				break;

				//Contact's answers
				case 'answer-contact':

					//Defining
					$sql	= 'SELECT * FROM contact_answer TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Order's answers
				case 'answer-order':

					//Defining
					$sql	= 'SELECT * FROM orders_answer TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Proposal's answers
				case 'answer-proposal':

					//Defining
					$sql	= 'SELECT * FROM proposal_answer TBL WHERE TBL.id IS NOT NULL ' . $complement;

				break;

				//Banner
				default:

					//Defining
					$sql	= 'SELECT * FROM banner TBL WHERE TBL.status = TRUE ' . $complement;

				break;

			}

			//Preparing
			$resource	= $this->connection->prepare( $sql );

			//Checking
			if( count( $params ) > 0 )
				//Listing
				foreach( $params as $field => $config )
					//Defining
					$resource->bindValue( $field, $config[ 'value' ], $config[ 'type' ] );

			//Executing
			$resource->execute();

			//Defining
			$records	= $resource->fetchAll( PDO::FETCH_OBJ );

			//Checking
			if( count( $records ) > 0 )
				//Returning
				return $records;
			//Checking
			else if( $this->exception )
				//Throwing the exception
				throw new Exception( 'Nenhum registro encontrado.' );
			else
				//Returning
				return null;

		}catch( PDOException $e ){

			//Throwing the exception
			throw new Exception( 'Ocorreu um erro durante a listagem. Por favor, tente novamente mais tarde.' );

		}

	}

	/**
	 * Listing orderly
	 *
	 * @access public
	 * @param integer $category Category
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses Util::defineDatabaseOrder Defining the database order
	 * @uses $this->byCategory Listing by category
	 * @return mixed
	 */
	public function byCategoryOrderly( $category, $order, $complement = null, $params = [] ){

		//Defining
		$complement	= 'ORDER BY ' . Util::defineDatabaseOrder( $order ) . ' ' . $complement;

		//Listing
		return $this->byCategory( $category, $complement, $params );

	}

	/**
	 * Listing by category
	 *
	 * @access public
	 * @param integer $category Category
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses $this->list Listing
	 * @return mixed
	 */
	public function byCategory( $category, $complement = null, $params = [] ){

		//Defining
		$complement	= 'AND TBL.category = :category ' . $complement;

		//Defining
		$params	= array_merge( [ ':category' => [ 'value' => $category, 'type' => PDO::PARAM_INT ] ], $params );

		//Listing
		return $this->list( $complement, $params );

	}

	/**
	 * Listing the not actives, by category and orderly
	 *
	 * @access public
	 * @param integer $id Identifier
	 * @param integer $category Category
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses Util::defineDatabaseOrder Defining the database order
	 * @uses $this->notActiveByCategory Listing the not actives and by category
	 * @return mixed
	 */
	public function notActiveByCategoryOrderly( $id, $category, $order, $complement = null, $params = [] ){

		//Defining
		$complement	= 'ORDER BY ' . Util::defineDatabaseOrder( $order ) . ' ' . $complement;

		//Listing
		return $this->notActiveByCategory( $id, $category, $complement, $params );

	}

	/**
	 * Listing the not actives and by category
	 *
	 * @access public
	 * @param integer $id Identifier
	 * @param integer $category Category
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses $this->notActive Listing the not actives
	 * @return mixed
	 */
	public function notActiveByCategory( $id, $category, $complement = null, $params = [] ){

		//Defining
		$complement	= 'AND TBL.category = :category ' . $complement;

		//Defining
		$params	= array_merge( [ ':category' => [ 'value' => $category, 'type' => PDO::PARAM_INT ] ], $params );

		//Listing
		return $this->notActive( $id, $complement, $params );

	}

	/**
	 * Listing the not actives orderly
	 *
	 * @access public
	 * @param integer $id Identifier
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses Util::defineDatabaseOrder Defining the database order
	 * @uses $this->notActive Listing the not actives
	 * @return mixed
	 */
	public function notActiveOrderly( $id, $order, $complement = null, $params = [] ){

		//Defining
		$complement	= 'ORDER BY ' . Util::defineDatabaseOrder( $order ) . ' ' . $complement;

		//Listing
		return $this->notActive( $id, $complement, $params );

	}

	/**
	 * Listing the not active
	 *
	 * @access public
	 * @param integer $id Identifier
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses $this->list Listing
	 * @return mixed
	 */
	public function notActive( $id, $complement = null, $params = [] ){

		//Defining
		$complement	= 'AND TBL.id <> :id ' . $complement;

		//Defining
		$params	= array_merge( [ ':id' => [ 'value' => $id, 'type' => PDO::PARAM_INT ] ], $params );

		//Listing
		return $this->list( $complement, $params );

	}

	/**
	 * Listing orderly and by quantity
	 *
	 * @access public
	 * @param string $order Order
	 * @param integer $quantity Quantity
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses $this->orderly Listing orderly
	 * @return mixed
	 */
	public function orderlyByQuantity( $order, $quantity, $complement = null, $params = [] ){

		//Defining
		$complement	= 'LIMIT :quantity ' . $complement;

		//Defining
		$params		= array_merge( [ ':quantity' => [ 'value' => $quantity, 'type' => PDO::PARAM_INT ] ], $params );

		//Listing
		return $this->orderly( $order, $complement, $params );

	}

	/**
	 * Listing orderly
	 *
	 * @access public
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param array $params Params
	 * @uses Util::defineDatabaseOrder Defining the database order
	 * @uses $this->list Listing
	 * @return mixed
	 */
	public function orderly( $order, $complement = null, $params = [] ){

		//Defining
		$complement	= 'ORDER BY ' . Util::defineDatabaseOrder( $order ) . ' ' . $complement;

		//Listing
		return $this->list( $complement, $params );

	}

	/**
	 * Listing by form and orderly
	 *
	 * @access public
	 * @param integer $form Form
	 * @param string $order Order
	 * @param string $complement Complement
	 * @param string $params Params
	 * @uses Util::defineDatabaseOrder Defining the database order
	 * @uses $this->byForm Listing by form
	 * @return mixed
	 */
	public function byFormOrderly( $form, $order, $complement = null, $params = [] ){

		//Defining
		$complement	= 'ORDER BY ' . Util::defineDatabaseOrder( $order ) . ' ' . $complement;

		//Listing
		return $this->byForm( $form, $complement, $params );

	}

	/**
	 * Listing by form
	 *
	 * @access public
	 * @param integer $form Form
	 * @param string $complement Complement
	 * @param string $params Param
	 * @uses $this->list Listing
	 * @return mixed
	 */
	public function byForm( $form, $complement = null, $params = [] ){

		//Defining
		$complement	= 'AND lead = :form ' . $complement;

		//Defining
		$params	= array_merge( [ ':form' => [ 'value' => $form, 'type' => PDO::PARAM_INT ] ], $params );

		//Listing
		return $this->list( $complement, $params );

	}

}