<?php
defined( 'IN_WEB') or die( 'Include Error!');
/**
 * 
 * bcache封装类
 * @author 张奎
 * 注意事项：
 * $aKeyWhere  key条件，二维数组，即可以指定多个条件 单键多值型  
 * 			        如：array(array('id' => 1001),array('id' => 1002),array('id' => 1003)))
 * $aWhere	  附加条件，二维数组（内层数组：0字段名，1条件符，2是值），条件符（=,<>,!=,>,>=,<,<=）
 * 			        如：array(array('desc','=','4515'));
 * 
 */
class mubcache {
	/**
	 * 
	 * 表配置
	 * @var unknown_type
	 */
	private $_config;
	private $_compositeKey; //是否组合主键
	private $_keyField; //主键字段
	private $_aKeyWhere; //主键条件
	private $_keyWhereCount; //条件值的数量
	/**
	 * @var BcServer
	 */
	private $_bcServer; //BcServer对象
	/**
	 * 
	 * 构造函数
	 * @param unknown_type $config
	 * server 	bcache地址
	 * port   	bcache端口
	 * key_field	键字段名
	 * key_type  键字段类型
	 */
	public function __construct(array $config) {
		$this->_config = $config;
		$this->_keyField = $config['keyField'];
		$this->_compositeKey = $config['compositeKey'];
		$this->_keys = $config['keys'];
	}
	/**
	 * 
	 * 设置bcache服务器
	 */
	public function createBcServer() {
		$this->_bcServer = new BcServer(); //创建BcServer对象
		$code = $this->_bcServer->setAddress( $this->_config['server'], $this->_config['port'] );
		if ($code != 0) { //错误码
			$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
		}
		//设置表名
		$code = $this->_bcServer->setTablename( $this->_config['tablename'] );
		if ($code != 0) { //错误码
			$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
		}
		//设置键
		//组合主键
		if ($this->_compositeKey) {
		
		} else {
			$keyType = intval( $this->_config['keyType'] );
			if ($this->_keyWhereCount > 1) { //单键多值
				if ( $this->_keyWhereCount > 31){
					bc_set_key_value_max( 20000);
				}
				$code = $this->_bcServer->addKey( $this->_keyField, $keyType );
				if ($code != 0) {
					$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
				}
			} else { //单键单值
				if ($keyType == BC_INT_KEY) {
					$code = $this->_bcServer->intKey();
					if ($code != 0) {
						$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
					}
				} elseif ($keyType == BC_STRING_KEY) {
					$code = $this->_bcServer->stringKey();
					if ($code != 0) {
						$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
					}
				}
			}
		}
	}
	private function reset() {
		$this->_aKeyWhere = null;
		$this->_bcServer = null;
	}
	/**
	 * 
	 * 新添加数据  键-值对
	 * @param unknown_type $aFieldVal array('key'=>value, 'key'=>value)
	 * @return int
	 */
	public function insert(array $aFieldVal) {
		if (! is_array( $aFieldVal )) {
			return 0;
		}
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_INSERT ); //创建BcRequest对象

