package com.infinite.focus.server.data;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.cloudinary.Cloudinary;
import com.cloudinary.utils.ObjectUtils;
import com.infinite.focus.server.auth.AccountRepository;
import com.infinite.focus.server.auth.AvatarRepository;
import com.infinite.focus.server.auth.Instructor;
import com.infinite.focus.server.auth.InstructorRepository;
import com.infinite.focus.server.auth.SecurityConstants;
import com.infinite.focus.server.auth.Student;
import com.infinite.focus.server.auth.StudentRepository;
import com.infinite.focus.server.home.DailyAppreciationRepository;
import com.infinite.focus.server.home.MoodUpdate;
import com.infinite.focus.server.home.MoodUpdateRepository;
import com.infinite.focus.server.home.QuoteRepository;
import com.infinite.focus.server.lessons.Lesson;
import com.infinite.focus.server.lessons.LessonRecord;
import com.infinite.focus.server.lessons.LessonRecordRepository;
import com.infinite.focus.server.lessons.LessonRecordWrapper;
import com.infinite.focus.server.lessons.LessonRepository;
import com.infinite.focus.server.moods.Mood;
import com.infinite.focus.server.moods.MoodRepository;
import com.infinite.focus.server.students.Class;
import com.infinite.focus.server.students.ClassRepository;
import com.infinite.focus.server.tests.AnswerRepository;
import com.infinite.focus.server.tests.CorrectAnswerRepository;
import com.infinite.focus.server.tests.MultipleChoiceOptionRepository;
import com.infinite.focus.server.tests.QuestionRepository;
import com.infinite.focus.server.tests.SocioEmotionalTestResult;
import com.infinite.focus.server.tests.SocioEmotionalTestResultRepository;
import com.infinite.focus.server.tests.Test;
import com.infinite.focus.server.tests.TestRepository;
import com.infinite.focus.server.tests.TestResult;
import com.infinite.focus.server.tests.TestResultGrade;
import com.infinite.focus.server.tests.TestResultGradeRepository;
import com.infinite.focus.server.tests.TestResultRepository;
import com.infinite.focus.server.wall.WallPost;
import com.infinite.focus.server.wall.WallPostAttachment;
import com.infinite.focus.server.wall.WallPostAttachmentRepository;
import com.infinite.focus.server.wall.WallPostRepository;
import com.infinite.focus.server.wall.WallPostRequestRepository;
import com.infinite.focus.server.wall.WallPostWrapper;

/**
 * 
 * @author Saboor
 * Created: 11/25/18
 * 
 *
 */


@CrossOrigin(origins = "http://localhost:8383")
@RestController
@RequestMapping("api/data")

public class DataController {
	
	 	private AccountRepository accountRepository;
		private StudentRepository studentRepository;
		private InstructorRepository instructorRepository;
		private AvatarRepository avatarRepository;
	    private BCryptPasswordEncoder bCryptPasswordEncoder;
	    private WallPostRepository wallPostRepository;
	    private WallPostAttachmentRepository wallPostAttachmentRepository;
	    private WallPostRequestRepository wallPostRequestRepository;
	    private QuoteRepository qouteRepository;
	    private MoodUpdateRepository moodUpdateRepository;
	    private DailyAppreciationRepository dailyAppreciationRepository;
	    private ClassRepository classRepository;
	    
	    private TestRepository testRepository;
	    private QuestionRepository questionRepository;
	    private CorrectAnswerRepository correctAnswerRepository;
	    private MultipleChoiceOptionRepository multipleChoiceOptionRepository;
	    private AnswerRepository answerRepository;
	    private TestResultRepository testResultRepository;
	    private TestResultGradeRepository testResultGradeRepository;
	    private LessonRepository lessonRepository;
	    
	    private LessonRecordRepository lessonRecordRepository;

	    private SocioEmotionalTestResultRepository socioEmotionalTestResultRepository;
	    
