<?php
namespace model\grid;
class lrtree extends \model
{
	var $struct =[];
	function __construct($options = null){
		parent::__construct();
		if($options==null){
			$options = [
				'table'=>'ltree',
				'id'=>'id',
				'parent_id'=>'parent_id',
				'left'=>'left',
				'right'=>'right',
				'level'=>'level',
				'ismove'=>'ismove',
				'name'=>'name',
				'sort'=>'sort',
				'create_time'=>'create_time',
				'update_time'=>'update_time'
			];
		}
		$this->struct = $options;
	}
	function list($where=[],$page=0,$pagesize=0,$sidx='',$sord='asc',$orderby=''){
		if($orderby=='') $orderby = $this->struct['left'];
		$where = $this->listWhere($where,$page,$pagesize,$sidx,$sord,$orderby);
		$table = $this->struct['table'];
		$fields = "*";
		if($page>0 && $pagesize>0){
			$pages = $this->paging($table,$where,$page,$pagesize);
			$where["LIMIT"] = [$pages['limit'],$pagesize];
		}
		$rows = $this->db->select($table,$fields,$where);
		$data = [
			'page'=> $page,
			'total'=> $pages['total'],
			'records' => $pages['records'],
			'rows' => $rows
		];
		return $data;
	}
	/**
	 * 重构左右值
	 *
	 * @return bool
	 */
	function restructure($root=0){
		//$this->db->begin();
		if($root==0){
			$this->db->update($this->struct['table'],[$this->struct['left']=>0,$this->struct['right']=>0,$this->struct['level']=>1]);
		}
		$rows = $this->db->select($this->struct['table'],"*",[$this->struct['parent_id']=>$root]);
		foreach($rows as $row){
			$id = $row[$this->struct['id']];
			$this->restructureUpdateLR($id, $root);
			if($this->hasChildrenByParent($id)){
				$this->restructure($id);
			}
		}
		//$this->db->end();
		return true;

	}
	function restructureUpdateLR($id,$parentKey){
		$data = $this->getAddNodeData($parentKey,[]);
		$savedata[$this->struct['left']]  = $data[$this->struct['left']];
		$savedata[$this->struct['right']] = $data[$this->struct['right']];
		$savedata[$this->struct['level']] = $data[$this->struct['level']];
		$this->db->update($this->struct['table'],$savedata,[$this->struct['id']=>$id]);
	}

	
	/**
	 * 添加节点
	 *
	 * @param int $parent_id 父ID
	 * @param arrat $data 其他字段数据
	 * @return bool
	 */
	function getAddNodeData($parent_id,$data){
		if($parent_id==0){
			$maxRight = $this->db->max($this->struct['table'],$this->struct['right']);
			$left = $maxRight*1+1;
			$level = 1;
		}else{
			$parentNode = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$parent_id]);
			$left = $parentNode[$this->struct['right']]*1;
			$level = $parentNode[$this->struct['level']]*1+1;
			//所有节点左值大于父节点右值的，左值+2
			$this->db->update($this->struct['table'],[$this->struct['left']."[+]"=>2],[$this->struct['left']."[>]"=>$left]);
			//所有节点右值大于父节点右值的，右值+2
			$this->db->update($this->struct['table'],[$this->struct['right']."[+]"=>2],[$this->struct['right']."[>]"=>$left]);
			//父节点右值+2
			$this->db->update($this->struct['table'],[$this->struct['right']."[+]"=>2],[$this->struct['id']=>$parent_id]);
		}
		$right = $left+1;
		$now = date('Y-m-d H:i:s',time());
		$data[$this->struct['parent_id']] = $parent_id;
		$data[$this->struct['left']] = $left;
		$data[$this->struct['right']] = $right;
		$data[$this->struct['level']] = $level;
		$data[$this->struct['create_time']] = $now;
		$data[$this->struct['update_time']] = $now;
		return $data;
	}

	function addNode($parent_id,$data){
		$savedata = $this->getAddNodeData($parent_id,$data);
		$this->db->insert($this->struct['table'],$savedata);
		return $this->db->id();
	}
	/**
	 * 删除节点
	 *
	 * @param int $id
	 * @return bool
	 */
	function deleteNode($id){
		$this->db->begin();
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$id]);
		$left = $node[$this->struct['left']]*1;
		$right = $node[$this->struct['right']]*1;
		$width = $right - $left + 1; //当前节点的宽度
		//删除所有左值大于等于当前节点的左值，并且右值小于等于当前节点右值的所有节点
		$this->db->delete($this->struct['table'],[
			$this->struct['left']."[>=]" => $left,
			$this->struct['right']."[<=]" => $right
		]);
		//所有左值大于当前节点的右值的节点的左值-当前节点的宽度
		$this->db->update($this->struct['table'],[
			$this->struct['left']."[-]" => $width
		],[
			$this->struct['left']."[>]" => $right
		]);
		//所有右值大于当前节点的右值的节点的右值-当前节点的宽度
		$this->db->update($this->struct['table'],[
			$this->struct['right']."[-]" => $width
		],[
			$this->struct['right']."[>]" => $right
		]);
		return $this->db->end();
	}
	/**
	 * 修改节点
	 *
	 * @param int $id
	 * @param int $parent_id 父ID
	 * @param arrat $data 其他字段数据
	 * @return bool
	 */
	function editNode($id,$parent_id,$data){
		$this->db->begin();
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$id]);
		$left = $node[$this->struct['left']]*1;
		$right = $node[$this->struct['right']]*1;
		if($parent_id == $node[$this->struct['parent_id']]){
			$now = date('Y-m-d H:i:s',time());
			$data[$this->struct['update_time']] = $now;
			$this->db->update($this->struct['table'],$data,[$this->struct['id']=>$id]);
		}else if($right-$left==1){
			//终节点
			$this->deleteNode($id);
			$data[$this->struct['id']] = $id;
			$this->addNode($parent_id,$data);
		}
        $result = $this->db->end();
		return $result;
	}

	
	/**
	 * 变更父节点（支持移动整个子树）
	 *
	 * @param int $id 当前节点ID
	 * @param int $parent_id 新父节点ID
	 * @param array $data 其他需要更新的字段数据
	 * @return bool
	 */
	function editNodeByChangePid($id, $parent_id, $data = []){
		$this->db->begin();
		
		// 1. 获取当前节点信息
		$node = $this->db->get($this->struct['table'], "*", [$this->struct['id'] => $id]);
		if(empty($node)){
			$this->db->end();
			return false;
		}

		$oldParentId = $node[$this->struct['parent_id']] * 1;
		$left = $node[$this->struct['left']] * 1;
		$right = $node[$this->struct['right']] * 1;
		$width = $right - $left + 1; // 子树宽度
		$level = $node[$this->struct['level']] * 1;

		// 2. 如果父节点没变，只更新普通字段
		if($parent_id == $oldParentId){
			$now = date('Y-m-d H:i:s', time());
			$data[$this->struct['update_time']] = $now;
			
			// 过滤掉树结构字段，防止意外覆盖
			$updateData = [];
			$treeFields = [$this->struct['left'], $this->struct['right'], $this->struct['level'], $this->struct['parent_id'], $this->struct['id']];
			foreach($data as $k => $v){
				if(!in_array($k, $treeFields)){
					$updateData[$k] = $v;
				}
			}
			
			if(!empty($updateData)){
				$this->db->update($this->struct['table'], $updateData, [$this->struct['id'] => $id]);
			}
			return $this->db->end();
		}

		// 3. 验证新父节点是否存在
		if($parent_id != 0){
			$parentNode = $this->db->get($this->struct['table'], "*", [$this->struct['id'] => $parent_id]);
			if(empty($parentNode)){
				$this->db->end();
				return false;
			}
			
			// 4. 计算新的位置和层级
			$targetLeft = $parentNode[$this->struct['right']] * 1;
			$newLevel = $parentNode[$this->struct['level']] * 1 + 1;
		} else {
			// 移动到根节点，不需要更新父节点
			$maxRight = $this->db->max($this->struct['table'], $this->struct['right']);
			$targetLeft = $maxRight + 1;
			$newLevel = 1;
		}

		$levelDiff = $newLevel - $level;


		// 第一步：缩小旧父节点及其所有祖先节点的right值（减少子树宽度）
		if($oldParentId != 0){
			$oldParentNode = $this->db->get($this->struct['table'], "*", [$this->struct['id'] => $oldParentId]);
			if(!empty($oldParentNode)){
				$oldParentRight = $oldParentNode[$this->struct['right']] * 1;
				// 找到所有left < oldParentRight 且 right >= oldParentRight 的节点（即旧父节点及其祖先）
				$this->db->update($this->struct['table'], [
					$this->struct['right'] . "[-]" => $width
				], [
					$this->struct['left'] . "[<]" => $oldParentRight,
					$this->struct['right'] . "[>=]" => $oldParentRight
				]);
			}
		}
		
		// 第二步：将当前子树临时移出到表的最末尾
		$maxRight = $this->db->max($this->struct['table'], $this->struct['right']);
		$tempOffset = $maxRight + 1;
		
		$this->db->update($this->struct['table'], [
			$this->struct['left'] . "[+]" => $tempOffset,
			$this->struct['right'] . "[+]" => $tempOffset
		], [
			$this->struct['left'] . "[>=]" => $left,
			$this->struct['right'] . "[<=]" => $right
		]);

		// 第三步：更新新父节点及其所有祖先节点的right值（增加子树宽度）
		if($parent_id != 0){
			$this->db->update($this->struct['table'], [
				$this->struct['right'] . "[+]" => $width
			], [
				$this->struct['left'] . "[<]" => $targetLeft,
				$this->struct['right'] . "[>=]" => $targetLeft
			]);
		}

		// 第四步：调整间隙
		if($targetLeft > $right){
			// 向右移动：收缩空洞
			$this->db->update($this->struct['table'], [
				$this->struct['left'] . "[-]" => $width,
				$this->struct['right'] . "[-]" => $width
			], [
				$this->struct['left'] . "[>]"=>$right,
				$this->struct['left'] . "[<]"=>$targetLeft
			]);

			$finalLeft = $targetLeft - $width;
		} else {
			// 向左移动：扩张空间
			$this->db->update($this->struct['table'], [
				$this->struct['left'] . "[+]" => $width,
				$this->struct['right'] . "[+]" => $width
			], [
				$this->struct['left'] . "[>=]"=>$targetLeft,
				$this->struct['left'] . "[<]"=>$left
			]);


			$finalLeft = $targetLeft;
		}
		
		
		
		// 第五步：将子树归位到新位置
		$moveDiff = $finalLeft - ($left + $tempOffset);
		
		$this->db->update($this->struct['table'], [
			$this->struct['left'] . "[+]" => $moveDiff,
			$this->struct['right'] . "[+]" => $moveDiff,
			$this->struct['level'] . "[+]" => $levelDiff
		], [
			$this->struct['left'] . "[>]"=> $maxRight
		]);

		// 第六步：更新字段
		
		
		$updateData = [
			$this->struct['parent_id'] => $parent_id,
			$this->struct['update_time'] => getNowTime()
		];
		$treeFields = [$this->struct['left'], $this->struct['right'], $this->struct['level'], $this->struct['id']];
		foreach($data as $k => $v){
			if(!in_array($k, $treeFields)){
				$updateData[$k] = $v;
			}
		}
		
		if(!empty($updateData)){
			$this->db->update($this->struct['table'], $updateData, [$this->struct['id'] => $id]);
		}

		return $this->db->end();
	}


	/**
	 * 移动节点
	 *
	 * @param int $prevKey 前一个节点
	 * @param int $key 当前节点
	 * @param int $nextKey 后一个节点
	 * @return bool
	 */
	function moveNode($prevKey,$key,$nextKey){
		$this->db->begin();
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$key]);
		$left = $node[$this->struct['left']]*1;
		$right = $node[$this->struct['right']]*1;
		$width = $right - $left + 1; //当前节点的宽度
		$nextNode = false;
		$prevNode = false;
		$isPrev = false;
		if($nextKey==0 && $prevKey>0){
			$nextKey = $prevKey;
			$isPrev = true;
		}
		if($nextKey>0){
			$nextNode = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$nextKey]);
			$nextLeft = $nextNode[$this->struct['left']]*1;
			$nextRight = $nextNode[$this->struct['right']]*1;
			$nextPrevNode = $this->db->get($this->struct['table'],"*",[$this->struct['right']=>$nextLeft-1]);
			$nextLevel = $nextNode[$this->struct['level']]*1;
			$nextParentId = $nextNode[$this->struct['parent_id']]*1;
			if($nextParentId==0 && $prevKey>0){
				$nextKey = $prevKey;
				$isPrev = true;
				$nextNode = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$nextKey]);
				$nextLeft = $nextNode[$this->struct['left']]*1;
				$nextRight = $nextNode[$this->struct['right']]*1;
				$nextPrevNode = $this->db->get($this->struct['table'],"*",[$this->struct['right']=>$nextLeft-1]);
				$nextLevel = $nextNode[$this->struct['level']]*1;
				$nextParentId = $nextNode[$this->struct['parent_id']]*1;
			}
			if($nextPrevNode[$this->struct['id']] == $node[$this->struct['parent_id']]){
				$nextLeft = $nextPrevNode[$this->struct['right']]*1;
				$nextLevel = $nextPrevNode[$this->struct['level']]*1 + 1;
				$nextParentId = $nextNode[$this->struct['id']]*1;
				$nextNode = $nextPrevNode;
			}
			$levelDiff = $nextLevel - $node[$this->struct['level']]*1;
		}
		if($nextNode!=false){
			if($right < $nextLeft){
				//从左往右移
				$diff = $nextLeft - $width - $left;
				$newLeft = $diff+$left;
				$newRight = $diff+$right;
				//dd($nextLeft,$right);
				//
				$this->db->update($this->struct['table'],[
					$this->struct['ismove'] => 1
				],[
					$this->struct['left']."[>=]" => $left,
					$this->struct['right']."[<=]" => $right
				]);
				$this->db->update($this->struct['table'],[
					$this->struct['parent_id'] => $nextParentId,
				],[
					$this->struct['id'] => $key,
				]);
				//所有左值大于当前节点的右值并且小于新树后节点右值的节点的  左值-当前节点的宽度
				$this->db->update($this->struct['table'],[
					$this->struct['left']."[-]" => $width
				],[
					$this->struct['left']."[>]" => $right,
					$this->struct['left']."[<]" => $nextLeft
				]);
				//所有右值大于当前节点的右值并且小于新树后节点右值的节点的  右值-当前节点的宽度
				$this->db->update($this->struct['table'],[
					$this->struct['right']."[-]" => $width
				],[
					$this->struct['right']."[>]" => $right,
					$this->struct['right']."[<=]" => $newRight
				]);
				//
				$this->db->update($this->struct['table'],[
					$this->struct['ismove'] => 0,
					$this->struct['left']."[+]" => $diff,
					$this->struct['right']."[+]" => $diff,
					$this->struct['level']."[+]" => $levelDiff
				],[
					$this->struct['ismove'] => 1,
					$this->struct['left']."[>=]" => $left,
					$this->struct['right']."[<=]" => $right
				]);
			}else{
				//从右往左移
				$diff = $nextLeft - $left;
				$newLeft = $diff+$left;
				$newRight = $diff+$right;
				//
				$this->db->update($this->struct['table'],[
					$this->struct['ismove'] => 1
				],[
					$this->struct['left']."[>=]" => $left,
					$this->struct['right']."[<=]" => $right
				]);
				$this->db->update($this->struct['table'],[
					$this->struct['parent_id'] => $nextParentId,
				],[
					$this->struct['id'] => $key,
				]);
				//所有左值大于当前节点的右值并且小于新树后节点右值的节点的  左值+当前节点的宽度
				$this->db->update($this->struct['table'],[
					$this->struct['left']."[+]" => $width
				],[
					$this->struct['left']."[>=]" => $nextLeft,
					$this->struct['left']."[<]" => $left
				]);
				//所有右值大于当前节点的右值并且小于新树后节点右值的节点的  右值+当前节点的宽度
				$this->db->update($this->struct['table'],[
					$this->struct['right']."[+]" => $width
				],[
					$this->struct['right']."[>=]" => $nextLeft,
					$this->struct['right']."[<]" => $left
				]);
				//
				$this->db->update($this->struct['table'],[
					$this->struct['ismove'] => 0,
					$this->struct['left']."[+]" => $diff,
					$this->struct['right']."[+]" => $diff,
					$this->struct['level']."[+]" => $levelDiff
				],[
					$this->struct['ismove'] => 1,
					$this->struct['left']."[>=]" => $left,
					$this->struct['right']."[<=]" => $right
				]);
			}

		}
		if($isPrev){
			$this->moveNode(0,$prevKey,$key);
		}
		return $this->db->end();
	}
	/**
	 * 通过ID得到节点
	 *
	 * @param int $id 节点
	 * @return array
	 */
	function getNode($id){
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$id]);
        return $node;
    }
	/**
	 * 通过IDS得到多个节点
	 *
	 * @param string|array $id 节点ID集
	 * @return array
	 */
	function getNodesByIds($ids){
        if(!is_array($ids)) $ids = explode(',',$ids);
		$rows = $this->db->select($this->struct['table'],"*",[$this->struct['id']=>$ids]);
        return $rows;
    }
	/**
	 * 是否有子节点
	 *
	 * @param int|array $node 节点,id或者是记录
	 * @return bool
	 */
	function hasChild($node){
        if(!is_array($node)){
            $node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$node]);
        }
        $left = $node[$this->struct['left']]*1;
        $right = $node[$this->struct['right']]*1;
        $level = $node[$this->struct['level']]*1;
        $where = [
            $this->struct['level'] => $level+1,
            $this->struct['left']."[>]" => $left,
            $this->struct['right']."[<]" => $right,
            'LIMIT'=>[0,1]
        ];
        $row = $this->db->get($this->struct['table'],"*",$where);
        return (!empty($row)) ? 1 : 0;
    }
	function hasChildrenByParent($id){
		return $this->db->has($this->struct['table'],[$this->struct['parent_id']=>$id]);
	}
	/**
	 * 得到所有子节点
	 *
	 * @param int $id 节点
	 * @return array
	 */
	function getChilds($id){
        if(!empty($id)){
            $node = $this->getNode($id);
            $left = $node[$this->struct['left']]*1;
            $right = $node[$this->struct['right']]*1;
            if(!empty($node)){
                $where = [
                    $this->struct['left']."[>]" => $left,
                    $this->struct['right']."[<]" => $right,
                ];
            }
        }else{
            $right = $this->db->max($this->struct['table'],$this->struct['right']);
            $where = [
                $this->struct['left']."[>]" => 0,
                $this->struct['right']."[<=]" => $right,
            ];
        }
        $where['ORDER'] = $this->struct['sort'];
        $rows = $this->db->select($this->struct['table'],"*",$where);
        return $rows;
    }
	/**
	 * 得到上一级父节点
	 *
	 * @param int $id 节点
	 * @param bool $hasSelf 返回结果是否包括节点自己
	 * @return array
	 */
	function getParent($id,$hasSelf=false){
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$id]);
		$where = [
			$this->struct['id'] => $node[$this->struct['parent_id']],
		];
        return $this->db->get($this->struct['table'],"*",$where);
    }
	/**
	 * 得到节点所有父节点
	 *
	 * @param int $id 节点
	 * @param bool $hasSelf 返回结果是否包括节点自己
	 * @return array
	 */
	function getParents($id,$hasSelf=false){
		$node = $this->db->get($this->struct['table'],"*",[$this->struct['id']=>$id]);
		$left = $node[$this->struct['left']]*1;
		$right = $node[$this->struct['right']]*1;
        if(!empty($node)){
            if($hasSelf=='true' || $hasSelf=='1'){
                $where = [
                    $this->struct['left']."[<=]" => $left,
                    $this->struct['right']."[>=]" => $right,
                ];
            }else{
                $where = [
                    $this->struct['left']."[<]" => $left,
                    $this->struct['right']."[>]" => $right,
                ];
            }
        }
        $rows = $this->db->select($this->struct['table'],"*",$where);
        return $rows;
    }

    /**
     * 是否需要code
     * @param int $parentId
     * @return false|mixed
     */
    public function hasCode($parentId)
    {
        return $this->db->get($this->struct['table'],'o_has_code',array('o_id' => $parentId));
    }
}