package com.github.mongobee.dao;

import com.github.mongobee.changeset.ChangeEntry;
import com.github.mongobee.exception.MongobeeConfigurationException;
import com.github.mongobee.exception.MongobeeConnectionException;
import com.mongodb.*;
import org.omg.PortableInterceptor.LOCATION_FORWARD;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.*;

import java.net.UnknownHostException;
import java.util.List;

import static com.github.mongobee.changeset.ChangeEntry.CHANGELOG_COLLECTION;
import static org.springframework.util.StringUtils.hasText;

/**
 * @author lstolowski
 * @since 27/07/2014
 */
public class ChangeEntryDao {
  private static final Logger logger = LoggerFactory.getLogger("Mongobee dao");

  private DB db;

  public DB getDb() {
    return db;
  }

  public DB connectMongoDb(Mongo mongo, String dbName) throws UnknownHostException {
    if (!hasText(dbName)){
      throw new MongobeeConfigurationException("DB name is not set. Should be defined in MongoDB URI or via setter");
    } else {
      db = mongo.getDB(dbName);
      // ensureChangelogCollectionIndexes(db.getCollection(CHANGELOG_COLLECTION)); // TODO Issue#14
      return db;
    }
  }

  public DB connectMongoDb(MongoClientURI mongoClientURI, String dbName) throws UnknownHostException {
    Mongo mongoClient = new MongoClient(mongoClientURI);
    String database = (!hasText(dbName)) ? mongoClientURI.getDatabase() : dbName;
    return this.connectMongoDb(mongoClient, database);
  }

  public boolean isNewChange(ChangeEntry changeEntry) {
    verifyDbConnection();

    DBCollection mongobeeChangeLog = getDb().getCollection(CHANGELOG_COLLECTION);
    DBObject entry = mongobeeChangeLog.findOne(changeEntry.buildSearchQueryDBObject());

    return entry == null ? true : false;
  }

  public WriteResult save(ChangeEntry changeEntry) {
    verifyDbConnection();

    DBCollection mongobeeLog = getDb().getCollection(CHANGELOG_COLLECTION);
    return mongobeeLog.save(changeEntry.buildFullDBObject());
  }

  private void verifyDbConnection(){
    if (getDb() == null) {
      throw new MongobeeConnectionException("Database is not connected. Mongobee thrown unexpected error",
        new NullPointerException());
    }
  }

  // TODO Issue#14: add changeId_1_author_1 + unique: true
  private void ensureChangelogCollectionIndexes(DBCollection collection) {

    List<DBObject> indexInfo = collection.getIndexInfo();
    for (com.mongodb.DBObject ind : indexInfo){
      Object key = ind.get("key");
      if (key instanceof BasicDBObject){

        // FIXME refactor: 1. search for it, if no: create, else check if unique if no: delete & add unique,

        BasicDBObject indexKey = (BasicDBObject) key;
        if (indexKey.get("changeId") instanceof Integer &&  ((Integer)indexKey.get("changeId")) == 1 &&
            indexKey.get("author") instanceof Integer &&  ((Integer)indexKey.get("author")) == 1){

          //indexes exist
          logger.debug("Indexes in collection " + CHANGELOG_COLLECTION + " are correct");
        } else {
          collection.createIndex(new BasicDBObject().append("changeId", 1).append("author", 1));

          // indexes created
          logger.debug("Indexes in collection " + CHANGELOG_COLLECTION + " was created");
        }

      }
    }

  }

}

@@ -1084,18 +1084,16 @@
 ;%0A      
-//
  ensureC
@@ -2178,15 +2178,22 @@
 bee 
+has 
 thrown 
+an 
 unex
@@ -2390,16 +2390,812 @@
 ion) %7B%0A%0A
+    BasicDBObject index = findIndex(collection);%0A    if (index != null && !isUnique(index))%7B%0A      // todo remove index,%0A%0A%0A      // todo create new one%0A      //collection.createIndex(new BasicDBObject().append(%22changeId%22, 1).append(%22author%22, 1), new BasicDBObject(%22unique%22, true));%0A%0A    %7D else if (index == null) %7B%0A      // todo create index%0A      // collection.createIndex(new BasicDBObject().append(%22changeId%22, 1).append(%22author%22, 1), new BasicDBObject(%22unique%22, true));%0A%0A      // indexes created%0A      logger.debug(%22Indexes in collection %22 + CHANGELOG_COLLECTION + %22 was created%22);%0A    %7D%0A%0A%0A  %7D%0A%0A  private boolean isUnique(BasicDBObject index) %7B%0A%0A    // todo check if the index has unique attribute%0A%0A    return false;  // fixme%0A  %7D%0A%0A  private BasicDBObject findIndex(DBCollection collection) %7B%0A
     List
@@ -3647,18 +3647,16 @@
         
-  
 indexKey
@@ -3749,377 +3749,157 @@
     
-//indexes exist%0A          logger.debug(%22Indexes in collection %22 + CHANGELOG_COLLECTION + %22 are correct%22);%0A        %7D else %7B%0A 
+return indexKey;%0A        %7D%0A%0A      %7D%0A
     
+%7D%0A%0A
     
- collection.createIndex(new BasicDBObject().append(%22changeId%22, 1).append(%22author%22, 1));%0A%0A          // indexes created%0A          logger.debug(%22Indexes in collection %22 + CHANGELOG_COLLECTION + %22 was created%22);%0A        %7D%0A%0A      %7D%0A    %7D%0A%0A  %7D
+return null;  // not found%0A  %7D%0A%0A  // todo refactor index checking and creating to separate util class%0A
 %0A%0A%7D%0A

refactor index checking logic, todo creating index, checking uniqueness, refactoring to util class