<?php
namespace aliyun;

/**
 * 控制器
 * 
 */
class Ots1{
	protected $error        ='';
	protected $trueTableName='';
	
	/**
     * @description 表格存储
     */
    public function __construct($config=array()){
    	foreach ($config as $k => $v) {
    		$this->$k=$v;
    	}
		$this->apiUrl=C('ALIYUN.OTS_APIURL')?C('ALIYUN.OTS_APIURL'):'http://wdtable1.cn-hangzhou.ots.aliyuncs.com';
		$this->ACCESS_KEY=isset($config['ACCESS_KEY'])?$config['ACCESS_KEY']:C('ALIYUN.ACCESS_KEY');
		$this->ACCESS_SECRET=isset($config['ACCESS_SECRET'])?$config['ACCESS_SECRET']:C('ALIYUN.ACCESS_SECRET');
		$this->name=C('ALIYUN.OTS_NAME')?C('ALIYUN.OTS_NAME'):$config['name'];
		//表
		if($config['table']){//O函数设置
		    $this->table=$config['table'];
		}else if($this->trueTableName){//模型设置
		    $this->table=$this->trueTableName;
		}else{//和模型名称一致
			$this->table=$config['model'];
		}
    }
	
	/**
	 * 是否具有管理权限
	 */
	public function isadmin(){}
	
	/*
	 * api
	 */
	public function api($param=array()){
		return $ots=new \aliyun\OTS\OTSClient (array (
		    'EndPoint' => $this->apiUrl,
		    'AccessKeyID' => $this->ACCESS_KEY,
		    'AccessKeySecret' => $this->ACCESS_SECRET,
		    'InstanceName' => $this->name,
		));
    }
	
	/**
	 * @description 创建表
	 */
	public function createTable(){
		$request = array (
		    'table_meta' => array (
		        'table_name' => $this->table, 
		        'primary_key_schema' => array (
		            'pk1' => 'STRING', 
		            'pk2' => 'STRING', 
		            'pk3' => 'STRING', 
		            'pk4' => 'STRING', 
		        )
		    ), 
		);
		$this->api()->createTable ($request);
	}
	
	/**
	 * @description 添加
	 * @param $data 一维数组
	 */
	public function add($data){
		if(false === $this->_before_insert($data)) {
			$this->ajaxReturn(array(
				'status'=>-1,
				'info'=>$this->error
			));
            exit;
        }
		if(false === $this->_before_write($data)) {
			$this->ajaxReturn(array(
				'status'=>-1,
				'info'=>$this->error
			));
            exit;
        }
		foreach ($data as $k => &$v) {
			if(is_numeric($v)){
				$v=(string)$v; 
			}
		}
		unset($v);
		$redata=$data;
		$pk=array(
			'pk1'=>isset($data['pk1'])?$data['pk1']:(string)getTime(),
			'pk2'=>isset($data['pk2'])?$data['pk2']:'',
			'pk3'=>isset($data['pk3'])?$data['pk3']:'',
			'pk4'=>isset($data['pk4'])?$data['pk4']:(string)getTime(),
		);
		$redata['pk']=base64_encode(json_encode($pk));
		unset($data['pk1'],$data['pk2'],$data['pk3'],$data['pk4']);
		$attr=$data;
		$attr['pk']=base64_encode(json_encode($pk));
		$request['primary_key']=$pk;
		if(isset($attr)){
			$request['attribute_columns']=$attr;
		}
		$request['table_name']=$this->table;
		if(isset($data['condition']) && in_array($data['condition'], array('IGNORE','EXPECT_EXIST','EXPECT_NOT_EXIST'))){
		    $request['condition']=$data['condition'];
		}else{
			$request['condition']='IGNORE';
		}
		$re=$this->api()->putRow($request);
		$this->_after_insert($redata);
		$this->_after_write($redata);
		return $re;
    }
	
