<?php

/// @Brief 任务操作
///
class TaskOperation
{
    private $userTasks = []; // 用户任务列表
    private $userInfo;       // 用户信息
    private $currTaskId;     // 当前任务编号
    private $idb;            // 用户任务db<参见IUserTaskDb>
    private $stepCount;      // 单个任务步骤数量
    private $runningTaskInfo;   // 正在执行的任务信息
    private $runningTaskId;     // 正在执行的任务信息编号
    private $runningTaskState;  // 正在执行任务的状态
    private $taskNoticeJson;    // 任务通知json<参考TaskNoticeJson>
    private $isCancelTask;      // 是否取消任务

    private static $instance = null; // 单例

    // @function 获取单例
    //
    // @return TaskPreconditionCompare
    public static function getInstance(){
        if (is_null(self::$instance)) { self::$instance =  new TaskOperation();}
        return self::$instance;
    }

    // @function 初始函数
    //
    // @param userId 用户编号
    // @param idb 数据接口<参考IUserTaskDb>
    public function init($userId,$idb){
        $this ->idb = $idb;
        $this ->userInfo     = $this ->getUserInfo($userId,$idb);
        $this ->userTasks    = $this ->getUserTasks($userId,$idb);
        $this ->taskNoticeJson = new TaskNoticeJson();
    }

    // @function 设置是否取消任务
    //
    // @param isCancelTask 当前任务编号
    public function setIsCancelTask($isCancelTask = false){
        $this ->isCancelTask = $isCancelTask;
    }

    // @function 设置当前任务编号
    //
    // @param currTaskId 当前任务编号
    public function setCurrTaskId($currTaskId = 0){
        $this ->resetTask();
        $this ->currTaskId = $currTaskId;
    }

    // @function 重置任务
    //
    private function resetTask(){
        $this ->stepCount = 0;
        $this ->runningTaskInfo = null;
        $this ->runningTaskId = null;
        $this ->runningTaskState = null;
        $this ->isCancelTask = null;
    }
    // @function 检测用户任务是否完成
    //
    // @return 状态
    public function checkUserTaskIsComplete(){
        $this ->runningTaskId = $this ->currTaskId;
        // 获取任务信息
        $taskInfo = new TaskInfo();
        $this ->getTaskInfoById($this ->currTaskId,$taskInfo);
        // 转换前置条件信息
        $taskPreconditionInfo = new TaskPreconditionInfo();
        $this ->transformPreconditionInfo($taskInfo,$taskPreconditionInfo);
        $taskInfo ->precondition = $taskPreconditionInfo;
        // 转换后置条件信息
        $taskPostcondition = new TaskPostcondition();
        $this ->transformTaskPostcondition($taskInfo,$taskPostcondition);
        $taskInfo ->postcondition = $taskPostcondition;
        $this ->runningTaskInfo = $taskInfo;

        // 检测用户一个任务是否完成
        $this ->checkUserOneTaskIsComplete($this ->userInfo,
            $taskInfo ->precondition,$taskInfo ->postcondition,$taskInfo ->postcondition);
    }

    // @function 检测用户任务是否可接
    //
    // @return 状态
    public function checkTaskIsAccessible(){

        // 获取用户当前任务
        $taskInfo = new TaskInfo();
        $this ->getTaskInfoById($this ->currTaskId,$taskInfo);

        // 转换前置条件信息
        $taskPreconditionInfo = new TaskPreconditionInfo();
        $this ->transformPreconditionInfo($taskInfo,$taskPreconditionInfo);

        $taskInfo ->precondition = $taskPreconditionInfo;

        // 转换后置条件信息
        $taskPostcondition = new TaskPostcondition();
        $this ->transformTaskPostcondition($taskInfo,$taskPostcondition);
        $taskInfo ->postcondition = $taskPostcondition;

        // 多任务触发
        if (!is_null($taskInfo ->precondition ->mtaskIds)
            &&!empty($taskInfo ->precondition ->mtaskIds)){
            $taskCount =  0;
            foreach ($taskInfo ->precondition ->mtaskIds as $mtaskId)
            {
                $utaskInfo = null;
                $utaskInfo = $this ->getUserTaskInfo($mtaskId);
                if (TaskState::COMPLETE == $utaskInfo ->taskState){
                    $taskCount++;
                }
            }

            if ($taskCount == count($taskInfo ->precondition ->mtaskIds))
                return true;
            else
                return null;
        }
        return $this ->checkOneTaskIsAccessible($this ->userInfo,
            $taskInfo ->precondition);

    }

