package com.infinite.focus.server.dashboard.stats;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.infinite.focus.server.activity.Activity;
import com.infinite.focus.server.activity.ActivityRepository;
import com.infinite.focus.server.activity.Activity_;
import com.infinite.focus.server.activity.service.ActivityService;
import com.infinite.focus.server.auth.AccountRepository;
import com.infinite.focus.server.auth.Instructor;
import com.infinite.focus.server.auth.InstructorRepository;
import com.infinite.focus.server.auth.Student;
import com.infinite.focus.server.auth.StudentRepository;
import com.infinite.focus.server.dashboard.DashboardController;
import com.infinite.focus.server.dashboard.GetDataDashBoardRequest;
import com.infinite.focus.server.dashboard.LabelAndValue;
import com.infinite.focus.server.dashboard.TimeLine;
import com.infinite.focus.server.grade.GradeRepository;
import com.infinite.focus.server.home.MoodUpdate;
import com.infinite.focus.server.instructor.Instructor_;
import com.infinite.focus.server.lessons.Lesson;
import com.infinite.focus.server.lessons.LessonRepository;
import com.infinite.focus.server.standard.Standard;
import com.infinite.focus.server.standard.StandardRepository;
import com.infinite.focus.server.standard.Standard_;
import com.infinite.focus.server.students.ClassRepository;
import com.infinite.focus.server.students.Student_;
import com.infinite.focus.server.tests.SocioEmotionalTestAnswer;
import com.infinite.focus.server.tests.SocioEmotionalTestDataWrapper;
import com.infinite.focus.server.tests.SocioEmotionalTestQuestion;
import com.infinite.focus.server.tests.SocioEmotionalTestQuestionOption;
import com.infinite.focus.server.tests.SocioEmotionalTestResult;
import com.infinite.focus.server.utils.AppUtils;
import com.infinite.focus.server.utils.DateUtils;
import com.infinite.focus.server.utils.DigitUtils;

@Service
public class StatsServiceImpl implements StatsService {

	@Autowired
	EntityManager entityManager;
	
	@Autowired
	AccountRepository accountRepository;

	@Autowired
	GradeRepository gradeRepository;

	@Autowired
	StandardRepository standardRepository;
	
	@Autowired
	StudentRepository studentRepository;

	@Autowired
	InstructorRepository instructorRepository;

	@Autowired
	ClassRepository classRepository;
	
	@Autowired
	ActivityRepository activityRepository;
	
	@Autowired
	LessonRepository lessonRepository;
	
	@Autowired
	ActivityService activityService;

	String forwardSlash = "/";
	
	@Override
	public Object getVideoViewList(GetDataDashBoardRequest request) {

		List<Object[]> results = request.getAscOrDesc().equals("DESC")  ? activityRepository.getVideoViewListOrderByCountAndFullWatchedPercentageDesc() : activityRepository.getVideoViewListOrderByCountAndFullWatchedPercentageASC();

		LinkedList<LinkedHashMap<String, Object>> videoViewList = new LinkedList<LinkedHashMap<String, Object>>();
		
		for (Object[] result : results) {
			
			LinkedHashMap<String, Object> videosMap = new LinkedHashMap<String, Object>();
			
			// Lesson
		    Long entity_id = ((Number) result[0]).longValue();
		    Lesson lesson = lessonRepository.getOne(entity_id);
		    
		    videosMap.put("Lesson", lesson);
		    
		    // Views
		    int count = ((Number) result[1]).intValue();
		    
		    if(count > 0) {
		    
		    	videosMap.put("Views", count);
			    
			    // Views
			    String fullWatchPercentage =  result[2].toString();
			    
			    videosMap.put("Full_Watch_Percentage", fullWatchPercentage);
			    
			    Long countOfWhoWatched = activityRepository.getCountOfStudentsWhoWatchedVideoByEnitityId(entity_id);
			    
			    videosMap.put("Unique_Users_That_Watched_Video", countOfWhoWatched);
			    		
			    List<Long> repeateStudents = activityRepository.getRepeteVideoWatchStudentIdListByEntityId(entity_id);
			    
			    videosMap.put("Unique_Users_That_Watched_Video_Again", repeateStudents.size());
			    
			    // Time
//			    List<Activity> activities = activityRepository.findAllByActivityTypeIdAndEntityIdOrderByStartDateTime(2L, entity_id);
//			    
//			    videosMap.put("Time", getTimeInString(getTotalTimeSpent(activities)));
			    
			    long totalTime = ((Number) result[3]).longValue();
			    videosMap.put("Time", getTimeInString(totalTime));
			    
			    long avgTime = ((Number) result[4]).longValue();
			    videosMap.put("Avg_Time", getTimeInString(avgTime));
			    
		    } else {
		    	videosMap.put("Views", "-");
		    	videosMap.put("Full_Watch_Percentage", "-");
		    	videosMap.put("Unique_Users_That_Watched_Video", "-");
		    	videosMap.put("Unique_Users_That_Watched_Video_Again", "-");
		    	videosMap.put("Time", "-");
		    	videosMap.put("Avg_Time", "-");
		    }
		    
		    
		    videoViewList.add(videosMap);
		}
		
		return videoViewList;
	}
	