	    @Autowired
	    private MoodRepository moodRepository;
	    
	    
	    public DataController(SocioEmotionalTestResultRepository socioEmotionalTestResultRepository, LessonRecordRepository lessonRecordRepository, LessonRepository lessonRepository, TestResultGradeRepository testResultGradeRepository, TestResultRepository testResultRepository, AnswerRepository answerRepository, TestRepository testRepository, QuestionRepository questionRepository, CorrectAnswerRepository correctAnswerRepository, MultipleChoiceOptionRepository multipleChoiceOptionRepository, ClassRepository classRepository, DailyAppreciationRepository dailyAppreciationRepository, MoodUpdateRepository moodUpdateRepository, QuoteRepository qouteRepository, WallPostRepository wallPostRepository, WallPostAttachmentRepository wallPostAttachmentRepository, WallPostRequestRepository wallPostRequestRepository, AvatarRepository avatarRepository,
	    		InstructorRepository instructorRepository, StudentRepository studentRepository,AccountRepository accountRepository, BCryptPasswordEncoder bCryptPasswordEncoder) {
	    	
	    	this.socioEmotionalTestResultRepository = socioEmotionalTestResultRepository;
	    	this.lessonRecordRepository = lessonRecordRepository;
	    	this.testResultRepository = testResultRepository;
	    	this.answerRepository = answerRepository;
	    	this.testRepository = testRepository;
	    	this.lessonRepository = lessonRepository;
	    	
	    	this.questionRepository  = questionRepository;
	    	this.correctAnswerRepository = correctAnswerRepository;
	    	this.multipleChoiceOptionRepository = multipleChoiceOptionRepository;
	    	this.testResultGradeRepository = testResultGradeRepository;
	    	
	    	this.classRepository = classRepository;
	    	this.qouteRepository = qouteRepository;
	    	this.wallPostRepository = wallPostRepository;
	    	this.wallPostAttachmentRepository = wallPostAttachmentRepository;
	    	this.wallPostRequestRepository = wallPostRequestRepository;
	    	this.avatarRepository = avatarRepository;
	    	this.bCryptPasswordEncoder= bCryptPasswordEncoder;
	    	this.instructorRepository = instructorRepository;
	    	this.studentRepository = studentRepository;
	    	this.accountRepository = accountRepository;
	    	this.moodUpdateRepository = moodUpdateRepository;
			this.dailyAppreciationRepository = dailyAppreciationRepository;
		}
	    
