<?php

/** Power By Tmac PHP MVC framework
 *  $Author: zhangwentao $
 *  $Id: Database.class.php 48 2011-12-02 11:10:31Z zhangwentao $
 */
abstract class Database
{

    /**
     * 数据库连接标识
     * 
     * @var resource
     */
    protected $link;

    /**
     * 执行SQL语句的次数
     *
     * @var integer
     * @access protected
     */
    protected $queryNum = 0;

    /**
     * 缓存实例
     *
     * @var objeact
     * @access protected
     */
    protected $cache;
    protected $is_cache = false;

    /**
     * 上一次事物是否执行成功
     *
     * @var bool
     * @access protected
     */
    protected $success = true;

    /**
     * 连接数据库
     */
    public abstract function connect();

    /**
     * 选择数据库
     *
     * @param string $database
     */
    public abstract function selectDatabase($database);

    /**
     * 执行一条SQL查询语句 返回资源标识符
     * 
     * @param string $sql
     */
    public abstract function query($sql);

    /**
     * 执行一条SQL语句 返回似乎执行成功
     *
     * @param string $sql
     */
    public abstract function execute($sql);

    /**
     * 从结果集中取出数据
     * 
     * @param resource $rs
     */
    protected abstract function fetch($rs);

    /**
     * 执行INSERT命令.返回AUTO_INCREMENT
     * 返回0为没有插入成功
     *
     * @param string $sql  SQL语句
     * @access public
     * @return integer
     */
    public abstract function insert($sql);

    /**
     * 释放结果集
     *
     * @param resource $rs 结果集
     * @access protected
     * @return boolean
     */
    protected abstract function free($rs);

    /**
     * 关闭数据库
     *
     * @access public
     * @return boolean
     */
    public abstract function close();

    /**
     * 获取错误信息
     *
     * @return void
     * @access public
     */
    public abstract function getError();

    /**
     * 获取执行SQL语句的个数
     *
     * @access public
     * @return integer
     */
    public function getQueryNum()
    {
        return $this->queryNum;
    }

    /**
     * 获取缓存实例
     *
     * @access protected
     * @final
     */
    protected final function getCache()
    {
        $this->cache = CacheDriver::getInstance();
        $this->is_cache = true;
    }

    /**
     * 得到结果集的第一个数据
     *
     * @param string $sql   SQL语句
     * @access public
     * @return mixed
     */
    public function getOne($sql)
    {
        if (!$rs = $this->query($sql)) {
            return false;
        }
        $row = $this->fetch($rs);
        $this->free($rs);
        return is_array($row) ? array_shift($row) : $row;
    }

    /**
     * 以缓存的方式获取结果集的第一个数据
     *
     * @param string $sql   SQL语句
     * @param int $expire   缓存时间
     * @return mixed
     * @access public
     */
    public function cacheGetOne($sql, $expire = 60)
    {
        $this->is_cache OR $this->getCache();
        $value = $this->cache->get($sql);
        if ($value === false) {
            $value = $this->getOne($sql);
            $this->cache->set($sql, $value, $expire);
        }
        return $value;
    }

    /**
     * 返回结果集的一行
     *
     * @param string $sql  SQL语句
     * @access public
     * @return array
     */
    public function getRow($sql)
    {
        if (!$rs = $this->query($sql)) {
            return false;
        }
        $row = $this->fetch($rs);
        $this->free($rs);
        return $row;
    }

    /**
     * 以缓存的方式取得结果集的第一行
     *
     * @param string $sql   SQL语句
     * @param int $expire   缓存时间
     * @return array
     * @access public
     */
    public function cacheGetRow($sql, $expire = 60)
    {
        $this->is_cache OR $this->getCache();
        $value = $this->cache->get($sql);
        if ($value === false) {
            $value = $this->getRow($sql);
            $this->cache->set($sql, $value, $expire);
        }
        return $value;
    }

