<?php
namespace model;
use \model;
/**
 * Class element
 * @package model
 */
class element extends model
{
    public $table = '';
    public $key = '';
    public $elecfg = null;
	public $dbcache = [];
    public $linkOneCache = [];
    public $linkMoreCache = [];

	/**
	 * @param array|string $elecfg 配置数据或者配置element名称
	 */
	public function __construct($elecfg)
    {
		parent::__construct();
        if(is_string($elecfg)){
            $elecfg = require(\mvc::$cfg['projectDir'].'/element/'.$elecfg.'.php');
        }
        $this->table = $elecfg['table'];
        $this->key = $elecfg['key'];
        $this->elecfg = $elecfg;
    }
	function getDb(){
	    return $this->db;
	}
	
	/**
	 * check1
	 */
    public function check1($ids,$state)
    {
        $check1 = $this->elecfg['url']['check1'];
        $this->db->update($this->table,[$check1['checkField']=>$state],[$this->key=>$ids]);
        return true;
    }

	/**
	 * 返回全部行记录
	 * @return array
	 */
	function getAll($where=null,$fields=null){
		if($fields==null) $fields = '*';
		//pf_is_sys desc,pf_is_gsp desc,pf_hasbar desc,pf_name
		if(!empty($this->elecfg['order'])) 
		{
			$where['ORDER'] = [];
			foreach(explode(',', $this->elecfg['order']) as $ov)
			{
				if(strpos($ov, ' '))
				{
					$tv = explode(' ', $ov);
					$where['ORDER'][$tv[0]] = $tv[1]; 
				}
				else
				{
					$where['ORDER'][$ov] = 'ASC';
				}
			}
		}
		return $this->db->select($this->table,$fields,$where);
	}

    /**
     * caption模糊查询
     * @param string $value  要查询的值
     * @param array $fields  ['code','name']
     * @return array ID数组
     */
    public function like($value,$fields=null)
    {
        $value = trim($value);
        if($fields==null){
            $where[$this->elecfg['caption'].'[~]'] = $value;
        }else{
            foreach($fields as $field){
                $where['OR'][$field.'[~]'] = $value;
            }
        }
        $rows = $this->db->select($this->table,$this->key,$where);
        $rows = array_unique($rows);
        if(count($rows)==1) $rows = $rows[0];
        if(empty($rows)) $rows = [0];
        return $rows;
    }

	/**
	 * caption精确查询
	 * @param string $value  要查询的值
     * @param string $field 'code'
	 * @return array
	 */
    public function eqname($value,$field=null)
    {
        $value = trim($value);
        if($fields==null){
            $where[$this->elecfg['caption']] = $value;
        }else{
            $where[$field] = $value;
        }
        return $this->db->get($this->table,$this->key,$where);
    }

    /**
     * 搜索字段查询Object
     * @param string $value  要查询的值
     * @return array ID数组
     */
    public function search($query,$limit=20)
    {
		$searchFields = (!empty($this->elecfg['search'])) ? $this->elecfg['search'] : [$this->elecfg['caption']];
		foreach($searchFields as $field){
			 $where['OR'][$field.'[~]'] = trim($query);
		}
		$where['LIMIT'] = $limit;
        return $this->db->select($this->table,'*',$where);
    }

