<?php

namespace TdySports\Table;

use TdySports\Model;
use TdyCommons\Table\Table;
use Zend\Db\ResultSet\HydratingResultSet;
use Zend\Db\Sql\Predicate;
use Zend\Db\Sql\Select;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Where;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Paginator\Paginator;

/**
 * Class Statuses
 *
 * @package TdySports\Table
 *
 * @author  James Lloyd Atwil <james@nadows.com>
 */
class Statuses extends Table
{

    /**
     * @var array
     */
    protected $conditions;

    /**
     * @param \Zend\Db\TableGateway\TableGateway $tableGateway
     * @param array                              $columns
     * @param array                              $conditions
     */
    public function __construct($tableGateway, $columns, $conditions)
    {
        parent::__construct($tableGateway, $columns);
        $this->conditions = $conditions;
    }

    /**
     * @param string $q
     * @param array  $exclusion
     * @param array  $filters
     * @param array  $sort
     * @param bool   $paginated
     *
     * @return bool|HydratingResultSet|Paginator
     */
    public function fetch($q = '', $exclusion = [], $filters = [], $sort = [], $paginated = false)
    {
        $this->getLogger()->debug($this->indent . 'Statuses::fetch() start.');

        $select = new Select();
        $select->from($this->getTableGateway()->getTable());
        $conditions = [];

        $where = new Where([]);
        $where->addPredicate(new Predicate\Expression($this->conditions['list-id']['key'] . ' = ?', $this->conditions['list-id']['value']));
        $conditions[] = $where;

        $where = new Where([]);
        $where->addPredicate(new Predicate\Expression('is_active = ?', 1));
        $conditions[] = $where;

        if (!empty($q)) {
            $where = new Where([], Predicate\PredicateSet::OP_OR);
            $where->addPredicate(new Predicate\Like($this->columns['slug'], '%' . $q . '%'));
            $where->addPredicate(new Predicate\Like($this->columns['name'], '%' . $q . '%'));
            $conditions[] = $where;
        }

        if (!empty($filters)) {
            $where = new Where([]);
            foreach ($filters as $k => $v) {
                if (is_array($v)) {
                    $where->addPredicate(new Predicate\In($k, $v));
                } else {
                    $where->addPredicate(new Predicate\Expression($k . ' = ?', $v));
                }
            }
            $conditions[] = $where;
        }

        if (!empty($exclusion)) {
            $where = new Where([]);
            $where->addPredicate(new Predicate\NotIn('id', $exclusion));
            $conditions[] = $where;
        }

        $select->where($conditions, Predicate\PredicateSet::OP_AND);

        if (!is_null($sort)) {
            if ($this->isSortEmpty($sort)) {
                $select->order([
                    $this->columns['id'] => 'ASC',
                    $this->columns['name']     => 'ASC',
                ]);
            } else {
                $select->order($sort);
            }
        } else {
            $select->order($sort);
        }

        $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'SQL Statement: ' . $select->getSqlString($this->getAdapter()->getPlatform()));

        $resultSet = new HydratingResultSet();
        $resultSet->setObjectPrototype(new Model\Status());

        if ($paginated) {
            $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Is Paginable: YES');

            $paginatorAdapter = new DbSelect($select, $this->getTableGateway()->getSql(), $resultSet);
            $paginator        = new Paginator($paginatorAdapter);

            $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Returns Paginator instance.');
            $this->getLogger()->debug($this->indent . 'Statuses::fetch() end.');

            return $paginator;
        } else {
            $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Is Paginable: NO');

            $sql       = new Sql($this->tableGateway->getAdapter());
            $statement = $sql->prepareStatementForSqlObject($select);

            $results = $statement->execute();
            $resultSet->initialize($results);

            if (!$resultSet) {
                $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Returns FALSE');
                $this->getLogger()->debug($this->indent . 'Statuses::fetch() end.');

                return false;
            } else {
                $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Returns HydratingResultSet instance.');
                $this->getLogger()->debug($this->indent . 'Statuses::fetch() end.');

                return $resultSet;
            }
        }
    }

    /**
     * Returns the Status.
     *
     * @param int $id
     *
     * @return Model\Status|null
     * @throws \Exception
     */
    public function get($id)
    {
        $rowset = $this->tableGateway->select([
            $this->columns['id']                => $id,
            $this->conditions['list-id']['key'] => $this->conditions['list-id']['value']
        ]);

        $row = $rowset->current();
        if (!$row) {
            return null;
        }

        return $row;
    }

    /**
     * @param Model\Status $status
     *
     * @return Model\Status
     * @throws \Exception
     */
    public function save(Model\Status $status)
    {
        $this->getLogger()->debug($this->indent . 'Statuses::save() start.');
        $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Method is not implemented. Tossed an exception grenade.');
        $this->getLogger()->debug($this->indent . 'Statuses::save() end.');
        throw new \Exception('Method is not implemented');
    }

    /**
     * @param Model\Status $status
     *
     * @throws \Exception
     */
    public function delete(Model\Status $status)
    {
        $this->getLogger()->debug($this->indent . 'Statuses::delete() start.');
        $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Method is not implemented. Tossed an exception grenade.');
        $this->getLogger()->debug($this->indent . 'Statuses::delete() end.');
        throw new \Exception('Method is not implemented');
    }

    /**
     * Restore Sport to the table. Sets the Sport to active.
     *
     * @param Model\Status $status
     *
     * @throws \Exception
     */
    public function restore(Model\Status $status)
    {
        $this->getLogger()->debug($this->indent . 'Statuses::restore() start.');
        $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Method is not implemented. Tossed an exception grenade.');
        $this->getLogger()->debug($this->indent . 'Statuses::restore() end.');
        throw new \Exception('Method is not implemented');
    }

    /**
     * Permanently delete the Status.
     *
     * @param Model\Status $status
     *
     * @throws \Exception
     */
    public function purge(Model\Status $status)
    {
        $this->getLogger()->debug($this->indent . 'Statuses::purge() start.');
        $this->getLogger()->debug($this->indent . self::LOGGER_INDENT . 'Method is not implemented. Tossed an exception grenade.');
        $this->getLogger()->debug($this->indent . 'Statuses::purge() end.');
        throw new \Exception('Method is not implemented');

    }

}
