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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;

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.service.ActivityService;
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.MoodInsight;
import com.infinite.focus.server.dashboard.MoodOccuranceAndCompetencyScore;
import com.infinite.focus.server.data.MoodOccurance;
import com.infinite.focus.server.grade.GradeRepository;
import com.infinite.focus.server.home.MoodUpdate;
import com.infinite.focus.server.home.MoodUpdateRepository;
import com.infinite.focus.server.home.MoodUpdate_;
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.students.service.StudentService;
import com.infinite.focus.server.tests.SocioEmotionalTestAnswer;
import com.infinite.focus.server.tests.SocioEmotionalTestAnswerRepository;
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.SocioEmotionalTestQuestionOptionRepository;
import com.infinite.focus.server.tests.SocioEmotionalTestQuestionRepository;
import com.infinite.focus.server.tests.SocioEmotionalTestResult;
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;
import com.infinite.focus.server.utils.MoodUpdateUtils;

@Service
public class MoodDataServiceImpl implements MoodDataService {
	
	@Autowired
	EntityManager entityManager;
	
	@Autowired
	SocioEmotionalTestQuestionOptionRepository socioEmotionalTestQuestionOptionRepository;
	
	@Autowired
	SocioEmotionalTestQuestionRepository socioEmotionalTestQuestionRepository;
	
	@Autowired
	SocioEmotionalTestAnswerRepository socioEmotionalTestAnswerRepository;
	
	@Autowired
	GradeRepository gradeRepository;
	
	@Autowired
	StandardRepository standardRepository;

	@Autowired
	StudentRepository studentRepository;

	@Autowired
	StudentService studentService;
	
	@Autowired
	InstructorRepository instructorRepository;

	@Autowired
	ClassRepository classRepository;
	
	@Autowired
	MoodUpdateRepository moodUpdateRepository;

	@Autowired
	LessonRepository lessonRepository;
	
	@Autowired
	ActivityService activityService;
	
	String forwardSlash = "/";
	
	
	@Override
	public LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>> getSelfReportingData(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());//moodUpdateList.get(moodUpdateList.size() - 1).getCreatedAt();
		
		LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>> graphData = new LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>>();
		
		System.out.println("----------------------------- Gender------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGenders())) {

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

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

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

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

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

				getDataDashBoardRequest.getEthnicity().add(ethnicity);

				ethnicityMap.put(ethnicity, getSelfReporting(getDataDashBoardRequest, fromDate, toDate));
			}
			