	/**
	 * @description 修改单条数据
	 * @param $data 一维数组
	 */
	public function save($data){
		if(false === $this->_before_write($data)) {
			$this->ajaxReturn(array(
				'status'=>-1,
				'info'=>$this->error
			));
            exit;
        }
		if(false === $this->_before_update($data)) {
			$this->ajaxReturn(array(
				'status'=>-1,
				'info'=>$this->error
			));
            exit;
        }
		foreach ($data as $k => &$v) {
			if(is_numeric($v)){
				$v=(string)$v; 
			}
		}
		unset($v);
		if($data['pk']){
		    $pk=json_decode(base64_decode($data['pk']),true);
		}else{
			$pk=array(
				'pk1'=>isset($data['pk1'])?$data['pk1']:'',
				'pk2'=>isset($data['pk2'])?$data['pk2']:'',
				'pk3'=>isset($data['pk3'])?$data['pk3']:'',
				'pk4'=>isset($data['pk4'])?$data['pk4']:'',
			);
		}
		$data['pk']=$data['pk']?$data['pk']:base64_encode(json_encode($pk));
		$redata=$data;
		unset($data['pk1'],$data['pk2'],$data['pk3'],$data['pk4'],$data['model']);
		$attr=$data;
		if(isset($data['condition']) && in_array($data['condition'], array('IGNORE','EXPECT_EXIST','EXPECT_NOT_EXIST'))){
		    $condition=$data['condition'];
		}else{
			$condition='IGNORE';
		}
		$request['condition']=$condition;
		$request['primary_key']=$pk;
		$request['attribute_columns_to_put']=$attr;
		$request['table_name']=$this->table;
		$re=$this->api()->updateRow($request);
		$this->_after_update($redata);
		$this->_after_write($redata);
		return $re;
    }

	/**
	 * @description 删除单条数据
	 * @param $data 一维数组或pk字符串
	 */
	public function delete($data){
		if(false === $this->_before_delete($data)) {
            return false;
        }
		if(!is_array($data)){
		    $pk=json_decode(base64_decode($data),true);
		}else if($data['pk']){
		    $pk=json_decode(base64_decode($data['pk']),true);
		}else{
			$pk=array(
				'pk1'=>isset($data['pk1'])?$data['pk1']:'',
				'pk2'=>isset($data['pk2'])?$data['pk2']:'',
				'pk3'=>isset($data['pk3'])?$data['pk3']:'',
				'pk4'=>isset($data['pk4'])?$data['pk4']:'',
			);
		}
		$info=$this->find($pk);
		$request['table_name']=$this->table;
		$request['primary_key']=$pk;
		$re=$this->api()->deleteRow($request);
		$this->_after_delete($info);
		return $re;
    }
	
	/**
	 * @description 查找单条数据
	 * @param $data 一维数组 或pk字符串
	 * @param $data['filter'] array 过滤 $data['filter']=array('abc'=>array('eq',1));
	 * @param $data['logic'] string 过滤关系 默认and;
	 * @param $data['field'] string 返回字段 $data['field']='a,b,c';
	 * @return array
	 */
	public function find($data=''){
		if(empty($data)){
		    $spk=array(
				'pk1'=>array('type' => 'INF_MAX'),
			);
			$epk=array(
				'pk1'=>array('type' => 'INF_MIN'),
			);
			$re=$this->select(array('spk'=>$spk,'epk'=>$epk));
			return $re[0];
		}
		if(!is_array($data)){
		    $pk=json_decode(base64_decode($data),true);
		}else if($data['pk']){
		    $pk=json_decode(base64_decode($data['pk']),true);
		}else{
			$pk=array(
				'pk1'=>isset($data['pk1'])?$data['pk1']:'',
				'pk2'=>isset($data['pk2'])?$data['pk2']:'',
				'pk3'=>isset($data['pk3'])?$data['pk3']:'',
				'pk4'=>isset($data['pk4'])?$data['pk4']:'',
			);
		}
		foreach ($pk as $k => &$v) {
			if(is_numeric($v)){
				$v=(string)$v; 
			}
		}
		unset($v);
		$request['primary_key']=$pk;
		if(isset($data['filter']) && is_array($data)){
			switch (strtolower($data['logic'])) {
				case 'not':
					$data['logic']=1;
					break;
				case 'or':
					$data['logic']=3;
					break;
				default:
					$data['logic']=2;
					break;
			}
			if($data['logic']==2){
			    $sub_conditions=array(array(
					'column_name' => 'abcdefg',
			        'value' =>'',
			        'comparator' => 4
				));
			}
			foreach ($data['filter'] as $k => $v) {
				switch (strtolower($v[0])) {
					case 'eq':
						$comparator=1;
						break;
					case 'neq':
						$comparator=2;
						break;
					case 'gt':
						$comparator=3;
						break;
					case 'egt':
						$comparator=4;
						break;
					case 'lt':
						$comparator=5;
						break;
					case 'elt':
						$comparator=6;
						break;
				}
				array_push($sub_conditions,array(
					'column_name' => (string)$k,
			        'value' =>(string)strtolower($v[1]),
			        'comparator' => $comparator
				));
			}
		    $request['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field'] && is_array($data)){
		    $field=explode(',', $data['field']);
			$request['columns_to_get']=$field;
		}
		$request['table_name']=$this->table;
		$re=$this->api()->getRow($request);
		$row=array_merge($re['row']['primary_key_columns'],$re['row']['attribute_columns']);
		if($data['json'] && is_array($data)){
		    $json=explode(',', $data['json']);
			foreach ($row as $k => &$v) {
				foreach ($json as $k1 => $v1) {
					if($v[$v1]){
					    $v[$v1]=json_decode($v[$v1],true);
					}
				}
			}
			unset($v);
		}
		return $row;
    }
	
