<?php !defined('APP_DIR') ? die('acceess not defined') : '';
class DAO {
    /**
     * 数据库服务器配置选项 读写分离主库
     *
     * @var string
     */
    public $dbserver = 'default';
    
    /**
     * 数据库服务器配置选项 读写分离从库
     *
     * @var unknown_type
     */
    public $dbserver_read = NULL;
    
    /**
     * 所在库名
     *
     * @var string
     */
    public $database = 'house';
    
    /**
     * DAO对象对应的表名
     *
     * @var string
     */
    public $table = null;
    
    /**
     * 表主键的字段名
     *
     * @var string
     */
    public $primaryKey = 'id';
    
    /**
     * 删除标记
     *
     * @var unknown_type
     */
    public $effect_flag = 'isdel';
    
    /**
     * 添加时间的字段
     *
     * @var string
     */
    public $add_time = 'create_time';
    
    /**
     * 更新时间的字段
     *
     * @var string
     */
    public $upd_time = 'update_time';
    
    /**
     * 数据库的连接 读写分离主库
     *
     * @var object
     */
    public $db = null;
    
    /**
     * 数据库的连接 读写分离从库
     *
     * @var unknown_type
     */
    public $db_read = NULL;
    
    /**
     * 最新一次数据库查询的SQL
     *
     * @var string
     */
    public $last_sql = '';
    
    /**
     * 表包含的字段
     *
     * @var array
     */
    public $fields = array();
    
    /**
     * DAO对象连接池
     *
     * @var array
     */
    static public $instance = array();
    
    /**
     * 初始化函数
     *
     */
    public function __construct( $dbserver=null, $database=null, $table=null, $primaryKey=null, $dbserver_read=null ){
        if($dbserver){
            $this->dbserver = $dbserver;
        }
        if($database){
            $this->database = $database;
        }
        if($table){
            $this->table = $table;
        }
        if($primaryKey){
            $this->primaryKey = $primaryKey;
        }
        if ($dbserver_read){
            $this->dbserver_read = $dbserver_read;
        }
        
        //获取数据库连接
        $this->fields = $this->_dbRead()->get_table_fields($this->database, $this->table);
       
    }
    
    /**
     * DAO的连接接口
     *
     * @param string $datebase
     * @return object
     */
    public function instance( $daoname, $dbserver=null, $database=null, $table=null, $primaryKey=null, $dbserver_read=null ){
        if ( isset(self::$instance[$daoname]) ) {
            return self::$instance[$daoname];
        }else {
            $_dao_obj = 'DAO_'.$daoname;
            if ( class_exists($_dao_obj) ){
                self::$instance[$daoname] = new $_dao_obj();
            }else {
                self::$instance[$daoname] = new DAO( $dbserver, $database, $table, $primaryKey );
            }
            return self::$instance[$daoname];
        }
    }
    
    /**
     * 获取数据库读连接资源
     *
     */
    public function _dbRead(){
        if ($this->dbserver_read){
            $this->db_read = db::instance($this->dbserver_read);
        }else {
            $this->db_read = db::instance($this->dbserver);
        }
        return $this->db_read;
    }
    
    /**
     * 获取数据库写连接资源
     *
     */
    public function _db(){
        $this->db = db::instance($this->dbserver);
        return $this->db;
    }
    
    /**
     * 根据查询条件获取单条记录
     *
     * @param int|array $condition     
     * @return array
     *
     */
    public function get($condition){
        if (!is_array($condition)) {
            $query_struct = array(
                'where' => array(
                    "{$this->primaryKey}" => $condition
                ),
            );
        }else {
            $query_struct = $condition;
        }
		//print_r($condition);
        if ( !isset($query_struct['where'][$this->effect_flag]) && $this->effect_flag ) {
        	$query_struct['where'][$this->effect_flag] = 0;
        }
        $sql = $this->_compile($this->database.'.'.$this->table, 'SELECT', $query_struct);
        //die($sql);
        $data = $this->_dbRead()->get($sql);
        if (!empty($data) && method_exists($this, '_outputer')) {
        	$data = $this->_outputer($data);
        }
        return $data;
    }
    
    /**
     * 获取满足条件的所有数据
     *
     * @param array $query_struct
     * @return array
     */
    public function get_all($query_struct, $key_field = NULL){
        if ( !isset($query_struct['where'][$this->effect_flag]) && $this->effect_flag  ) {
        	$query_struct['where'][$this->effect_flag] = 0;
        }
        $sql = $this->_compile($this->database.'.'.$this->table, 'SELECT', $query_struct);
        //echo $sql;die();

        $data = $this->_dbRead()->get_all($sql, $key_field);
		//print_r($data);
        if (!empty($data) && method_exists($this, '_outputer')) {
            foreach ($data as $key => $value){
                $data[$key] = $this->_outputer($value);
            }
        }
        return $data;
    }
    
