package com.vogella.jersey.first.util;

import static com.mongodb.client.model.Filters.and;
import static com.mongodb.client.model.Filters.eq;
import static com.mongodb.client.model.Filters.gte;

import java.util.ArrayList;
import java.util.List;

import org.bson.Document;
import org.bson.conversions.Bson;

import com.google.gson.Gson;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.vogella.jersey.first.model.mapobject.Coin;

public class ChatManager<T extends Coin> extends MapObjectManager<T>{

	public static final String COLLECTION_NAME = "coins";

	public ChatManager(Class<T> cls,MongoClient mongoClient){
		super(cls,mongoClient,retrieveCollection(mongoClient));
	}

	private static MongoCollection<Document> retrieveCollection(MongoClient mongoClient){
		try{
			return mongoClient.getDatabase(GameMongoDBUtils.DATABASE_NAME).getCollection(COLLECTION_NAME);
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}

	public List<T> getWithValue(int value){
		List<T> mapObjects = new ArrayList<>();
		FindIterable<Document> listDoc = null;
		try{
			Bson bson = null;
			bson = eq(Coin.KEY_VALUE,value);
			listDoc = getCollection().find(bson);
		}catch(Exception e){
			e.printStackTrace();
			return mapObjects;
		}
		MongoCursor<Document> cursor = listDoc.iterator();
		try{
			T mapObject;
			Gson gson = new Gson();
			while(cursor.hasNext()){
				mapObject = gson.fromJson(cursor.next().toJson(),type);
				if(mapObject != null){
					mapObjects.add(mapObject);
				}
			}
		}finally{
			try{
				cursor.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return mapObjects;
	}

	public List<T> getBetweenValues(int valueMin,int valueMax,boolean includeValueMin,boolean includeValueMax){
		if(valueMax < valueMin){
			int temp = valueMin;
			valueMin = valueMax;
			valueMax = temp;
		}
		List<T> mapObjects = new ArrayList<>();
		FindIterable<Document> listDoc = null;
		try{
			Bson bson = null;
			if(includeValueMin){
				bson = gte(Coin.KEY_VALUE,valueMin);
			}else{
				bson = gte(Coin.KEY_VALUE,valueMin + 1);
			}
			if(includeValueMax){
				bson = and(bson,gte(Coin.KEY_VALUE,valueMax));
			}else{
				bson = and(bson,gte(Coin.KEY_VALUE,valueMax - 1));
			}
			listDoc = getCollection().find(bson);
		}catch(Exception e){
			e.printStackTrace();
			return mapObjects;
		}
		MongoCursor<Document> cursor = listDoc.iterator();
		try{
			T mapObject;
			Gson gson = new Gson();
			while(cursor.hasNext()){
				mapObject = gson.fromJson(cursor.next().toJson(),type);
				if(mapObject != null){
					mapObjects.add(mapObject);
				}
			}
		}finally{
			try{
				cursor.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return mapObjects;
	}

	public List<T> getWithGreaterValue(int valueMin,boolean includeValueMin){
		List<T> mapObjects = new ArrayList<>();
		FindIterable<Document> listDoc = null;
		try{
			Bson bson = null;
			if(includeValueMin){
				bson = gte(Coin.KEY_VALUE,valueMin);
			}else{
				bson = gte(Coin.KEY_VALUE,valueMin + 1);
			}
			listDoc = getCollection().find(bson);
		}catch(Exception e){
			e.printStackTrace();
			return mapObjects;
		}
		MongoCursor<Document> cursor = listDoc.iterator();
		try{
			T mapObject;
			Gson gson = new Gson();
			while(cursor.hasNext()){
				mapObject = gson.fromJson(cursor.next().toJson(),type);
				if(mapObject != null){
					mapObjects.add(mapObject);
				}
			}
		}finally{
			try{
				cursor.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return mapObjects;
	}

	public List<T> getWithLesserValue(int valueMax,boolean includeValueMax){
		List<T> mapObjects = new ArrayList<>();
		FindIterable<Document> listDoc = null;
		try{
			Bson bson = null;
			if(includeValueMax){
				bson = gte(Coin.KEY_VALUE,valueMax);
			}else{
				bson = gte(Coin.KEY_VALUE,valueMax - 1);
			}
			listDoc = getCollection().find(bson);
		}catch(Exception e){
			e.printStackTrace();
			return mapObjects;
		}
		MongoCursor<Document> cursor = listDoc.iterator();
		try{
			T mapObject;
			Gson gson = new Gson();
			while(cursor.hasNext()){
				mapObject = gson.fromJson(cursor.next().toJson(),type);
				if(mapObject != null){
					mapObjects.add(mapObject);
				}
			}
		}finally{
			try{
				cursor.close();
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		return mapObjects;
	}

	public List<T> deleteWithValue(int value){
		return delete(getWithValue(value));
	}

	public List<T> deleteBetweenValues(int valueMin,int valueMax,boolean includeValueMin,boolean includeValueMax){
		return delete(getBetweenValues(valueMin,valueMax,includeValueMin,includeValueMax));
	}

	public List<T> deleteWithGreaterValue(int valueMin,boolean includeValueMin){
		return delete(getWithGreaterValue(valueMin,includeValueMin));
	}

	public List<T> deleteWithLesserValue(int valueMax,boolean includeValueMax){
		return delete(getWithLesserValue(valueMax,includeValueMax));
	}
}