	/*
	 * 返回检索
	 * @param $data 二维数组
	 * @param $data['spk'] 起始主键
	 * @param $data['epk'] 结束主键
	 * @param $data['order'] 排序方式 默认 desc
	 * @param $data['logic'] 过滤逻辑,默认为单个， and 表示并且  or 表示或者
	 * @param $data['filter'] 过滤字段  array('status'=>array('eq'=>0))
	 */
	public function select($data){
		$data['spk']=array(
			'pk1'=>isset($data['spk']['pk1'])?$data['spk']['pk1']:array('type' => 'INF_MAX'),
			'pk2'=>isset($data['spk']['pk2'])?$data['spk']['pk2']:'',
			'pk3'=>isset($data['spk']['pk3'])?$data['spk']['pk3']:'',
			'pk4'=>isset($data['spk']['pk4'])?$data['spk']['pk4']:'',
		);
		$data['epk']=array(
			'pk1'=>isset($data['epk']['pk1'])?$data['epk']['pk1']:array('type' => 'INF_MIN'),
			'pk2'=>isset($data['epk']['pk2'])?$data['epk']['pk2']:'',
			'pk3'=>isset($data['epk']['pk3'])?$data['epk']['pk3']:'',
			'pk4'=>isset($data['epk']['pk4'])?$data['epk']['pk4']:'',
		);
		foreach ($data['spk'] as $k => $v) {
			if(is_numeric($v)){
				$data['spk'][$k]=(string)$v;
			}
		}
		foreach ($data['epk'] as $k => $v) {
			if(is_numeric($v)){
				$data['epk'][$k]=(string)$v; 
			}
		}
		
		foreach ($data['attr'] as $k => $v) {
			if(is_numeric($v)){
				$data['attr'][$k]=(string)$v; 
			}
		}
		switch (strtolower($data['order'])) {
			case 'asc':
				$data['order']='FORWARD';
				break;
			default:
				$data['order']='BACKWARD';
				break;
		}
		$request = array (
		    'direction' => $data['order'], 
		    'inclusive_start_primary_key' => $data['spk'], 
		    'exclusive_end_primary_key' => $data['epk'], 
		);
		if(isset($data['limit'])){
			$request['limit']=$data['limit'];
		}
		if($data['filter']){
			switch (strtolower($data['logic'])) {
				case 'not':
					$data['logic']=1;
					break;
				case 'or':
					$data['logic']=3;
					break;
				default:
					$data['logic']=2;
					break;
			}
			if($data['logic']==2){
			    $sub_conditions=array(array(
					'column_name' => 'abcdefg',
			        'value' =>'',
			        'comparator' => 4
				));
			}
			foreach ($data['filter'] as $k => $v) {
				switch (strtolower($v[0])) {
					case 'eq':
						$comparator=1;
						break;
					case 'neq':
						$comparator=2;
						break;
					case 'gt':
						$comparator=3;
						break;
					case 'egt':
						$comparator=4;
						break;
					case 'lt':
						$comparator=5;
						break;
					case 'elt':
						$comparator=6;
						break;
				}
				array_push($sub_conditions,array(
					'column_name' => (string)$k,
			        'value' =>(string)strtolower($v[1]),
			        'comparator' => $comparator
				));
			}
		    $request['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field']){
		    $field=explode(',', $data['field']);
			$request['columns_to_get']=$field;
		}
		$request['table_name']=$this->table;
		$re=$this->api()->getRange($request);
		$rows=$re['rows'];
		foreach ($rows as $k => &$v) {
			$v=array_merge($v['primary_key_columns'],$v['attribute_columns']);
		}
		unset($v);
		if($data['json']){
		    $json=explode(',', $data['json']);
			foreach ($rows as $k => &$v) {
				foreach ($json as $k1 => $v1) {
					if($v[$v1]){
					    $v[$v1]=json_decode($v[$v1],true);
					}
				}
			}
			unset($v);
		}
		if($data['page']){
			$re['rows']=$rows;
		    return $re;
		}else{
			return $rows;
		}
    }
	