    /**
     * 根据SQL获取满足条件的所有数据
     *
     * @param unknown_type $sql
     * @param unknown_type $key_field
     * @return unknown
     */
    public function get_all_by_sql($sql, $key_field = NULL){
        $data = $this->_dbRead()->get_all($sql, $key_field);
        if (!empty($data) && method_exists($this, '_outputer')) {
            foreach ($data as $key => $value){
                $data[$key] = $this->_outputer($value);
            }
        }
        return $data;
    }
    
    /**
     * 获取满足条件的数量
     *
     * @param array $query_struct
     * @return int
     */
    public function count($query_struct){
        if ( !isset($query_struct['where'][$this->effect_flag]) && $this->effect_flag  ) {
        	$query_struct['where'][$this->effect_flag] = 0;
        }
        $sql = $this->_compile($this->database.'.'.$this->table, 'COUNT', $query_struct);
		//echo $sql;
		//echo "<br/>";
		$data = $this->_dbRead()->count($sql);
        return $data;
    }

	public function get_sqlstr($query_struct){
        if ( !isset($query_struct['where'][$this->effect_flag]) && $this->effect_flag  ) {
        	$query_struct['where'][$this->effect_flag] = 0;
        }
		
        $sql = $this->_compile($this->database.'.'.$this->table, 'COUNT', $query_struct);
		//echo $sql;
       
        return $sql;
    }
    
    /**
     * 添加新数据
     *
     * @param unknown_type $data
     */
    public function add($data){
        $sql = $this->_compile($this->database.'.'.$this->table, 'INSERT', $data);
        $_data = $this->_db()->save($sql);
        return $_data;
    }
    
    public function replace($data){
        $sql = $this->_compile($this->database.'.'.$this->table, 'REPLACE', $data);
        $_data = $this->_db()->save($sql);
        return $_data;
    }
    
    public function edit($data){
        if (!isset( $data[$this->primaryKey]) ) {
        	return false;
        }
        $id = $data[$this->primaryKey];
        unset($data[$this->primaryKey]);
        $query_struct = array(
            'where' => array(
                "$this->primaryKey" => $id
            ),
            'set' => $data,
        );
        $sql = $this->_compile($this->database.'.'.$this->table, 'UPDATE', $query_struct);

        $_data = $this->_db()->save($sql);
        return $_data;
    }
    
    /**
     * 删除数据
     *
     * @param int $id
     * @return bool
     */
    public function delete($id){
        $query_struct = array(
            'where' => array(
                "$this->primaryKey" => $id
            ),
            'set' => array(
                "$this->effect_flag" => 1,
            ),
        );
        $sql = $this->_compile($this->database.'.'.$this->table, 'UPDATE', $query_struct);
        $_data = $this->_db()->save($sql);
        return $_data;
    }
    
    /**
     * 物理删除
     *
     * @param int $id
     * @return bool
     */
    public function remove($id){
        $query_struct = array(
            'where' => array(
                "$this->primaryKey" => $id
            ),
        );
        $sql = $this->_compile($this->database.'.'.$this->table, 'delete', $query_struct);
        $_data = $this->_db()->delete($sql);
        return $_data;
    }
    
    /**
     * 物理删除
     *
     * @param int $id
     * @return bool
     */
    public function removeWhere($where){
        $query_struct = array(
            'where' => $where
        );
        $sql = $this->_compile($this->database.'.'.$this->table, 'delete', $query_struct);
        $_data = $this->_db()->delete($sql);
        return $_data;
    }
    
    /**
     * 直接执行SQL，返回执行的结果
     *
     * @param string $sql
     * @return mixed
     */
    public function query($sql){
        $_data = $this->_db()->query($sql);
        return $_data;
    }
    
    /**
     * 自动创建DAO
     *
     */
    public function auto_creat_dao(){
        $sql =  'SHOW TABLES';
        $rows = $this->_dbRead()->fetch_arrays($sql);
        if (!$rows) {
        	return false;
        }
        $dao_dir = ROOT_DIR.'/library/dao/';
        foreach ($rows as $_row){
            $table_name = $_row[0];
            $file_path = $dao_dir.$table_name.'.php';
            //tool::mkdirs(dirname($file_path));
            $dao_str = "<?php !defined('APP_DIR') ? die('acceess not defined') : '';
class DAO_$table_name extends DAO {
    /**
     * DAO对象对应的表名
     *
     * @var string
     */
    public \$table = '$table_name';
}
?>";
            @file_put_contents($file_path,$dao_str);
        }
        return true;
    }
    