    public function list($rules = [],$where='',$page=0,$pagesize=0,$sidx='',$sord='asc',$orderby='')
    {
		$table = $this->table.'(e)';
        $fields = '*';
        $this->join = [];
		$this->joinWhere = [];
		$this->group = [];
		$objList = []; //用于回调方法中，创建的对象缓存
        $where = $this->filter2medoo($where,function(&$field,&$op,&$data){
            if(is_string($data)) $data = trim($data);
            $cfg = $this->elecfg['fields'][$field];
            if(!empty($cfg['formartSearchBegin'])){
                $cfg['formartSearchBegin']($field,$op,$data);
            }
            //取其他表值
            if(!empty($cfg['linkOne'])){
                $link = $cfg['linkOne'];
                if(isset($link['search']) && !empty($link['search']['function'])){
                    $link['search']['function']($field,$op,$data,$this->join,$this->joinWhere,$this->group,$objList,$this->db);
                }else{
                    if(isset($link['myfield']) && $link['myfield']){
                        $field = $link['myfield'];
                    }
                    if(isset($cfg['list']['valuetype']) && $cfg['list']['valuetype']=='key'){
                        if(empty($data)){
                            $op = null;
                        }else{
                            $op = 'eq';
                        }
                    }else{
                        $captionField = (isset($link['captionField']) && $link['captionField']) ? $link['captionField'] : $link['caption'];
                        $w = [
                            $captionField.'['.$this->getMedooOp($op).']'=> $data
                        ];
                        $data = $this->db->select($link['table'],$link['field'],$w);
                        if(empty($data)) $data = [0];
                        $op = 'eq';
                        $data = array_unique($data);
                    }
                }
                
            }else if(!empty($cfg['linkMore'])){
				$as = 't'.$field;
				$on = ["e.".$this->key => $cfg['linkMore']['mykey_link_field']];
				if(!empty($cfg['linkMore']['AND'])){
					$on['AND'] = $cfg['linkMore']['AND'];
				}
				if(!empty($cfg['linkMore']['element'])){
				    if(!empty($data)){
    				    if(isset($cfg['list']['valuetype']) && $cfg['list']['valuetype']=='key'){
            				$linkIds = $data;
    				    }else{
            				$linkIds = makeOne(\model\element::class,$cfg['linkMore']['element'])->like($data);
    				    }
        				$op = 'eq';
        				$field = $cfg['linkMore']['field'];
        				$data = $linkIds;
				    }else{
				        $op = null;
				    }
				}
				if(!is_null($op)){
				    $this->join['[>]'.$cfg['linkMore']['table'].'('.$as.')'] = $on;
				}
            }
            //其他修正
            if(!empty($cfg['list']['searchField'])){
                $field = $cfg['list']['searchField'];
            }
            if(!empty($cfg['formartSearch'])){
                $cfg['formartSearch']($field,$op,$data);
            }
        });
        if(!is_array($where)) $where =[];
        
		if(!empty($rules)){
		    if(!empty($rules['keys'])){
		        $where[$this->key] = $rules['keys'];
		        unset($rules['keys']);
		    }
			foreach($rules as $field=>$value){
			    if(isset($this->elecfg['rules'][$field])){
			        //自定义规则查询
			        $this->elecfg['rules'][$field]($rules,$field,$value,$this->join,$this->joinWhere,$this->group);
			    }else{
    				$cfg = $this->elecfg['fields'][$field];
    				if(!empty($cfg['linkMore'])){
    					$as = 't'.$field;
    					$on = ["e.".$this->key => $cfg['linkMore']['mykey_link_field']];
    					if(!empty($cfg['linkMore']['AND'])){
    						$on['AND'] = $cfg['linkMore']['AND'];
    					}
    					$this->join['[>]'.$cfg['linkMore']['table'].'('.$as.')'] = $on;
    					$this->joinWhere[$as.'.'.$cfg['linkMore']['field']] = $value;
    					unset($rules[$field]);
    				}
			    }
			}
			$where = array_merge($rules,$where);
		}
		
		//check1
		if(!empty($this->elecfg['url']['check1']['checkField'])){
		    if(\p::has($this->elecfg['pwcode'],'check1')){
		        ;
		    }else{
		        $where['OR #user'] = [
		            $this->elecfg['url']['check1']['checkField']=> 1,
		            $this->elecfg['url']['check1']['userField']=> getOpuser(),
		        ];
		    }
		}
	
		if(!empty($this->joinWhere)){
			$where = array_merge($where, $this->joinWhere);
		}

		if(!empty($this->group)){
			$where = array_merge($where, $this->group);
		}
		
		
		//自定义排序
        if($sidx!='' && isset($this->elecfg['fields'][$sidx]['linkOne']) && isset($this->elecfg['fields'][$sidx]['linkOne']['order'])){
    		$sidx = $this->elecfg['fields'][$sidx]['linkOne']['order']['function']($this->join,$this->joinWhere,$this->group,$objList,$this->db);
        }
        
		$where = $this->listWhere($where,$page,$pagesize,$sidx,$sord,$orderby);
		if($this->elecfg['where']){
			$where = array_merge($this->elecfg['where'],$where);
		}

		if($page>0 && $pagesize>0){
            if(empty($this->join)){
                $pages = $this->paging($table,$where,$page,$pagesize);
            }else{
                $pages = $this->paging($table,$this->join,'1',$where,$page,$pagesize);
            }
			$where["LIMIT"] = [$pages['limit'],$pagesize];
		}
        if(empty($this->join)){
            $rows = $this->db->select($table,$fields,$where);
        }else{
            $rows = $this->db->select($table,$this->join,$fields,$where);
        }

		// dd($this->db->last());
        if(!empty($rows)) {
            // 在调用 getRowInfo 之前的循环中，预先查询并缓存 linkOne 和 linkMore 数据
            $rows = $this->preProcess($rows);
            foreach($rows as $k=>&$row){
                $row = $this->getRowInfo($row);
            }
        }
		$data = [
			'page'=> $page,
			'total'=> $pages['total'],
			'records' => $pages['records'],
			'rows' => $rows
		];
		return $data;
    }
    /**
     * 得到记录全量信息
     * @param id|row $var id或者行记录
     * @return array
     * @return string
     */
	function getRowInfo($var){
        $row = $var;
		if(!is_array($var)){
            $row = $this->getRowByKey($var);
            if(empty($row)){
                return [];
            }
            $row = $this->preProcess([$row])[0];
        }
        foreach($this->elecfg['fields'] as $field=>$cfg){
			//格式化数据
			if(!empty($cfg['formartValue'])){
				$row[$cfg['field']] = $cfg['formartValue']($row[$cfg['field']],$row,$this->db);
			}
			//一对一
            if (!empty($cfg['linkOne'])) {
                $link = $cfg['linkOne'];
                $key = $row[$link['myfield']?:$field];
                

                if(is_string($link['caption'])||is_array($link['caption'])){ //caption是字段
                    $row['captions'][$cfg['field']] = $this->linkOneCache[$cfg['field']][$link['table']][$key] ?? null;
                }else{ //function
                    $where = [
                        $link['field']=>$row[$link['myfield']]
                    ];
                    $row['captions'][$cfg['field']] = $link['caption']($this->db->get($link['table'],'*',$where),$this->db);
                }

            } else if (!empty($cfg['linkMore'])) {
                $link = $cfg['linkMore'];
                if(!isset($link['function'])){
                    $key = $row[$this->key];
                    $linkRows = $this->linkMoreCache[$cfg['field']][$link['table']][$key]['values'] ?? [];
                    $values = implode($link['split'] ?: ',', $linkRows);
                    $row[$cfg['field']] = $values;
                    if($this->linkMoreCache[$cfg['field']][$link['table']][$key]['captions'])
                    {
                        $row['captions'][$cfg['field']] =  $this->linkMoreCache[$cfg['field']][$link['table']][$key]['captions']?? '';
                    }
                    
                }
               
            }else if(!empty($cfg['linkAny'])){
				if(!empty($cfg['linkAny']['class'])){
					$caption = call_user_func_array([new $cfg['linkAny']['class'](), $cfg['linkAny']['function']], [$row]);
				}else{
					$caption = call_user_func_array([$this, $cfg['linkAny']['function']], [$row]);
				}
				$row['captions'][$cfg['field']]= $caption;
			}

			//格式化captions
			if(!empty($cfg['formartCaption'])){
				$c = $cfg['formartCaption']($row['captions'],$cfg['field'],$row[$cfg['field']],$row,$this->db);
				if($c!==false){
					$row['captions'][$cfg['field']] = $c;
				}
			}
        }
		if(!empty($row['captions'])){
			foreach($row['captions'] as $field=>$caption){
				$row['captionsValues'][$field] = $row[$field];
			}
		}
        return $row;
    }