		foreach ( $aFieldVal as $field => $value ) {
			if ($field == $this->_keyField) { //主键
				$code = $req->setKey( $value );
				if ($code != 0) {
					$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
				}
			} else {
				$code = $req->set( $field, $value ); //其他字段值
				if ($code != 0) {
					$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
				}
			}
		}
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		$affected = $res->affectedRows();
		$insertId = $res->insertId();
		$this->reset();
		return ($affected && $insertId ? $insertId : $affected);
	}
	/**
	 * 
	 * 更新记录
	 * @param unknown_type $aSet		需要修改的键值对
	 * @param unknown_type $aKeyWhere	主键条件键值对
	 * @param unknown_type $aWhere		附加条件
	 * @param unknown_type $aLimit		限制记录数 array(array(1))
	 * @return int(true/false)
	 */
	public function update(array $aSet, array $aKeyWhere, array $aWhere = array(), array $aLimit = array()) {
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_UPDATE ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, $aLimit );
		foreach ( $aSet as $field => $value ) {
			$code = $req->set( $field, $value );
		}
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		return $res->affectedRows();
	}
	/**
	 * 删除记录(一次只能删除一条记录)
	 * @param unknown_type $aKeyWhere	主键条件键值对
	 * @param unknown_type $aWhere		附加条件
	 * @param unknown_type $aLimit		限制记录数
	 * @return int(0失败/1成功)
	 */
	public function delete(array $aKeyWhere, array $aWhere = array(), array $aLimit = array()) {
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_DELETE ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, $aLimit );
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		return $res->affectedRows();
	}
	/**
	 * 查询一条记录
	 * @param array $fields 	需要的字段 array( key=>value, key=>value)
	 * @param array $aKeyWhere	主键条件键值对 array( array(key=>value)))
	 * @param array $aWhere		附加条件 array
	 * @return array()
	 */
	public function getOne(array $fields, array $aKeyWhere, array $aWhere = array()) {
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_SELECT ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, array(0, 1 ) );
		foreach ( $fields as $field ) {
			$code = $req->need( $field );
			if ($code != 0) {
				$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
			}
		}
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		return $res->fetchRow( BC_FETCH_ASSOC );
	}
	/**
	 * 
	 * 查询多条记录
	 * @param array $fields 	需要的字段
	 * @param array $aKeyWhere	主键条件键值对
	 * @param array $aWhere		附加条件
	 * @param array $aLimit		限制记录数
	 */
	public function getMulti(array $fields, array $aKeyWhere, array $aWhere = array(), array $aLimit = array()) {
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_SELECT ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, $aLimit );
		foreach ( $fields as $field ) {
			$code = $req->need( $field );
			if ($code != 0) {
				$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
			}
		}
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		$result = array();
		while ( $row = $res->fetchRow( BC_FETCH_ASSOC ) ) {
			$result[] = $row;
		}
		return $result;
	}
	
	/**
	 * 统计记录数
	 * @param unknown_type $aKeyWhere
	 * @param unknown_type $aWhere
	 */
	public function count(array $aKeyWhere, array $aWhere = array()){
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_SELECT ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, array() );
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		return $res->totalRows();
	}
	/**
	 * 自增操作(int++)
	 * @param unknown_type $field  		自增字段
	 * @param unknown_type $step   		步长
	 * @param unknown_type $aKeyWhere	主键条件
	 * @param unknown_type $aWhere		附加条件
	 */
	public function inc($field, array $aKeyWhere, array $aWhere = array(), $step = 1){
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_UPDATE ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, array() );
		$req->add($field, $step);
		
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		
		return $res->affectedRows();
	}
	
	/**
	 * 自减操作(int--)
	 * @param unknown_type $field  		自增字段
	 * @param unknown_type $step   		步长
	 * @param unknown_type $aKeyWhere	主键条件
	 * @param unknown_type $aWhere		附加条件
	 */
	public function dec($field, array $aKeyWhere, array $aWhere = array(), $step = 1){
		$this->_aKeyWhere = $aKeyWhere;
		$this->_keyWhereCount = count( $aKeyWhere );
		$this->createBcServer();
		$req = new BcRequest( $this->_bcServer, BC_UPDATE ); //创建BcRequest对象
		$this->makeKeyWhere( $req, $aKeyWhere );
		$this->makeWhereAndLimit( $req, $aWhere, array() );
		$req->sub($field, $step);
		
		$res = new BcResult();
		$code = $req->execute( $res );
		if ($code != 0) {
			$this->error( $code, $res->errorMessage() . 'DB:' . $res->errorFrom(), __LINE__ );
		}
		
		return $res->affectedRows();
	}
	/**
	 * 
	 * 生成主键条件
	 * @param unknown_type $req
	 */
	public function makeKeyWhere(&$req, array $aKeyWhere) {
		foreach ( $aKeyWhere as $row ) {
			foreach ( $row as $field => $value ) {
				if ($this->_keyWhereCount > 1) { //单键多值
					$code = $req->addKeyValue( $field, $value );
					//var_dump( $code, 'xxxxxxxxxxx', $field, '------',$value,'<br><br>');
				} else {
					$code = $req->setKey( $value );
				}
				if ($code != 0) {
					$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
				}
			}
		}
	}
	/**
	 * 
	 * 生成附加条件和限制记录
	 * @param unknown_type $aWhere
	 * @param unknown_type $aLimit
	 */
	public function makeWhereAndLimit(&$req, array $aWhere, array $aLimit = array()) {
		foreach ( $aWhere as $row ) {
			$field = $row[0];
			$op = strtolower( $row[1] );
			$value = $row[2];
			$op = strtolower( $op );
			switch ($op) {
				case '!=' :
				case '<>' :
					$op = 'ne';
					break;
				case '<' :
					$op = 'lt';
					break;
				case '>' :
					$op = 'gt';
					break;
				case '<=' :
					$op = 'le';
					break;
				case '>=' :
					$op = 'ge';
					break;
				default :
					$op = 'eq';
					break;
			}
			$code = $req->$op( $field, $value );
			if ($code != 0) {
				$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
			}
		}
		if (intval( $aLimit[1] ) > 0) {
			$code = $req->limit( intval( $aLimit[0] ), intval( $aLimit[1] ) );
			if ($code != 0) {
				$this->error( $code, $this->_bcServer->errorMessage(), __LINE__ );
			}
		}
		return true;
	
	}
	public function error($code, $msg, $line) {
		$str = 'line:' . $line . '--code:' . $code . '---msg:' . $msg;
		die( $str );
	}
}
