angular.module('cs.timeline', ['cs.services', 'ark-ui-bootstrap', 'cs.services.util']).directive('csTimeline', function($timeout, $compile, $http, csApi, csUtils) {
	return {
		restrict: 'E',
		scope: {
			'csObject': '=?csobject',
			'serverUrl': '@',
			'customerId': '@',
			'refresh': '=?',
			'selectionCallback': '&',
			'renderCallback': '&',
			'journeyStats': '=?',
			'journeyFilter':'=?',
			'isAnon': '@'
		},
		link: function(scope, ele) {

			if (!scope.journeyFilter){ // if there's no filter, then don't filter but select all.
				scope.journeyFilter = { selectedFilters : ['Select All']};
			}
			
			function loadInfo() {
				var filePath = 'url.txt';
				$http.get(filePath)
				.then(function(response) {
				// The URL is in the response.data
				var baseUrl = response.data.trim(); // Trimming any newline characters
				
				if(!baseUrl){
					baseUrl = '/genesys/1/cs';
				}

				if (baseUrl) {
					scope.customerInfo = null;
					csApi.getBusinessAttributes(baseUrl).then(function(data) {
						scope.businessAttributes = data;
					});
					csApi.queryCustomerServices(baseUrl, scope.customerId, scope.isAnon === 'true').then(function(response) {
						scope.customerInfo = response.data;
					});

				}
				})
				.catch(function(error) {
                    console.error("Error reading the URL from file:", error);
				});
				
			}

			function getDisplayName(i){
				if(angular.isDefined(scope.businessAttributes.service[scope.customerInfo[i].service_type].display_name) &&
					scope.businessAttributes.service[scope.customerInfo[i].service_type].display_name !== ''){
					return scope.businessAttributes.service[scope.customerInfo[i].service_type].display_name;
				} else {
					return scope.businessAttributes.service[scope.customerInfo[i].service_type].name;
				}
			}

			function pushToday() {
				var today = new Date();
				today.setHours(0);
				today.setMinutes(0);
				today.setSeconds(0);
				var todayObject = {
					startDate: today.toISOString(),
					headline: "TODAY",
					type: 'start',
					classname: "today-object"
				}
				scope.timelineObject.timeline.date.push(todayObject);
			}
			
			scope.serviceFilter = function(startObj, endObj) {
				// Combines all filters, if all filters return true, then this function returns true. 
				// if you want to add more filters, add as separate function then && it here.  
				
				
				return scope.durationFilter(startObj, endObj) && scope.statusFilter(startObj, endObj) 
							&& scope.serviceTypeFilter(startObj, endObj) && scope.stateTypeFilter(startObj, endObj)
							&& scope.searchFilter(startObj,endObj);

			}
			
			
			scope.searchFilter = function (startObj, endObj){
				if (scope.journeyFilter.search === undefined || scope.journeyFilter.search.length === 0)
					return true; // user did not search. 
				
				else {
					var objName = startObj.headline.toLowerCase().trim(); 
					var searchText = scope.journeyFilter.search.toLowerCase().trim();
										
					return objName.indexOf(searchText) !== -1 
					
				}

			}
			
			scope.serviceTypeFilter = function (startObj, endObj){
				// this function filters off the service type. If select all is chosen then this filter always returns true
				// otherwise, check the type and return true if the type matches the filtered type. 
					
				 if (scope.journeyFilter.serviceTypeFilter[0] === 'Select All')
					 return true;
				 else 
					 return scope.journeyFilter.serviceTypeFilter.indexOf(startObj.headline) !== -1;
				
			}
			
			scope.stateTypeFilter = function (startObj, endObj){
				// this function filters off the state. If select all is chosen then this filter always returns true
				// otherwise, check the state and return true if the state matches the filtered state. 
					
				 if (scope.journeyFilter.stateTypeFilter[0] === 'Select All')
					 return true;
				 else {
					if (!scope.serviceList)
						scope.createServiceList();
					for (var i = 0; i < scope.serviceList.length ; i++){
						if (startObj.tag === scope.serviceList[i].service_id){						
							var activeStatesList = scope.serviceList[i].active_states;
							var completedStatesList = scope.serviceList[i].completed_states;
							
							if (activeStatesList.length === 0 && completedStatesList.length === 0 && scope.journeyFilter.stateTypeFilter.indexOf("No States") !== -1 )
								return true; // case where service has no states and no states filter is on. 
							else {
								for(var j = 0 ; j < activeStatesList.length ; j++){
									if (scope.journeyFilter.stateTypeFilter.indexOf(activeStatesList[j].entityString.trim()) !== -1 )
										return true;
								}
								
								for(var k = 0 ; k < completedStatesList.length; k++){
									if (scope.journeyFilter.stateTypeFilter.indexOf(completedStatesList[k].entityString.trim()) !== -1 )
										return true;
								}
								
							}
							return false;
						}

					}
					return false;
				 }				
			}
					
			
			scope.createServiceList = function (){
				scope.serviceList =  scope.journeyFilter.customerData.hideChildren || scope.journeyFilter.customerData.children;
			}

			
			scope.statusFilter = function(startObj, endObj){
			// this function filters off the status. If select all is chosen then this filter always returns true
			// otherwise, check the status and return true if the status matches the filtered status. 
				
			 if (scope.journeyFilter.statusFilters[0] === 'Select All')
				 return true;
			 else {
				 if (startObj.status === "Started" && endObj.status === "Completed")
					 return scope.journeyFilter.statusFilters.indexOf('Completed') !== -1 ;
				 else
					 return scope.journeyFilter.statusFilters.indexOf('Active') !== -1;
			 }
			 	return false;
			}
			
			scope.durationFilter  = function (startObj, endObj) {
/*				This function filters based of if the startObj and endObj
				fit within the interval the user decided. There would always be a startObj
				but there does not have to be an endObj (status is 'active')*/
				
				if (scope.journeyFilter.dateFilter === "Show All"){
					return true;
				}
				
				else if(scope.journeyFilter.dateFilter === "This Month"){
					
					var startingThisMonth = moment().format("MM YYYY") === moment(startObj.startDate).format("MM YYYY");
					
					if (endObj !== undefined)
						var endingThisMonth = moment().format("MM YYYY") === moment(endObj.startDate).format("MM YYYY");
					else
						var endingThisMonth = false;

					return scope.startEndSwitch(startingThisMonth, endingThisMonth);				

				}
				
				else if(scope.journeyFilter.dateFilter === "Last Month"){
					var lastMonth =  moment(moment().subtract(1,'month')._d).format("MM YYYY"); 
					
					// same code as This Month filter. 
					
					var startingLastMonth = lastMonth === moment(startObj.startDate).format("MM YYYY");
					
					if (endObj !== undefined)
						var endingLastMonth = lastMonth === moment(endObj.startDate).format("MM YYYY");
					else
						var endingLastMonth = false;

					return scope.startEndSwitch(startingLastMonth, endingLastMonth);				
										
					
				}
				else if(scope.journeyFilter.dateFilter === "Last 90 Days"){
					var ninetyDaysAgo = moment(moment().subtract(90,'day')._d).format("YYYY MM DD");
					var today = moment().format("YYYY MM DD");
					var startingLast90Days = scope.dateInBetween(ninetyDaysAgo, today, moment(startObj.startDate).format("YYYY MM DD"));
					
					if (endObj !== undefined)
						var endingLast90Days = scope.dateInBetween(ninetyDaysAgo, today, moment(endObj.startDate).format("YYYY MM DD"));
					else
						var endingLast90Days = false;

					return scope.startEndSwitch(startingLast90Days, endingLast90Days);				
					
					
				}
				else if(scope.journeyFilter.dateFilter === "This Year"){
					// similar to this month; 
					
					var startingThisYear = moment().format("YYYY") === moment(startObj.startDate).format("YYYY");
					
					if (endObj !== undefined)
						var endingThisYear = moment().format("YYYY") === moment(endObj.startDate).format("YYYY");
					else
						var endingThisYear = false;

					return scope.startEndSwitch(startingThisYear, endingThisYear);
					
				}
				else if(scope.journeyFilter.dateFilter === "Last Year"){
					// similar to last month; 
					var lastYear =  moment(moment().subtract(1,'year')._d).format("YYYY"); 
					
					// same code as This Year filter. 
					
					var startingLastYear = lastYear === moment(startObj.startDate).format("YYYY");
					
					if (endObj !== undefined)
						var endingLastYear = lastYear === moment(endObj.startDate).format("YYYY");
					else
						var endingLastYear = false;

					return scope.startEndSwitch (startingLastYear, endingLastYear);
				}
				else {
					// custom range.
					
					
					var startDate = moment(scope.journeyFilter.fromDate).format();
					var endDate = moment(scope.journeyFilter.toDate).format();
					var startingInBetween = scope.dateInBetween(startDate, endDate, moment(startObj.startDate).format()) ;
					
					if (endObj !== undefined)
						var endingInBetween = scope.dateInBetween(startDate, endDate, moment(endObj.startDate).format()) ;
					else
						var endingInBetween = false;
					return scope.startEndSwitch (startingInBetween, endingInBetween);
			
				}
				
				
					
					
				return false;
				
			}
			
			scope.startEndSwitch = function (startCondition, endCondition){
				//decides what to return based off if user selected starting, ending, or both.
				
				switch (scope.journeyFilter.dateFilterType){
				case ('Starting'):
					return startCondition;

				case ('Ending'):
					return endCondition !== undefined  ? endCondition : startCondition;
				
				case ('Starting and Ending'):
					return endCondition !== undefined  ? endCondition && startCondition : startCondition;
				
				default:
					return endCondition !== undefined  ? endCondition || startCondition : startCondition;
			
				}
				
			}
			
			scope.dateInBetween = function (startDate, endDate, comparingDate) {
/*				 takes comparingDate and returns true if it is in between startDate and endDate.
				 Written to make the filter more readable. 
				 if the user does not put a date, it will result in Invalid Date in moment, which we treat as no filter. */
				
				if (startDate === "Invalid date")
					var afterStartDate = true;
				else
					var afterStartDate = comparingDate >= startDate;
					
				if (endDate === "Invalid date")
					var beforeEndDate = true;
				else
					var beforeEndDate = comparingDate <= endDate
					
				return ( afterStartDate && beforeEndDate) ;
				
			}
			
			scope.journeyFilter.updateTimeline = function () {
				scope.journeyFilter.timeLineReady = false; 
				
				scope.timelineObject = {
					'timeline': {
						'headline': 'Context Services Timeline',
						'type': 'default',
						'text': 'Context Services',
						'date': []
					}
				};
				
				if (scope.journeyStats){ // collect statistics if journeystats exist
					scope.journeyStats.activeJourneys = 0; 
					scope.journeyStats.nbJourneys = 0 ; 
					scope.journeyStats.completedJourneys = 0 ; 
				}

				
				// below are used for average. 
				var entries = 0; 
				var sum = 0 ; 
				
				if (scope.journeyStats)
					scope.journeyStats.average = 0 ; 
				
				pushToday();
				for (var i = 0; i < scope.customerInfo.length; i++) {
					if (scope.customerInfo[i].service_id && !scope.customerInfo[i].task_id && !scope.customerInfo[i].state_id ) {
						var startObject = {
							'selection': {
								'selected': false
							}
						};
						var shouldShow = undefined; 
						var startDate = new Date(scope.customerInfo[i].started.timestamp);
						var startTime = startDate;
						startObject.startDate = startDate.toISOString();
						startObject.headline = (scope.businessAttributes.service[scope.customerInfo[i].service_type] ?
							getDisplayName(i) : '(' + scope.customerInfo[i].service_type + ')');

						startObject.text = scope.customerInfo[i].service_id;
						startObject.tag = scope.customerInfo[i].service_id;
						startObject.color = '#4AC764';
						startObject.status = 'Active';
						
						if (scope.journeyFilter)
							startObject.durationStyle = scope.journeyFilter.durationStyle;
						else
							startObject.durationStyle = "event line";
						
						
						
						if (scope.journeyStats){
							var sumOfStates = scope.journeyStats.getTotalStates(scope.customerInfo[i].service_id);
							
							if (sumOfStates >= 0 )
								startObject.totalStates = sumOfStates;
						}

						
						
						if (scope.journeyStats)
							scope.journeyStats.activeJourneys++; 
						
						if (scope.customerInfo[i].completed && scope.customerInfo[i].completed.timestamp) {
							
							if (scope.journeyStats) {
								scope.journeyStats.completedJourneys++; 
								
								if (scope.journeyStats.activeJourneys > 0) 
									scope.journeyStats.activeJourneys--; 
							}

							
							
							startObject.color = '#2E69DB';
							startObject.status = 'Started';
							
							var endObject = {
								'selection': {
									'selected': false
								}
							};
							var endDate = new Date(scope.customerInfo[i].completed.timestamp);
							var endTime = endDate;
							
							var timeFrame = csUtils.convertToReadableDate(Math.abs(endTime - startTime))
							startObject.timeFrame = timeFrame;
							scope.customerInfo[i].duration = endTime - startTime;
							
							endObject.startDate = endDate.toISOString();
							startObject.endDate = endObject.startDate;
							
							endObject.headline = startObject.headline;
							endObject.text = scope.customerInfo[i].service_id;
							endObject.tag = scope.customerInfo[i].service_id;
							endObject.color = '#2E69DB';
							endObject.timeFrame = timeFrame;
							endObject.status = 'Completed';
							
							if (scope.journeyFilter)
								endObject.durationStyle = scope.journeyFilter.durationStyle;
							else
								endObject.durationStyle = "event line"

							
							if (scope.journeyStats){

								var sumOfStates = scope.journeyStats.getTotalStates(scope.customerInfo[i].service_id);
								
								if (sumOfStates >= 0 )
									endObject.totalStates = sumOfStates;  
							}
							
							shouldShow = scope.serviceFilter(startObject , endObject)
							
							if (shouldShow )
								scope.timelineObject.timeline.date.push(endObject);
							
							//for avg journey resolution time
							var ans = Math.abs(endDate - startDate);
							sum += ans; 
							entries++; 
							
						}
						
						

								
			
						if (scope.journeyStats){
							scope.journeyStats.average = scope.journeyStats.convertToReadableDate(sum/entries); 
							scope.journeyStats.nbJourneys++; 
						}

						if (shouldShow === undefined){
							shouldShow = scope.serviceFilter(startObject);
						}
						
						if (shouldShow)
							scope.timelineObject.timeline.date.push(startObject);
						
						
						scope.journeyFilter.timeLineReady = true; 
					}
				}
				
				if (!scope.timeline) {
					scope.timeline = new VMM.Timeline('my-timeline');
					scope.timeline.init({
						type: 'timeline',
						width: '800',
						height: '150',
						source: scope.timelineObject,
						embed_id: 'my-timeline',
						css: 'app/libs/NUKnightLab-TimelineJS/build/css/timeline.css',
						js: 'app/libs/NUKnightLab-TimelineJS/build/js/timeline.js',
						debug: false,
						lang: 'en',
						scope: scope
					});
				} else {
					scope.timeline.reload(scope.timelineObject);
				}

				$timeout(function() {
					$compile(ele.children()[0])(scope)
					if (scope.renderCallback()){
						scope.renderCallback()();
					}
				}, 0);
			}
			
			scope.$watchCollection(function() {
				return [scope.businessAttributes, scope.customerInfo];
			}, function(data) {
				if (data[0] && data[1]) {
					
					if (scope.journeyStats)
						scope.journeyStats.servicesExist = true ; 
					
					scope.journeyFilter.updateTimeline();
				}
				
				else {
					if (scope.journeyStats)
						scope.journeyStats.servicesExist = false; 
				}
			})

			if (scope.csObject) {
				scope.$watchCollection('csObject', function(data) {
					scope.timelineObject = {
						'timeline': {
							'headline': 'Context Services Timeline',
							'type': 'default',
							'text': 'Context Services',
							'date': []
						}
					};
					pushToday();
					for (var i = 0; i < data.items.length; i++) {
						var startObject = {
							'selection': {
								'selected': false
							}
						};
						var shouldShow = undefined; 

						
						var startDate = new Date(data.items[i].started.timestamp);
						var startTime = startDate; 
						startObject.startDate = startDate.toISOString();
						startObject.headline = data.items[i].label;
						startObject.text = data.items[i].service_id;
						startObject.tag = data.items[i].service_id;
						startObject.color = '#4AC764';
						startObject.status = 'Active';
						
						if (scope.journeyFilter)
							startObject.durationStyle = scope.journeyFilter.durationStyle;
						else
							startObject.durationStyle = "event line";

						if (scope.journeyStats){

							var sumOfStates = scope.journeyStats.getTotalStates(data.items[i].service_id);
							
							if (sumOfStates >= 0 )
								startObject.totalStates = sumOfStates ;
						}

						if (scope.journeyStats)
							scope.journeyStats.activeJourneys++; 
						
						if (data.items[i].completed && data.items[i].completed.timestamp) {
							startObject.color = '#2E69DB';
							startObject.status = 'Started';

							var endObject = {
								'selection': {
									'selected': false
								}
							};
							var endDate = new Date(data.items[i].completed.timestamp);
							var endTime = endDate;
							
							var timeFrame = csUtils.convertToReadableDate(Math.abs(endTime - startTime))
							startObject.timeFrame = timeFrame;
							data.items[i].duration = endTime - startTime;
							
							endObject.startDate = endDate.toISOString();
							startObject.endDate = endObject.startDate;
							
							endObject.headline = data.items[i].label;
							endObject.text = data.items[i].service_id;
							endObject.tag = data.items[i].service_id;
							endObject.color = '#2E69DB';
							endObject.timeFrame = timeFrame;
							endObject.status = 'Completed';
							
							if (scope.journeyFilter)
								endObject.durationStyle = scope.journeyFilter.durationStyle;
							else
								endObject.durationStyle = "event line";

							if (scope.journeyStats){

								var sumOfStates = scope.journeyStats.getTotalStates(data.items[i].service_id); 
								
								if (sumOfStates >= 0 )
								endObject.totalStates = sumOfStates;
							
							}
							
							if (scope.journeyStats) {
								scope.journeyStats.completedJourneys++;
								
								
								if (scope.journeyStats.activeJourneys > 0) 
									scope.journeyStats.activeJourneys--; 
							}

							shouldShow = scope.serviceFilter(startObject , endObject);
							
							if (shouldShow )
								scope.timelineObject.timeline.date.push(endObject);
							
							var ans = Math.abs(endDate - startDate); 
							sum += ans; 
							entries++; 
					
						}
						
					

					
						if (scope.journeyStats){
							scope.journeyStats.average = scope.journeyStats.convertToReadableDate(sum/entries); 
							scope.journeyStats.nbJourneys++; 							
						}

						
						if(shouldShow === undefined)
							shouldShow = scope.serviceFilter(startObject);
						
						if (shouldShow)
							scope.timelineObject.timeline.date.push(startObject);
					}
					VMM.debug = true;
					if (!scope.timeline) {
						scope.timeline = new VMM.Timeline('my-timeline');
						scope.timeline.init({
							type: 'timeline',
							width: '700',
							height: '150',
							source: scope.timelineObject,
							embed_id: 'my-timeline',
							css: 'app/libs/NUKnightLab-TimelineJS/build/css/timeline.css',
							js: 'app/libs/NUKnightLab-TimelineJS/build/js/timeline.js',
							debug: true,
							lang: 'en',
							scope: scope
						});
					} else {
						scope.timeline.reload(scope.timelineObject);
					}
					$timeout(function() {
						$compile(ele.children()[0])(scope)
						if (scope.renderCallback){
							scope.renderCallback()();
						}
					}, 0);
				});
			} else {
				loadInfo();
				scope.$watch('serverUrl + customerId + isAnon', function() {
					loadInfo();
					if (scope.selectionCallback) {
						scope.selectionCallback()('');
					}
				});
			}
			if (scope.selectionCallback) {
				scope.$watch('timelineObject.timeline.date',
					function(dates) {
						if (dates) {		
							for (var i = 0; i < dates.length; i++) {
								if (dates[i].selection && dates[i].selection.selected) {
									scope.selectionCallback()(dates[i]);
									break;
								}
							}
							
						}
					}, true);
			}
		}
	}
}).config(function($provide) {
	$provide.decorator('popoverPopupDirective', function($delegate) {
		$delegate[0].templateUrl = './app/modules/context-services/popover.html';
		return $delegate;
	});
});