	    @GetMapping("/get/socio/emotional/data")   
	    public ResponseEntity<List<SocioEmotionalTestResult>> getSocioEmotionalRecords(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

	    	List<SocioEmotionalTestResult> results = socioEmotionalTestResultRepository.findByStudentIdOrderByCreatedAtLatestToOldest(student_id);
	    	String date = null;
	    	
	    	List<SocioEmotionalTestResult> socioEmotionalTestResults = new ArrayList<SocioEmotionalTestResult>(results);
	    	
	    	for(SocioEmotionalTestResult t : results) {
	    		String createdAt = format.format(t.getCreatedAt());
	    		if(date == null || !date.equals(createdAt)) {
	    			date = createdAt;
	    		} else if(date.equals(createdAt)) {
	    			socioEmotionalTestResults.remove(t);
	    		}
	    	}
	    	
    	   	return new ResponseEntity<List<SocioEmotionalTestResult>>(socioEmotionalTestResults, HttpStatus.OK);
	    }
	    
	    
	    @GetMapping("/get/socio/emotional/data/by/class")   
	    public ResponseEntity<List<SocioEmotionalDataWrapper>> getSocioEmotionalRecordsByClass(@RequestParam(value="class_id", defaultValue="aEn24") Long class_id){
    	   	
	    	List<Student> students = studentRepository.findByClassId(class_id);
	    	List<SocioEmotionalDataWrapper> list = new ArrayList<>();
	    		    		    	
	    	for(Student s: students) {   
	    		
	    		for(SocioEmotionalTestResult t: socioEmotionalTestResultRepository.findByStudentId(s.getStudent_id())){
	    			
	    			boolean found = false; 
	    			
	    			for(SocioEmotionalDataWrapper sdw:list) {
	    				
	    				if(t.getCreatedAt().getMonth()+1 == sdw.month && t.getCreatedAt().getYear()+1900 == sdw.year) {
	    					sdw.score += t.score;
	    					sdw.count++;
	    					found = true;
	    				}
	    				
	    			}
	    			
	    			if(!found) {
	    				list.add(new SocioEmotionalDataWrapper(t.score,1, t.getCreatedAt().getMonth()+1, t.getCreatedAt().getYear() + 1900));
	    			}
	    			
	    		}
	    		
	    	}
	    	
	    	for(SocioEmotionalDataWrapper a:list) {
    			
	    		a.score = a.score/a.count;
    		
    		}
	    	
	    	
	    	
	    	return new ResponseEntity<List<SocioEmotionalDataWrapper>>(list, HttpStatus.OK);
	    }
	    
	    
	    @GetMapping("/get/assessment/data/by/class")   
	    public ResponseEntity<List<AssessmentDataWrapper>> getAssessmentByClass(@RequestParam(value="class_id", defaultValue="aEn24") Long class_id){
	    	
	    	List<Student> students = studentRepository.findByClassId(class_id);
	    	
	    	List<AssessmentDataWrapper> list = new ArrayList<>();
	    		    	
	    	for(Student s: students) {    	
	    	
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(s.getStudent_id())) {
	    		
	    		AssessmentDataWrapper adw = new AssessmentDataWrapper();
	    			    		
	    		Lesson lesson = lessonRepository.getOne(l.getLesson_id());
	    		
	    		if(lesson == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setLesson(lesson);
	    		
	    		Test test = testRepository.getOne(lesson.getTest_id());
	    		
	    		if(test == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setTest(test);
	    	
	    		
	    		TestResult testResult = testResultRepository.findMostRecentByStudent(test.getTest_id(), s.getStudent_id());
	    		
	    		if(testResult != null) {
	    			
	    			TestResultGrade trg = testResultGradeRepository.findByTestResultId(testResult.getTest_result_id());
	    			
	    			if(trg != null) {
	    			adw.setGrade(trg.getGrade());
	    			}else {
	    				adw.setGrade(0f);
	    			}
	    			
	    			adw.setTestResult(testResult);

	    		}
	    		
	    		boolean found = false;
	    		
	    		for(AssessmentDataWrapper a:list) {
	    			
	    			if(a.getTest().getTest_id() == adw.getTest().getTest_id()) {
	    				
	    				a.setCount(a.getCount()+1);
	    				a.setGrade(a.getGrade() + adw.getGrade());
	    				
	    	//			System.out.println("FOUND!!");
	    	//			System.out.println("Test id: " + a.getTest().getTest_id());
	    	//			System.out.println("Total Grade is: " + a.getGrade());
	    				
	    				found = true;
	    				
	    			}
	    			
	    		}
	    		
	    		if(!found) {
	    			adw.count++;
	    			list.add(adw);
	  //  			System.out.println("NOT FOUND! ADDING TO LIST");
	    		}	    		
	    		
	    		
	    		}
	    	
	    	}
	    	
	    	for(AssessmentDataWrapper a:list) {
    			
	    		a.grade = a.grade/(float)a.count;
    		
    		}
	    	
	    	
   		    	
    	   	return new ResponseEntity<List<AssessmentDataWrapper>>(list, HttpStatus.OK);
	    }
	    
	    @GetMapping("/get/assessment/data")   
	    public ResponseEntity<List<AssessmentDataWrapper>> getRecords(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
	    	
	    	List<AssessmentDataWrapper> list = new ArrayList<>();
	    	
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(student_id)) {
	    		
	    		AssessmentDataWrapper adw = new AssessmentDataWrapper();
	    			    		
	    		Lesson lesson = lessonRepository.getOne(l.getLesson_id());
	    		
	    		if(lesson == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setLesson(lesson);
	    		
	    		Test test = testRepository.getOne(lesson.getTest_id());
	    		
	    		if(test == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setTest(test);
	    	
	    		
	    		TestResult testResult = testResultRepository.findMostRecentByStudent(test.getTest_id(), student_id);
	    		
	    		if(testResult != null) {
	    			adw.setGrade(testResultGradeRepository.findByTestResultId(testResult.getTest_result_id()).getGrade());
	    			adw.setTestResult(testResult);
	    		}
	    		
	    		list.add(adw);
	    		
	    		
	    	}
   		    	
    	   	return new ResponseEntity<List<AssessmentDataWrapper>>(list, HttpStatus.OK);
	    }
	    
	    @GetMapping("/get/mood/analysis")   
	    public ResponseEntity<List<MoodOccurance>> getMoodAnalysis(@RequestParam(value="student_id", defaultValue="aEn24") Long student_id){
	    	
	    	List<MoodOccurance> list = new ArrayList<>();
	    	
	    	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: moodUpdateRepository.findByStudentId(student_id)) {
	    		
	    		if(containsMood("excited", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("excited")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
	    		
			if(containsMood("shy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("shy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
			if(containsMood("mad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("mad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
	    		if(containsMood("annoyed", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("annoyed")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("scared", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("scared")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("silly", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("silly")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("happy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("happy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    	   if(containsMood("sad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("sad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    	   
	    	   if(containsMood("angry", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("angry")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    	   }
	    	
	    	
	    	
    	   	return new ResponseEntity<List<MoodOccurance>>(list, HttpStatus.OK);
	    		    	
	    }
	    
	    
	    @GetMapping("/get/mood/analysis/by/class")   
	    public ResponseEntity<List<MoodOccurance>> getMoodAnalysisByClass(@RequestParam(value="class_id", defaultValue="aEn24") Long class_id){
	    	
	    	List<MoodOccurance> list = new ArrayList<>();
	    	List<Student> students = studentRepository.findByClassId(class_id);
	    	
	    	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(Student s: students) {
	    		
	    	for(MoodUpdate m: moodUpdateRepository.findByStudentId(s.getStudent_id())) {
	    		
	    		if(containsMood("excited", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("excited")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
	    		
			if(containsMood("shy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("shy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
			if(containsMood("mad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("mad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
	    		if(containsMood("annoyed", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("annoyed")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("scared", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("scared")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("silly", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("silly")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		if(containsMood("happy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("happy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    	   if(containsMood("sad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("sad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    	   
	    	   if(containsMood("angry", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("angry")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    	   }
	    	
	    	}
	    	
	    	
	    	for(MoodOccurance m:list) {
	    		
	    		m.count = m.count / students.size();
	    		
	    	}
	    	
	    	
    	   	return new ResponseEntity<List<MoodOccurance>>(list, HttpStatus.OK);
	    		    	
	    }
	    
	    
	    @GetMapping("/get/socio/emotional/data/by/school")   
	    public ResponseEntity<List<SocioEmotionalDataWrapper>> getSocioEmotionalRecordsBySchool(@RequestParam(value="school_id", defaultValue="aEn24") Long school_id){
    	   	
	    	//Retrieve all instructors
	    	List<Instructor> instructors = instructorRepository.findBySchoolId(school_id);
	    	
	    	List<Student> students = new ArrayList<>();
	    	
	    	//Loop all instructors of a school
	    	for(Instructor i: instructors) {
	    		
	    		//Get all classes of this instructor
	    		List<com.infinite.focus.server.students.Class> classes = classRepository.findByInstructorId(i.getInstructor_id());
	    		
	    		for(com.infinite.focus.server.students.Class c: classes) {
	    			
	    			//Get students of class and add to larger list
	    			students.addAll(studentRepository.findByClassId(c.getClass_id()));
	    			
	    		}
	    		
	    	}	 
	    	
	    	//Create lists to hold all groupings of test results
	    	List<SocioEmotionalDataWrapper> list = new ArrayList<>();
	    	
	    	//Loop through all students 
	    	for(Student s: students) {  
	    		
	    		//Get socio emotional test result for student 
	    		for(SocioEmotionalTestResult t: socioEmotionalTestResultRepository.findByStudentId(s.getStudent_id())){
	    			
	    			boolean found = false; 
	    			
	    			//Loop through group list to check if a group already exists for the month this test result is from
	    			for(SocioEmotionalDataWrapper sdw:list) {
	    				
	    				//If the months are the same add this score to the total and increment the count
	    				if(t.getCreatedAt().getMonth()+1 == sdw.month && t.getCreatedAt().getYear()+1900 == sdw.year) {
	    					
	    					sdw.score += t.score;
	    					
	    					sdw.count++;
	    					
	    					//Set found to true
	    					found = true;
	    				}
	    				
	    			}
	    			
	    			//If a match is not found create a new grouping 
	    			if(!found) {
	    				
	    				//Add grouping to list with necessary updates to the date
	    				list.add(new SocioEmotionalDataWrapper(t.score,1, t.getCreatedAt().getMonth()+1, t.getCreatedAt().getYear() + 1900));
	    				
	    			}
	    			
	    		}
	    		
	    	}
	    	
	    	//Loop through and average each month grouping
	    	for(SocioEmotionalDataWrapper a:list) {
    			
	    		//Compute average for each grouping 
	    		a.score = a.score/a.count;
    		
    		}
	    	
	    	
	    	
	    	return new ResponseEntity<List<SocioEmotionalDataWrapper>>(list, HttpStatus.OK);
	    }
	    
	    
	    //Get assessment data for a school
	    @GetMapping("/get/assessment/data/by/school")   
	    public ResponseEntity<List<AssessmentDataWrapper>> getAssessmentBySchool(@RequestParam(value="school_id", defaultValue="aEn24") Long school_id){
	    	

	    	//Retrieve all instructors under school
	    	List<Instructor> instructors = instructorRepository.findBySchoolId(school_id);
	    	
	    	List<Student> students = new ArrayList<>();
	    		 
	    	//Loop through all instructors retrieved
	    	for(Instructor i: instructors) {
	    		
	    		//Find all classes for this particular instructor
	    		List<com.infinite.focus.server.students.Class> classes = classRepository.findByInstructorId(i.getInstructor_id());
	    		
	    		//Find all students for each class and add to list of all students
	    		for(com.infinite.focus.server.students.Class c: classes) {
	    			
	    			students.addAll(studentRepository.findByClassId(c.getClass_id()));
	    			
	    		}
	    		
	    	}	 
	    	
	    	
	    	List<AssessmentDataWrapper> list = new ArrayList<>();
	    	
	    	//Loop through all students
	    	for(Student s: students) {    	
	    	
	        //Get all records for all lessons this student has completed
	    	for(LessonRecord l:lessonRecordRepository.findByStudentId(s.getStudent_id())) {
	    		
	    		AssessmentDataWrapper adw = new AssessmentDataWrapper();
	    		
	    		//Get lesson associated with this record
	    		Lesson lesson = lessonRepository.getOne(l.getLesson_id());
	    		
	    		//If lesson cannot be found return error
	    		if(lesson == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setLesson(lesson);
	    		
	    		//Get test associated with this record
	    		Test test = testRepository.getOne(lesson.getTest_id());
	    		
	    		//If test cannot be found return error
	    		if(test == null) {
	    			new ResponseEntity<List<Lesson>>(HttpStatus.NOT_FOUND);
	    		}
	    		
	    		adw.setTest(test);
	    	
	    		//Get test result for most recent time this student took the test
	    		TestResult testResult = testResultRepository.findMostRecentByStudent(test.getTest_id(), s.getStudent_id());
	    		
	    		//If this test result exists
	    		if(testResult != null) {
	    			
	    			//Get grade from this test result
	    			TestResultGrade trg = testResultGradeRepository.findByTestResultId(testResult.getTest_result_id());
	    			
	    			//If grade exists else set to 0
	    			if(trg != null) {
	    			adw.setGrade(trg.getGrade());
	    			}else {
	    				adw.setGrade(0f);
	    			}
	    			
	    			adw.setTestResult(testResult);

	    		}
	    		
	    		boolean found = false;
	    		
	    		
	    		//Group grades of all tests to compute averages 
	    		
	    		//Loop through all assessments
	    		for(AssessmentDataWrapper a:list) {
	    			
	    			//If this is the same test
	    			if(a.getTest().getTest_id() == adw.getTest().getTest_id()) {
	    				
	    				//Increment count
	    				a.setCount(a.getCount()+1);
	    				
	    				//Add to total grade count for that test
	    				a.setGrade(a.getGrade() + adw.getGrade());
	    				
	    	//			System.out.println("FOUND!!");
	    	//			System.out.println("Test id: " + a.getTest().getTest_id());
	    	//			System.out.println("Total Grade is: " + a.getGrade());
	    				
	    				found = true;
	    				
	    			}
	    			
	    		}
	    		
	    		//Else add test to list
	    		if(!found) {
	    			adw.count++;
	    			list.add(adw);
	    	//		System.out.println("NOT FOUND! ADDING TO LIST");
	    		}	    		
	    		
	    		
	    		}
	    	
	    	}
	    	
	    	//Loop through and average out grades 
	    	for(AssessmentDataWrapper a:list) {
    			
	    		a.grade = a.grade/(float)a.count;
    		
    		}
	    	
	    	
   		    	
    	   	return new ResponseEntity<List<AssessmentDataWrapper>>(list, HttpStatus.OK);
	    }
	    
	    
	    
	    //Get mood analysis for a school
	    @GetMapping("/get/mood/analysis/by/school")   
	    public ResponseEntity<List<MoodOccurance>> getMoodAnalysisBySchool(@RequestParam(value="school_id", defaultValue="aEn24") Long school_id){
	    	
	    	//Retrieve all instructors
	    	List<Instructor> instructors = instructorRepository.findBySchoolId(school_id);
	    	
	    	List<Student> students = new ArrayList<>();
	    	
	    	//Loop all instructors of a school
	    	for(Instructor i: instructors) {
	    		
	    		//Get all classes of this instructor
	    		List<com.infinite.focus.server.students.Class> classes = classRepository.findByInstructorId(i.getInstructor_id());
	    		
	    		for(com.infinite.focus.server.students.Class c: classes) {
	    			
	    			//Get students of class and add to larger list
	    			students.addAll(studentRepository.findByClassId(c.getClass_id()));
	    			
	    		}
	    		
	    	}	    	
	    	
	    	
	    	List<MoodOccurance> list = new ArrayList<>();
	    	
	    	//Create list of each mood to hold all occurrences
	    	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));
	    	
	    	//Loop through all students
	    	for(Student s: students) {
	    		
	 //   		System.out.println("Checking " + s.getFirst_name());
	    	
	    	//Find all mood updates for this student	
	    	for(MoodUpdate m: moodUpdateRepository.findByStudentId(s.getStudent_id())) {
	    		
	    //		System.out.println("Checking mood update " + m.getText());
	    		
	    		//Check for each mood if present update count 
	    		if(containsMood("excited", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("excited")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		
	    		//Check for each mood if present update count 	
			if(containsMood("shy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("shy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
			//Check for each mood if present update count 
			if(containsMood("mad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("mad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
			//Check for each mood if present update count 
	    		if(containsMood("annoyed", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("annoyed")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		//Check for each mood if present update count 
	    		if(containsMood("scared", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("scared")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		//Check for each mood if present update count 
	    		if(containsMood("silly", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("silly")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    		//Check for each mood if present update count 
	    		if(containsMood("happy", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("happy")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		//Check for each mood if present update count 
	    	   if(containsMood("sad", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("sad")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    	 //Check for each mood if present update count 
	    	   if(containsMood("angry", m.getText())){
	    			
	    			for(MoodOccurance o: list) {
	    				
	    				if(o.getMood().equals("angry")) {
	    					
	    					o.setCount(o.getCount()+1);
	    				}
	    				
	    			}
	    			
	    		}
	    		
	    	   }
	    	
	    	}
	    	
	    	
	    	//Average out each occurance
	    	for(MoodOccurance m:list) {
	    		
	    		//If there are 0 or more students divide total count by # of students to get average
	    		if(students.size() > 0) {
	    		m.count = m.count / students.size();
	    		}else {
	    			m.count = m.count;
	    		}
	    		
	    	}
	    	
	    	
    	   	return new ResponseEntity<List<MoodOccurance>>(list, HttpStatus.OK);
	    		    	
	    }
	    
	    
	    
	    private boolean containsMood(String mood, String text) {
	    	
	    	if(text.toLowerCase().trim().contains(mood.toLowerCase().trim())) {
	    		
	    		return true;
	    		
	    	} else {
	    		
	    		String[] words = text.split("\\s+");
	    		
	    		for(String s:words) {
	    			
	    			if(calculate(s.toLowerCase().trim(), mood.toLowerCase().trim()) < 2) {
	    				
	    				return true;
	    				
	    			}
	    			
	    		}

	    		
	    	}
	    	
			return false;
	    	
	    	
	    }
	    
	    public int calculate(String x, String y) {
	    	
	        if (x.isEmpty()) {
	        	
	            return y.length();
	            
	        }
	 
	        if (y.isEmpty()) {
	        	
	            return x.length();
	            
	        } 
	 
	        int substitution = calculate(x.substring(1), y.substring(1)) 
	         + costOfSubstitution(x.charAt(0), y.charAt(0));
	        int insertion = calculate(x, y.substring(1)) + 1;
	        int deletion = calculate(x.substring(1), y) + 1;
	 
	        return min(substitution, insertion, deletion);
	    }
	 
	    public int costOfSubstitution(char a, char b) {
	        return a == b ? 0 : 1;
	    }
	
	    public int min(int... numbers) {
	    	
	        return Arrays.stream(numbers)
	          .min().orElse(Integer.MAX_VALUE);
	    }    
	    
		@GetMapping("/get/assessment-master-details")
		public ResponseEntity<AssessmentMasterDetailsWrapper> getAssessmentMasterDetails(@RequestHeader(SecurityConstants.HEADER_STRING) String token) {
			
			AssessmentMasterDetailsWrapper assessmentMasterDetailsWrapper = new AssessmentMasterDetailsWrapper();
			
			List<Mood> moods = moodRepository.getAllMoodsOrderByMoodId();
			assessmentMasterDetailsWrapper.setMoods(moods);
			
			return new ResponseEntity<AssessmentMasterDetailsWrapper>(assessmentMasterDetailsWrapper, HttpStatus.OK);
		}
	    
}