    /**
     * 通过ID集取多行记录
     * @param array|string $ids id数组或者用,号分隔的字符串
     * @return array
     */
	function getRowsByIds($ids){
        if(empty($this->table) || empty($ids))
            return '';
		if(!is_array($ids)){
            $ids = explode(',',$ids);
        }
        $rows = $this->db->select($this->table,'*',[$this->key=>$ids]);
        return $rows;
    }

    /**
     * 通过ID集取多行记录的caption
     * @param array|string $ids id数组或者用,号分隔的字符串
     * @return array
     */
	function getCaptionByIds($ids){
        if(empty($this->table) || empty($ids))
            return '';
		if(!is_array($ids)){
            $ids = explode(',',$ids);
        }
        // 多抽出来了一层values
        if(!empty($ids['values'])){
            $ids = $ids['values'];
        }
        
        $rows = $this->db->select($this->table,$this->elecfg['caption'],[$this->key=>$ids]);
        return $rows;
    }

    /**
     * 是否存在某记录
     * @param array $where 条件
     * @return var 返回主键
     */
	function hasWhere($where){
        $result = $this->db->get($this->table,$this->key,$where);
        return $result;
    }

    /**
     * 重复记录判断
     * @param $id,$field,$value
     * @return bool
     */
	function hasUnique($id,$field,$value){
		if(isset($this->elecfg['uniqueFields']) && !empty($this->elecfg['uniqueFields'])){
			$uniqueFields = $this->elecfg['uniqueFields'];
			$row = $this->getRowByKey($id);
			$where = [];
			foreach($uniqueFields as $uf){
				$where[$uf] = $row[$uf];
			}
			$where[$field] = $value;
			$where[$this->key.'[!]'] = $id;
			return $this->db->has($this->table,$where);
		}else{
			return false;
		}
    }

    /**
     * 修改记录
     * @param int $key 主键值
     * @param array $data 字段与值数组
     * @return bool
     */
	function edit($key,$data){
        $this->db->Begin();
        $saveData = $this->formartSaveData($data);
        $this->db->update($this->table,$saveData,[$this->key=>$key]);
        $this->tolink($key,$data);
        $this->db->End();
        return $key;
    }