    /**
     * 返回所有结果集
     *
     * @param string $sql   SQL语句
     * @access public
     * @return mixed
     */
    public function getAll($sql)
    {
        if (!$rs = $this->query($sql)) {
            return false;
        }
        $all_rows = array();
        while ($rows = $this->fetch($rs)) {
            $all_rows[] = $rows;
        }
        $this->free($rs);
        return $all_rows;
    }

    /**
     * 以缓存的方式取得所有结果集
     *
     * @param string $sql   SQL语句
     * @param int $expire   缓存时间
     * @return array
     * @access public
     */
    public function cacheGetAll($sql, $expire = 60)
    {
        $this->is_cache OR $this->getCache();
        $value = $this->cache->get($sql);
        if ($value === false) {
            $value = $this->getAll($sql);
            $this->cache->set($sql, $value, $expire);
        }
        return $value;
    }

    /**
     * 取所有行的第一个字段信息
     *
     * @param string $sql   SQL语句
     * @return array
     * @access public
     */
    function getCol($sql)
    {
        $res = $this->query($sql);
        if ($res !== false) {
            $arr = array();
            while ($row = mysql_fetch_row($res)) {
                $arr[] = $row[0];
            }

            return $arr;
        } else {
            return false;
        }
    }

    /**
     * 以缓存方式取所有行的第一个字段信息
     *
     * @param string $sql   SQL语句
     * @param int $expire   缓存时间
     * @return array
     * @access public
     */
    function cachegetCol($sql, $expire = 60)
    {
        $this->is_cache OR $this->getCache();
        $value = $this->cache->get($sql);
        if ($value === false) {
            $value = $this->getCol($sql);
            $this->cache->set($sql, $value, $expire);
        }
        return $value;
    }

    /**
     * insert update For Mysql
     * @param <type> $table
     * @param <type> $field_values
     * @param <type> $mode
     * @param <type> $where
     * @return <type>
     */
    function autoExecute($table, $field_values, $mode = 'INSERT', $where = '')
    {
        $field_names = $this->getCol('DESC ' . $table);

        $sql = '';
        if ($mode == 'INSERT') {
            $fields = $values = array();
            foreach ($field_names AS $value) {
                if (array_key_exists($value, $field_values) == true) {
                    $fields[] = '`' . $value . '`';
                    $values[] = "'" . $field_values[$value] . "'";
                }
            }

            if (!empty($fields)) {
                $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
            }
        } else {
            $sets = array();
            foreach ($field_names AS $value) {
                if (array_key_exists($value, $field_values) == true) {
                    $sets[] = '`' . $value . "` = '" . $field_values[$value] . "'";
                }
            }

            if (!empty($sets)) {
                $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $sets) . ' WHERE ' . $where;
            }
        }

        if ($sql) {
            return $this->query($sql);
        } else {
            return false;
        }
    }

    /**
     * insert For Mysql return 有返回值 返回mysql_insert_id
     * @param <type> $table
     * @param <type> $field_values
     * @param <type> $mode
     * @param <type> $where
     * @return <type>
     */
    function autoInsertReturn($table, $field_values)
    {
        $field_names = $this->getCol('DESC ' . $table);

        $sql = '';
        $fields = $values = array();
        foreach ($field_names AS $value) {
            if (array_key_exists($value, $field_values) == true) {
                $fields[] = '`' . $value . '`';
                $values[] = "'" . $field_values[$value] . "'";
            }
        }

        if (!empty($fields)) {
            $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
        }

        if ($sql) {
            return $this->insert($sql);
        } else {
            return false;
        }
    }

    /**
     * 获取上次事物是否执行成功
     * 
     * @return bool
     */
    public function isSuccess()
    {
        return $this->success;
    }

    /**
     * DEBUG信息
     * 
     * @param string $sql
     * @param bool $success
     * @param error string
     */
    public function debug($sql, $success = true, $error = null)
    {
        global $TmacConfig;
        if ($TmacConfig['Common']['debug']) {
            $debug = Debug::getInstance();
            $debug->setSQL($sql, $success, $error);
        }
    }

}