package test;

import com.chenyang.fastjson.JSONObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import org.bson.BSON;
import org.bson.BSONObject;
import org.bson.BasicBSONDecoder;
import org.bson.BsonBinaryReader;
import org.bson.BsonBinaryWriter;
import org.bson.BsonDocument;
import org.bson.BsonInt64;
import org.bson.ByteBuf;
import org.bson.Document;
import org.bson.codecs.BsonDocumentCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.conversions.Bson;
import org.bson.io.BasicOutputBuffer;
import org.bson.json.JsonReader;
import util.StringJoin;

public class BsonTest {
   public static void main(String[] args) throws Exception {
      bsonDecode();
   }

   public static void main2() {
      MongoClient client = new MongoClient("127.0.0.1", 27017);
      MongoDatabase database = client.getDatabase("test");
      MongoCollection<Document> collection = database.getCollection("te");
      System.out.println(collection.find().first());

      try {
         Bson command = new BsonDocument("dbStats", new BsonInt64(1L));
         Document commandResult = database.runCommand(command);
         System.out.println("dbStats: " + commandResult.toJson());
         String hex = "5c0000000266696e6400030000007465000366696c7465720010000000017800000000000000244000036c736964001e00000005696400100000000472de6e27d4424fedacc3c3fc48bab9e500022464620005000000746573740000";
         byte[] bytes = hexStringToBytes(hex);
         BsonDocument test = (new BsonDocumentCodec()).decode(new BsonBinaryReader(ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)), DecoderContext.builder().build());
         test.remove("$db");
         commandResult = database.runCommand(test);
         System.out.println("result: " + commandResult.toJson());
         BasicOutputBuffer output = new BasicOutputBuffer();
         (new BsonDocumentCodec()).encode(new BsonBinaryWriter(output), test, EncoderContext.builder().build());
         List<ByteBuf> ob = output.getByteBuffers();
         byte[] bytes3 = output.toByteArray();
         System.out.println(byteToHex(bytes3));
         BsonDocument test3 = (new BsonDocumentCodec()).decode(new BsonBinaryReader(ByteBuffer.wrap(bytes3).order(ByteOrder.LITTLE_ENDIAN)), DecoderContext.builder().build());
         System.out.println(test3);
      } catch (MongoException me) {
         System.err.println("An error occurred: " + me);
      } catch (Exception me) {
         System.err.println("An error occurred: " + me);
      }

   }

   private static void bsonDecode() {
      String hex = "5c0000000266696e6400030000007465000366696c7465720010000000017800000000000000244000036c736964001e00000005696400100000000472de6e27d4424fedacc3c3fc48bab9e500022464620005000000746573740000";
      byte[] bytes = hexStringToBytes(hex);
      BSONObject decode = BSON.decode(bytes);
      System.out.println(decode.toString());
      Bson bson = Filters.gt("a", 10);
      BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
      System.out.println(bsonDocument.toString());
      byte[] array = (new BigInteger("130000001069734d6173746572000100000000", 16)).toByteArray();
      BasicBSONDecoder decoder = new BasicBSONDecoder();
      BSONObject bsonObject = decoder.readObject(array);
      System.out.println(bsonObject.toString());
      JSONObject json = new JSONObject(decode.toMap());
      System.out.println(json);
      BsonDocument test = (new BsonDocumentCodec()).decode(new BsonBinaryReader(ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)), DecoderContext.builder().build());
      System.out.println(test.toString());
      BsonDocument test2 = (new BsonDocumentCodec()).decode(new JsonReader(test.toString()), DecoderContext.builder().build());
      System.out.println(test2.toString());
   }

   public static byte[] hexStringToBytes(String hexString) {
      if (StringJoin.isEmpty(hexString)) {
         return null;
      } else {
         hexString = hexString.toLowerCase();
         byte[] byteArray = new byte[hexString.length() >> 1];
         int index = 0;

         for(int i = 0; i < hexString.length(); ++i) {
            if (index > hexString.length() - 1) {
               return byteArray;
            }

            byte highDit = (byte)(Character.digit(hexString.charAt(index), 16) & 255);
            byte lowDit = (byte)(Character.digit(hexString.charAt(index + 1), 16) & 255);
            byteArray[i] = (byte)(highDit << 4 | lowDit);
            index += 2;
         }

         return byteArray;
      }
   }

   public static String byteToHex(byte[] bytes) {
      String strHex = "";
      StringBuilder sb = new StringBuilder("");

      for(int n = 0; n < bytes.length; ++n) {
         strHex = Integer.toHexString(bytes[n] & 255);
         sb.append(strHex.length() == 1 ? "0" + strHex : strHex);
      }

      return sb.toString().trim();
   }
}