    // @function 获取任务信息
    //
    // @param id 任务编号
    // @param taskInfo 任务信息<参见TaskInfo>
    // @return 任务信息
    private function getTaskInfoById($id,$taskInfo){
        $dbTaskInfo = $this ->idb ->getTaskInfoById($id);

        if (!empty($dbTaskInfo) && !is_null($dbTaskInfo)){
            $taskInfo ->id = $dbTaskInfo['id'];
            $taskInfo ->taskName = $dbTaskInfo['task_name'];
            $taskInfo ->taskDescription = $dbTaskInfo['task_description'];
            $taskInfo ->precondition = $dbTaskInfo['precondition'];
            $taskInfo ->prefunction = $dbTaskInfo['prefunction'];
            $taskInfo ->postcondition = $dbTaskInfo['postcondition'];
            $taskInfo ->postfunction = $dbTaskInfo['postfunction'];
            $taskInfo ->stepFuns = $dbTaskInfo['stepfunction'];
            $taskInfo ->stepCount = $dbTaskInfo['stepcount'];
            $taskInfo ->stepclassname = $dbTaskInfo['stepclassname'];
        }
        return null;
    }

    // @function 检测用户一个任务是否完成
    //
    // @function userInfo 用户信息<参见UserDataInfo>
    // @function taskPreconditionInfo 用户信息<参见TaskPreconditionInfo>
    // @function taskPostcondition 任务后缀条件<参见TaskPostcondition>
    // @function outTaskPreconditionInfo 输出任何后缀条件信息<参见OutTaskPreconditionInfo>
    // @return 状态
    private function checkUserOneTaskIsComplete($userInfo,
                                                $taskPreconditionInfo,$taskPostcondition,$outTaskPreconditionInfo){
        // 获取用户任务信息
        $userTaskInfo = $this ->getUserTaskInfo($this ->runningTaskId);

        // 如果任务当前的步骤数大于0,那么起始步骤数等于任务当前的步骤数
        if(!is_null($userTaskInfo ->tcurrStepCount)
            && 0 < $userTaskInfo ->tcurrStepCount){
            $this ->stepCount = $userTaskInfo ->tcurrStepCount;
        }

        if (is_null($userTaskInfo ->taskState))
            return false;

//        // 如果用户的正在执行的任务已完成,就更新正在执行用户的任务状态
//        if (TaskState::COMPLETE == $this ->runningTaskState
//            && !is_null($this ->runningTaskState)){
//            $userTaskInfo ->taskState = $this ->runningTaskState;
//        }

        // 取消任务
        if (true == $this ->isCancelTask
            && !is_null($this ->isCancelTask)){
            $userTaskInfo ->taskState = TaskState::CANCEL;
        }

        if (TaskState::COMPLETE == $userTaskInfo ->taskState){

             // 任务完成
             // out_后置条件 设置
             // 是否激活下一个任务
            if (!is_null($taskPostcondition ->nextTask)
                && 0 < $taskPostcondition ->nextTask){
                $this ->resetTask();
                $this ->runningTaskId = $taskPostcondition ->nextTask;
                $this ->runningTaskInfo = new TaskInfo();
                $this ->getTaskInfoById($taskPostcondition ->nextTask,$this ->runningTaskInfo);
                // 转换前置条件信息
                $taskPreconditionInfo = new TaskPreconditionInfo();
                $this ->transformPreconditionInfo($this ->runningTaskInfo,$taskPreconditionInfo);
                $this ->runningTaskInfo ->precondition = $taskPreconditionInfo;
                // 转换后置条件信息
                $taskPostcondition = new TaskPostcondition();
                $this ->transformTaskPostcondition($this ->runningTaskInfo,$taskPostcondition);
                $this ->runningTaskInfo ->postcondition = $taskPostcondition;
                $this ->checkUserOneTaskIsComplete($this ->userInfo,
                    $this ->runningTaskInfo ->precondition,
                    $this ->runningTaskInfo ->postcondition,$outTaskPreconditionInfo);
            }
            // 返回 out_后置条件
        }elseif (TaskState::CANCEL == $userTaskInfo ->taskState)
        {
            // 任务取消
            // 通知到前端取消成功<由客户端执行更新用户任务状态>
            $stepFuncInfo = $this ->findCurrStepFunc($this ->stepCount);
            $this ->taskNoticeJson ->id = $this ->runningTaskId;
            $this ->taskNoticeJson ->stepCount = $this ->stepCount;
            $this ->taskNoticeJson ->stepFunc = isset($stepFuncInfo['name'])?$stepFuncInfo['name']:'';
            $this ->taskNoticeJson ->stepMsgType = isset($stepFuncInfo['type'])?$stepFuncInfo['type']:'';
            $this ->taskNoticeJson ->stepReturn = '';
            $this ->taskNoticeJson ->stepMsg = "你好";
        }elseif (TaskState::CONDUCT == $userTaskInfo ->taskState){

            // 任务进行
            $stepFuncInfo = $this ->findCurrStepFunc($this ->stepCount);
            $stepFuncResult = $this ->execTaskStepFunc($this ->runningTaskInfo ->stepclassname,$stepFuncInfo);

            if (!is_bool($stepFuncResult)
                && false != $stepFuncResult){
                $this ->taskNoticeJson ->id = $this ->runningTaskId;
                $this ->taskNoticeJson ->stepCount = $this ->stepCount;
                $this ->taskNoticeJson ->stepFunc = isset($stepFuncInfo['name'])?$stepFuncInfo['name']:'';
                $this ->taskNoticeJson ->stepMsgType = isset($stepFuncInfo['type'])?$stepFuncInfo['type']:'';
                $this ->taskNoticeJson ->stepReturn = $stepFuncResult;
                $this ->taskNoticeJson ->stepMsg = "你好";
                ++$this ->stepCount;
                // 如果任务步骤数执行完了,任务就完成了
                if ((int)$this ->runningTaskInfo ->stepCount
                    == $this ->stepCount){
                    $this ->taskNoticeJson ->taskState = TaskState::COMPLETE;
                }
                // 通知到前端()
            }
        }
    }

