<?php
/**
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Cloud
 * @subpackage DocumentService
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */

require_once 'Zend/Cloud/DocumentService/QueryAdapter.php';

/**
 * Generic query object
 *
 * Aggregates operations in an array of clauses, where the first element
 * describes the clause type, and the next element describes the criteria.
 *
 * @category   Zend
 * @package    Zend_Cloud
 * @subpackage DocumentService
 * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Cloud_DocumentService_Query
    implements Zend_Cloud_DocumentService_QueryAdapter
{
    /**
     * Known query types
     */
    const QUERY_SELECT  = 'select';
    const QUERY_FROM    = 'from';
    const QUERY_WHERE   = 'where';
    const QUERY_WHEREID = 'whereid'; // request element by ID
    const QUERY_LIMIT   = 'limit';
    const QUERY_ORDER   = 'order';

    /**
     * Clause list
     *
     * @var array
     */
    protected $_clauses = [];

    /**
     * Generic clause
     *
     * You can use any clause by doing $query->foo('bar')
     * but concrete adapters should be able to recognise it
     *
     * The call will be iterpreted as clause 'foo' with argument 'bar'
     *
     * @param  string $name Clause/method name
     * @param  mixed $args
     * @return Zend_Cloud_DocumentService_Query
     */
    public function __call($name, $args)
    {
        $this->_clauses[] = [strtolower($name), $args];
        return $this;
    }

    /**
     * SELECT clause (fields to be selected)
     *
     * @param  null|string|array $select
     * @return Zend_Cloud_DocumentService_Query
     */
    public function select($select)
    {
        if (empty($select)) {
            return $this;
        }
        if (!is_string($select) && !is_array($select)) {
            require_once 'Zend/Cloud/DocumentService/Exception.php';
            throw new Zend_Cloud_DocumentService_Exception("SELECT argument must be a string or an array of strings");
        }
        $this->_clauses[] = [self::QUERY_SELECT, $select];
        return $this;
    }

    /**
     * FROM clause
     *
     * @param string $name Field names
     * @return Zend_Cloud_DocumentService_Query
     */
    public function from($name)
    {
        if(!is_string($name)) {
            require_once 'Zend/Cloud/DocumentService/Exception.php';
            throw new Zend_Cloud_DocumentService_Exception("FROM argument must be a string");
        }
        $this->_clauses[] = [self::QUERY_FROM, $name];
        return $this;
    }

    /**
     * WHERE query
     *
     * @param string $cond Condition
     * @param array $args Arguments to substitute instead of ?'s in condition
     * @param string $op relation to other clauses - and/or
     * @return Zend_Cloud_DocumentService_Query
     */
    public function where($cond, $value = null, $op = 'and')
    {
        if (!is_string($cond)) {
            require_once 'Zend/Cloud/DocumentService/Exception.php';
            throw new Zend_Cloud_DocumentService_Exception("WHERE argument must be a string");
        }
        $this->_clauses[] = [self::QUERY_WHERE, [$cond, $value, $op]];
        return $this;
    }

    /**
     * Select record or fields by ID
     *
     * @param  string|int $value Identifier to select by
     * @return Zend_Cloud_DocumentService_Query
     */
    public function whereId($value)
    {
        if (!is_scalar($value)) {
            require_once 'Zend/Cloud/DocumentService/Exception.php';
            throw new Zend_Cloud_DocumentService_Exception("WHEREID argument must be a scalar");
        }
        $this->_clauses[] = [self::QUERY_WHEREID, $value];
        return $this;
    }

    /**
     * LIMIT clause (how many items to return)
     *
     * @param  int $limit
     * @return Zend_Cloud_DocumentService_Query
     */
    public function limit($limit)
    {
        if ($limit != (int) $limit) {
            require_once 'Zend/Cloud/DocumentService/Exception.php';
            throw new Zend_Cloud_DocumentService_Exception("LIMIT argument must be an integer");
        }
        $this->_clauses[] = [self::QUERY_LIMIT, $limit];
        return $this;
    }

    /**
     * ORDER clause; field or fields to sort by, and direction to sort
     *
     * @param  string|int|array $sort
     * @param  string $direction
     * @return Zend_Cloud_DocumentService_Query
     */
    public function order($sort, $direction = 'asc')
    {
        $this->_clauses[] = [self::QUERY_ORDER, [$sort, $direction]];
        return $this;
    }

    /**
     * "Assemble" the query
     *
     * Simply returns the clauses present.
     *
     * @return array
     */
    public function assemble()
    {
        return $this->getClauses();
    }

    /**
     * Return query clauses as an array
     *
     * @return array Clauses in the query
     */
    public function getClauses()
    {
         return $this->_clauses;
    }
}