			graphData.put("Ethnicity", ethnicityMap);
			
		} 
		
		
		System.out.println("----------------------------- Grade------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			
			LinkedHashMap<String, LinkedList<Double>> grades = new LinkedHashMap<String, LinkedList<Double>>();
			
			for (Long grade_id : request.getGradeIds()) {
				
				String grade_name = gradeRepository.getOne(grade_id).getGrade_name();
				
				System.out.println("-----------------------------" + grade_id + " -> "+ grade_name +"------------------------------");


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

				grades.put(grade_name, getSelfReporting(getDataDashBoardRequest, fromDate, toDate));
			}
			
			graphData.put("Grade", grades);
			
		} 
		
		System.out.println("----------------------------- Classroom ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getClassIds())) {
			
			LinkedHashMap<String, LinkedList<Double>> classrooms = new LinkedHashMap<String, LinkedList<Double>>();
			
			for (Long class_id : request.getClassIds()) {
				
				String class_name = DashboardController.getClassNameWithInstructorFullName(class_id, classRepository, instructorRepository);
				
				System.out.println("-----------------------------" + class_id  + " -> "+ class_name +"------------------------------");


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

				classrooms.put(class_name, getSelfReporting(getDataDashBoardRequest, fromDate, toDate));
			}
			
			graphData.put("Classroom", classrooms);
			
		} 
				
		return graphData;
	}
	
	@Override
	public LinkedList<LabelAndValue> getMoodUpdateDemographicComparisonGraphData(GetDataDashBoardRequest request) {
		
		List<Long> student_ids = studentService.getStudentByDemographics(request);
		
		List<MoodUpdate> moodUpdateList = getMoodUpdateByStudentIds(student_ids, request.getFromDate(), request.getToDate());
		
		LinkedList<MoodOccurance> moodOccurances = getMoodAnalysis(moodUpdateList, false);		
		
		LinkedList<LabelAndValue> graphData = new LinkedList<LabelAndValue>();
		
		for(int i = 0; i < moodOccurances.size(); i++) {
			graphData.add(new LabelAndValue(moodOccurances.get(i).getMood(), moodOccurances.get(i).getCount()));
		}
		
		return graphData;
	}
	
	@Override
	public LinkedHashMap<String, LinkedList<Double>> getMoodAnalysisGraphData(GetDataDashBoardRequest request) {
		
		System.out.println("----------------------------MOOD_ANALYSIS--------------------------------------");
		
		List<Long> student_ids = studentService.getStudentByDemographics(request);
		
		List<MoodUpdate> moodUpdateList = getMoodUpdateByStudentIds(student_ids, request.getFromDate(), request.getToDate());
		
		LinkedList<MoodOccurance> moodOccurances = getMoodAnalysis(moodUpdateList, false);
		
		Double totalCount = 0.0;
		
		for(int i = 0; i < moodOccurances.size(); i++) {
			
			totalCount = totalCount + moodOccurances.get(i).getCount();
			
			System.out.println(moodOccurances.get(i).getMood() + " - " + moodOccurances.get(i).getCount());
		}
		
		System.out.println("-------------------------------------------------------------------");
		
		System.out.println("Total occournce " + totalCount);
		
		String forwordSlash = "/";
		
		System.out.println("------------------------Percentage = (Value "+ forwordSlash +" Total Value) � 100-------------------------------------------");

		LinkedHashMap<String, LinkedList<Double>> graphData = new LinkedHashMap<String, LinkedList<Double>>();
		
		double percentageTotal = 0.0;
		
		for(int i = 0; i < moodOccurances.size(); i++) {
									
			LinkedList<Double> list = new LinkedList<Double>();
			
			String mood = moodOccurances.get(i).getMood();
			Double count = (double) moodOccurances.get(i).getCount();
			Double percentage = DigitUtils.getPercentage(count, totalCount);
			
			percentageTotal = percentageTotal + percentage;

			System.out.println(mood + "	=	( Value	" + count + "	" + forwordSlash +	"	Total Value	"+ totalCount +" ) X 100 =	percentage	" + percentage);

			list.add(DigitUtils.formatDoubleInTwoDigit((double) count));			
			list.add(DigitUtils.formatDoubleInTwoDigit(percentage));
			
			graphData.put(moodOccurances.get(i).getMood(), list);
		}
		
		System.out.println("-----------------------------------------------------------------------------------------------------------------------------");

		System.out.println("		( Value	" + totalCount + "	" + forwordSlash +	"	Total Value	"+ totalCount +" ) X 100 =	percentage	" + percentageTotal);
		
		return graphData;
	}
	
	@Override
	public LinkedHashMap<String, LinkedHashMap<String, LinkedList<String>>> getMostAndLeastReportedData(GetDataDashBoardRequest request) {

		
		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>> genderMap = new LinkedHashMap<String, LinkedList<String>>();
			
			for (String gender : request.getGenders()) {

				System.out.println("-----------------------------" + gender +"------------------------------");
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getGenders().add(gender);
				
				genderMap.put(gender, getMostAndLeast(getDataDashBoardRequest));
			}
			
			graphData.put("Gender", genderMap);
			
		} 
		
		System.out.println("----------------------------- Age ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getAges())) {

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

				System.out.println("-----------------------------" + age +"------------------------------");
				
				GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
						request);
				
				getDataDashBoardRequest.getAges().add(age);
				
				ageMap.put(String.valueOf(age), getMostAndLeast(getDataDashBoardRequest));
			}
			
			graphData.put("Age", ageMap);
			
		} 
		
		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, getMostAndLeast(getDataDashBoardRequest));
			}
			
			graphData.put("Ethnicity", ethnicityMap);
			
		} 
		
		System.out.println("----------------------------- Grade ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getGradeIds())) {
			
			LinkedHashMap<String, LinkedList<String>> gradeMap = 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);

				gradeMap.put(gradeRepository.getOne(grade_id).getGrade_name(), getMostAndLeast(getDataDashBoardRequest));
			}
			
			graphData.put("Grade", gradeMap);
			
		} 
		
		System.out.println("----------------------------- Class ------------------------------");
		
		if (AppUtils.isNotNullOrEmpty(request.getClassIds())) {
			
			LinkedHashMap<String, LinkedList<String>> classroomMap = 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);

				
				
				classroomMap.put(DashboardController.getClassNameWithInstructorFullName(class_id, classRepository, instructorRepository), getMostAndLeast(getDataDashBoardRequest));
			}
			
			graphData.put("Classroom", classroomMap);
			
		} 
		
		System.out.println("----------------------------- Overall ------------------------------");
		
		GetDataDashBoardRequest getDataDashBoardRequest = getGetDataDashBoardRequestWithReqeuest(
				request);
		LinkedHashMap<String, LinkedList<String>> overall = new LinkedHashMap<String, LinkedList<String>>();
		overall.put("Overall", getMostAndLeast(getDataDashBoardRequest));
		graphData.put("Overall", overall);
		
		return graphData;
	}
	
	
	
	public LinkedList<String> getMostAndLeast(GetDataDashBoardRequest request){
		
		List<Long> student_ids = studentService.getStudentByDemographics(request);
		
		List<MoodUpdate> moodUpdateList = getMoodUpdateByStudentIds(student_ids, request.getFromDate(), request.getToDate());
		
		LinkedList<MoodOccurance> moodOccurances = removeMoodOccuranceWithZeroCountFromMoodOccuranceList(getMoodAnalysis(moodUpdateList, true));
		
		LinkedList<String> mostAndLeast = new LinkedList<>();
		
		if(AppUtils.isNotNullOrEmpty(moodOccurances)) {
			MoodOccurance most = moodOccurances.get(0);
			MoodOccurance least = moodOccurances.get(moodOccurances.size()-1);
			
			if(most.getCount() > 0) {
				mostAndLeast.add(most.getMood() + " ( " + most.getCount() + " ) ");
			} else {
				mostAndLeast.add(""+ " ( " + least.getCount() + " ) ");
			}
			
			if(least.getCount() > 0) {
				mostAndLeast.add(least.getMood() + " ( " + least.getCount() + " ) ");
			} else {
				mostAndLeast.add(""+ " ( " + least.getCount() + " ) ");
			}
		} else {
			mostAndLeast.add("");
			mostAndLeast.add("");
		}
		
		return mostAndLeast;
	}

	private LinkedList<MoodOccurance> removeMoodOccuranceWithZeroCountFromMoodOccuranceList(LinkedList<MoodOccurance> list){
		Iterator<MoodOccurance> itr = list.iterator();
        while (itr.hasNext()) {
        	MoodOccurance x = itr.next();
            if (x.getCount() == 0) {
                itr.remove();
            }
        }
		return list;
	}
	
	@Override
	public LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>> getMoodAnalysisAndCompetencyScoreGraphData(GetDataDashBoardRequest request) {
		
		LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>> graphData = new LinkedHashMap<String, LinkedHashMap<String, LinkedList<Double>>>();

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

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

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

		}

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

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

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

		}

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

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

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

		}

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

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

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

		}

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

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

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

		}

		return graphData;
	}

	public LinkedHashMap<String, LinkedList<Double>> getMoodAnalysisAndCompetencyScore(
			GetDataDashBoardRequest request) {

		System.out.println(
				"----------------------------MODD_ANALYSIS_AND_COMPETENCY_SCORE--------------------------------------");

		List<Long> student_ids = studentService.getStudentByDemographics(request);

		List<MoodUpdate> moodUpdateList = getMoodUpdateByStudentIds(student_ids, request.getFromDate(),
				request.getToDate());

		LinkedList<MoodOccuranceAndCompetencyScore> moodOccurances = getMoodAnalysisCompetencyScore(moodUpdateList,
				false);

		LinkedHashMap<String, LinkedList<Double>> graphData = new LinkedHashMap<String, LinkedList<Double>>();

		Long socio_emotional_test_question_type_id = request.getSocio_emotional_test_question_type_id();

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

			if (moodOccurances.get(i).getCount() > 0
					&& AppUtils.isNotNullOrEmpty(moodOccurances.get(i).getStudentIds())) {
				List<SocioEmotionalTestResult> values = getSocioEmotionalTestResultByStudentIds(
						moodOccurances.get(i).getStudentIds(), request.getFromDate(), request.getToDate());

				if (socio_emotional_test_question_type_id == null) {

					if (!values.isEmpty()) {

						Double score = 0.0;

						for (SocioEmotionalTestResult test : values) {
							score = score + test.getScore();
						}

						moodOccurances.get(i).setScore(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getAverage(score, (double) values.size())));
					}

				} else {

					SocioEmotionalTestDataWrapper s = new SocioEmotionalTestDataWrapper();
					s.setOptions(socioEmotionalTestQuestionOptionRepository.findAll());
					s.setQuestions(socioEmotionalTestQuestionRepository
							.findBySocioEmotionalTestQuestionTypeId(socio_emotional_test_question_type_id));

					if (!values.isEmpty()) {

						Double score = 0.0;

						for (SocioEmotionalTestResult test : values) {

							Double total_score = 0.0;

							List<SocioEmotionalTestAnswer> socioEmotionalTestAnswers = socioEmotionalTestAnswerRepository
									.findBySocioEmotionalTestResultId(test.getSocio_emotional_test_result_id());

							for (int q = 0; q < s.getQuestions().size(); q++) {

								SocioEmotionalTestQuestion socioEmotionalTestQuestion = s.getQuestions().get(q);

								for (int a = 0; a < socioEmotionalTestAnswers.size(); a++) {
									if (socioEmotionalTestQuestion
											.getSocio_emotional_test_question_id() == socioEmotionalTestAnswers.get(a)
													.getSocio_emotional_test_question_id()) {

										SocioEmotionalTestAnswer socioEmotionalTestAnswer = socioEmotionalTestAnswers
												.get(a);

										for (int o = 0; o < s.getOptions().size(); o++) {
											if (socioEmotionalTestAnswer
													.getSocio_emotional_test_question_option_id() == s.getOptions()
															.get(o).getSocio_emotional_test_question_option_id()) {

												SocioEmotionalTestQuestionOption socioEmotionalTestQuestionOption = s
														.getOptions().get(o);

												if (socioEmotionalTestQuestion.isReversed()) {
													total_score += socioEmotionalTestQuestionOption.getReverse_weight();
												} else {
													total_score += socioEmotionalTestQuestionOption.getWeight();
												}
												System.out.println("total_score = " + total_score);
												break;
											}
										}
									}

								}

							}

							score = score + total_score;
							System.out.println(
									"test id " + test.getSocio_emotional_test_result_id() + "  score = " + score);
						}

						moodOccurances.get(i).setScore(DigitUtils.formatDoubleInTwoDigit(DigitUtils.getAverage(score, (double) values.size())));
					}

				}
			}
			
			LinkedList<Double> list = new LinkedList<>();
			list.add(DigitUtils.formatDoubleInTwoDigit((double) moodOccurances.get(i).getCount()));
			list.add(DigitUtils.formatDoubleInTwoDigit(moodOccurances.get(i).getScore()));
			
			graphData.put(moodOccurances.get(i).getMood(), list);
		}

		return graphData;
	}
	
	public LinkedList<MoodOccuranceAndCompetencyScore> getMoodAnalysisCompetencyScore(List<MoodUpdate> moodUpdateList, boolean isSortData) {

		LinkedList<MoodOccuranceAndCompetencyScore> list = new LinkedList<>();

		list.add(new MoodOccuranceAndCompetencyScore("happy", 0));
		list.add(new MoodOccuranceAndCompetencyScore("angry", 0));
		list.add(new MoodOccuranceAndCompetencyScore("sad", 0));
		list.add(new MoodOccuranceAndCompetencyScore("mad", 0));
		list.add(new MoodOccuranceAndCompetencyScore("scared", 0));
		list.add(new MoodOccuranceAndCompetencyScore("annoyed", 0));
		list.add(new MoodOccuranceAndCompetencyScore("shy", 0));
		list.add(new MoodOccuranceAndCompetencyScore("silly", 0));
		list.add(new MoodOccuranceAndCompetencyScore("excited", 0));

		for (MoodUpdate m : moodUpdateList) {

			if (MoodUpdateUtils.containsMood("excited", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("excited")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("shy", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("shy")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("mad", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("mad")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("annoyed", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("annoyed")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("scared", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("scared")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("silly", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("silly")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("happy", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("happy")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("sad", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("sad")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

			if (MoodUpdateUtils.containsMood("angry", m.getText())) {

				for (MoodOccuranceAndCompetencyScore o : list) {

					if (o.getMood().equals("angry")) {

						o.setCount(o.getCount() + 1);
						o.getStudentIds().add(m.getStudent_id());
					}

				}

			}

		}

		if(isSortData) {
			Collections.sort(list, new Comparator<MoodOccuranceAndCompetencyScore>() {
				@Override
				public int compare(MoodOccuranceAndCompetencyScore u1, MoodOccuranceAndCompetencyScore u2) {

					Integer count1 = u1.getCount();
					Integer count2 = u2.getCount();

					return count2.compareTo(count1);
				}
			});
		}

		return list;
	}
	
	public LinkedList<MoodOccurance> getMoodAnalysis(List<MoodUpdate> moodUpdateList, boolean isSortData) {

		LinkedList<MoodOccurance> list = new LinkedList<>();

		list.add(new MoodOccurance("happy", 0));
		list.add(new MoodOccurance("angry", 0));
		list.add(new MoodOccurance("sad", 0));
		list.add(new MoodOccurance("mad", 0));
		list.add(new MoodOccurance("scared", 0));
		list.add(new MoodOccurance("annoyed", 0));
		list.add(new MoodOccurance("shy", 0));
		list.add(new MoodOccurance("silly", 0));
		list.add(new MoodOccurance("excited", 0));

		for (MoodUpdate m : moodUpdateList) {

			if (MoodUpdateUtils.containsMood("excited", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("excited")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("shy", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("shy")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("mad", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("mad")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("annoyed", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("annoyed")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("scared", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("scared")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("silly", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("silly")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("happy", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("happy")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("sad", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("sad")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

			if (MoodUpdateUtils.containsMood("angry", m.getText())) {

				for (MoodOccurance o : list) {

					if (o.getMood().equals("angry")) {

						o.setCount(o.getCount() + 1);
					}

				}

			}

		}

		if(isSortData) {
			Collections.sort(list, new Comparator<MoodOccurance>() {
				@Override
				public int compare(MoodOccurance u1, MoodOccurance u2) {

					Integer count1 = u1.getCount();
					Integer count2 = u2.getCount();

					return count2.compareTo(count1);
				}
			});
		}

		return list;
	}
	
	public LinkedList<Double> getSelfReporting(GetDataDashBoardRequest request, Date fromDate, Date toDate) {

		List<Long> student_ids = studentService.getStudentByDemographics(request);

		List<MoodUpdate> moodUpdateList = getMoodUpdateByStudentIds(student_ids, null, null);

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

		if(AppUtils.isNotNullOrEmpty(moodUpdateList)) {
			
			Double size = (double) moodUpdateList.size();
			
			System.out.println("MoodUpdate List Size - " + size + " FromDate - " + DateUtils.dayWitTimeFormat.format(fromDate) + " ToDate - " + DateUtils.dayWitTimeFormat.format(toDate));
			
			System.out.println("----------------------------Daily---------------------------------");
			
			Double days = (double) DateUtils.getDayCountByFromDateAndToDate(fromDate, toDate);
			
			Double dailyReporting = DigitUtils.getAverage(size, days); 

			System.out.println("dailyReporting - " +  dailyReporting + " = Size: " + size + " / Days: " + days);
			
			reportings.add(dailyReporting); //
			
			System.out.println("----------------------------Weekly---------------------------------");
			
			Double weeks = (double) DateUtils.getWeekCountByFromDateAndToDate(fromDate, toDate);
			
			Double weeklyReporting = DigitUtils.getAverage(size, weeks); 
						
			System.out.println("weeklyReporting - " +  weeklyReporting + " = Size: " + size + " / Weeks: " + weeks);
			
			reportings.add(weeklyReporting);
			
			System.out.println("----------------------------Monthly---------------------------------");
			
			Double months = (double) DateUtils.getMonthCountByFromDateAndToDate(fromDate, toDate);
			
			Double monthlyReporting = DigitUtils.getAverage(size, months); 
			
			System.out.println("monthlyReporting - " +  monthlyReporting + " = Size: " + size + " / Months: " + months);
			
			reportings.add(monthlyReporting);
			
			System.out.println("----------------------------Yearly---------------------------------");
			
			Double years = (double) DateUtils.getYearCountByFromDateAndToDate(fromDate, toDate);
			
			Double yearlyReporting = DigitUtils.getAverage(size, years); 
						
			System.out.println("yearlyReporting - " +  yearlyReporting + " = Size: " + size + " / Years: " + years);
			
			reportings.add(yearlyReporting);

		} else {
			
			reportings.add(0.0);
			reportings.add(0.0);
			reportings.add(0.0);
			reportings.add(0.0);
		}
		
		return reportings;
	}
	
	
	private List<MoodUpdate> getMoodUpdateByStudentIds(List<Long> student_ids, Date fromDate, Date toDate) {
		
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<MoodUpdate> query = criteriaBuilder.createQuery(MoodUpdate.class);
		Root<MoodUpdate> root = query.from(MoodUpdate.class);

		List<Predicate> predicates = new ArrayList<>();

		if (AppUtils.isNotNullOrEmpty(student_ids)) {
			Predicate genderPredicate = criteriaBuilder.in(root.get(MoodUpdate_.STUDENT_ID)).value(student_ids);
			predicates.add(genderPredicate);
		} else {
			return new ArrayList<>();
		}

		if(fromDate != null && toDate != null) {
			System.out.println("getMoodUpdateByStudentIds FromDate " + DateUtils.dailyDateFormat.format(fromDate) + " - ToDate " + DateUtils.dailyDateFormat.format(toDate));

			predicates.add(criteriaBuilder.between(root.<Date>get(MoodUpdate_.CREATEDAT), fromDate, toDate));
		}
		
		query.where(predicates.toArray(new Predicate[0]))
				.orderBy(criteriaBuilder.asc(root.<Date>get(MoodUpdate_.CREATEDAT)));
		
		TypedQuery<MoodUpdate> typedQuery = entityManager.createQuery(query);
		List<MoodUpdate> moodUpdateList = typedQuery.getResultList();
		/*for(MoodUpdate moodUpdate : moodUpdateList) {
			System.out.println("MoodUpdate " + moodUpdate.toString());
		}*/
		System.out.println("MoodUpdate Count = " + moodUpdateList.size());
		return moodUpdateList;
	}
	
	private List<SocioEmotionalTestResult> getSocioEmotionalTestResultByStudentIds(LinkedHashSet<Long> student_ids,
			Date fromDate, Date toDate) {
		CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
		CriteriaQuery<SocioEmotionalTestResult> query = criteriaBuilder.createQuery(SocioEmotionalTestResult.class);
		Root<SocioEmotionalTestResult> root = query.from(SocioEmotionalTestResult.class);

		List<Predicate> predicates = new ArrayList<>();

		if (AppUtils.isNotNullOrEmpty(student_ids)) {
			Predicate genderPredicate = criteriaBuilder.in(root.get(SocioEmotionalTestResult_.STUDENT_ID)).value(student_ids);
			predicates.add(genderPredicate);
		}

		if(fromDate != null && toDate != null) {
			System.out.println("getSocioEmotionalTestResultByStudentIds FromDate " + DateUtils.dailyDateFormat.format(fromDate) + " - ToDate " + DateUtils.dailyDateFormat.format(toDate));

			predicates.add(criteriaBuilder.between(root.<Date>get(SocioEmotionalTestResult_.CREATEDAT), fromDate, toDate));
		}

		query.where(predicates.toArray(new Predicate[0]));

		TypedQuery<SocioEmotionalTestResult> typedQuery = entityManager.createQuery(query);
		List<SocioEmotionalTestResult> socioEmotionalTestResultList = typedQuery.getResultList();
		System.out.println("SocioEmotionalTestResult Count = " + socioEmotionalTestResultList.size());
		return socioEmotionalTestResultList;
	}
	
	private GetDataDashBoardRequest getGetDataDashBoardRequestWithReqeuest(
			GetDataDashBoardRequest request) {
		GetDataDashBoardRequest getDataDashBoardRequest = new GetDataDashBoardRequest();
		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;
	}
	
	@Override
	public LinkedList<MoodInsight> getMoodInsightByInstructerId(GetDataDashBoardRequest request) {
		
		LinkedList<MoodInsight> moodInsightList = new LinkedList<MoodInsight>();
		
		List<Activity> activities = activityService.getMoodInsightByInstructerId(request);
				
		for(Activity activity: activities) {
						
			MoodInsight moodInsight = new MoodInsight();
			
			if(activity.getStudent() != null) {
				moodInsight.setStudent_name(activity.getStudent().getFirst_name() + " " + activity.getStudent().getLast_name());
			}
			
			moodInsight.setMood_before(getNAIfNull(activity.getMood_update_before()) + " (" + activity.getLevel_of_focus_before() +")");
			
			Lesson lesson = lessonRepository.findByLessonId(activity.getEntity_id());
			if(lesson != null) {
				moodInsight.setVideo_watched(lesson.getVideo_url());
			}
			moodInsight.setMood_after(getNAIfNull(activity.getMood_update_after()) + " (" + activity.getLevel_of_focus_after() +")");
			
			moodInsightList.add(moodInsight);		
		}
		
		return moodInsightList;
	}

	private String getNAIfNull(String strValue) {
		if(strValue == null) {
			return "N/A";
		}
		return strValue;
	}
}