	/**
	 * @description 根据pk获取多条数据
	 * @param $data 二维数组
	 * @param $data['pks'] pk二维数组
	 * @param $data['filter'] 过滤
	 * @param $data['logic'] 过滤逻辑
	 * @param $data['field']  返回字段
	 * @return array
	 */
	public function get($data){
		$data['pks']=array_unique($data['pks']);
		foreach ($data['pks'] as $k => &$v) {
			if(!is_array($v)){
			    $v=json_decode(base64_decode($v),true);
				if(empty($v['pk1'])){
				    unset($data['pks'][$k]);
				}
			}
		}
		unset($v);
		$rows=array();
		foreach ($data['pks'] as $k => $v) {
			$rows[$k]['primary_key']=$v;
		}
		$request['rows']=$rows;
		if(isset($data['filter'])){
			switch (strtolower($data['logic'])) {
				case 'not':
					$data['logic']=1;
					break;
				case 'or':
					$data['logic']=3;
					break;
				default:
					$data['logic']=2;
					break;
			}
			if($data['logic']==2){
			    $sub_conditions=array(array(
					'column_name' => 'abcdefg',
			        'value' =>'',
			        'comparator' => 4
				));
			}
			foreach ($data['filter'] as $k => $v) {
				switch (strtolower($v[0])) {
					case 'eq':
						$comparator=1;
						break;
					case 'neq':
						$comparator=2;
						break;
					case 'gt':
						$comparator=3;
						break;
					case 'egt':
						$comparator=4;
						break;
					case 'lt':
						$comparator=5;
						break;
					case 'elt':
						$comparator=6;
						break;
				}
				array_push($sub_conditions,array(
					'column_name' => (string)$k,
			        'value' =>(string)strtolower($v[1]),
			        'comparator' => $comparator
				));
			}
		    $request['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field']){
		    $field=explode(',', $data['field']);
			$request['columns_to_get']=$field;
		}
		$request['table_name']=$this->table;
		$re=$this->api()->batchGetRow (array('tables'=>array($request)));
		$rows=$re['tables'][0]['rows'];
		$redata=array();
		foreach ($rows as $k => $v) {
			if($v['is_ok'] && $v['row']['primary_key_columns']){
			    $redata[$k]=array_merge($v['row']['primary_key_columns'],$v['row']['attribute_columns']);
			}
		}
		unset($re,$request);
		return $redata;
    }