	@Override
	public List<LabelAndValue> getVideosDemographicData(GetDataDashBoardRequest request) {
		
		List<LabelAndValue> graphData = new ArrayList<LabelAndValue>();

		if (AppUtils.isNotNullOrEmpty(request.getGenders())) {

			for (String gender : request.getGenders()) {

				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getGenders().add(gender);

				graphData.add(new LabelAndValue(gender, getVideosDemographic(getDataDashBoardRequest)));
			}
		} else if (AppUtils.isNotNullOrEmpty(request.getAges())) {
			for (Integer age : request.getAges()) {

				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getAges().add(age);

				graphData.add(new LabelAndValue(String.valueOf(age), getVideosDemographic(getDataDashBoardRequest)));
			}
		} else if (AppUtils.isNotNullOrEmpty(request.getEthnicity())) {

			for (String ethnicity : request.getEthnicity()) {

				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getEthnicity().add(ethnicity);

				graphData.add(new LabelAndValue(ethnicity, getVideosDemographic(getDataDashBoardRequest)));
			}
		} else if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			for (Long grade_id : request.getGradeIds()) {
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);

				getDataDashBoardRequest.getGradeIds().add(grade_id);

				graphData.add(new LabelAndValue(gradeRepository.getOne(grade_id).getGrade_name(),
						getVideosDemographic(getDataDashBoardRequest)));
			}
		} else if (AppUtils.isNotNullOrEmpty(request.getClassIds())) {
			for (Long class_id : request.getClassIds()) {

				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getClassIds().add(class_id);
				
				graphData.add(new LabelAndValue(DashboardController.getClassNameWithInstructorFullName(class_id, classRepository, instructorRepository),
						getVideosDemographic(getDataDashBoardRequest)));
			}
		}
		
		return graphData;
	}
	
	public long getVideosDemographic(GetDataDashBoardRequest request){
		
		List<Long> activities = activityService.getAllStudentActivitiesByActivityTypeIdAndEnitityId(request, 2L, request.getEntity_id());
		
		
		return activities.size();
	}
	
	

	@Override
	public LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>> getTimeSpentByStudents(
			GetDataDashBoardRequest request) {

		List<Student> students = studentRepository.findAllOrderById();
		
		System.out.println("Students - " + students.size());
		
		Date fromDate = AppUtils.isNullOrEmpty(students) ? DateUtils.setTimeToFromDate(new Date()) : DateUtils.setTimeToFromDate(students.get(0).getAccount().getCreatedAt());
		Date toDate = DateUtils.setTimeToToDate(new Date());// students.get(students.size() - 1).getAccount().getCreatedAt();
		
		LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>> graphData = new LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>>();
				
		System.out.println("----------------------------- Gender------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGenders())) {

			LinkedHashMap<String, LinkedList<String>> genders = new LinkedHashMap<String, LinkedList<String>>();
			
			for (String gender : request.getGenders()) {

				System.out.println("----------------------------- "+ gender + "------------------------------");
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
								request);
				getDataDashBoardRequest.getGenders().add(gender);
				
				genders.put(gender, getTimeSpent(activityService.getAllStudentActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Gender", genders);
			
		} 
		
		System.out.println("----------------------------- Age ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getAges())) {

			LinkedHashMap<String, LinkedList<String>> ages = new LinkedHashMap<String, LinkedList<String>>();
			
			for (Integer age : request.getAges()) {

				System.out.println("----------------------------- "+ age + "------------------------------");
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
								request);
				getDataDashBoardRequest.getAges().add(age);
				
				ages.put(String.valueOf(age), getTimeSpent(activityService.getAllStudentActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Age", ages);
			
		} 
		
		System.out.println("----------------------------- Ethnicity------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getEthnicity())) {

			LinkedHashMap<String, LinkedList<String>> ethnicityMap = new LinkedHashMap<String, LinkedList<String>>();
			
			for (String ethnicity : request.getEthnicity()) {
				
				System.out.println("----------------------------- "+ ethnicity + "------------------------------");
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);

				getDataDashBoardRequest.getEthnicity().add(ethnicity);

				ethnicityMap.put(ethnicity, getTimeSpent(activityService.getAllStudentActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Ethnicity", ethnicityMap);
			
		} 
		
		
		System.out.println("----------------------------- Grade------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			
			LinkedHashMap<String, LinkedList<String>> grades = new LinkedHashMap<String, LinkedList<String>>();
			
			for (Long grade_id : request.getGradeIds()) {
				
				System.out.println("-----------------------------" + grade_id +"------------------------------");


				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getGradeIds().add(grade_id);

				grades.put(gradeRepository.getOne(grade_id).getGrade_name(), getTimeSpent(activityService.getAllStudentActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Grade", grades);
			
		} 
				
		System.out.println("----------------------------- Class ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getClassIds())) {
			
			LinkedHashMap<String, LinkedList<String>> classes = new LinkedHashMap<String, LinkedList<String>>();
			
			for (Long class_id : request.getClassIds()) {
				
				System.out.println("-----------------------------" + class_id +"------------------------------");


				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getClassIds().add(class_id);

				classes.put(DashboardController.getClassNameWithInstructorFullName(class_id, classRepository, instructorRepository), getTimeSpent(activityService.getAllStudentActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Classroom", classes);
			
		} 
		return graphData;
		
	}

	@Override
	public LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>> getTimeSpentByTeachers(
			GetDataDashBoardRequest request) {

		System.out.println("----------------------------- TIME_SPENT_BY_TEACHERS------------------------------");
		
		List<Instructor> instructors = instructorRepository.findAllOrderById();
		
		System.out.println("Instructors - " + instructors.size());
		
		Date fromDate = AppUtils.isNullOrEmpty(instructors) ? DateUtils.setTimeToFromDate(new Date()) : accountRepository.findByAccountId(instructors.get(0).getAccount_id()).getCreatedAt();
		Date toDate = DateUtils.setTimeToToDate(new Date()); //accountRepository.findByAccountId(instructors.get(instructors.size() - 1).getAccount_id()).getCreatedAt();
		
		
		LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>> graphData = new LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>>();
				
	
		System.out.println("----------------------------- Grade------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			
			LinkedHashMap<String, LinkedList<String>> grades = new LinkedHashMap<String, LinkedList<String>>();
			
			for (Long grade_id : request.getGradeIds()) {
				
				System.out.println("-----------------------------" + grade_id +"------------------------------");


				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getGradeIds().add(grade_id);

				grades.put(gradeRepository.getOne(grade_id).getGrade_name(), getTimeSpent(activityService.getAllInstructorActivitiesByActivityType(getDataDashBoardRequest, 1L), fromDate, toDate));
			}
			
			graphData.put("Grade", grades);
			
		} 
				
		return graphData;
		
	}
	
	private GetDataDashBoardRequest getGetDataDashBoardRequestWithReqeuest(
			GetDataDashBoardRequest request) {
		GetDataDashBoardRequest getDataDashBoardRequest = new GetDataDashBoardRequest();
		getDataDashBoardRequest.setEntity_id(request.getEntity_id());
		getDataDashBoardRequest.setTimeLine(request.getTimeLine());
		getDataDashBoardRequest
				.setSocio_emotional_test_question_type_id(request.getSocio_emotional_test_question_type_id());
		getDataDashBoardRequest.setGraphType(request.getGraphType());
		getDataDashBoardRequest.setFromDate(request.getFromDate());
		getDataDashBoardRequest.setToDate(request.getToDate());
		return getDataDashBoardRequest;
	}
	
	public LinkedList<String> getTimeSpent(List<Activity> activities, Date fromDate, Date toDate) {

		LinkedList<String> reportings = new LinkedList<String>();

		if(AppUtils.isNotNullOrEmpty(activities)) {
			
			long timeSpent = getTotalTimeSpent(activities);
			
			System.out.println("Time Spent Diff - " + timeSpent + " FromDate - " + DateUtils.dailyDateFormat.format(fromDate) + " ToDate - " + DateUtils.dailyDateFormat.format(toDate));
			
			System.out.println("----------------------------Daily---------------------------------");
			
			Double days = (double) DateUtils.getDayCountByFromDateAndToDate(fromDate, toDate);
			
			Long dailyTimeSpent = Math.round(timeSpent / days); 
			
			System.out.println("dailyTimeSpent - " +  dailyTimeSpent + " = timeSpent: " + timeSpent + " / Days: " + days);
			
			reportings.add(getTimeInString(dailyTimeSpent)); //
			
			System.out.println("----------------------------Weekly---------------------------------");
			
			Double weeks = (double) DateUtils.getWeekCountByFromDateAndToDate(fromDate, toDate);
			
			Long weeklyTimeSpent = Math.round(timeSpent / weeks); 
						
			System.out.println("weeklyTimeSpent - " +  weeklyTimeSpent + " = timeSpent: " + timeSpent + " / Weeks: " + weeks);
			
			reportings.add(getTimeInString(weeklyTimeSpent));
			
			System.out.println("----------------------------Monthly---------------------------------");
			
			Double months = (double) DateUtils.getMonthCountByFromDateAndToDate(fromDate, toDate);
			
			Long monthlyTimeSpent = Math.round(timeSpent / months); 
			
			System.out.println("monthlyReporting - " +  monthlyTimeSpent + " = timeSpent: " + timeSpent + " / Months: " + months);
			
			reportings.add(getTimeInString(monthlyTimeSpent));
			
			System.out.println("----------------------------Yearly---------------------------------");
			
			Double years = (double) DateUtils.getYearCountByFromDateAndToDate(fromDate, toDate);
			
			Long yearlyTimeSpent = Math.round(timeSpent / years); 
						
			System.out.println("yearlyTimeSpent - " +  yearlyTimeSpent + " = timeSpent: " + timeSpent + " / Years: " + years);
			
			reportings.add(getTimeInString(yearlyTimeSpent));

		} else {
			
			reportings.add("00:00:00");
			reportings.add("00:00:00");
			reportings.add("00:00:00");
			reportings.add("00:00:00");
		}
		
		return reportings;
	}
	
	private String getTimeInString(long time) {
		 String timeString = String.format("%02d:%02d:%02d", TimeUnit.MILLISECONDS.toHours(time),
	                TimeUnit.MILLISECONDS.toMinutes(time) % TimeUnit.HOURS.toMinutes(1),
	                TimeUnit.MILLISECONDS.toSeconds(time) % TimeUnit.MINUTES.toSeconds(1));
		 return timeString;
	}
	
	private Long getTotalTimeSpent(List<Activity> activities) {
		
		Long totalTimeSpent = 0L;
		
		for(int i = 0; i <activities.size(); i++) {
			
			Activity activity = activities.get(i);
			
			 long appUsedTime = activity.getEnd_date_time().getTime() - activity.getStart_date_time().getTime();
			 
			 totalTimeSpent = totalTimeSpent + appUsedTime;
			 
			// System.out.println("Diff - " + appUsedTime + " EndDate - " + activity.getEnd_date_time() + " StartDate -" + activity.getStart_date_time());
		}
		
		return totalTimeSpent;
	}
	
	@Override
	public LinkedHashMap<String, List<LabelAndValue>> getTimeSpentByDemographicsData(GetDataDashBoardRequest request) {
		
		LinkedHashMap<String, List<LabelAndValue>> graphData = new LinkedHashMap<String, List<LabelAndValue>>();

		if (AppUtils.isNotNullOrEmpty(request.getGenders())) {
			
			GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
					request);

			getDataDashBoardRequest.getGenders().addAll(request.getGenders());

			graphData.put("Gender", getTimeSpentByDemographics(getDataDashBoardRequest));

		}

		if (AppUtils.isNotNullOrEmpty(request.getAges())) {

			GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			
			getDataDashBoardRequest.getAges().addAll(request.getAges());

			graphData.put("Age", getTimeSpentByDemographics(getDataDashBoardRequest));

		}

		if (AppUtils.isNotNullOrEmpty(request.getEthnicity())) {

			GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			
			getDataDashBoardRequest.getEthnicity().addAll(request.getEthnicity());

			graphData.put("Ethnicity", getTimeSpentByDemographics(getDataDashBoardRequest));

		}

		if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			
			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);

			getSocioEmotionalDataAnalyticsRequest.getGradeIds().addAll(request.getGradeIds());

			graphData.put("Grade", getTimeSpentByDemographics(getSocioEmotionalDataAnalyticsRequest));

		}

		if (AppUtils.isNotNullOrEmpty(request.getClassIds())) {

			GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			
			getDataDashBoardRequest.getClassIds().addAll(request.getClassIds());

			graphData.put("Classroom", getTimeSpentByDemographics(getDataDashBoardRequest));

		}

		return graphData;
	}

	public List<LabelAndValue> getTimeSpentByDemographics(GetDataDashBoardRequest request) {

		List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(request, 1L);
		
		LinkedHashMap<String, List<Activity>> activityMap = activityService.getActivityMapByTimeLine(request.getTimeLine(), activities);


		List<LabelAndValue> labelAndValues = new ArrayList<>();

		for (String key : activityMap.keySet()) {

			List<Activity> values = activityMap.get(key);

			if (!values.isEmpty()) {

				/*double appUsedTime = 0;

				for (Activity activity : values) {
					 //milliseconds
			        double differnce = (activity.getEnd_date_time().getTime() - activity.getStart_date_time().getTime())/1000;
			        if(differnce >= 1) {
			        	appUsedTime = (appUsedTime + differnce);
			        }
				}*/

				long timeSpent = getTotalTimeSpent(values);
				
				double avgTime = DigitUtils.getAverage((double) (timeSpent/1000), 60.0);
				
				System.out.println("getTimeSpentByDemographics " + key + "Time in double - " + timeSpent + " - Time in string " + getTimeInString(timeSpent));
				
				labelAndValues.add(new LabelAndValue(key, avgTime));

			} else {
				labelAndValues.add(new LabelAndValue(key, 0.0));
			}

		}

		return labelAndValues;
	}
	
	@Override
	public LinkedHashMap<String, LinkedList<Object>> getTimeSpentByDemographicData(GetDataDashBoardRequest request) {

		switch (request.getDemographicType()) {
		case GENDER: {
			return getStudentsTimeSpentByGender(request);
		}
		case AGE: {
			return getStudentsTimeSpentByAge(request);
		}
		case ETHNICITY: {
			return getStudentsTimeSpentByEthnicity(request);
		}
		case GRADE: {
			return getStudentsTimeSpentByGrade(request);
		}
		case CLASSROOM: {
			return getStudentsTimeSpentByClassroom(request);
		}
		}

		return new LinkedHashMap<String, LinkedList<Object>>();
	}

	public LinkedHashMap<String, LinkedList<Object>> getStudentsTimeSpentByGender(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gendersAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gendersAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;


		for (int i = 0; i < request.getGenders().size(); i++) {

			String key = request.getGenders().get(i); 
			
			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			getSocioEmotionalDataAnalyticsRequest.getGenders().clear();
			getSocioEmotionalDataAnalyticsRequest.getGenders().add(key);

			List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);
			
			System.out.println("Gender "+ key + " Time Spent " + getTimeInString(timeSpent) + " Total Time Spent" + totalTimeSpent);

			gendersAndTime.put(key, list);
		}

		for (String key : gendersAndTime.keySet()) {
			
			long timeSpent = gendersAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gendersAndAverageAndTime.put(key, list);
		}

		return gendersAndAverageAndTime;
	}
	
	public LinkedHashMap<String, LinkedList<Object>> getStudentsTimeSpentByAge(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gendersAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gendersAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;

		for (int i = 0; i < request.getAges().size(); i++) {

			Integer key = request.getAges().get(i);

			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			getSocioEmotionalDataAnalyticsRequest.getAges().clear();
			getSocioEmotionalDataAnalyticsRequest.getAges().add(key);

			List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);

			gendersAndTime.put(String.valueOf(key), list);
		}

		for (String key : gendersAndTime.keySet()) {
			
			long timeSpent = gendersAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gendersAndAverageAndTime.put(key, list);
		}

		return gendersAndAverageAndTime;
	}
	
	public LinkedHashMap<String, LinkedList<Object>> getStudentsTimeSpentByEthnicity(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gendersAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gendersAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;

		for (int i = 0; i < request.getEthnicity().size(); i++) {

			String key = request.getEthnicity().get(i);
			
			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			getSocioEmotionalDataAnalyticsRequest.getEthnicity().clear();
			getSocioEmotionalDataAnalyticsRequest.getEthnicity().add(key);

			List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);

			gendersAndTime.put(key, list);
		}

		for (String key : gendersAndTime.keySet()) {
			
			long timeSpent = gendersAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gendersAndAverageAndTime.put(key, list);
		}

		return gendersAndAverageAndTime;
	}
	
	public LinkedHashMap<String, LinkedList<Object>> getStudentsTimeSpentByGrade(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gendersAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gendersAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;

		for (int i = 0; i < request.getGradeIds().size(); i++) {

			Long key = request.getGradeIds().get(i);

			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			getSocioEmotionalDataAnalyticsRequest.getGradeIds().clear();
			getSocioEmotionalDataAnalyticsRequest.getGradeIds().add(key);

			List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);

			gendersAndTime.put(gradeRepository.getOne(key).getGrade_name(), list);
		}

		for (String key : gendersAndTime.keySet()) {
			
			long timeSpent = gendersAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gendersAndAverageAndTime.put(key, list);
		}

		return gendersAndAverageAndTime;
	}
	
	public LinkedHashMap<String, LinkedList<Object>> getStudentsTimeSpentByClassroom(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gendersAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gendersAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;

		for (int i = 0; i < request.getClassIds().size(); i++) {

			Long key = request.getClassIds().get(i);
			
			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);
			getSocioEmotionalDataAnalyticsRequest.getClassIds().clear();
			getSocioEmotionalDataAnalyticsRequest.getClassIds().add(key);

			List<Activity> activities = activityService.getAllStudentActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);

			gendersAndTime.put(DashboardController.getClassNameWithInstructorFullName(key, classRepository, instructorRepository), list);
		}

		for (String key : gendersAndTime.keySet()) {
			
			long timeSpent = gendersAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gendersAndAverageAndTime.put(key, list);
		}

		return gendersAndAverageAndTime;
	}
	
	@Override
	public LinkedHashMap<String, List<LabelAndValue>> getTimeSpentByGradesData(GetDataDashBoardRequest request) {
		
		LinkedHashMap<String, List<LabelAndValue>> graphData = new LinkedHashMap<String, List<LabelAndValue>>();

		for(Long grade_id: request.getGradeIds()) {
			
			GetDataDashBoardRequest getSocioEmotionalDataAnalyticsRequest = getGetDataDashBoardRequestWithReqeuest(
					request);

			getSocioEmotionalDataAnalyticsRequest.getGradeIds().add(grade_id);
			
			List<Activity> activities = activityService.getAllInstructorActivitiesByActivityType(getSocioEmotionalDataAnalyticsRequest, 1L);
			
			LinkedHashMap<String, List<Activity>> activityMap = activityService.getActivityMapByTimeLine(getSocioEmotionalDataAnalyticsRequest.getTimeLine(), activities);

			List<LabelAndValue> labelAndValues = new ArrayList<>();

			for (String key : activityMap.keySet()) {

				List<Activity> values = activityMap.get(key);

				if (!values.isEmpty()) {

					double appUsedTime = 0;

					for (Activity activity : values) {
						 //milliseconds
				        double differnce = (activity.getEnd_date_time().getTime() - activity.getStart_date_time().getTime())/1000;
				        if(differnce >= 1) {
				        	appUsedTime = (appUsedTime + differnce);
				        }
					}

					labelAndValues.add(new LabelAndValue(key, DigitUtils.getAverage((double) appUsedTime, 60.0)));

				} else {
					labelAndValues.add(new LabelAndValue(key, 0.0));
				}

			}

			graphData.put(gradeRepository.getOne(grade_id).getGrade_name(), labelAndValues);
		}
		
		return graphData;
	}

	@Override
	public LinkedHashMap<String, LinkedList<Object>> getTimeSpentByGradeData(GetDataDashBoardRequest request) {

		LinkedHashMap<String, LinkedList<Object>> gradesAndAverageAndTime = new LinkedHashMap<String, LinkedList<Object>>();
		LinkedHashMap<String, LinkedList<Long>> gradesAndTime = new LinkedHashMap<String, LinkedList<Long>>();

		long totalTimeSpent = 0;

		List<Long> grade_ids = new ArrayList<>();
		grade_ids.addAll(request.getGradeIds());

		for (int i = 0; i < grade_ids.size(); i++) {

			Long key = grade_ids.get(i);
			request.getGradeIds().clear();
			request.getGradeIds().add(key);

			List<Activity> activities = activityService.getAllInstructorActivitiesByActivityType(request, 1L);

			long timeSpent = getTotalTimeSpent(activities);
			
			totalTimeSpent = totalTimeSpent + timeSpent;

			LinkedList<Long> list = new LinkedList<Long>();
			list.add(timeSpent);

			gradesAndTime.put(gradeRepository.getOne(key).getGrade_name(), list);
		}

		for (String key : gradesAndTime.keySet()) {
			
			long timeSpent = gradesAndTime.get(key).get(0);
			
			LinkedList<Object> list = new LinkedList<Object>();
			list.add(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getPercentage(timeSpent, totalTimeSpent)));
			list.add(getTimeInString(timeSpent));
			
			gradesAndAverageAndTime.put(key, list);
		}

		return gradesAndAverageAndTime;
	}
}
