#include "myjson.h"
#include "board.h"
#include "debug.h"
#include "mystdlib.h"
#include "bytearray.h"





// json字符串转化为json,返回临时指针
cJSON *json_parse(const char *jstr)
{
  cJSON *json=cJSON_Parse(jstr);
  if(json){
    return tappend(json,cJSON_Delete);
  }
  return json;
}






/*r{ json 转列表 }c*/
list_def *jarray_to_list(cJSON *jarray,obj_def *obj)
{
  param_check(obj);
  param_check(obj->to_obj_fun);
  param_check(obj->obj_size);
  param_check(jarray);
  list_def *l=list_creat(obj->obj_size,obj->sub,obj->del,0);
  void *o;
  int array_size;
  if(jarray->type!=cJSON_Array){
    DBG_WARN("json:%s not a array obj.",jarray->string?jarray->string:"null");
    goto err;
  }
  array_size=cJSON_GetArraySize(jarray);
  for(int i=0;i<array_size;i++)
  {
    o=obj->to_obj_fun(cJSON_GetArrayItem(jarray,i));
    if(o==0)
    {
      DBG_WARN("json:%s conversion failed.",jarray->string?jarray->string:"null");
      goto err;
    }
    list_append(l,o);
    if(obj->del_fun) obj->del_fun(o);
  }
  err:
  return l;
}


/*r{ json转整形 }c*/
static void *json_to_int(cJSON *j)
{
  if(j->type==cJSON_Number)
  {
    int *ret=malloc(sizeof(int));
    param_check(ret);
    *ret=j->valueint;
    return ret;
  }
  return 0;
}



static obj_def g_obj_int={
  .obj_size=sizeof(int),
  .to_obj_fun=json_to_int,
  .del_fun=free,
  .sub=INT_SUB,
  .del=INT_DEL
};


obj_def *obj_int(void)
{
  return &g_obj_int;
}








/*r{ json转字符串 }c*/
static void *json_to_str(cJSON *j)
{
  if(j->type==cJSON_String)
  {
    int len=strlen(j->valuestring)+1;
    char *ret=malloc(len);
    char **ret_ptr=malloc(sizeof(char *));
    param_check(ret);
    param_check(ret_ptr);
    memcpy(ret,j->valuestring,len+1);
    *ret_ptr=ret;
    return ret_ptr;
  }
  return 0;
}



static obj_def g_obj_str={
  .obj_size=sizeof(char *),
  .to_obj_fun=json_to_str,
  .del_fun=free,
  .sub=STR_SUB,
  .del=STR_DEL
};


obj_def *obj_str(void)
{
  return &g_obj_str;
}





static void *json_to_range(cJSON *j)
{
  sch_range *s=malloc(sizeof(sch_range));
  param_check(s);
  JSON_GET_INT(cJSON_GetObjectItem(j,"Max"),s->max);
  JSON_GET_INT(cJSON_GetObjectItem(j,"Min"),s->min);
  if(s->min>s->max){
    DBG_WARN("range is empty.");
  }
  return s;
}





static obj_def g_obj_range={
  .obj_size=sizeof(sch_range),
  .to_obj_fun=json_to_range,
  .del_fun=free,
  .sub=0,
  .del=0
};


obj_def *obj_range(void)
{
  return &g_obj_range;
}

// 返回1，在范围内
int range_in_range(sch_range *r,int num)
{
  if(num>=r->min&&num<=r->max)
    return 1;
  else
    return 0;
}








