<?php
/**
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage db
 * @since 2011-11-15
 */

/**
 * @property MongoDriver $driver
 * @property MongoCursor $result
 */
class MongoStatement extends DbStatement
{

    protected $insertId = false;

    public function count()
    {
        if ($this->result instanceof MongoCursor) {
            return $this->result->count();
        } else {
            throw new GeneralException('MongoStatement error. Impossible count result of opened cursor.');
        }
    }

    public function order($sort = array())
    {
        if ($this->result instanceof MongoCursor) {
            $this->result->sort($sort);
            return $this;
        } else {
            throw new GeneralException('MongoStatement error. Impossible order results of opened cursor.');
        }
    }

    public function skip($skip = 0)
    {
        if ($this->result instanceof MongoCursor) {
            $this->result->skip($skip);
            return $this;
        } else {
            throw new GeneralException('MongoStatement error. Impossible skip results of opened cursor.');
        }
    }

    public function limit($limit = 0)
    {
        if ($this->result instanceof MongoCursor) {
            $this->result->limit($limit);
            return $this;
        } else {
            throw new GeneralException('MongoStatement error. Impossible limit results of opened cursor.');
        }
    }

    public function fetch($style = Db::FETCH_OBJ)
    {
        if (!$this->result) {
            return false;
        }
        if (is_array($this->result) && isset($this->result['retval'])) {
            return $this->result['retval'];
        }

        switch ($style) {
            case Db::FETCH_OBJ:
                $row = $this->fetchObject();
                break;
            case Db::FETCH_ASSOC:
                if ($this->result instanceof MongoCursor) {
                    $row = $this->result->getNext();
                } else {
                    $row = $this->result;
                }
                break;
            default:
                throw new GeneralException('Invalid fetch mode "' . $style . '" specified');
        }
        return $row;
    }

    public function fetchObject($class = 'stdClass')
    {
        if ($this->result instanceof MongoCursor) {
            $row = $this->result->getNext();
        } else {
            $row = $this->result;
        }
        if (is_array($row) && isset($row['_id'])) {
            $row = new ArrayObject($row, ArrayObject::ARRAY_AS_PROPS);
        } else {
            $row = false;
        }
        return $row;
    }

    public function close()
    {
        $this->result = null;
    }

    /**
     * @return int
     */
    public function affectedRows()
    {
        if (is_array($this->result)) {
            if (isset($this->result['ok']) && $this->result['ok'] == 1) {
                if (isset($this->result['n'])) {
                    return $this->result['n'];
                }
            } else {
                return false;
            }
        } elseif (is_int($this->result) || $this->result instanceof MongoId) {
            return $this->result;
        }
        return false;
    }

    public function numRows()
    {
        if ($this->result instanceof MongoCursor) {
            return $this->result->count();
        } else {
            return false;
        }
    }

    /**
     * @param MongoDbCommand $request
     * @throws GeneralException
     * @return bool
     */
    protected function driverExecute($request)
    {
        $this->result = false;
        $mongo = $this->driver->getConnection();
        if ($mongo instanceof Mongo) {
            if (Config::get('PROFILER_DETAILS')) {
                $profiler = Profiler::getInstance()->profilerCommand('Mongo', $request);
                $result = $request->execute();
                $profiler->end();
            } else {
                $result = $request->execute();
            }
            if ($result === false) {
                throw new GeneralException('MongoDB request error.');
            }
            if ($result instanceof MongoCursor || is_array($result)) {
                $this->result = $result;
                if (is_array($result) && isset($result['value'])) {
                    $this->result = $result['value'];
                }
                if (is_array($result) && isset($result['values'])) {
                    $this->result = $result['values'];
                }
                if (is_array($result) && isset($result['upserted'])) {
                    $this->result = $result['n'] > 1 ? $result['n'] : $result['upserted'];
                }
            } elseif (is_int($result)) {
                $this->result = $result;
            }
            if ($request instanceof InsertMongoCommand) {
                $this->insertId = $request->getInsertId();
            }
            return true;
        } else {
            throw new GeneralException('No connection to MongoDB server.');
        }
    }

    public function bindParam($param, &$value)
    {
        $this->request->bindParam($param, $value);
    }

    protected function assemble()
    {
        return $this->request;
    }

    public function getInsertId()
    {
        return $this->insertId;
    }
}