    /**
     * 添加一条记录
     * @param array $data 字段与值数组
     * @return bool
     */
	function add($data){
        $this->db->Begin();
        $saveData = $this->formartSaveData($data);
        $this->db->insert($this->table,$saveData);
		if($this->table == 'adm_user'){
			$key = $saveData['au_id'];
		}else{
			$key = $this->db->id();	
		}
        if($key) $this->tolink($key,$data);
        $this->db->End();
        return $key;
    }

    function formartSaveData($data){
        $saveData = [];
        foreach($data as $k=>$v){
            if(isset($this->elecfg['fields'][$k]['editor']['formatValue']) && !empty($this->elecfg['fields'][$k]['editor']['formatValue'])){
                $saveData[$k]= $this->elecfg['fields'][$k]['editor']['formatValue']($v);
            }else if(empty($this->elecfg['fields'][$k]['link']) && empty($this->elecfg['fields'][$k]['linkMore'])){
                $saveData[$k]=$v;
            }
        }
        return $saveData;
    }

    //一对多链表
    function tolink($key,$data){
        foreach($data as $k=>$v){
            //一对多
            if(!empty($this->elecfg['fields'][$k]['linkMore'])){
                $link = $this->elecfg['fields'][$k]['linkMore'];
                $where = [
                    $link['mykey_link_field']=>$key
                ];
                $this->db->delete($link['table'],$where);
                $arr = explode(',',$v);
                if(count($arr)>0){
                    foreach($arr as $lv){
                        if($lv!=''){
                            $linkData = [ $link['mykey_link_field']=>$key, $link['field']=>$lv ];
                            $this->db->insert($link['table'],$linkData,$where);
                        }
                    }
                }
            }
        }
    }

    function preProcess($rows)
    {

        // 预处理 linkOne 数据
        foreach ($this->elecfg['fields'] as $field => $cfg) {
            if (!empty($cfg['linkOne'])) {
                $link = $cfg['linkOne'];
                if (!isset($link['myfield']) || $link['myfield'] == '') {
                    $link['myfield'] = $cfg['field'];
                }
                $keys = array_column($rows, $link['myfield']);
                $keys = array_unique(array_filter($keys)); // 去除空值
                if (!empty($keys)) {
                    $where = [$link['field'] => $keys];

                    if(is_string($link['caption'])){
                        $field = [$link['field'], $link['caption']];
                    }elseif (is_array($link['caption'])) {
                        $field = array_merge([$link['field']], $link['caption']);
                    }
                    if(is_string($link['caption']) || is_array($link['caption'])){
                        if($link['join']){
                            $res = $this->db->select($link['table'],$link['join'],$field, $where);
                        }else{
                            $res = $this->db->select($link['table'], $field, $where);
                        }
                        if($res)
                        {   
                            foreach ($res as $key => $value) {
                                if(is_array($link['caption'])){
                                    foreach ($link['caption'] as $captionkey => $captionval) {
                                        $this->linkOneCache[$cfg['field']][$link['table']][$value[$link['field']]] = $value[$captionkey];
                                    }
                                }else{
                                    $this->linkOneCache[$cfg['field']][$link['table']][$value[$link['field']]] = $value[$link['caption']];
                                }
                               
                            }
                        }
                    }
                    
                }
            }

            if (!empty($cfg['linkMore'])) {
                $link = $cfg['linkMore'];
                if($link['function'])
                {
                    $link['function']($rows,$this->linkMoreCache, $this->db);
                }
                else
                {   
                    $keys = array_column($rows, $this->key);
                    $keys = array_unique(array_filter($keys)); // 去除空值
                    if (!empty($keys)) {

                        $where = [$link['mykey_link_field'] => $keys];
                        $res = $this->db->select($link['table'], [$link['mykey_link_field'], $link['field']], $where);
                        if($res){
                            foreach ($res as $key => $value) {
                                $this->linkMoreCache[$cfg['field']][$link['table']][$value[$link['mykey_link_field']]]['values'][] = $value[$link['field']];
                            }
                            $values = array_column($res, $link['field']);
                        }

                        if($link['element'] &&  $this->linkMoreCache[$cfg['field']][$link['table']]){
                            foreach ($this->linkMoreCache[$cfg['field']][$link['table']] as $mykey_link_field => $values) 
                            {
                                if(!isset($this->elementExtList[$link['element']])){
                                    $this->elementExtList[$link['element']] = new element($link['element']);
                                }
                                $caption = $this->elementExtList[$link['element']]->getCaptionByIds($values);
                                if($caption!=''){
                                    $caption = implode(', ',$caption);
                                    $this->linkMoreCache[$cfg['field']][$link['table']][$mykey_link_field]['captions']= $caption;
                                }
                            }
                            
                        }
                    
                    }
                    
                }
                
                
            }
        }
        return $rows;
    }
}