<?php
namespace aliyun;

/**
 * 控制器
 * 
 */
class Ots{
	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'];
		}
    }
	
	/*
	 * api
	 */
	public function api($param=array()){
		$ots=new \aliyun\OTS\OTSClient (array (
		    'EndPoint' => $this->apiUrl,
		    'AccessKeyID' => $this->ACCESS_KEY,
		    'AccessKeySecret' => $this->ACCESS_SECRET,
		    'InstanceName' => $this->name,
		));
		$param['data']['table_name']=$this->table;
		if($param['name']=='putRow'){
		    return $ots->putRow ($param['data']);
		}
		if($param['name']=='getRow'){
		    return $ots->getRow ($param['data'],$param['json']);
		}
		if($param['name']=='getRange'){
		    return $ots->getRange ($param['data']);
		}
		if($param['name']=='updateRow'){
			$param['data']['condition']=$param['data']['condition']?$param['data']['condition']:'IGNORE';
		    return $ots->updateRow ($param['data']);
		}
		if($param['name']=='deleteRow'){
			$param['data']['condition']=$param['data']['condition']?$param['data']['condition']:'IGNORE';
		    return $ots->deleteRow ($param['data']);
		}
		if($param['name']=='get'){
		    return $ots->batchGetRow (array('tables'=>array($param['data'])));
		}
		if($param['name']=='write'){
			$param['data']['condition']=$param['data']['condition']?$param['data']['condition']:'IGNORE';
		    return $ots->batchWriteRow ($param['data']);
		}
    }
	
	/*
	 * add
	 * @param pk  主键
	 * @param attr 属性列
	 */
	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['pk'] as $k => $v) {
			if(is_numeric($v)){
				$data['pk'][$k]=(string)$v; 
			}
		}
		$data_api['primary_key']=$data['pk'];
		if(isset($data['attr'])){
		    foreach ($data['attr'] as $k => $v) {
				if(is_numeric($v)){
					$data['attr'][$k]=(string)$v;
				}
			}
			$data['attr']['pk']=base64_encode(json_encode($data['pk']));
			$data_api['attribute_columns']=$data['attr'];
		}
		
		$re=$this->api(array(
			'name'=>'putRow',
			'data'=>$data_api,
		));
		$this->_after_insert($data);
		$this->_after_write($data);
		return $re;
    }
	
	/*
	 * find
	 * @param pk 主键
	 */
	public function find($data){
		foreach ($data['pk'] as $k => $v) {
			if(is_numeric($v)){
				$data['pk'][$k]=(string)$v; 
			}
		}
		$data_api['primary_key']=$data['pk'];
		$json=isset($data['json'])?$data['json']:'';
		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
				));
			}
		    $data_api['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field']){
		    $field=explode(',', $data['field']);
			$data_api['columns_to_get']=$field;
		}
		return $this->api(array(
			'name'=>'getRow',
			'data'=>$data_api,
			'json'=>$json,
		));
    }
	
	/*
	 * select
	 * @param spk 起始主键
	 * @param epk 结束主键
	 * @param order 排序方式 默认 desc
	 * @param logic 过滤逻辑,默认为单个， and 表示并且  or 表示或者
	 * @param 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;
		}
		$data_api = array (
		    'direction' => $data['order'], 
		    'inclusive_start_primary_key' => $data['spk'], 
		    'exclusive_end_primary_key' => $data['epk'], 
		);
		if(isset($data['limit'])){
			$data_api['limit']=$data['limit'];
		}
		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
				));
			}
		    $data_api['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field']){
		    $field=explode(',', $data['field']);
			$data_api['columns_to_get']=$field;
		}
		$re=$this->api(array(
			'name'=>'getRange',
			'data'=>$data_api,
		));
		
		$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;
		}
		
		
		
    }
	
	
	/*
	 * page
	 * @param spk 起始主键
	 * @param epk 结束主键
	 * @param order 排序方式 默认 desc
	 * @param logic 过滤逻辑,默认为单个， and 表示并且  or 表示或者
	 * @param filter 过滤字段  array('status'=>array('eq'=>0))
	 */
	public function page($data){
	}
	
	/*
	 * save
	 */
	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['pk'] as $k => $v) {
			if(is_numeric($v)){
				$data['pk'][$k]=(string)$v;
			}
		}
		foreach ($data['attr'] as $k => $v) {
			if(is_numeric($v)){
				$data['attr'][$k]=(string)$v;
			}
		}
		if($data['add']){
			$ishave=$this->find(array('pk'=>$data['pk']));
			if(!$ishave){
			    $re=$this->add(array('pk'=>$data['pk'],'attr'=>$data['attr']));
				return $re;
			}
		}
		$re = $this->api(array(
			'name'=>'updateRow',
			'data'=>array (
			    'primary_key' => $data['pk'],
			    'attribute_columns_to_put' => $data['attr']
			),
		));
		$this->_after_write($data);
		$this->_after_update($data);
		return $re;
    }
	
	/*
	 * delete
	 */
	public function delete($data){
		if(false === $this->_before_delete($options)) {
            return false;
        }
		$pk=$data['pk'];
		$info_file=$this->find(array('pk'=>$pk));
		$re=$this->api(array(
			'name'=>'deleteRow',
			'data'=>array (
			    'primary_key' => $data['pk'],
			),
		));
		$this->_after_delete($info_file);
		return $re;
    }
	
	/*
	 * get
	 */
	public function get($data){
		foreach ($data['pks'] as $k => $v) {
			foreach ($v as $k1 => $v1) {
				if(is_numeric($v1)){
					$data['pks'][$k][$k1]=(string)$v1; 
				}
			}
		}
		$rows=array();
		foreach ($data['pks'] as $k => $v) {
			$rows[$k]['primary_key']=$v;
		}
		$data_api['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
				));
			}
		    $data_api['column_filter']=array(
				'logical_operator'=>$data['logic'],
				'sub_conditions'=>$sub_conditions,
			);
		}
		if($data['field']){
		    $field=explode(',', $data['field']);
			$data_api['columns_to_get']=$field;
		}
		return $this->api(array(
			'name'=>'get',
			'data'=>$data_api,
			'json'=>$json,
		));
    }

	/*
	 * write
	 */
	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'=>$data['add'][$k]['pk1'],
						'pk2'=>$data['add'][$k]['pk2'],
						'pk3'=>$data['add'][$k]['pk3'],
						'pk4'=>$data['add'][$k]['pk4'],
					),
                    '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'=>$data['mod'][$k]['pk1'],
						'pk2'=>$data['mod'][$k]['pk2'],
						'pk3'=>$data['mod'][$k]['pk3'],
						'pk4'=>$data['mod'][$k]['pk4'],
					),
                    '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'=>$data['del'][$k]['pk1'],
						'pk2'=>$data['del'][$k]['pk2'],
						'pk3'=>$data['del'][$k]['pk3'],
						'pk4'=>$data['del'][$k]['pk4'],
					),
				);
			}
		}
		$request = array (
		    'tables' => array (
		        array (
		            'table_name' => $this->table,
		            'put_rows' => array_merge($put_rows),
		            'update_rows' =>  array_merge($update_rows),
		            'delete_rows' =>  array_merge($delete_rows),
		        )
		    )
		);
		$ots=new \aliyun\OTS\OTSClient (array (
		    'EndPoint' => $this->apiUrl,
		    'AccessKeyID' => $this->ACCESS_KEY,
		    'AccessKeySecret' => $this->ACCESS_SECRET,
		    'InstanceName' => $this->name,
		));
		$re=$ots->batchWriteRow ($request);
		if($data['add']){
			$row=0;
			foreach ($re['tables'][0]['put_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
			$data['add'][0]['row']=$row;
			$data['add'][0]['table']=$re['tables'][0]['table_name'];
		    $this->_after_write_add($data['add'][0]);
		}
		if($data['mod']){
		    $row=0;
			foreach ($re['tables'][0]['update_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
			$data['mod'][0]['row']=$row;
			$data['mod'][0]['table']=$re['tables'][0]['table_name'];
		    $this->_after_write_mod($data['mod'][0]);
		}
		if($data['del']){
		    $row=0;
			foreach ($re['tables'][0]['delete_rows'] as $k => $v) {
				if($v['is_ok']){
				    $row++;
				}
			}
			$data['del'][0]['row']=$row;
			$data['del'][0]['table']=$re['tables'][0]['table_name'];
		    $this->_after_write_del($data['del'][0]);
		}
		return $re;
    }
	
    protected function _before_update(&$data) {}
    protected function _after_update($data) {}
	
	protected function _before_delete(&$options) {}    
    protected function _after_delete($data) {}
	
	protected function _before_insert(&$data) {}
    protected function _after_insert($data) {}
	
	protected function _before_write(&$data) {}
	protected function _after_write($data) {}
	
	
	protected function _after_find(&$data) {}
	protected function _after_select(&$data) {}
	
	protected function _after_write_add($data) {}
	protected function _after_write_mod($data) {}
	protected function _after_write_del($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);
        }
    }
}