static void *json_to_task(cJSON *j)
{
  sch_task *task=calloc(1,sizeof(sch_range));
  JSON_GET_STR(cJSON_GetObjectItem(j,"TaskBrief"),task->brief);
  JSON_GET_INT(cJSON_GetObjectItem(j,"TaskID"),task->task_id);
  JSON_GET_INT(cJSON_GetObjectItem(j,"TaskIndex"),task->index);
  JSON_GET_INT(cJSON_GetObjectItem(j,"ErrJumpTo"),task->err_jump);
  JSON_GET_INT(cJSON_GetObjectItem(j,"RetryCount"),task->retry);
  JSON_GET_INT(cJSON_GetObjectItem(j,"ParamCount"),task->param_num);
  JSON_GET_INT(cJSON_GetObjectItem(j,"ReturnCount"),task->return_num);
  task->params_info=jarray_to_list(cJSON_GetObjectItem(j,"ParamInfo"),obj_str());
  task->returns_info=jarray_to_list(cJSON_GetObjectItem(j,"ReturnInfo"),obj_str());
  task->params=jarray_to_list(cJSON_GetObjectItem(j,"ParamVal"),obj_int());
  task->ranges=jarray_to_list(cJSON_GetObjectItem(j,"TestStandard"),obj_range());
  JSON_GET_INT(cJSON_GetObjectItem(j,"ExecuteErrCode"),task->failed_code);
  task->ret_failed_code=jarray_to_list(cJSON_GetObjectItem(j,"ResultErrCode"),obj_int());
  return task;
}




static int _list_del_task(void *p)
{
  sch_task *t=p;
  CHECK_DO(t->brief,free);
  CHECK_DO(t->params_info,list_delete);
  CHECK_DO(t->returns_info,list_delete);
  CHECK_DO(t->params,list_delete);
  CHECK_DO(t->ranges,list_delete);
  CHECK_DO(t->ret_failed_code,list_delete);
  CHECK_DO(t->ch_errcode,list_delete);
  return 0;
}



static obj_def g_obj_task={
  .obj_size=sizeof(sch_task),
  .to_obj_fun=json_to_task,
  .del_fun=free,
  .sub=0,
  .del=_list_del_task
};


obj_def *obj_task(void)
{
  return &g_obj_task;
}

// 任务转化为数组
array_def *task_to_array(sch_task *t)
{
  array_def *a=arr_creat();
  arr_append(a,(uint8_t)t->task_id);
  arr_append(a,(uint8_t)t->index);
  arr_append(a,(uint8_t)t->retry);
  arr_append(a,(uint8_t)t->err_jump);
  arr_append(a,(uint8_t)(t->param_num&0x0f)|(t->return_num<<4));
  for(int i=0;i<list_length(t->params);i++)
  {
    arr_append(a,(uint8_t)(list_get_int(t->params,i)&0xff));
    arr_append(a,(uint8_t)(list_get_int(t->params,i)>>8));
  }
  if(list_length(t->params)!=t->param_num)
  {
    DBG_WARN("name=%s param_num!=params.size().",t->brief);
  }
  if(t->return_num>list_length(t->returns_info))
  {
    DBG_WARN("name=%s return_num>returns_info.size().",t->brief);
  }
  if(list_length(t->ch_errcode)!=list_length(t->ranges))
  {
    DBG_WARN("name=%s ch_errcode.size()!=ranges.size().",t->brief);
  }
  return a;
}



// ack==0成功
task_returns *task_check_returns(sch_task *t,int ack,array_def *data)
{
  int size=sizeof(task_returns)+sizeof(reurn_item)*t->return_num;
  task_returns *res=malloc(size);
  param_check(res);
  res->size=size;
  memset(res,0,size);
  if(t->ch_errcode==0) t->ch_errcode=list_creat_int();
  list_clear(t->ch_errcode);
  res->index=t->index;
  res->id=t->task_id;
  res->ack=ack;
  if(res->ack==0){
    res->exe_err=0;
  }else{
    res->exe_err=t->failed_code;
    list_append_int(t->ch_errcode,t->failed_code);
  }
  if(arr_length(data)/2<t->return_num){
    DBG_WARN("task=%s, data size too less.",t->brief);
  }else{
    for(int i=0;i<t->return_num;i++)
    {
      reurn_item *item=&res->items[i];
      int value=arr_get(data,i*2)|(arr_get(data,i*2+1)<<8);
      item->value=value;
      if(list_length(t->ranges)>i)
      {
        if(range_in_range(list_get(t->ranges,i),value))
          item->err=0;
        else{
          if(list_length(t->ret_failed_code)>i)
          {
            item->err=list_get_int(t->ret_failed_code,i);
            list_append_int(t->ch_errcode,item->err);
          }
        }
      }
    }
  }
  return res;
}





