/**
 * Created by TalhaAkkas on 19/03/15.
 */
var mongoose = rekuire('mongoose');
var utils = rekuire('lib/utils');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
var utils = rekuire('/lib/utils');
var elderwand = require("../");
var threads = elderwand.threads;
var MongoClient = require('mongodb').MongoClient

var soft_delete = elderwand.soft_delete;

var EventLogScheme = new Schema({
	user:{type:String},
	masterUser:{type:String},
	problems:[{}],
	rawData:{},
	eventType: String,
	functionType: String,
	classType: String,
	status: Number, 
	totalTime: Number, 
	method: String,
	startTime: {type:Number, index:true},
	endTime: {type:Number, index:true}
});
EventLogScheme.plugin(soft_delete);
/**
 * Methods
 */

EventLogScheme.method({
});

/**
 * Statics
 */

EventLogScheme.static({

	saveEvent: function(event, cb){
		var event = new EventLog(event);
		event.save(cb)
	},

	load: function (options, cb) {
		if (options.filter == undefined || options.filter == true) {
			if( typeof options == "string" ||
				(typeof options == "object" && options.constructor === String) ||
				(typeof options == "object" && options.toString() && mongoose.Types.ObjectId.isValid(options.toString()))
			){
				this.findOne({_id:options})
					.exec(cb);
			}else if(Object.keys(options).length > 0 && options.criteria == undefined){
				this.findOne(options)
					.exec(cb);
			}else {
				var $this = this.findOne(options.criteria);
				$this.exec(cb);
			}
		}else{
			var $this = this.findOne(options.criteria);
			if(options.populate!=null) $this.populate(options.populate);
			$this.exec(cb);
		}
	},

	listEventLogClasses: function(options, cb){
		var $this = EventLog.aggregate().allowDiskUse(true);

		var match = [];
		if(options.classAndFunctionFilter && options.classAndFunctionFilter.length){
			if(options.classAndFunctionFilter.constructor !== Array) options.classAndFunctionFilter = [options.classAndFunctionFilter];
			for(var key in options.classAndFunctionFilter){
				if(options.classAndFunctionFilter[key].indexOf('c||')==0){
					match.push({classType:options.classAndFunctionFilter[key].substring(3)});
				}else if(options.classAndFunctionFilter[key].indexOf('f||')==0){
					var matchF = options.classAndFunctionFilter[key].substring(3)
					match.push({$and:[{classType:matchF.split('%%')[0]},{functionType:matchF.split('%%')[1]}]});
				}
			}
		}
		if(options.status != undefined && options.status != null && options.status != "")
			match.push({status:options.status});
		if(options.startTime != undefined && options.startTime != null && options.startTime != "" && options.startTime != 0)
			match.push({startTime:{$gt:options.startTime}});
		if(options.endTime != undefined && options.endTime != null && options.endTime != "" && options.endTime != 0)
			match.push({endTime:{$lt:options.endTime}});

		if(match.length>1){
			$this.match({$and:match});
		}else if(match.length==1){
			$this.match(match[0]);
		}

		$this.project({
			classType: 1,
			functionType:1,
			status: 1,
			timeDif: {"$subtract": ["$endTime", "$startTime"]}
		});

		var groupId = {classType: "$classType"};
		if(options.functionQuery) groupId.functionType = "$functionType";
		if(options.statusQuery) groupId.$status = "$status";

		$this.group({
			_id: groupId,
			maxTimeDif: {$max: '$timeDif'},
			minTimeDif: {$min: '$timeDif'},
			avgTimeDif: {$avg: '$timeDif'},
			sumTimeDif: {$sum: '$timeDif'},
			count: {$sum: 1},
			classType: {$first: '$classType'},
			functionType: {$first: '$functionType'},
			status: {$first: '$status'}
		});

		$this.exec(cb);
	},

	listEventLogFunctions: function(options, cb){
		var $this = EventLog.aggregate().allowDiskUse(true);

		var match = [];
		if(options.selectClass != undefined && options.selectClass != null && options.selectClass != "")
			match.push({classType:options.selectClass});
		if(options.status != undefined && options.status != null && options.status != "")
			match.push({status:options.status});
		if(options.startTime != undefined && options.startTime != null && options.startTime != "" && options.startTime != 0)
			match.push({startTime:{$gt:options.startTime}});
		if(options.endTime != undefined && options.endTime != null && options.endTime != "" && options.endTime != 0)
			match.push({endTime:{$lt:options.endTime}});

		if(match.length>1){
			$this.match({$and:match});
		}else if(match.length==1){
			$this.match(match[0]);
		}

		$this.project({
			classType: 1,
			functionType:1,
			status: 1,
			timeDif: {"$subtract": ["$endTime", "$startTime"]}
		});

		var groupId = {functionType: "$functionType"};
		if(options.statusQuery) groupId.$status = "$status";

		$this.group({
			_id: groupId,
			maxTimeDif: {$max: '$timeDif'},
			minTimeDif: {$min: '$timeDif'},
			avgTimeDif: {$avg: '$timeDif'},
			sumTimeDif: {$sum: '$timeDif'},
			count: {$sum: 1},
			classType: {$first: '$classType'},
			functionType: {$first: '$functionType'},
			status: {$first: '$status'}
		});

		$this.exec(cb);
	},

	listEventLogProcesses: function(options, cb){
		var find = [];
		if(options.selectClass != undefined && options.selectClass != null && options.selectClass != "")
			find.push({classType:options.selectClass});
		if(options.selectFunction != undefined && options.selectFunction != null && options.selectFunction != "")
			find.push({functionType:options.selectFunction});
		if(options.status != undefined && options.status != null && options.status != "")
			find.push({status:options.status});
		if(options.startTime != undefined && options.startTime != null && options.startTime != "" && options.startTime != 0)
			find.push({startTime:{$gt:options.startTime}});
		if(options.endTime != undefined && options.endTime != null && options.endTime != "" && options.endTime != 0)
			find.push({endTime:{$lt:options.endTime}});

		if(find.length>1){
			find = {$and:find};
		}else if(find.length==1){
			find = find[0];
		}

		EventLog.find(find)
			.populate('user masterUser driver')
			.exec(cb);
	},

	getClassAndFunctionByGroup: function(options, cb){
		var that = EventLog.aggregate().allowDiskUse(true);

		var match = [];
		if(options.startTime != undefined && options.startTime != null && options.startTime != "" && options.startTime != 0)
			match.push({startTime:{$gt:options.startTime}});
		if(options.endTime != undefined && options.endTime != null && options.endTime != "" && options.endTime != 0)
			match.push({endTime:{$lt:options.endTime}});

		if(match.length>1){
			that.match({$and:match});
		}else if(match.length==1){
			that.match(match[0]);
		}

		var groupId = {};
		if(options.classQuery) groupId.classType = "$classType";
		if(options.functionQuery) groupId.functionType = "$functionType";

		if(Object.keys(groupId).length == 0) groupId.classType = "$classType";

		that.group({
			_id: groupId,
			classType: {$first: '$classType'},
			functionType: {$first: '$functionType'}
		});

		that.exec(cb);
	},

	listEventLogChart: function(options, cb){
		var match = [];
		var matchClassAndFunction = [];
		if(options.classAndFunctionFilter && options.classAndFunctionFilter.length){
			if(options.classAndFunctionFilter.constructor !== Array) options.classAndFunctionFilter = [options.classAndFunctionFilter];
			for(var key in options.classAndFunctionFilter){
				if(options.classAndFunctionFilter[key].indexOf('c||')==0){
					matchClassAndFunction.push({classType:options.classAndFunctionFilter[key].substring(3)});
				}else if(options.classAndFunctionFilter[key].indexOf('f||')==0){
					var matchF = options.classAndFunctionFilter[key].substring(3)
					matchClassAndFunction.push({$and:[{classType:matchF.split('%%')[0]},{functionType:matchF.split('%%')[1]}]});
				}
			}
		}
		if(options.status != undefined && options.status != null && options.status != "")
			match.push({status:options.status});
		if(options.startTime != undefined && options.startTime != null && options.startTime != "" && options.startTime != 0)
			match.push({startTime:{$gt:options.startTime}});
		if(options.endTime != undefined && options.endTime != null && options.endTime != "" && options.endTime != 0)
			match.push({endTime:{$lt:options.endTime}});

		var that;
		if(match.length>1){
			if(matchClassAndFunction.length){

				MongoClient.connect(require('config').db, function(err, db) {
					var geolocCollection = db.collection('eventlogs');
					geolocCollection.find({$and:[{$and:match},{$or:matchClassAndFunction}]}).sort({startTime:1}).toArray(function (err, list) {
						cb(err, list);
						db.close();
					});
				});
				//that = EventLog.find({$and:[{$and:match},{$or:matchClassAndFunction}]});
			}else{

				MongoClient.connect(require('config').db, function(err, db) {
					var geolocCollection = db.collection('eventlogs');
					geolocCollection.find({$and:match}).sort({startTime:1}).toArray(function (err, list) {
						cb(err, list);
						db.close();
					});
				});
				//that = EventLog.find({$and:match});
			}
		}else if(match.length==1){

			MongoClient.connect(require('config').db, function(err, db) {
				var geolocCollection = db.collection('eventlogs');
				geolocCollection.find(match[0]).sort({startTime:1}).toArray(function (err, list) {
					cb(err, list);
					db.close();
				});
			});
		}

	},

	listEventLogTestProcesses: function(options, cb){
		var match = [];
		var matchClassAndFunction = [];
		if(options.classAndFunctionFilter && options.classAndFunctionFilter.length){
			if(options.classAndFunctionFilter.constructor !== Array) options.classAndFunctionFilter = [options.classAndFunctionFilter];
			for(var key in options.classAndFunctionFilter){
				if(options.classAndFunctionFilter[key].indexOf('c||')==0){
					matchClassAndFunction.push({classType:options.classAndFunctionFilter[key].substring(3)});
				}else if(options.classAndFunctionFilter[key].indexOf('f||')==0){
					var matchF = options.classAndFunctionFilter[key].substring(3);
					matchClassAndFunction.push({$and:[{classType:matchF.split('%%')[0]},{functionType:matchF.split('%%')[1]}]});
				}
			}
		}
		if(options.status && options.status != ""){
			options.status = options.status.split(",");
			options.status = options.status.map(function (item) {
				return parseInt(item);
			});
			if(options.status[1]){
				match.push({status:{$in:options.status}});
			}else{
				match.push({status:options.status[0]});
			}
		}
		if(options.startTime && options.startTime != "" && options.startTime != 0)
			match.push({startTime:{$gt:options.startTime}});
		if(options.endTime && options.endTime != "" && options.endTime != 0)
			match.push({endTime:{$lt:options.endTime}});

		if(match.length>1){
			if(matchClassAndFunction.length){
				MongoClient.connect(require('config').db, function(err, db) {
					db.collection('eventlogs').find({$and:[{$and:match},{$or:matchClassAndFunction}]}).toArray(function (err, list) {
						cb(err, list);
						db.close();
					});
				});
			}else{
				MongoClient.connect(require('config').db, function(err, db) {
					db.collection('eventlogs').find({$and:match}).toArray(function (err, list) {
						cb(err, list);
						db.close();
					});
				});
			}
		}else if(match.length==1){
			MongoClient.connect(require('config').db, function(err, db) {
				db.collection('eventlogs').find(match[0]).toArray(function (err, list) {
					cb(err, list);
					db.close();
				});
			});
		}else{
			cb("Empty filter", []);
		}
	}

});

//threads.encapsulateFunction(EventLogScheme.statics, 'saveEvent', 'EventLog');
//threads.encapsulateFunction(EventLogScheme.statics, 'listEventLogFunctions', 'EventLog');
//threads.encapsulateFunction(EventLogScheme.statics, 'listEventLogClasses', 'EventLog');
//threads.encapsulateFunction(EventLogScheme.statics, 'getClassAndFunctionByGroup', 'EventLog');
//threads.encapsulateFunction(EventLogScheme.statics, 'listEventLogTestProcesses', 'EventLog');

var EventLog = mongoose.model('EventLog', EventLogScheme);