<?php

namespace ModulesAbstract\PluginReports\Report\Model\Builder\ArrayEmulator;

/**
 * Stores key=>value in database - used for huge amount of data.
 * @author Gabriel Grosu
 */
class Database implements GeneralInterface
{

	/**
	 * The db temporary table name.
	 * @var String
	 */
	private $dbTableName;

	/**
	 * SQL part that defines the database column that is used for ordering - eg: "VARCHAR(100) NOT NULL DEFAULT ''" or "DECIMAL(10,2) DEFAULT 0"
	 * @var String
	 */
	private $orderFieldType;

	/**
	 * SQL part that defines the key column (PK) - eg: "INT(10) UNSIGNED NOT NULL''" or "VARCHAR(100) NOT NULL"
	 * @var String
	 */
	private $keyFieldType = 'VARCHAR(50) NOT NULL';

	/**
	 * Collects main info for the table creation.
	 * @param String $dbTableName
	 * @param String $keyFieldType
	 * @param String $orderFieldType
	 * @throws \Exception
	 */
	public function __construct($orderFieldType)
	{

		if (!$orderFieldType) {
			throw new \Exception('The database order column type was not set.');
		}

		$this->dbTableName = 'arrayEmulator_'.uniqid();
		$this->orderFieldType = $orderFieldType;

	}

	/**
	 * Creates the temporary table in the db.
	 * @throws \DBException - if the SQL fails
	 */
	public function initialize()
	{

		$CFG = \Engine\Loader_Cfg::getInstance()->getGlobal();
		$db = \DB::getInstance();

		$createTableSQL = "CREATE TEMPORARY TABLE `{$this->dbTableName}` (
			`key` {$this->keyFieldType},
			`data` TEXT NOT NULL ,
			`ordering` {$this->orderFieldType},
			PRIMARY KEY (`key`),
			KEY (`ordering`)
		) ENGINE=InnoDB DEFAULT CHARSET={$CFG['encodings']['dbCharacterSet']} COLLATE={$CFG['encodings']['dbCollation']} ROW_FORMAT=DYNAMIC
		";
		if (!$db->Execute($createTableSQL)) {
			throw new \DBException('Invalid SQL for creating a temporary table.');
		}

	}

	/**
	 * {@inheritDoc}
	 * @see \ModulesAbstract\PluginReports\Report\Model\Builder\ArrayEmulator\GeneralInterface::set()
	 */
	public function set($key, Array $data, $orderValue)
	{

		$db = \DB::getInstance();

		$insertDataSQL = "REPLACE INTO `{$this->dbTableName}` (`key`, `data`, `ordering`) VALUES (?, ?, ?)";
		$insertDataEx = $db->Execute($insertDataSQL, [$key, serialize($data), $orderValue]);

		if (!$insertDataEx) {
			throw new \DBException('Could not insert data into temporary table.');
		}

	}

	/**
	 * {@inheritDoc}
	 * @see \ModulesAbstract\PluginReports\Report\Model\Builder\ArrayEmulator\GeneralInterface::get()
	 */
	public function get($key)
	{
		$db = \DB::getInstance();

		$getDataSQL = "SELECT data FROM `{$this->dbTableName}` WHERE `key`=?";
		$getData = $db->GetRow($getDataSQL, [$key]);

		if (!is_array($getData)) {
			throw new \DBException('Could not insert data into temporary table.');
		}

		return unserialize((string)$getData['data']);

	}

	/**
	 * {@inheritDoc}
	 * @see \ModulesAbstract\PluginReports\Report\Model\Builder\ArrayEmulator\GeneralInterface::getAllOrdered()
	 */
	public function getAllOrdered($direction = 'ASC')
	{

		if ($direction!='ASC' and $direction!='DESC') {
			throw new \Exception("Invalid direction - you can only set ASC/DESC. `{$direction}` was set.");
		}

		$db = \DB::getInstance();

		$getDataSQL = "SELECT data FROM `{$this->dbTableName}` ORDER BY `ordering` {$direction}";
		foreach($db->Execute($getDataSQL) as $row) {
			yield unserialize($row['data']);
		}

	}


	/**
	 * Drops the table on object destruct.
	 * {@inheritDoc}
	 * @see \ModulesAbstract\PluginReports\Report\Model\Builder\ArrayEmulator\GeneralInterface::destroy()
	 */
	public function destroy()
	{
		$db = \DB::getInstance();

		$dropTblSQL = "DROP TEMPORARY TABLE `{$this->dbTableName}`";
		$dropTblEx = $db->Execute($dropTblSQL);

		if (!$dropTblEx) {
			throw new \DBException('Could not drop temporary table.');
		}
	}

}