	/*
	 * write
	 */
	/**
	 * @description 批量操作
	 * @param $data 二维数组
	 */
	public function write($data){
		if($data['add']){
			$put_rows=array();
			foreach ($data['add'] as $k => $v) {
				foreach ($data['add'][$k] as $k1 => &$v1) {
					if(!is_string($v1)){
						$v1=(string)$v1;
					}
				}
				unset($v1);
				$attr=$data['add'][$k];
				$attr['pk']=base64_encode(json_encode(array('pk1'=>$attr['pk1'],'pk2'=>$attr['pk2'],'pk3'=>$attr['pk3'],'pk4'=>$attr['pk4'])));
				unset($attr['pk1'],$attr['pk2'],$attr['pk3'],$attr['pk4']);
				$put_rows[$k]=array (
                    'condition' => $data['add_condition']?$data['add_condition']:'EXPECT_NOT_EXIST',
                    'primary_key' => array(
						'pk1'=>isset($data['add'][$k]['pk1'])?$data['add'][$k]['pk1']:'',
						'pk2'=>isset($data['add'][$k]['pk2'])?$data['add'][$k]['pk2']:'',
						'pk3'=>isset($data['add'][$k]['pk3'])?$data['add'][$k]['pk3']:'',
						'pk4'=>isset($data['add'][$k]['pk4'])?$data['add'][$k]['pk4']:(string)getTime(),
					),
                    'attribute_columns' => $attr
                );
			}
		}
		if($data['mod']){
			$update_rows=array();
			$condition=$data['mod_condition']?$data['mod_condition']:'EXPECT_EXIST';
			if($data['mod_filter']){
				switch (strtolower($data['mod_logic'])) {
					case 'not':
						$logic=1;
						break;
					case 'or':
						$logic=3;
						break;
					default:
						$logic=2;
						break;
				}
				if($logic==2){
				    $sub_conditions=array(array(
						'column_name' => 'abcdefg',
				        'value' =>'',
				        'comparator' => 4
					));
				}
				foreach ($data['mod_filter'] as $k => $v) {
					switch (strtolower($v[0])) {
						case 'eq':
							$comparator=1;
							break;
						case 'neq':
							$comparator=2;
							break;
						case 'gt':
							$comparator=3;
							break;
						case 'egt':
							$comparator=4;
							break;
						case 'lt':
							$comparator=5;
							break;
						case 'elt':
							$comparator=6;
							break;
					}
					array_push($sub_conditions,array(
						'column_name' => (string)$k,
				        'value' =>(string)strtolower($v[1]),
				        'comparator' => $comparator
					));
				}
			    $condition = array (
                    'row_existence' => $condition,
                    'column_filter' => array (
                        'logical_operator' => $logic,
                        'sub_conditions' => $sub_conditions
                    )
                );
			}
			
			foreach ($data['mod'] as $k => $v) {
				foreach ($data['mod'][$k] as $k1 => &$v1) {
					if(!is_string($v1)){
						$v1=(string)$v1;
					}
				}
				unset($v1);
				$attr=$data['mod'][$k];
				unset($attr['pk1'],$attr['pk2'],$attr['pk3'],$attr['pk4']);
				$update_rows[$k]=array (
                    'condition' => $condition,
					'primary_key' => array(
						'pk1'=>isset($data['mod'][$k]['pk1'])?$data['mod'][$k]['pk1']:'',
						'pk2'=>isset($data['mod'][$k]['pk2'])?$data['mod'][$k]['pk2']:'',
						'pk3'=>isset($data['mod'][$k]['pk3'])?$data['mod'][$k]['pk3']:'',
						'pk4'=>isset($data['mod'][$k]['pk4'])?$data['mod'][$k]['pk4']:(string)getTime(),
					),
                    'attribute_columns_to_put' => $attr
                );
			}
		}
		if($data['del']){
			$delete_rows=array();
			$condition=$data['del_condition']?$data['del_condition']:'EXPECT_EXIST';
			if($data['del_filter']){
				switch (strtolower($data['del_logic'])) {
					case 'not':
						$logic=1;
						break;
					case 'or':
						$logic=3;
						break;
					default:
						$logic=2;
						break;
				}
				if($logic==2){
				    $sub_conditions=array(array(
						'column_name' => 'abcdefg',
				        'value' =>'',
				        'comparator' => 4
					));
				}
				foreach ($data['del_filter'] as $k => $v) {
					switch (strtolower($v[0])) {
						case 'eq':
							$comparator=1;
							break;
						case 'neq':
							$comparator=2;
							break;
						case 'gt':
							$comparator=3;
							break;
						case 'egt':
							$comparator=4;
							break;
						case 'lt':
							$comparator=5;
							break;
						case 'elt':
							$comparator=6;
							break;
					}
					array_push($sub_conditions,array(
						'column_name' => (string)$k,
				        'value' =>(string)strtolower($v[1]),
				        'comparator' => $comparator
					));
				}
			    $condition = array (
                    'row_existence' => $condition,
                    'column_filter' => array (
                        'logical_operator' => $logic,
                        'sub_conditions' => $sub_conditions
                    )
                );
			}
			foreach ($data['del'] as $k => $v) {
				foreach ($data['del'][$k] as $k1 => &$v1) {
					if(!is_string($v1)){
						$v1=(string)$v1;
					}
				}
				unset($v1);
				$delete_rows[$k]=array(
					'condition' => $condition,
                    'primary_key' => array(
						'pk1'=>isset($data['del'][$k]['pk1'])?$data['del'][$k]['pk1']:'',
						'pk2'=>isset($data['del'][$k]['pk2'])?$data['del'][$k]['pk2']:'',
						'pk3'=>isset($data['del'][$k]['pk3'])?$data['del'][$k]['pk3']:'',
						'pk4'=>isset($data['del'][$k]['pk4'])?$data['del'][$k]['pk4']:'',
					),
				);
			}
		}
		$request = array (
		    'tables' => array (
		        array (
		            'table_name' => $this->table,
		            'put_rows' => $put_rows,
		            'update_rows' => $update_rows,
		            'delete_rows' => $delete_rows,
		        )
		    )
		);
		$re=$this->api()->batchWriteRow ($request);
		if($data['add']){
			$row=0;
			foreach ($re['tables'][0]['put_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
		    $this->_after_write_add(array('row'=>$row));
		}
		if($data['mod']){
		    $row=0;
			foreach ($re['tables'][0]['update_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
			$this->_after_write_mod(array('row'=>$row));
		}
		if($data['del']){
		    $row=0;
			foreach ($re['tables'][0]['delete_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
			$this->_after_write_del(array('row'=>$row));
		}
		return $re;
    }
	
    protected function _before_update(&$data) {}
	protected function _before_insert(&$data) {}
	protected function _before_delete(&$data) {}  
	protected function _before_write(&$data) {}
    protected function _after_update($data) {}
    protected function _after_delete($data) {}
    protected function _after_insert($data) {}
	protected function _after_write($data) {}
	protected function _after_write_add($data) {}
	protected function _after_write_mod($data) {}
	protected function _after_write_del($data) {}
	protected function _after_find(&$data) {}
	protected function _after_select(&$data) {}
	
	/**
     * Ajax方式返回数据到客户端
     * @access protected
     * @param mixed $data 要返回的数据
     * @param String $type AJAX返回数据格式
     * @param int $json_option 传递给json_encode的option参数
     * @return void
     */
    protected function ajaxReturn($data,$type='',$json_option=0) {
        if(empty($type)) $type  =   C('DEFAULT_AJAX_RETURN');
        switch (strtoupper($type)){
            case 'JSON' :
                // 返回JSON数据格式到客户端 包含状态信息
                header('Content-Type:application/json; charset=utf-8');
                exit(json_encode($data,$json_option));
            case 'XML'  :
                // 返回xml格式数据
                header('Content-Type:text/xml; charset=utf-8');
                exit(xml_encode($data));
            case 'JSONP':
                // 返回JSON数据格式到客户端 包含状态信息
                header('Content-Type:application/json; charset=utf-8');
                $handler  =   isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');
                exit($handler.'('.json_encode($data,$json_option).');');  
            case 'EVAL' :
                // 返回可执行的js脚本
                header('Content-Type:text/html; charset=utf-8');
                exit($data);            
            default     :
                // 用于扩展其他返回格式数据
                Hook::listen('ajax_return',$data);
        }
    }
}