static void *json_to_errcode(cJSON *j)
{
  sch_errcode *e=calloc(1,sizeof(sch_errcode));
  param_check(e);
  JSON_GET_INT(cJSON_GetObjectItem(j,"MajorErrCode"),e->err);
  JSON_GET_STR(cJSON_GetObjectItem(j,"Info"),e->info);
  e->suberr=jarray_to_list(cJSON_GetObjectItem(j,"SubErrCode"),obj_int());
  return e;
}

static int _list_del_errcode(void *p)
{
  sch_errcode *e=p;
  CHECK_DO(e->info,free);
  CHECK_DO(e->suberr,list_delete);
  return 0;
}

static obj_def g_obj_errcode={
  .obj_size=sizeof(sch_errcode),
  .to_obj_fun=json_to_errcode,
  .del_fun=free,
  .sub=0,
  .del=_list_del_errcode
};


obj_def *obj_errcode(void)
{
  return &g_obj_errcode;
}

// 返回1在范围内
int errcode_in_range(sch_errcode *e,int subcode)
{
  param_check(e);
  for(int i=0;i<list_length(e->suberr);i++)
  {
    if(subcode==list_get_int(e->suberr,i))
      return 1;
  }
  return 0;
}





static void *_json_to_scheme(cJSON *j)
{
  scheme_def *s=calloc(1,sizeof(scheme_def));
  param_check(s);
  JSON_GET_INT(cJSON_GetObjectItem(j,"PlanID"),s->plan_id);
  JSON_GET_STR(cJSON_GetObjectItem(j,"PlanBrief"),s->brief);
  s->slave_soft_versions=jarray_to_list(cJSON_GetObjectItem(j,"CheckSoftVersion"),obj_int());
  s->slave_hard_versions=jarray_to_list(cJSON_GetObjectItem(j,"CheckHardVersion"),obj_int());
  JSON_GET_INT(cJSON_GetObjectItem(j,"TimeOutS"),s->timeout_s);
  JSON_GET_INT(cJSON_GetObjectItem(j,"TimeOutM"),s->timeout_m);
  JSON_GET_INT(cJSON_GetObjectItem(j,"TaskIDMax"),s->task_id_max);
  s->errs=jarray_to_list(cJSON_GetObjectItem(j,"MajorErrInfo"),obj_errcode());
  s->tasks=jarray_to_list(cJSON_GetObjectItem(j,"TaskArray"),obj_task());
  return s;
}



static int _list_del_scheme(void *p)
{
  scheme_def *t=p;
  CHECK_DO(t->brief,free);
  CHECK_DO(t->slave_soft_versions,list_delete);
  CHECK_DO(t->slave_hard_versions,list_delete);
  CHECK_DO(t->errs,list_delete);
  CHECK_DO(t->tasks,list_delete);
  CHECK_DO(t->ch_errcode,list_delete);
  return 0;
}

static obj_def g_obj_scheme={
  .obj_size=sizeof(scheme_def),
  .to_obj_fun=_json_to_scheme,
  .del_fun=free,
  .sub=0,
  .del=_list_del_scheme
};


obj_def *obj_scheme(void)
{
  return &g_obj_scheme;
}



scheme_def *json_to_scheme(cJSON *j)
{
  param_check(j);
  obj_def *obj=obj_scheme();
  scheme_def *s=obj->to_obj_fun(j);
  return s;
}
void scheme_delete(scheme_def *s)
{
  obj_def *obj=obj_scheme();
  param_check(s);
  obj->del(s);
  obj->del_fun(s);
}


