package util.sqlparse.visitor.mongo.desensitization;

import java.util.Map;
import org.bson.BsonString;
import org.bson.BsonValue;
import util.JdbcUtil;
import util.sqlparse.visitor.mongo.BsonArrayNode;
import util.sqlparse.visitor.mongo.BsonObjectNode;
import util.sqlparse.visitor.mongo.Identifier;
import util.sqlparse.visitor.mongo.MongoNode;
import util.sqlparse.visitor.mongo.MongoVisitor;
import util.sqlparse.visitor.mongo.ParseResult;

public class TableReplaceVisitor implements MongoVisitor<ParseResult> {
   private ParseResult result;
   private Map params;

   public ParseResult getResult() {
      return this.result;
   }

   public TableReplaceVisitor(Map params) {
      this.params = params;
      this.result = new ParseResult();
      this.result.isMatched = false;
   }

   public ParseResult visitFind(MongoNode context) {
      BsonObjectNode ctx = (BsonObjectNode)context;
      this.replaceTable(ctx, Identifier.Find);
      this.result.newMongoNode = context;
      return this.result;
   }

   private void replaceTable(BsonObjectNode ctx, Identifier identifier) {
      MongoNode find = ctx.get(identifier.code);
      String collection = find.value().toString();
      String replaceTable = this.params.get("replaceTable").toString();
      String replaceNewTable = this.params.get("replaceNewTable").toString();
      boolean isMatched = JdbcUtil.followRulesCaseSens(collection, replaceTable);
      if (isMatched) {
         ctx.put(identifier.code, (BsonValue)(new BsonString(replaceNewTable)));
      }

      this.result.isMatched = isMatched;
   }

   public ParseResult visitInsert(MongoNode ctx) {
      BsonArrayNode array = (BsonArrayNode)ctx;
      BsonObjectNode insert = (BsonObjectNode)array.get(array.size() - 1);
      this.replaceTable(insert, Identifier.Insert);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitUpdate(MongoNode ctx) {
      BsonArrayNode array = (BsonArrayNode)ctx;
      BsonObjectNode updateCtx = (BsonObjectNode)array.get(array.size() - 1);
      this.replaceTable(updateCtx, Identifier.Update);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitFindAndModify(MongoNode ctx) {
      BsonObjectNode objCtx = (BsonObjectNode)ctx;
      this.replaceTable(objCtx, Identifier.FindAndModify);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitDelete(MongoNode ctx) {
      BsonArrayNode array = (BsonArrayNode)ctx;
      BsonObjectNode collectionCtx = (BsonObjectNode)array.get(array.size() - 1);
      this.replaceTable(collectionCtx, Identifier.Delete);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCount(MongoNode ctx) {
      BsonObjectNode objCtx = (BsonObjectNode)ctx;
      this.replaceTable(objCtx, Identifier.Count);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitAggregate(MongoNode ctx) {
      BsonObjectNode objNode = (BsonObjectNode)ctx;
      this.replaceTable(objNode, Identifier.Aggregate);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitDistinct(MongoNode ctx) {
      BsonObjectNode objNode = (BsonObjectNode)ctx;
      this.replaceTable(objNode, Identifier.Distinct);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitDrop(MongoNode ctx) {
      BsonObjectNode objNode = (BsonObjectNode)ctx;
      this.replaceTable(objNode, Identifier.Drop);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCreate(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCreateIndexes(MongoNode ctx) {
      BsonObjectNode createIndexesCtx = (BsonObjectNode)ctx;
      this.replaceTable(createIndexesCtx, Identifier.CreateIndexes);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitDropIndexes(MongoNode ctx) {
      BsonObjectNode dropIndexesCtx = (BsonObjectNode)ctx;
      this.replaceTable(dropIndexesCtx, Identifier.DropIndexes);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitReIndex(MongoNode ctx) {
      BsonObjectNode dropIndexesCtx = (BsonObjectNode)ctx;
      this.replaceTable(dropIndexesCtx, Identifier.ReIndex);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitRenameCollection(MongoNode ctx) {
      BsonObjectNode renameCollectionCtx = (BsonObjectNode)ctx;
      this.replaceTable(renameCollectionCtx, Identifier.RenameCollection);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitMapreduce(MongoNode ctx) {
      BsonObjectNode mapreduceCtx = (BsonObjectNode)ctx;
      this.replaceTable(mapreduceCtx, Identifier.Mapreduce);
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCreateUser(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitSaslSupportedMechs(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitUpdateUser(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitUsersInfo(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitGrantRolesToUser(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitRevokeRolesFromUser(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitDropUser(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCreateCollection(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }

   public ParseResult visitCommand(MongoNode ctx) {
      this.result.newMongoNode = ctx;
      return this.result;
   }
}