    // @function 获取用户信息
    //
    // @param userId 用户编号
    // @param idb 数据接口<参考IUserTaskDb>
    private function getUserInfo($userId,$idb){
        $userInfo = (new UserTaskDb()) ->getUserInfoByUserId($userId);
        $userDataInfo = new UserDataInfo();
        if (!empty($userInfo) && !is_null($userInfo)){
            $this ->transformUserInfo($userInfo,$userDataInfo);
        }
        return $userDataInfo;
    }

    // @function 查找当前步骤函数
    //
    // @param step 第几步
    // @return 步骤函数
    private function findCurrStepFunc($step){
        if (is_null($this ->runningTaskInfo))
            return '';
        if (is_null($this ->runningTaskInfo ->stepFuns) || empty($this ->runningTaskInfo ->stepFuns))
            return '';

        $this ->runningTaskInfo ->stepFuns = json_decode($this ->runningTaskInfo ->stepFuns,true);

        foreach ($this ->runningTaskInfo ->stepFuns
                 as $key => $stepFun)
        {
            if ($key == $step)
                return $stepFun;
        }
    }

    // @function 执行任务步骤函数
    //
    // @param stepclassname 步骤函数保存文件名称
    // @param stepFuncInfo 步骤函数信息
    // @return 执行结果
    private function execTaskStepFunc($stepclassname,$stepFuncInfo)
    {

       if (is_null($stepclassname) || empty($stepclassname))
           return false;

        if (is_null($stepFuncInfo) || empty($stepFuncInfo))
            return false;

        // 如果任务步骤函数对象,不存在
        if (!class_exists($stepclassname))
            return false;

        // 建立任务步骤函数对象反射类
        $reflectStepFuncClass = new ReflectionClass($stepclassname);
        // 实例化任务步骤函数对象
        $instanceStepFuncClass  = $reflectStepFuncClass->newInstanceArgs();
        $stepFuncName = isset($stepFuncInfo['name'])?$stepFuncInfo['name']:'';
        // 判断步骤函数对象,函数是否存在
        if (method_exists($stepclassname,$stepFuncName)){
            return $instanceStepFuncClass ->$stepFuncName();
        }
        return false;
    }

