/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

//
// Created by Wangyunlai on 2021/5/14.
//

#ifndef __OBSERVER_SQL_EXECUTOR_VALUE_H_
#define __OBSERVER_SQL_EXECUTOR_VALUE_H_

#include <string.h>
#include <iomanip>
#include <string>
#include <ostream>
#include <sstream>
#include <unordered_map>
#include <set>
#include <stack>
#include "sql/executor/tuple.h"
#include "common/log/log.h"
class TupleValue {
public:
  TupleValue() = default;
  virtual ~TupleValue() = default;

  virtual void to_string(std::ostream &os) const = 0;
  virtual int compare(const TupleValue &other) const = 0;

  virtual void to_ss(std::stringstream& str) const=0;
  virtual const AttrType type() const = 0;
  virtual const void *get_value() const = 0;
  bool is_null() const{
    return is_null_;
  }
protected:
  bool is_null_;
};

class IntValue : public TupleValue {
public:
  const AttrType type() const {
    return AttrType::INTS;
  }
  const void *get_value() const{
    return (void *)(&value_);
  }
  explicit IntValue(int value, bool is_null = false) : value_(value) {
    is_null_ = is_null;
  }

  void to_string(std::ostream &os) const override {
    if(is_null_){
      os << "NULL";
      return;
    }
    os << value_;
  }

  int compare(const TupleValue &other) const override {
    const IntValue & int_other = (const IntValue &)other;
    return value_ - int_other.value_;
  }

    void to_ss(std::stringstream& str) const override{
        str<<value_;
    }

  int value_;
};

class FloatValue : public TupleValue {
public:
  const AttrType type() const {
    return AttrType::FLOATS;
  }
  const void *get_value() const{
    return (void *)(&value_);
  }
  explicit FloatValue(float value, bool is_null = false) : value_(value) {
    is_null_ = is_null;
  }
  std::string convert(float value) const
  {
    char buffer[64];
    snprintf(buffer, 64, "%.2f", value);
    std::string str(buffer);
    if(str.find(".00") != std::string::npos) {
      str.erase(str.find(".00"), std::string::npos);
    } else if(str.find('.') != std::string::npos && str[str.size() - 1] == '0') {
      str.erase(str.find_last_of('0'), std::string::npos);
    }
    return str;
  }

  void to_string(std::ostream &os) const override {
    if(is_null_){
      os << "NULL";
      return;
    }
    os << convert(value_);
  }

    void to_ss(std::stringstream& str) const override{
      str << convert(value_);
    }

  int compare(const TupleValue &other) const override {

    float result;
    if(other.type() == FLOATS){
      const FloatValue & float_other = (const FloatValue &)other;
      result  = value_ - float_other.value_;


    } else{
      const IntValue & int_other = (const IntValue &)other;
      result =  value_ - (float)int_other.value_;
      LOG_ERROR("it is %f %f %f",  value_ , (float)int_other.value_, result);
    }
    if (result > 1e-6) { // 浮点数没有考虑精度问题
        return 1;
      }
      if (result < -1e-6) {
        return -1;
      }
      return 0;
  }
  float value_;
};

class StringValue : public TupleValue {
public:
  const AttrType type() const {
    return AttrType::CHARS;
  }
  const void *get_value() const{
    return (std::string *)(&value_);
  }
  StringValue(const char *value, int len, bool is_null = false) : value_(value, len) {
    is_null_ = is_null;
  }
  explicit StringValue(const char *value) : value_(value) {
  }

  void to_string(std::ostream &os) const override {
    if(is_null_){
      os << "NULL";
      return;
    }
    os << value_;
  }

  int compare(const TupleValue &other) const override {
    const StringValue &string_other = (const StringValue &)other;
    return strcmp(value_.c_str(), string_other.value_.c_str());
  }

    void to_ss(std::stringstream& str) const override{
        str<<value_;
    }

  StringValue* copy() {
    return new StringValue(value_.c_str(), value_.size());
  }
private:
  std::string value_;
};

