package util.sqlparse.visitor.dm.test;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import util.StringJoin;
import util.sqlparse.visitor.common.bean.FieldInfo;
import util.sqlparse.visitor.common.bean.SQLResult;
import util.sqlparse.visitor.common.bean.TableInfo;
import util.sqlparse.visitor.common.bean.ValueInfo;
import util.sqlparse.visitor.common.memo.FieldMemo;
import util.sqlparse.visitor.common.memo.TableMemo;

public class TestSet {
   public static final String TABLES_INFO = "TABLES-INFO";
   public static final String TABLES_MEMO = "TABLES-MEMO";
   public static final String FIELDS_INFO = "FIELDS-INFO";
   public static final String FIELDS_MEMO = "FIELDS-MEMO";
   public static final String OUTPUT_INFO = "OUTPUT-INFO";
   public static final String OUTPUT_MEMO = "OUTPUT-MEMO";
   public static final String VALUES_INFO = "VALUES-INFO";
   public static final String STATEMENT_STRING = "STATEMENT-STRING";
   public static final String DELIMITER = "<----delimiter---->";

   static List<String> getValuesInfo(SQLResult result) {
      List<String> list = new ArrayList();

      for(ValueInfo x : result.values) {
         list.add(x.value.toString() + " -> " + x.field.getQualifiedName());
      }

      return list;
   }

   static List<String> getOutputInfo(SQLResult result) {
      List<String> list = new ArrayList();

      for(FieldInfo x : result.outputs) {
         list.add(x.getFullName() + "->" + getString(x.getMemo()));
      }

      return list;
   }

   static List<String> getFiledsInfo(SQLResult result) {
      List<String> list = new ArrayList();

      for(FieldInfo x : result.fields) {
         list.add(x.getAtomName().toString());
      }

      return list;
   }

   static List<String> getTableINfo(SQLResult result) {
      List<String> list = new ArrayList();

      for(TableInfo x : result.tables) {
         list.add(x.getTable().getAtomName());
      }

      return list;
   }

   static void saveToJson(SQLResult result, String inputSql, JSONObject json) {
      List<String> tableInfos = getTableINfo(result);
      JSONObject tableInfoJson = new JSONObject();
      tableInfoJson.put((String)"TABLES-INFO", StringJoin.join(tableInfos, "<----delimiter---->"));
      List<String> tableMemos = getTableMemos(result);
      tableInfoJson.put((String)"TABLES-MEMO", StringJoin.join(tableMemos, "<----delimiter---->"));
      List<String> fieldsInfo = getFiledsInfo(result);
      tableInfoJson.put((String)"FIELDS-INFO", StringJoin.join(fieldsInfo, "<----delimiter---->"));
      List<String> fieldMemos = getFieldMemos(result);
      tableInfoJson.put((String)"FIELDS-MEMO", StringJoin.join(fieldMemos, "<----delimiter---->"));
      List<String> outputs = getOutputInfo(result);
      tableInfoJson.put((String)"OUTPUT-INFO", StringJoin.join(outputs, "<----delimiter---->"));
      List<String> outputMemos = getOutputMemos(result);
      tableInfoJson.put((String)"OUTPUT-MEMO", StringJoin.join(outputMemos, "<----delimiter---->"));
      List<String> values = getValuesInfo(result);
      tableInfoJson.put((String)"VALUES-INFO", StringJoin.join(values, "<----delimiter---->"));
      tableInfoJson.put((String)"STATEMENT-STRING", result.statement.toString());
      json.put((String)inputSql, tableInfoJson);
   }

   static List<String> getOutputMemos(SQLResult result) {
      List<String> list = new ArrayList();

      for(FieldMemo x : result.outputMemos) {
         list.add(x.getQualifiedName().replace("[\r  ]+", " ") + " " + getString(x));
      }

      return list;
   }

   static List<String> getFieldMemos(SQLResult result) {
      List<String> list = new ArrayList();

      for(FieldMemo x : result.fieldMemos) {
         list.add(x.getAtomName() + "{ as " + x.getQualifiedName() + "}->" + getString(x));
      }

      return list;
   }

