package util.sqlparse.visitor.mongo;

import bean.DataBase;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.bson.BsonArray;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
import org.bson.json.JsonReader;
import util.sqlparse.visitor.common.bean.FieldInfo;
import util.sqlparse.visitor.common.bean.ValueInfo;
import util.sqlparse.visitor.common.memo.FieldMemo;
import util.sqlparse.visitor.common.memo.ValueMemo;

public class ApiParser {
   public ParseResult parse(String sql, DataBase dataBase, String schema) {
      MongoNode node = this.convert(sql);
      ScopeVisitor visitor = new ScopeVisitor(dataBase, schema);
      MongoParser parser = new MongoParser(visitor);
      parser.parse(node);
      ParseResult result = visitor.getResult();
      Translator translator = new Translator(dataBase, result);
      parser = new MongoParser(translator);
      parser.parse(node);
      FieldVisitor fieldVisitor = new FieldVisitor(dataBase, result, schema);
      parser = new MongoParser(fieldVisitor);
      parser.parse(node);

      for(ValueMemo value : fieldVisitor.values) {
         ValueInfo valueInfo = new ValueInfo(value);
         FieldMemo field = value.field;
         List<FieldInfo> fields = new ArrayList();
         FieldInfo fieldInfo = new FieldInfo();
         fieldInfo.setName(field.name);
         fieldInfo.setMemo(field);
         fieldInfo.setAlias(field.name);
         fieldInfo.setFullName(field.getAtomName());
         fields.add(fieldInfo);
         valueInfo.setFields(fields);
         result.values.add(valueInfo);
      }

      result.api = translator.getShellApi();
      result.newMongoNode = node;
      return result;
   }

   public String encode(String api, DataBase dataBase, String schema) {
      Encoder encoder = new Encoder(dataBase, schema, api);
      MongoParser parser = new MongoParser(encoder);
      return parser.encode();
   }

   public MongoNode convert(String sql) {
      if (sql != null && sql.length() != 0) {
         String[] sqls = sql.split("\r\n\r\n");
         List<BsonValue> values = this.getBsonValues(sqls);
         if (values != null && values.size() != 0) {
            MongoNode node = null;
            if (values.size() == 1) {
               node = new BsonObjectNode(null, ((BsonValue)values.get(0)).asDocument());
            } else {
               BsonArray array = new BsonArray();
               array.addAll(values);
               node = new BsonArrayNode(null, array);
            }

            return node;
         } else {
            return null;
         }
      } else {
         return null;
      }
   }

   private List<BsonValue> getBsonValues(String... sqls) {
      List<BsonValue> datas = new ArrayList();

      for(String sql : sqls) {
         BsonDocument data = (new BsonDocumentCodec()).decode(new JsonReader(sql), DecoderContext.builder().build());
         datas.add(data);
      }

      return datas;
   }

   public List<String> where(String sql) {
      MongoNode node = this.convert(sql);
      WhereVisitor visitor = new WhereVisitor();
      MongoParser parser = new MongoParser(visitor);
      parser.parse(node);
      return visitor.getWheres();
   }

   public void replace(List<ValueInfo> values, List<Map> whereList) {
      ValueReplacer replacer = new ValueReplacer(whereList);
      replacer.replaceValuesWithList(values);
   }
}