    // @function 转换用户信息
    //
    // source 源
    // target 目标<参见UserDataInfo>
    private function transformUserInfo($source,$target){

        if (isset($source['baseInfo']) && !empty($source['baseInfo'])){
            $userBaseInfo =  new UserBaseInfo();
            $userBaseInfo ->age = $source['baseInfo']['age'];
            $userBaseInfo ->sex = $source['baseInfo']['sex'];
            $userBaseInfo ->time = $source['baseInfo']['time'];
            $userBaseInfo ->ulevel = $source['baseInfo']['ulevel'];
            $userBaseInfo ->place = $source['baseInfo']['place'];
            $userBaseInfo ->weather = $source['baseInfo']['weather'];
            $userBaseInfo ->age = $source['baseInfo']['age'];
            $target ->baseInfo = $userBaseInfo;
        }

        if (isset($source['physical']) && !empty($source['physical'])){
            $taskPhysicalDataPInfo =  new TaskPhysicalDataPInfo();
            $taskPhysicalDataPInfo ->isLikeSports = $source['physical']['isLikeSports'];
            $taskPhysicalDataPInfo ->isHypertension = $source['physical']['isHypertension'];
            $taskPhysicalDataPInfo ->isHeartAttack = $source['physical']['isHeartAttack'];
            $taskPhysicalDataPInfo ->isAgile = $source['physical']['isAgile'];
            $taskPhysicalDataPInfo ->isHardBody = $source['physical']['isHardBody'];
            $target ->userPhysicalDataPInfo = $taskPhysicalDataPInfo;
        }
    }

    // @function 检测一个任务是否可接
    //
    // @param userDataInfo          用户数据信息<参见UserDataInfo>
    // @param taskPreconditionInfo  任务前置条件信息<参考TaskPreconditionInfo>
    // @return boolean
    private function checkOneTaskIsAccessible($userDataInfo,
                                             $taskPreconditionInfo){

        return TaskPreconditionCompare::getInstance() ->getResult($userDataInfo,
            $taskPreconditionInfo);
    }

    // @function 获取用户任务信息
    //
    // @param taskId  任务编号
    // @return 用户当前任务
    private function getUserTaskInfo($taskId)
    {

      foreach ($this ->userTasks as $userTask)
      {
          if ($userTask instanceof  UserTaskInfo){
              if ($userTask ->taskId == $taskId)
                  return $userTask;
          }

          if (is_array($userTask)){
              if ($userTask['id'] == $taskId)
                  return $userTask;
          }
      }
    }

    // @function 获取用户任务
    //
    // @param userId 用户编号
    // @param idb 数据接口<参考IUserTaskDb>
    private function getUserTasks($userId,$idb)
    {
        $userTasks = [];
        $dbUserTasks  = $idb ->getUserTaskByUserId($userId);
        foreach ($dbUserTasks as $userTask){
            $taskInfo = new UserTaskInfo();
            $this ->transformTasks($userTask,$taskInfo);
            $userTasks[] = $taskInfo;
        }
        return $userTasks;
    }

    // @function 获取用户任务
    //
    // @param dbTaskInfo 数据库任务信息
    // @param tTaskInfo  转化的信息信息<参考UserTaskInfo>
    private function transformTasks($dbTaskInfo,$tTaskInfo){
        $tTaskInfo ->userId = $dbTaskInfo['user_id'];
        $tTaskInfo ->taskId = $dbTaskInfo['task_id'];
        $tTaskInfo ->tcurrStepfun = $dbTaskInfo['tcurr_step_fun'];
        $tTaskInfo ->tcurrStepCount = $dbTaskInfo['tcurr_step_count'];
        $tTaskInfo ->taskState = 0 == $dbTaskInfo['task_state']?3:$dbTaskInfo['task_state'];
    }

    // @function 转换后置条件信息
    //
    // @param taskInfo  任务信息                    <参考TaskInfo>
    // @param taskPostcondition 任务后置条件信息     <参考TaskPostcondition>
    // @return void
    private function transformTaskPostcondition($taskInfo,$taskPostcondition){
        if (!is_null($taskInfo)
            && !empty($taskInfo ->postfunction)) {
            $postfunctions = explode(',', $taskInfo->postfunction);
            $taskPostcondition ->nextTask = current($postfunctions);
        }
    }