   static List<String> getTableMemos(SQLResult result) {
      List<String> list = new ArrayList();

      for(TableMemo x : result.tableMemos) {
         List<String> nameList = new ArrayList();

         for(TableMemo z : x.getChildren()) {
            nameList.add(z.getQualifiedName());
         }

         list.add(x.getAtomName() + "->" + StringJoin.join(nameList, ","));
      }

      return list;
   }

   static String getString(FieldMemo memo) {
      StringBuffer s = new StringBuffer();
      s.append(memo.getAtomName());
      if (memo.children.size() > 0) {
         s.append(" [ ");
         if (memo.children != null) {
            for(FieldMemo child : memo.children) {
               s.append(getString(child));
               s.append(",");
            }

            s.deleteCharAt(s.length() - 1);
         }

         s.append(" ] ");
      }

      return s.toString();
   }

   static JSONObject test(SQLResult result, String inputSql, String path, JSONObject jsonObject) throws Exception {
      if (jsonObject == null) {
         jsonObject = readFromJson(path);
      }

      JSONObject json = (JSONObject)jsonObject.get(inputSql);
      String tableInfo = (String)json.get("TABLES-INFO");
      List<String> tableInfos = toStringList(tableInfo);
      compare(getTableINfo(result), tableInfos, "TABLES-INFO");
      String tableMemosStr = (String)json.get("TABLES-MEMO");
      List<String> tableMemos = toStringList(tableMemosStr);
      compare(getTableMemos(result), tableMemos, "TABLES-MEMO");
      String fieldInfoStr = (String)json.get("FIELDS-INFO");
      List<String> fieldInfo = toStringList(fieldInfoStr);
      compare(getFiledsInfo(result), fieldInfo, "FIELDS-INFO");
      String fieldMemoStr = (String)json.get("FIELDS-MEMO");
      List<String> fieldMemo = toStringList(fieldMemoStr);
      compare(getFieldMemos(result), fieldMemo, "FIELDS-MEMO");
      String outputInfoStr = (String)json.get("OUTPUT-INFO");
      List<String> outputInfo = toStringList(outputInfoStr);
      compare(getOutputInfo(result), outputInfo, "OUTPUT-INFO");
      String outputMemoStr = (String)json.get("OUTPUT-MEMO");
      List<String> outputMemo = toStringList(outputMemoStr);
      compare(getOutputMemos(result), outputMemo, "OUTPUT-MEMO");
      String ValueInfoStr = (String)json.get("VALUES-INFO");
      List<String> ValueInfo = toStringList(ValueInfoStr);
      compare(getValuesInfo(result), ValueInfo, "VALUES-INFO");
      String statementString = (String)json.get("STATEMENT-STRING");
      if (!statementString.equalsIgnoreCase(result.statement.toString())) {
         throw new Exception("STATEMENT-STRING");
      } else {
         return jsonObject;
      }
   }

   private static List<String> toStringList(String valueInfoStr) {
      return (List<String>)(valueInfoStr != null && !valueInfoStr.equals("") ? Arrays.asList(valueInfoStr.split("<----delimiter---->")) : new ArrayList(0));
   }

   private static void compare(List<String> src, List<String> tableInfos, String tag) throws Exception {
      List<CompareStruct> listCompares = new ArrayList();

      for(String tableinfo : tableInfos) {
         listCompares.add(new CompareStruct(tableinfo));
      }

      if (src.size() != listCompares.size()) {
         String error = "ERROR, " + tag + "size error.";
         throw new Exception(error);
      } else {
         compareTo(listCompares, src, tag);
      }
   }

   private static JSONObject readFromJson(String path) {
      String jsonString = JsonUtil.readJson(path);
      JSONObject json = JSON.parseObject(jsonString);
      return json;
   }

   private static void compareTo(List<CompareStruct> listCompares, List<String> tableInfos2, String tag) throws Exception {
      for(String src : tableInfos2) {
         for(CompareStruct target : listCompares) {
            if (!target.find && src.equalsIgnoreCase((String)target.object)) {
               target.find = true;
               break;
            }
         }
      }

      List<CompareStruct> notHitList = new ArrayList();

      for(CompareStruct x : listCompares) {
         if (!x.find) {
            notHitList.add(x);
         }
      }

      if (notHitList.size() > 0) {
         String error = "ERROR,  " + tag + "not hit. \n" + notHitList.toString();
         throw new Exception(error);
      }
   }
}
