/**
   * 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;
  }
  /**
   * Validates the user input for criteria.
   *
   * @param object - Populated object of CRStudentPerformanceTemplate to validate
   * @param errors - contain errors related to fields.
   */
  public void validate(Object object, Errors errors) {

    CRStudentPerformanceTemplate cRStudentPerformanceTemplate =
        (CRStudentPerformanceTemplate) object;

    if (cRStudentPerformanceTemplate.getGradeDescription().equals(VAR_ZERO)
        || cRStudentPerformanceTemplate.getTerm().equals(VAR_ZERO)) {
      errors.rejectValue(IN_BETWEEN_GREATER_VALUE, REF_UI_MANDATORY_FIELD_REQUIRED);

    } else if (cRStudentPerformanceTemplate.getInBetweenLessValue() == 0
        && cRStudentPerformanceTemplate.getInBetweenGreaterValue() == 0) {

      errors.rejectValue(IN_BETWEEN_GREATER_VALUE, ERROR_MSG_FORMAT_ERROR_INBETWEEN_LESS_GRATER);

    } else if (cRStudentPerformanceTemplate.getInBetweenLessValue() < 0
        || cRStudentPerformanceTemplate.getInBetweenGreaterValue() < 0) {
      errors.rejectValue(
          IN_BETWEEN_GREATER_VALUE, ERROR_MSG_FORMAT_ERROR_INBETWEEN_LESS_GRATER_NEGETIVE);
    } else if (cRStudentPerformanceTemplate.getInBetweenLessValue()
        >= cRStudentPerformanceTemplate.getInBetweenGreaterValue()) {
      errors.rejectValue(IN_BETWEEN_GREATER_VALUE, REF_UI_FORMAT_ERROR_INBETWEEN);
    } else if (cRStudentPerformanceTemplate.getInBetweenLessValue() > MAX_MARKS
        || cRStudentPerformanceTemplate.getInBetweenGreaterValue() > MAX_MARKS) {

      errors.rejectValue(IN_BETWEEN_GREATER_VALUE, ERROR_MSG_FORMAT_ERROR_THANHUNDARD);
    }
  }