package eu.dnetlib.common.logging.dao;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import org.springframework.beans.factory.annotation.Required;

import com.google.common.collect.Maps;
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;

import eu.dnetlib.common.logging.LogMessage;
import eu.dnetlib.miscutils.datetime.DateUtils;

public class DnetLoggerMongoDao implements DnetLoggerDao {

	private DB db;

	@Override
	public void init(final String collection) {
		db.createCollection(collection, null);
	}

	@Override
	public void configureIndex(final String collection, final Map<String, IndexConf> conf) {
		final DBCollection coll = db.getCollection(collection);
		coll.resetIndexCache();

		for (String key : conf.keySet()) {
			coll.ensureIndex(key);
		}
	}

	@Override
	public void writeLog(final String collection, final Map<String, Object> map) {
		final DBCollection coll = db.getCollection(collection);
		DBObject obj = BasicDBObjectBuilder.start(map).get();
		coll.insert(obj);
	}

	@Override
	public Map<String, String> findOne(final String collection, final String key, final String value) {
		final DBCollection coll = db.getCollection(collection);
		final DBObject obj = coll.findOne(new BasicDBObject(key, value));
		return dbObject2Map(obj);
	}

	@Override
	public Iterator<Map<String, String>> obtainLogIterator(final String collection) {
		final DBCollection coll = db.getCollection(collection);
		return iter(collection, coll.find());
	}

	@Override
	public Iterator<Map<String, String>> find(final String collection, final String key, final String value) {
		final DBCollection coll = db.getCollection(collection);
		return iter(collection, coll.find(new BasicDBObject(key, value)));
	}

	@Override
	public Iterator<Map<String, String>> findByDateRange(final String collection, final Date startDate, final Date endDate) {
		final DBCollection coll = db.getCollection(collection);
		DBObject mongoQueryObject = new BasicDBObject(LogMessage.LOG_DATE_FIELD, BasicDBObjectBuilder.start("$gte", startDate).append("$lt", endDate).get());
		// System.out.println(mongoQueryObject);
		return iter(collection, coll.find(mongoQueryObject));
	}

	private Iterator<Map<String, String>> iter(final String collection, final DBCursor cursor) {
		return new Iterator<Map<String, String>>() {

			@Override
			public boolean hasNext() {
				return cursor.hasNext();
			}

			@Override
			public Map<String, String> next() {
				return dbObject2Map(cursor.next());
			}

			@Override
			public void remove() {
				throw new RuntimeException("NOT IMPLEMENTED");
			}
		};
	}

	public DB getDb() {
		return db;
	}

	@Required
	public void setDb(final DB db) {
		this.db = db;
	}

	private Map<String, String> dbObject2Map(final DBObject obj) {
		final Map<String, String> res = Maps.newHashMap();
		for (String k : obj.keySet()) {
			if (k.equals(LogMessage.LOG_DATE_FIELD) && (obj.get(k) instanceof Date)) {
				res.put(LogMessage.LOG_DATE_FIELD, DateUtils.calculate_ISO8601(((Date) obj.get(k)).getTime()));
				res.put(LogMessage.LOG_PRETTY_PRINT_DATE, "" + obj.get(k));
			} else {
				res.put(k, "" + obj.get(k));
			}
		}
		return res;
	}
}