// 任务id转化为字节数据
#define TASKSID_MAX_SIZE 0x100
static array_def *scheme_taskid_to_array(scheme_def *s)
{
  param_check(s);
  array_def *res=arr_creat();
  param_check(res);
  arr_append(res,s->plan_id&0xff);
  arr_append(res,(s->plan_id>>8)&0xff);
  arr_append(res,(s->plan_id>>16)&0xff);
  arr_append(res,(s->plan_id>>24)&0xff);
  for(int i=0;i<list_length(s->tasks);i++)
  {
    sch_task *t=list_get(s->tasks,i);
    arr_append(res,t->task_id);
  }
  int size=arr_length(res);
  if(size<TASKSID_MAX_SIZE){
    arr_append_num(res,TASKSID_MAX_SIZE-size,0xff);
  }else{
    DBG_WARN("taskid array size too larg.");
  }
  return res;
}

// 任务转化为字节数据
#define TASKS_MAX_SIZE (0x700-4)
static array_def *scheme_tasks_to_array(scheme_def *s)
{
  param_check(s);
  array_def *res=arr_creat();
  param_check(res);
  for(int i=0;i<list_length(s->tasks);i++)
  {
    sch_task *t=list_get(s->tasks,i);
    array_def *a=task_to_array(t);
    arr_appends_from(res,a);
    arr_delete(a);
  }
  int size=arr_length(res);
  if(size<TASKS_MAX_SIZE)
  {
    arr_append_num(res,TASKS_MAX_SIZE-size,0xff);
  }else{
    DBG_WARN("tasks array size too larg.");
  }
  return res;
}

// 方案转化为字节数据
array_def *scheme_to_byte_array(scheme_def *s)
{
  param_check(s);
  array_def *res=arr_creat();
  param_check(res);
  array_def *src;
  src=scheme_taskid_to_array(s);
  arr_appends_from(res,src);
  arr_delete(src);
  src=scheme_tasks_to_array(s);
  arr_appends_from(res,src);
  arr_delete(src);
  return res;
}


// 统计返回数据长度
int scheme_get_returns_num(scheme_def *s)
{
  int num=0;
  for(int i=0;i<list_length(s->tasks);i++)
  {
    sch_task *t=list_get(s->tasks,i);
    num+=t->return_num;
  }
  return num;
}

// 返回0成功，1失败
int scheme_check_ack(array_def *data,int index)
{
  param_check(index>=0);
  param_check(index<arr_length(data)*8);
  uint8_t temp=arr_get(data,index/8);
  if((temp&(1<<(index%8)))!=0)
  {return 1;}else{return 0;}
}

// 返回子错误所在的主错误，失败返回0
int scheme_fine_majercode(scheme_def *s,int subcode)
{
  for(int i=0;i<list_length(s->errs);i++)
  {
    sch_errcode *e=list_get(s->errs,i);
    if(errcode_in_range(e,subcode))
      return e->err;
  }
  return 0;
}


// 判定检测数据
scheme_returns *scheme_check_returns(scheme_def *s,array_def *data)
{
  int size=0;
  size+=sizeof(scheme_returns);
  size+=sizeof(task_returns)*list_length(s->tasks);
  size+=sizeof(reurn_item)*scheme_get_returns_num(s);
  scheme_returns *res=malloc(size);
  param_check(res);
  memset(res,0,size);
  res->size=size;
  if(s->ch_errcode==0) s->ch_errcode= list_creat_int();
  list_clear(s->ch_errcode);
  
  int start=16;
  int off=0;
  for(int i=0;i<list_length(s->tasks);i++)
  {
    int ack=scheme_check_ack(data,i);
    sch_task *t=list_get(s->tasks,i);
    array_def *arr_temp=arr_mid(data,start,t->return_num*2);
    task_returns *task_ret=task_check_returns(t,ack,arr_temp);
    arr_delete(arr_temp);
    memcpy(&res->data[off],task_ret,task_ret->size);
    off+=task_ret->size;
    start+=t->return_num*2;
    list_append_from(s->ch_errcode,t->ch_errcode);
  }
  if(list_length(s->ch_errcode)>0)
  {
    res->errcode=scheme_fine_majercode(s,list_get_int(s->ch_errcode,0));
  }else{
    res->errcode=0;
  }
  return res;
}




