/**
   * Method is to return GradeClass list.
   *
   * @param request - HttpServletRequest
   * @param modelMap - ModelMap attribute.
   * @return list of classGrade
   * @throws AkuraAppException - Detailed exception
   */
  @RequestMapping(value = ATTENDANCE_GRADE_CLASS_LIST_HTM)
  @ResponseBody
  public String populateGradeClass(ModelMap modelMap, HttpServletRequest request)
      throws AkuraAppException {

    StringBuilder allGradeClass = new StringBuilder();
    int gradeId = Integer.parseInt(request.getParameter(SELECTED_VALUE));
    Grade grade = commonService.findGradeById(gradeId);
    List<ClassGrade> classGrades =
        SortUtil.sortClassGradeList(commonService.getClassGradeListByGrade(grade));
    boolean isFirst = true;
    StringBuilder classes = new StringBuilder();

    for (ClassGrade classGrade : classGrades) {
      classes.append(classGrade.getDescription());
      classes.append(AkuraWebConstant.UNDERSCORE_STRING);
      classes.append(classGrade.getClassGradeId());

      if (isFirst) {
        allGradeClass.append(classes.toString()); // no comma
        isFirst = false;
      } else {
        allGradeClass.append(AkuraWebConstant.STRING_COMMA); // comma
        allGradeClass.append(classes.toString());
      }
      classes.delete(0, classes.length());
    }
    return allGradeClass.toString();
  }
  /**
   * Method is set the attendance dash board dto with selected month and selected class.
   *
   * @param request type HttpServletRequest
   * @param attendanceDashboardDto type AttendanceDashboardDto.
   * @throws AkuraAppException - The exception details that occurred when processing.
   */
  private void setMonthAndClass(
      HttpServletRequest request, AttendanceDashboardDto attendanceDashboardDto)
      throws AkuraAppException {

    int monthId = 0;
    int classId = 0;
    String selectedMonth = request.getParameter(SELECT_MONTHS);
    if (selectedMonth != null && !selectedMonth.equals(AkuraWebConstant.STRING_ZERO)) {
      monthId = Integer.parseInt(selectedMonth);
    }
    attendanceDashboardDto.setMonth(monthId);

    String selectedClass = request.getParameter(SELECT_CLASSES);
    if (selectedClass != null && !selectedClass.equals(AkuraWebConstant.STRING_ZERO)) {

      ClassGrade classGradeObj =
          commonService.findClassGrade(Integer.parseInt(request.getParameter(SELECT_CLASSES)));

      if (classGradeObj != null) {
        classId = classGradeObj.getSchoolClass().getClassId();
      }
      attendanceDashboardDto.setSelectedClassId(Integer.parseInt(selectedClass));
    } else {
      attendanceDashboardDto.setSelectedClassId(classId);
    }

    attendanceDashboardDto.setClassGradeId(classId);
  }
  /**
   * Method is return the academic day count.
   *
   * @param attendanceDashboardDto type AttendanceDashboardDto
   * @return academic days type integer
   * @throws AkuraAppException - The exception details that occurred when processing.
   */
  private int getAcademicDays(AttendanceDashboardDto attendanceDashboardDto)
      throws AkuraAppException {

    Date fDate = null;
    Date tDate = null;

    int year = attendanceDashboardDto.getYear();
    if (attendanceDashboardDto.getMonth() == 0) {

      fDate = DateUtil.getFistDayOfSelectedYearMonth(year, 1);
      tDate = DateUtil.getLastDayOfSelectedYearMonth(year, MONTH_DECEMBER);
    } else {
      fDate = DateUtil.getFistDayOfSelectedYearMonth(year, attendanceDashboardDto.getMonth());
      tDate = DateUtil.getLastDayOfSelectedYearMonth(year, attendanceDashboardDto.getMonth());
    }

    Calendar firstDateOfPreviousMonth = Calendar.getInstance();
    Calendar lastDateOfPreviousMonth = Calendar.getInstance();
    firstDateOfPreviousMonth.setTime(fDate);
    lastDateOfPreviousMonth.setTime(tDate);

    List<Holiday> holidayList =
        commonService.findHolidayByYear(
            firstDateOfPreviousMonth.getTime(), lastDateOfPreviousMonth.getTime());

    return HolidayUtil.countWorkingDays(
        firstDateOfPreviousMonth, lastDateOfPreviousMonth, holidayList);
  }
  /**
   * Returns the attendance dash board information with pagination.
   *
   * @param modelMap - a model map contains the data.
   * @param request - request scope data.
   * @param response - response scope data.
   * @param attendanceDashboardDto - AttendanceDashboardDto
   * @return - the name of the view to be redirected.
   * @throws AkuraAppException - The exception details that occurred when processing.
   */
  @RequestMapping(value = ATTENDANCE_PAGINATION, method = RequestMethod.POST)
  public ModelAndView getPagination(
      HttpServletRequest request,
      HttpServletResponse response,
      @ModelAttribute(MODEL_ATT_TEMPLATE) AttendanceDashboardDto attendanceDashboardDto,
      ModelMap modelMap)
      throws AkuraAppException {

    boolean flag = false;
    modelMap.addAttribute(STATUS, Boolean.FALSE);

    String selectedClass = request.getParameter(SELECT_CLASSES);

    if (selectedClass != null) {
      ClassGrade classGradeObj = commonService.findClassGrade(Integer.parseInt(selectedClass));

      if (classGradeObj != null) {
        attendanceDashboardDto.setClassDescription(classGradeObj.getDescription());
      }
    }

    setMonthAndClass(request, attendanceDashboardDto);
    attendanceDashboardDto.setAcademicDays(getAcademicDays(attendanceDashboardDto));
    setSelectedValues(attendanceDashboardDto, modelMap);
    List<BestStudentAttendanceTemplate> bestStudentAttendanceList =
        getBestAttendanceInfoWithPagination(modelMap, request, attendanceDashboardDto, flag);

    if (bestStudentAttendanceList == null) {

      int minNo = attendanceDashboardDto.getMinNo() - PAGINATION_NO;
      attendanceDashboardDto.setMinNo(minNo);
      bestStudentAttendanceList =
          dailyAttendanceService.getTopAttendanceList(attendanceDashboardDto);
      modelMap.addAttribute(STATUS, Boolean.TRUE);
      modelMap.addAttribute(PAGE_MIN_NO, minNo);
    }

    if (bestStudentAttendanceList != null) {
      if (attendanceDashboardDto.isFlag()) {

        modelMap.addAttribute(PAGE_MAX_NO, bestStudentAttendanceList.size() + PAGINATION_NO);
      } else {
        modelMap.addAttribute(PAGE_MAX_NO, bestStudentAttendanceList.size());
      }
    }

    modelMap.addAttribute(BEST_STUDENT_ATTENDANCE_LIST, bestStudentAttendanceList);

    return new ModelAndView(VIEW_ATTENDANCE_DASHBOARD, modelMap);
  }
  /**
   * Handle POST requests for attendance dash board view.
   *
   * @param request - HttpServletRequest
   * @param response - HttpServletResponse
   * @param attendanceDashboardDto - AttendanceDashboardDto
   * @param result - BindingResult
   * @param modelView - ModelAndView
   * @param modelMap - ModelMap
   * @return the name of the view.
   * @throws AkuraAppException - The exception details that occurred when processing.
   */
  @RequestMapping(value = ATTENDANCE_DASHBOARD_HTM, method = RequestMethod.POST)
  public ModelAndView searchAttendanceDashboard(
      HttpServletRequest request,
      HttpServletResponse response,
      @ModelAttribute() AttendanceDashboardDto attendanceDashboardDto,
      BindingResult result,
      ModelAndView modelView,
      ModelMap modelMap)
      throws AkuraAppException {

    // String for error messages.
    String message = null;

    // Set the selected month and class.
    setMonthAndClass(request, attendanceDashboardDto);

    attendanceDashboardValidator.validate(attendanceDashboardDto, result);

    // Check the validations.
    if (result.hasErrors()) {
      return new ModelAndView(VIEW_ATTENDANCE_DASHBOARD, modelMap);

    } else {

      // Get the academic days.
      int academicDays = getAcademicDays(attendanceDashboardDto);
      if (academicDays >= AkuraConstant.TEN) {

        String selectedClass = request.getParameter(SELECT_CLASSES);

        if (selectedClass != null) {
          ClassGrade classGradeObj = commonService.findClassGrade(Integer.parseInt(selectedClass));

          if (classGradeObj != null) {
            attendanceDashboardDto.setClassDescription(classGradeObj.getDescription());
          }
        }

        boolean flag = false;

        attendanceDashboardDto.setAcademicDays(academicDays);
        // Get student attendance list
        List<BestStudentAttendanceTemplate> bestStudentAttendanceList =
            getBestAttendanceInfoWithPagination(modelMap, request, attendanceDashboardDto, flag);

        if (bestStudentAttendanceList != null) {
          if (!bestStudentAttendanceList.isEmpty()) {
            modelMap.addAttribute(BEST_STUDENT_ATTENDANCE_LIST, bestStudentAttendanceList);
          } else {
            message = new ErrorMsgLoader().getErrorMessage(NOT_MINIMUM_ATTENDANCE_ERROR);
          }
        } else {
          message = new ErrorMsgLoader().getErrorMessage(NO_DATA_ERROR_MESSAGE);
        }
      } else {
        message = new ErrorMsgLoader().getErrorMessage(WORKING_DAYS_ERROR);
      }

      setSelectedValues(attendanceDashboardDto, modelMap);
      modelMap.addAttribute(MODEL_ATT_MESSAGE, message);
      modelMap.addAttribute(MODEL_ATT_ATTENDANCE_DASHBOARD, attendanceDashboardDto);
    }

    return new ModelAndView(VIEW_ATTENDANCE_DASHBOARD, modelMap);
  }
  /**
   * Method is to return Grade list reference data.
   *
   * @return GradeList - Grade reference data.
   * @throws AkuraAppException - throw SMSExeption.
   */
  @ModelAttribute(MODEL_ATT_GRADE_LIST)
  public List<Grade> populateGradeList() throws AkuraAppException {

    return SortUtil.sortGradeList(commonService.getGradeList());
  }
  /**
   * Generate Student Performance Reports .
   *
   * @param studentTemplate collect user input data to generate the report.
   * @param request of type HttpServletRequest
   * @param response of type HttpServletResponse
   * @param errors of type BindingResult
   * @return java.lang.String
   * @param map of type ModelMap
   * @throws AkuraAppException AkuraAppException
   */
  @RequestMapping(value = REQ_MAP_PERFORMANCE, method = RequestMethod.POST)
  public String onSubmit(
      HttpServletRequest request,
      HttpServletResponse response,
      @ModelAttribute(MODEL_ATT_STUDENT_PERFORMANCE_TEMPLATE)
          CRStudentPerformanceTemplate studentTemplate,
      BindingResult errors,
      ModelMap map)
      throws AkuraAppException {

    String returnString = STRING_EMPTY;

    // get the grade id of selected grade in UI
    int gradeId = Integer.parseInt(request.getParameter(REQUEST_PARA_GRADE_DESCRIPTION));

    LOG.info("Start processing user data for Student Perforance Report");
    Map<String, Object> params = new HashMap<String, Object>();

    // get the inserted marks range and assigned to variable for display in report
    String inBetweenText =
        studentTemplate.getInBetweenLessValue() >= 0
                && studentTemplate.getInBetweenGreaterValue() > 0
            ? MessageFormat.format(
                PropertyReader.getPropertyValue(
                    ReportUtil.REPORT_TEMPLATE, STU_PERFORMANCE_MARKS_RANGE_IN_BETWEEN),
                studentTemplate.getInBetweenLessValue(),
                studentTemplate.getInBetweenGreaterValue())
            : null;

    cRStudentPerformanceBetweenValidator.validate(studentTemplate, errors);
    if (errors.hasErrors()) {
      map.addAttribute(SELECTED_GRADE_ID, gradeId);
      return VIEW_METHOD_REPORTING_STUDENT_PERFORMANCE;
    }
    // set range marks in report
    params.put(REPORT_PARA_MARKS_RANGE_LABLE_TEXT, inBetweenText);

    // find grade object by grade id
    Grade gradeObj = commonService.findGradeById(gradeId);

    // get grade description of selected grade
    String gradeDescription = gradeObj.getDescription();

    // get term id as integer , getting from template
    int termId = Integer.parseInt(studentTemplate.getTerm());

    // list of grade subjects which is related to the grade
    List<GradeSubject> gradeSubjects = commonService.getGradeSubjectList(gradeId);

    // sort the grade subjects
    SortUtil.sortGradeSubjectList(gradeSubjects);

    // set the number of subject columns
    List<String> subjects = StaticDataUtil.getListWithEmptyValues(SUBJECT_COLUMNS);

    List<Integer> gradeSubjectsIds = new LinkedList<Integer>();

    // get all the subjects assigned for particular grade up to 20 subjects
    if (gradeSubjects.size() > 0) {
      for (int i = 0; i < SUBJECT_COLUMNS; i++) {

        Subject subject = gradeSubjects.get(i).getSubject();
        String subjectDescription = subject.getDescription();

        if (subject.getSubjectCode() == null) {

          if (subjectDescription.length() >= SUBJECT_NAME_DISPLAY_CRACTERS) {

            subjects.set(i, subjectDescription.substring(0, SUBJECT_NAME_DISPLAY_CRACTERS));
          } else {

            subjects.set(i, subjectDescription);
          }
        } else {
          subjects.set(i, subject.getSubjectCode());
        }
        gradeSubjectsIds.add(gradeSubjects.get(i).getGradeSubjectId());

        if (i > (gradeSubjects.size() - 2)) {
          break;
        }
      }
    }

    // get the system date - year
    Date currentDate = new Date();
    String year = DateUtil.getStringYear(currentDate);

    // get selected less than mark
    float lessMark = studentTemplate.getInBetweenLessValue();

    // get selected grater than mark
    float graterMark = studentTemplate.getInBetweenGreaterValue();

    // StudentTermMarkPerformance dto for hbm, DB map
    // get all students in selected grade, term, and with in marks range, for only current year
    List<StudentTermMarkPerformance> studentTermsMarksList =
        studentService.getTermMarksByGradeYear(
            gradeDescription, termId, year, lessMark, graterMark);

    // get the data source as for reporting data
    List<StudentPerformanceReportData> reportDataList =
        this.processReportData(studentTermsMarksList, gradeSubjectsIds);

    // set grade description for template
    studentTemplate.setGradeDescription(gradeDescription);

    // set subjects list for report parameter
    params.put(REPORT_PARA_SUBJECTS2, subjects);

    // set grade description as field
    params.put(REPORT_PARA_GRADE_DESCRIPTION, gradeDescription);

    // set parameter names for report attributes
    params.put(
        REPORT_PARA_TERM_DESCRIPTION_LABLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_TERM_DESCRIPTION_LABLE_TEXT));
    params.put(
        REPORT_PARA_STUDY_MEDIUM,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_STUDY_MEDIUM_LABLE_TEXT));
    params.put(
        REPORT_PARA_STUDENT_PERFORMANCE_GENERAL_TITLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_TITLE_TEXT));
    params.put(
        REPORT_PARA_GRADE_CLASS_LABLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_GRADE_CLASS_LABLE_TEXT));
    params.put(
        REPORT_PARA_CLASS_LABEL_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_CLASS_LABEL_TEXT));
    params.put(
        REPORT_PARA_CLASS_LABEL_TEXT2,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_CLASS_LABEL_TEXT2));
    params.put(
        REPORT_PARA_ADMISSION_NUMBER_LABLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_ADMISSION_NUMBER_LABLE_TEXT));
    params.put(
        REPORT_PARA_FULL_NAME_LABLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_FULL_NAME_LABLE_TEXT));
    params.put(
        REPORT_PARA_SUBJECT_DESCRIPTION_LABLE_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE,
            REPORT_VALUE_STU_PERFORMANCE_SUBJECT_DESCRIPTION_LABLE_TEXT));
    params.put(
        REPORT_PARA_MARKS_LABEL_TEXT,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_MARKS_LABLE_TEXT));
    params.put(
        REPORT_PARA_MARKS,
        PropertyReader.getPropertyValue(
            ReportUtil.REPORT_TEMPLATE, REPORT_VALUE_STU_PERFORMANCE_MARKS_LABLE_TEXT1));
    params.put(REPORT_PARA_LOGO_PATH, ReportUtil.getReportLogo());
    params.put(
        STYLE_TEMPLATE,
        PropertyReader.getPropertyValue(SYSTEM_CONFIG, APPSERVER_HOME)
            + PropertyReader.getPropertyValue(SYSTEM_CONFIG, STYLE_PATH));
    params.put(
        REPORT_GENERATED_ON,
        PropertyReader.getPropertyValue(ReportUtil.REPORT_TEMPLATE, REPORT_GENERATED_ON_TEXT));
    params.put(
        GENERATED_DATE,
        DateUtil.getReportGeneratedDate(
            PropertyReader.getPropertyValue(
                ReportUtil.REPORT_TEMPLATE, REPORT_GENERATED_DATE_LOCALE)));
    params.put(PAGE, PropertyReader.getPropertyValue(ReportUtil.REPORT_TEMPLATE, REPORT_PAGE));
    params.put(GPL, AkuraWebConstant.REPORT_GPL);
    params.put(
        NOTE_LABEL,
        PropertyReader.getPropertyValue(ReportUtil.REPORT_TEMPLATE, REPORT_MAXMARK_NOTE));
    // generate report - pass data source list to Jasper report
    JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(reportDataList);

    // check report data is empty
    if (dataSource.getRecordCount() != 0) {
      ReportUtil.displayReportInPdfForm(
          response, dataSource, params, REPORT_NAME_STUDENT_PERFORMANCE_GENERAL);
    } else {
      // set error message , no data message
      setErrorMessage(map, gradeId);
      returnString = VIEW_METHOD_REPORTING_STUDENT_PERFORMANCE;
    }
    return returnString;
  }
  /**
   * Returns list of terms.
   *
   * @return the term list.
   * @throws AkuraAppException AkuraAppException
   */
  @ModelAttribute(TERM_LIST)
  public List<Term> populateTermList() throws AkuraAppException {

    return SortUtil.sortTermList(commonService.getTermList());
  }