class DateValue : public TupleValue {
public:
  const AttrType type() const {
    return AttrType::DATES;
  }
  const void *get_value() const{
    return (void *)(&value_);
  }
  explicit DateValue(int value, bool is_null = false) : value_(value) {
    is_null_ = is_null;
  }

  void to_string(std::ostream &os) const override {
    if(is_null_){
      os << "NULL";
      return;
    }
    os << value_/10000 << "-" << (value_ / 100 % 100 < 10 ? "0" : "") << value_ / 100 % 100
      << "-" << (value_ % 100 < 10 ? "0" : "") << value_ % 100;
  }

  int compare(const TupleValue &other) const override {
    const DateValue & date_other = (const DateValue &)other;
    return value_ - date_other.value_;
  }

  void to_ss(std::stringstream& str) const override{
      str<<value_;
  }

  int trans(int year, int month, int day){
    return year*10000 + month*100 + day;//如果这里改了，yacc里也要改
  }
private:
  int value_;
};

struct hash_pair { 
    template <class T1, class T2> 
    size_t operator()(const std::pair<T1, T2>& p) const
    { 
        auto hash1 = std::hash<T1>{}(p.first); 
        auto hash2 = std::hash<T2>{}(p.second); 
        return hash1 ^ hash2; 
    } 
};
struct cmp_rel {  
    bool operator()(const RelAttr &a,const RelAttr &b) {  
        std::string str_a = std::string(a.attribute_name);
        str_a.append("_");
        if(a.relation_name != nullptr) str_a.append(a.relation_name);
        std::string str_b = std::string(b.attribute_name);
        if(b.relation_name != nullptr) str_b.append(b.relation_name);
        return str_a < str_b;  
    }  
};
struct TupleValueNode {
  ValueNode *node_;
  std::vector<RelAttr> attrs_;
  int type_,pos_;
  TupleValueNode(ValueNode *node, int type, int pos){
    node_ = node;
    type_ = type;
    pos_ = pos;
  }
  size_t get_tables(std::set<std::string> &tables){
    for(auto &attr : attrs_){
      tables.emplace(attr.relation_name);
    }
    return tables.size();
  }
  std::string value_str(Value *value){
    std::stringstream ss;
    TupleValue *val;
    switch (value->type){
      case AttrType::INTS:
        val = new IntValue(*(int *)value->data);
        break;
      case AttrType::FLOATS:
        val = new FloatValue(*(float *)value->data);
        break;
      case AttrType::CHARS:
        val = new StringValue((const char *)value->data);
        break;
      case AttrType::DATES:
        val = new DateValue(*(int *)value->data);
        break;
      default:
        return "ERROR";
        break;
    }
    val->to_string(ss);
    delete val;
    return ss.str();
  }
  RC node_str(ValueNode *node, std::string &str, bool multi){

    if(node == nullptr){
      return RC::CONSTRAINT_NOTNULL;
    }

    if(node->opt == 1) str.append("-(");
    for(int i = 0;i < node->brace_num;i++){
      str.append("(");
    }
    if(node->left != nullptr){
      node_str(node->left, str, multi);
    }
    switch (node->opt){
    case 0:
      if(node->is_attr){
        if(0 != strcmp(node->attr.function_name,"")){
          str.append(node->attr.function_name).append("(");
        }
        if(node->attr.relation_name != nullptr && multi){
          str.append(node->attr.relation_name).append(".");
        }
        str.append(node->attr.attribute_name);
        if(0 != strcmp(node->attr.function_name,"")){
          str.append(")");
        }
      }else{
        str.append(value_str(&node->value));
      }
      
    break;
    case 1:
      break;
    case 2:
      str.append("+");
      break;
    case 3:
      str.append("-");
      break;  
    case 4:
      str.append("*");
      break;  
    case 5:
      str.append("/");
      break;  
    default:
      return RC::INVALID_ARGUMENT;
  }
  if(node->right != nullptr){
    node_str(node->right, str, multi);
  }
  for(int i = 0;i < node->brace_num;i++){
    str.append(")");
  }
  if(node->opt == 1) str.append(")");
  return RC::SUCCESS;
}
  RC node_str(std::string &str, bool multi){
    if(node_ == nullptr){
      return RC::CONSTRAINT_NOTNULL;
    }
    return node_str(node_,str, multi);
  }
  RC node_attrs(ValueNode *node, std::vector<RelAttr> &attrs){
    if(node == nullptr){
      return RC::CONSTRAINT_NOTNULL;
    }
    std::stack<std::pair<ValueNode *,bool> >st;
    st.push({node,false});
    while(!st.empty()){
      auto now = st.top();
      st.pop();
      if(now.second){
        if(now.first->is_attr && now.first->left == nullptr && now.first->right == nullptr){
          attrs.push_back(now.first->attr);
          //LOG_ERROR("push %s.%s",now.first->attr.relation_name,now.first->attr.attribute_name);
        }
      }else{
        if(now.first->right) st.push({now.first->right,false});
        st.push({now.first,true});
        if(now.first->left) st.push({now.first->left,false});
      }
    }
    return RC::SUCCESS;
  }
  RC node_attrs(){
    return node_attrs(node_,attrs_);
  }
  void print_attrs(){
    /*
    LOG_ERROR("begin");
    for(auto &it:attrs_){
      LOG_ERROR("%s",it.attribute_name);
    }
    LOG_ERROR("end");
    */
  }
  float do_opt(int opt,float a,float b){
    LOG_ERROR("f f %f %f",a,b);
    switch (opt)
    {
    case 2:
      return a + b;
      break;
    case 3:
      return a - b;
      break;
    case 4:
      return a * b;
      break;
    case 5:
      return a / b;
      break;    
    default:
      break;
    }
  }
  float do_opt(int opt,int a,float b){
        LOG_ERROR("l f %d,%f",a,b);
    return do_opt(opt, (float)a, b);
  }
  float do_opt(int opt,float a,int b){
    LOG_ERROR("f i %f,%d",a,b);
    return do_opt(opt, a, (float)b);
  }
  int do_opt(int opt,int a,int b){
    LOG_ERROR("d d %d %d",opt,a,b);
    switch (opt)
    {
    case 2:
      return a + b;
      break;
    case 3:
      return a - b;
      break;
    case 4:
      return a * b;
      break;
    case 5:
      return a / b;
      break;    
    default:
      break;
    }
  }
  std::shared_ptr<TupleValue> node_value(ValueNode *node, std::vector<std::shared_ptr<TupleValue> > &values, int &pos, bool &zero){
    //values顺序必须与上述attrs函数返回结果一致
    if(zero) return nullptr;
    if(node == nullptr){
      return nullptr;
    }
    std::shared_ptr<TupleValue> left = nullptr,mid = nullptr,right = nullptr;
    if(node->left){
      left = node_value(node->left,values,pos,zero);
    }
    if(node->left == nullptr && node->right == nullptr){
      if(node->is_attr){
        mid = values.at(pos);
        pos++;
        if(mid->is_null()){
          node->is_null = 1;
          return nullptr;
        }
      } else {
        Value *v = &node->value;
        //实在不喜欢switch太长了，虽然跳转效率高
        if(v->type==AttrType::INTS) mid = std::make_shared<IntValue>(*(int *)v->data,false);
        else if(v->type==AttrType::FLOATS) mid = std::make_shared<FloatValue>(*(float *)v->data,false);
        else if(v->type==AttrType::DATES) mid = std::make_shared<DateValue>(*(int *)v->data,false);
        else if(v->type==AttrType::CHARS) mid = std::make_shared<StringValue>((const char *)v->data);
        else if(v->type==AttrType::NULLVAL){
          node->is_null = 1;
          return nullptr;
        }
      }
    }
    if(node->right){
      right = node_value(node->right,values,pos,zero);
    }
    if(node->left == nullptr && node->right == nullptr){
      return mid;
    }else if(node->left == nullptr && node->right != nullptr){
      mid = right;
      if(mid->type() == AttrType::INTS) (*(int *)mid->get_value()) *= -1;
      else if(mid->type() == AttrType::FLOATS) (*(float *)mid->get_value()) *= -1;
      else return nullptr;
    }else{
      if(zero) return nullptr;
      const void *left_val = left->get_value();
      const void *right_val = right->get_value();
      if(node->opt == 5){
        if(right->type() == AttrType::FLOATS){
          float val = *(float *)right_val;
          if(val > -1e-5 && val < 1e-5) zero = true;
          if(zero) LOG_ERROR("become zero float %f",val);
        }
        if(right->type() == AttrType::INTS){
          int val = *(int *)right_val;
          if(val == 0) zero = true;
          if(zero) LOG_ERROR("become zero int %d",val);
        }
      }
      if(zero) return nullptr;
      if(left->type() == AttrType::FLOATS && right->type() == AttrType::FLOATS){
        mid = std::make_shared<FloatValue>(do_opt(node->opt,*(float *)left_val,*(float *)right_val));
      }
      else if(left->type() == AttrType::INTS && right->type() == AttrType::FLOATS){
        mid = std::make_shared<FloatValue>(do_opt(node->opt,*(int *)left_val,*(float *)right_val));
      }
      else if(left->type() == AttrType::FLOATS && right->type() == AttrType::INTS){
        mid = std::make_shared<FloatValue>(do_opt(node->opt,*(float *)left_val,*(int *)right_val));
      }
      else if(left->type() == AttrType::INTS && right->type() == AttrType::INTS){
        if(node->opt != 5){
          mid = std::make_shared<IntValue>(do_opt(node->opt,*(int *)left_val,*(int *)right_val));
          LOG_ERROR("res %d",do_opt(node->opt,*(int *)left_val,*(int *)right_val));
        }else{
          mid = std::make_shared<FloatValue>(do_opt(node->opt,(float)(*(int *)left_val),(float)(*(int *)right_val)));
        }
        
      }else{
        return nullptr;
      }
    }
    return mid;
  }
  bool node_value(std::vector<std::shared_ptr<TupleValue> >&values,std::shared_ptr<TupleValue> &res){
    int pos = 0;
    bool ok = false;
    res = node_value(node_,values,pos,ok);
    return ok;
  }
};
struct Node_Manager {
  std::unordered_map<std::pair<int,int>, std::shared_ptr<TupleValueNode>, hash_pair> nodes;
  bool star;
  ~Node_Manager(){
    nodes.clear();
  }
  ValueNode *lturn(ValueNode *root){
    ValueNode *rson = root->right;
    root->right = rson->left;
    rson->left = root;
    return rson;
  }
  ValueNode *reverse_sec(ValueNode *root){
    assert(root != nullptr);
    if(root->opt == 1 || root->opt == 0) return root;
    while(root->right != nullptr && (root->right->opt == 4 || root->right->opt == 5)){
      root = lturn(root);
    }
    return root;
  }
  ValueNode *reverse_exp(ValueNode *root){
    assert(root != nullptr);
    if(root->opt == 4 || root->opt == 5) return reverse_sec(root);
    if(root->opt == 1 || root->opt == 0) return root;
    while(true){
      if(root->left != nullptr && (root->left->opt == 4 || root->left->opt == 5)){
        root->left = reverse_sec(root->left);
      }
      if(root->right != nullptr){
        if(root->right->opt == 2 || root->right->opt == 3){
          root = lturn(root);
        }else if(root->right->opt == 4 || root->right->opt == 5){
          root->right = reverse_sec(root->right);
          break;
        }else{
          break;
        }
      }else{
        break;
      }
    }
    return root;
  }
  RC add(int type,int pos,ValueNode *node){
    if(node == nullptr){
      return RC::CONSTRAINT_NOTNULL;
    }
    std::pair<int,int> cp = std::make_pair(type,pos);
    if(nodes.find(cp) != nodes.end()){
      return RC::GENERIC_ERROR;
    }
    auto pt =  std::make_shared<TupleValueNode>(node,type,pos);
    auto ret = nodes.insert({cp,pt});
    if(!ret.second){
      return RC::GENERIC_ERROR;
    }
    return RC::SUCCESS;
  }
  std::shared_ptr<TupleValueNode> get(int type,int pos){
    return nodes.at({type,pos});
  }
  int init(Selects &selects){
    //返回是否有表达式，如果没有还原到以前的形式
    int node_num = selects.attr_node_num, cond_num = selects.condition_num;
    int cnts = 0;
    for(int i = 0;i < node_num;i++){
      if(selects.attribute_nodes[i]->left != nullptr || selects.attribute_nodes[i]->right != nullptr){
        cnts++;
      }
    }
    for(int i = 0;i < cond_num;i++){
      ValueNode *left_cond = selects.conditions[i].left;
      ValueNode *right_cond = selects.conditions[i].right;
      if(left_cond != nullptr && (left_cond->left != nullptr || left_cond->right != nullptr)) cnts++;
      if(right_cond != nullptr && (right_cond->left != nullptr || right_cond->right != nullptr)) cnts++;
    }
    if(cnts == 0){
        for(int i = 0;i < node_num;i++) selects.attributes[selects.attr_num++] = selects.attribute_nodes[i]->attr;
        for(int i = 0;i < cond_num;i++) {
          ValueNode *left_cond = selects.conditions[i].left;
          ValueNode *right_cond = selects.conditions[i].right;
          selects.conditions[i].is_composite = 0;
          if(left_cond){
            selects.conditions[i].left_is_attr = left_cond->is_attr;
            selects.conditions[i].left_attr = left_cond->attr;
            selects.conditions[i].left_value = left_cond->value;
          }
          if(right_cond){
            selects.conditions[i].right_is_attr = right_cond->is_attr;
            selects.conditions[i].right_attr = right_cond->attr;
            selects.conditions[i].right_value = right_cond->value;
          }

        }
        return cnts;
    }
    for(int i = 0;i < node_num;i++){
      selects.attribute_nodes[i] = reverse_exp(selects.attribute_nodes[i]);
      add(0,i,selects.attribute_nodes[i]);
      get(0,i)->node_attrs();
    }
    for(int i = 0;i < cond_num;i++){
      selects.conditions[i].left = reverse_exp(selects.conditions[i].left);
      selects.conditions[i].right = reverse_exp(selects.conditions[i].right);
      add(1,i,selects.conditions[i].left);
      add(2,i,selects.conditions[i].right);
      get(1,i)->node_attrs();
      get(2,i)->node_attrs();
      get(1,i)->print_attrs();
      get(2,i)->print_attrs();

    }
    return cnts;
  }
  RC generate_all_attrs(Selects &selects){
    std::set<RelAttr,cmp_rel> st;
    int node_num = selects.attr_node_num, cond_num = selects.condition_num;
    std::shared_ptr<TupleValueNode> now;
    for(auto &it:nodes){
      now = it.second;
      for(auto &attr:now->attrs_){
        st.insert(attr);
      }
      
    }
    for(auto &it:st){
      selects.attributes[selects.attr_num++] = it;
    }
    return RC::SUCCESS;
  }
  bool judge(std::shared_ptr<TupleValue> left,std::shared_ptr<TupleValue> right,CompOp op){

    int cmp_result;
    if(left->type() == INTS) cmp_result = -right->compare(*left);
    else cmp_result = left->compare(*right);
    switch (op) {
      case EQUAL_TO:
        return 0 == cmp_result;
      case LESS_EQUAL:
        return cmp_result <= 0;
      case NOT_EQUAL:
        return cmp_result != 0;
      case LESS_THAN:
        return cmp_result < 0;
      case GREAT_EQUAL:
        return cmp_result >= 0;
      case GREAT_THAN:
        return cmp_result > 0;

      default:
        break;
    }

  }


};



#endif //__OBSERVER_SQL_EXECUTOR_VALUE_H_