    // @function 转换前置条件信息
    //
    // @param taskInfo  任务信息                    <参考TaskInfo>
    // @param taskPreconditionInfo 任务前置条件信息   <参考TaskPreconditionInfo>
    // @return void
    private function transformPreconditionInfo($taskInfo,$taskPreconditionInfo){

        if (!is_null($taskInfo)
            && !empty($taskInfo ->precondition)){
            $precondition = json_decode($taskInfo ->precondition,true);
            // 转化基本数据
            if (isset($precondition['or'])){

                $taskPreconditionInfo ->age     = $this ->transformPreconditionCompare('age',$precondition['or']);
                $taskPreconditionInfo ->sex     = $this ->transformPreconditionCompare('sex',$precondition['or']);
                $taskPreconditionInfo ->time    = $this ->transformPreconditionCompare('time',$precondition['or']);
                $taskPreconditionInfo ->ulevel  = $this ->transformPreconditionCompare('ulevel',$precondition['or']);
                $taskPreconditionInfo ->place   = $this ->transformPreconditionCompare('place',$precondition['or']);
                $taskPreconditionInfo ->weather = $this ->transformPreconditionCompare('weather',$precondition['or']);
            }

            // 转化生理信息
            if (isset($precondition['sl'])) {
                $taskPhysicalDataPInfo = new TaskPhysicalDataPInfo();
                $taskPhysicalDataPInfo ->isAgile = $this ->transformPreconditionCompare('isAgile',
                    $precondition['sl']);
                $taskPhysicalDataPInfo ->isLikeSports = $this ->transformPreconditionCompare('isLikeSports',
                    $precondition['sl']);
                $taskPhysicalDataPInfo ->isHypertension = $this ->transformPreconditionCompare('isHypertension',
                    $precondition['sl']);
                $taskPhysicalDataPInfo ->isHeartAttack = $this ->transformPreconditionCompare('isHeartAttack',
                    $precondition['sl']);
                $taskPhysicalDataPInfo ->isHardBody = $this ->transformPreconditionCompare('isHardBody',
                    $precondition['sl']);
                $taskPreconditionInfo ->taskPhysicalDataPInfo = $taskPhysicalDataPInfo;
            }

            // 前置任务
            if (!empty($taskInfo ->prefunction)
                && !is_null($taskInfo ->prefunction))
            {
                $taskPreconditionInfo ->mtaskIds = explode(',',$taskInfo ->prefunction);
                $taskPreconditionInfo ->mtaskIds = array_filter($taskPreconditionInfo ->mtaskIds);
            }

        }
    }

    // @function 转化前置条件比较
    //
    // @param name
    // @param values
    // @return
    private function transformPreconditionCompare($name,$values){

        if(!empty($values))
        {
            // 获取值类型列表
            $valueTypes = TaskPreConditionValueType::getValueTypes();
            foreach ($values as $value)
            {
//                $value = json_decode($value,true);
                if ($value['short'] == $name){
                    $taskCondtionInfo = new TaskCondtionInfo();
                    // 查找值类型
                    $valueType = TaskPreConditionValueType::findValueType($value['preRelationId'],$valueTypes);

                    if (2 == $valueType['id']){
                        $taskCondtionInfo ->maxValue = $value['preRelationStart'];
                    }elseif (4 == $valueType['id'])
                    {
                        $taskCondtionInfo ->minValue = $value['preRelationStart'];
                    }elseif (5 == $valueType['id'])
                    {
                        $taskCondtionInfo ->minValue = $value['preRelationStart'];
                    }elseif (6 == $valueType['id']){
                        $taskCondtionInfo ->minValue = $value['preRelationStart'];
                        $taskCondtionInfo ->maxValue = $value['preRelationEnd'];
                    }elseif (in_array($valueType['id'],[0,1,7,8,9,10])){
                        $taskCondtionInfo ->equalValue = $value['preRelationName'];
                    } else{
                        $taskCondtionInfo ->equalValue = $value['preRelationStart'];
                    }

                    return $taskCondtionInfo;
                }
            }
        }
    }

    // @function 通知客户端
    //
    public function noticeClient(){
        return $this ->taskNoticeJson;
    }




}