    /**
     * 编译参数，变成可执行SQL
     *
     * @param string $table
     * @param string $method
     * @param array $query_struct
     * @return string
     */
    private function _compile($table,$method='SELECT',$query_struct=array()){
        $sql = '';
        $method = strtoupper($method);
        switch ($method){
            case 'SELECT':
                $fields = $this->_compile_fields($query_struct);
                $where  = $this->_compile_where($query_struct);
                $orderby= $this->_compile_orderby($query_struct);
                $limit  = $this->_compile_limit($query_struct);
                $sql = "SELECT {$fields} FROM {$table} WHERE {$where} {$orderby} {$limit}";
                //echo $sql.'<br>';
                break;
                
            case 'DELETE':
                $where  = $this->_compile_where($query_struct);
                $limit  = $this->_compile_limit($query_struct);
                $sql = "DELETE FROM {$table} WHERE {$where} {$limit}";
                break;
                
            case 'UPDATE':
                $set    = $this->_compile_set($query_struct);
                $where  = $this->_compile_where($query_struct);
                $limit  = $this->_compile_limit($query_struct);
                $sql = "UPDATE {$table} SET {$set} WHERE {$where} {$limit}";
                break;
                
            case 'COUNT':
                $where  = $this->_compile_where($query_struct);
                $sql = "SELECT COUNT(*) FROM {$table} WHERE {$where}";
                break;
                
            case 'INSERT':
                $data = $this->_compile_data($query_struct);
                $sql = "INSERT INTO {$table} {$data}";
                break;
                
            case 'REPLACE':
                $data = $this->_compile_data($query_struct);
                $sql = "REPLACE INTO {$table} {$data}";
                break;
        }
        $this->last_sql = $sql;
        
        return $sql;
    }
    
    /**
     * 编译要查询的字段
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_fields($query_struct){
        if ( !isset($query_struct['fields']) || empty($query_struct['fields']) ) {
            return '*';
        }elseif ( is_array($query_struct['fields']) ){
            $fields = $query_struct['fields'];
            foreach ($fields as $key => $val){
                if (!in_array($val, $this->fields)) {
                	unset($fields[$key]);
                }
            }
            return implode(',',$fields);
        }else {
            return $query_struct['fields'];
        }
    }
    
    /**
     * 编译查询条件
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_where($query_struct){
        $where = '';
        if ( !isset($query_struct['where']) || empty($query_struct['where']) ) {
            $where = '1';
            return $where;
        }
        $_where = $query_struct['where'];
        foreach ($_where as $key => $value){
            $case = 'AND';
            if( is_int($key) ){
                $case = 'SQL';
            }elseif ( preg_match('/^or\s([a-zA-Z0-9_]+)/i', $key, $match) ) {
            	$case = 'OR';
            	$_key = $match[1];
            }elseif ( preg_match('/([a-zA-Z0-9_]+)\slike/i',$key, $match) ){
                $case = 'LIKE';
                $_key = $match[1];
            }elseif ( preg_match('/([a-zA-Z0-9_]+)\s!=/i',$key, $match) ){
                $case = '!=';
                $_key = $match[1];
            }elseif (preg_match('/([a-zA-Z0-9_]+)\s(>=|>|<=|<)/i',$key, $match)){
                $case = 'compare';
                $_key = $match[1];
                $_sign = $match[2];
            }else {
                $_key = $key;
            }
            //过滤非表内字段的查询
            if ( isset($_key) && !in_array($_key, $this->fields) ) {
                continue;
            }
            switch ($case){
                case 'AND':
                    if ( is_array($value) ) {
                    	$value = "('" . implode("', '",$value) . "')";
                    	$where .= $where=='' ? "`$_key` IN $value" : " AND `$_key` IN $value";
                    }else {
                        //$value = mysql_escape_string($value);
                        if (is_int($value) || is_float($value)){
                            $where .= $where=='' ? "`$_key` = $value" : " AND `$_key` = $value";
                        }else {
                            $where .= $where=='' ? "`$_key` = '$value'" : " AND `$_key` = '$value'";
                        }
                    }
                    break;
                case 'SQL':
                    if (is_array($value)) {
                    	die('SQL string can not be array');
                    }
                    $where .= $where=='' ? "$value" : " $value";
                    break;
                case 'OR':
                    if ( is_array($value) ) {
                    	$value = "('" . implode("', '",$value) . "')";
                    	$where .= $where=='' ? "`$_key` IN $value" : " OR `$_key` IN $value";
                    }else {
                        //$value = mysql_escape_string($value);
                        $where .= $where=='' ? "`$_key` = '$value'" : " OR `$_key` = '$value'";
                    }
                    break;
                case 'LIKE':
                    if (is_array($value)) {
                    	die('SQL like can not be array');
                    }
                    //$value = mysql_escape_string($value);
                    $where .= $where=='' ? "`$_key` LIKE '%$value%'" : " AND `$_key` LIKE '%$value%'";
                    break;
                case '!=':
                    if ( is_array($value) ) {
                    	$value = "('" . implode("', '",$value) . "')";
                    	$where .= $where=='' ? "`$_key` NOT IN $value" : " AND `$_key` NOT IN $value";
                    }else {
                        //$value = mysql_escape_string($value);
                        if (is_int($value) || is_float($value)){
                            $where .= $where=='' ? "`$_key` != $value" : " AND `$_key` != $value";
                        }else {
                            $where .= $where=='' ? "`$_key` != '$value'" : " AND `$_key` != '$value'";
                        }
                    }
                    break;
                case 'compare':
                    if (is_array($value)) {
                        die('SQL compare can not be array');
                    }
                    if (is_int($value) || is_float($value)){
                        $where .= $where=='' ? "`$_key` $_sign $value" : " AND `$_key` $_sign $value";
                    }else {
                        $where .= $where=='' ? "`$_key` $_sign '$value'" : " AND `$_key` $_sign '$value'";
                    }
                    break;
            }
        }
        return $where;
    }
    
    /**
     * 编译需要修改的值
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_set($query_struct){
        $set = '';
        if ( !isset($query_struct['set']) || empty($query_struct['set']) ) {
            die('No Data To SET');
        }
        if (isset($this->upd_time)) {
        	$query_struct['set'][$this->upd_time] = time();
        }
        $set_arr = $query_struct['set'];
        if(method_exists($this, '_inputer')){
            $set_arr = $this->_inputer($set_arr);
        }
        foreach ($set_arr as $key => $value){
            if ( in_array($key, $this->fields)) {
            	//$value = mysql_escape_string($value);
                $set .= $set=='' ? "`$key`='$value'" : ", `$key`='$value'";
            }
        }
        return $set;
    }
    
    /**
     * 编译排序
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_orderby($query_struct){
        $orderby = '';
        if ( !isset($query_struct['orderby']) || empty($query_struct['orderby']) ) {
            return $orderby;
        }
        $orderby = '';
        $orderby_arr = $query_struct['orderby'];
        foreach ($orderby_arr as $key => $value){
            if(in_array($key, $this->fields)) {
            	$orderby .= $orderby=='' ? "`$key` $value" : ", `$key` $value";
            }
        }
        $orderby = "ORDER BY $orderby";
        return $orderby;
    }
    
    /**
     * 编译查询个数
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_limit($query_struct){
        $limit = '';
        if ( !isset($query_struct['limit']) || empty($query_struct['limit']) ) {
            return $limit;
        }
        if (!is_array($query_struct['limit'])) {
            $limit = "LIMIT {$query_struct['limit']}";
            return $limit;
        }
        $limit = isset($query_struct['limit'][1]) ? "LIMIT {$query_struct['limit'][0]}, {$query_struct['limit'][1]}" : "LIMIT {$query_struct['limit'][0]}";
        //echo $limit;die();
        return $limit;
    }
    
    /**
     * 编译要插入的数据
     *
     * @param array $query_struct
     * @return string
     */
    private function _compile_data($data){
        if(method_exists($this, '_inputer')){
            $data = $this->_inputer($data);
        }
        //$date = date('Y-m-d H:i:s');
        $date = time();
        if (isset($this->upd_time)) {
        	$data[$this->upd_time] = $date;
        }
        if (isset($this->add_time)) {
        	$data[$this->add_time] = $date;
        }
        //die();
        foreach ($data as $key => $value){
            if (!in_array($key, $this->fields)) {
            	unset($data[$key]);
            }else {
                $data[$key] = $value;//mysql_escape_string($value);
            }
        }
        $data_key_arr = array_keys($data);
        $data_key = '(`' . implode('`,`', $data_key_arr) . '`)';
        $data_val = "('" . implode("', '", $data) . "')";
        return "$data_key VALUES $data_val";
    }
}
?>