Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 25
CRAP
0.00% covered (danger)
0.00%
0 / 1221
GraceMarkDistributionService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 25
83232.00
0.00% covered (danger)
0.00%
0 / 1221
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 getAllGraceMarkDistributionStudents
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 36
 getAllGraceMarkDistributionStudentList
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 46
 getGraceMarkPercent
0.00% covered (danger)
0.00%
0 / 1
240.00
0.00% covered (danger)
0.00%
0 / 62
 utf8ize
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 10
 getConsoliidatedMarksCardData
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 95
 distributeStudentGraceMark
0.00% covered (danger)
0.00%
0 / 1
8010.00
0.00% covered (danger)
0.00%
0 / 322
 carryForwardStudentGraceMark
0.00% covered (danger)
0.00%
0 / 1
1640.00
0.00% covered (danger)
0.00%
0 / 159
 redistributeStudentGraceMark
0.00% covered (danger)
0.00%
0 / 1
930.00
0.00% covered (danger)
0.00%
0 / 127
 totalMarkNeededtoPass
0.00% covered (danger)
0.00%
0 / 1
1056.00
0.00% covered (danger)
0.00%
0 / 94
 getGradeByPercentage
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 8
 saveMarkDistribution
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 44
 saveSubjectGraceMarkDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 saveSemesterGraceMarkDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 getSemesterGraceMarkDistribution
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getSubjectGraceMarkDistribution
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 16
 saveCarryForwardedMarkDistribution
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 47
 unDistributeStudentGraceMark
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 15
 deleteSemesterGraceMarkDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 deleteSubjectGraceMarkDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 deleteRedistributionGraceMarkDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 deleteRedistributionGraceMarkAppliedDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getAllGraceMarkReDistributionStudents
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 21
 saveRedistributionMarkDetails
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 33
 saveSubjectGraceMarkRedistributionDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
<?php
namespace com\linways\ec\core\service;
use com\linways\ec\core\dto\FalseNumberSetting;
use com\linways\ec\core\dto\FalseNumberSettingExamLog;
use com\linways\base\util\MakeSingletonTrait;
use com\linways\base\util\SecurityUtils;
use com\linways\ec\core\constant\StatusConstants;
use com\linways\ec\core\exception\ExamControllerException;
use com\linways\ec\core\mapper\GraceMarkApplicationServiceMapper;
use com\linways\core\ams\professional\service\CommonService;
use com\linways\core\ams\professional\dto\SettingsConstents;
use com\linways\core\ams\professional\service\GraceMarkService as ProfessionalGraceMarkService;
use com\linways\core\ams\professional\request\academic\SearchAcademicTermRequest;
use com\linways\core\ams\professional\service\academic\AcademicTermService;
use com\linways\ec\core\service\GradeSchemeService;
use com\linways\oe\core\service\ExamUserMarkService;
use com\linways\oe\core\request\ExamUserMarkRequest;
class GraceMarkDistributionService extends BaseService
{
    use MakeSingletonTrait;
    private function __construct() {
        $this->mapper = GraceMarkApplicationServiceMapper::getInstance()->getMapper();
    }
    
    /**
     * get grace mark distribution students
     * @param $searchRequest 
     * @return $response 
     */
    public function getAllGraceMarkDistributionStudents($searchRequest) {
        $searchRequest = $this->realEscapeObject($searchRequest);
        try
        {
            $batchList = $this->getAllGraceMarkDistributionStudentList($searchRequest);
            $students = [];
            $categoryList = ProfessionalGraceMarkService::getInstance()->getGraceMarkCategoryAndLevel(); 
            foreach($batchList as $batch){
                $students[$batch->studentID]->id = $batch->id;
                $students[$batch->studentID]->studentId = $batch->studentID;
                $students[$batch->studentID]->regNo = $batch->regNo;
                $students[$batch->studentID]->studentName = $batch->studentName;
                $students[$batch->studentID]->isAppliedForRedistribution = $batch->isAppliedForRedistribution;
                $students[$batch->studentID]->semesters = $batch->semesters;
                $semester = json_decode($batch->semesters);
                $semNames = [];
                $semesterRequest = new SearchAcademicTermRequest();
                $semesterRequest->id = current($semester);
                $sem = reset(AcademicTermService::getInstance()->searchAcademicTerm($semesterRequest));
                $percentage = $this->getGraceMarkPercent($batch, $categoryList);
                $students[$batch->studentID]->year[$sem->properties->year] = $percentage;
                // $students[$batch->studentID]->sem[$batch->semesters] = $percentage;
                $students[$batch->studentID]->sem[$semester[0]] = $percentage;
                $students[$batch->studentID]->sem[$semester[1]] = $percentage;
                $graceMarkRequest = new \stdClass();
                $graceMarkRequest->studentId =  $batch->studentID;
                $graceMarkDetails = $this->getSubjectGraceMarkDistribution($graceMarkRequest);
                if($graceMarkDetails){
                    $students[$batch->studentID]->isDistributed = 1;
                }
                // $reDistributionDetails = GraceMarkService::getInstance()->getStudentRedistributionDetails($batch->studentID);
                // if($reDistributionDetails){
                //     $students[$batch->studentID]->isReDistributed = 1;
                // }
                }
        }
        catch (\Exception $e)
        {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        return $students;
    }
     /**
     * Get grace mark distribution student details
     * @param $request
     */
    public function getAllGraceMarkDistributionStudentList($request) 
    {    
        $request = $this->realEscapeObject($request);
        $sql = "SELECT 
                    egmas.id,
                    egmas.applNo,
                    egmas.applied_events,
                    egmas.applied_date,
                    egmas.isConfirmed,
                    egmas.studentID,
                    spa.properties->>'$.registerNumber' AS regNo,
                    spa.properties->>'$.rollNumber' AS rollNo,
                    sa.studentName,
                    egmi.properties ->> '$.semesters' as semesters,
                    erasd.isApplied as isAppliedForRedistribution,
                    erasd.startDate as redistributionApplnStartDate,
                    erasd.endDate as redistributionApplnEndDate
                FROM 
                    ec_grace_mark_applied_students egmas  
                INNER JOIN 
                    ec_grace_mark_appln_initiate egmi ON
                    (egmas.gracemark_appln_id = egmi.id) 
                INNER JOIN
                    ec_grace_mark_appln_assigned_batches egmsb  ON 
                    (egmsb.gracemark_appln_id = egmi.id) 
                INNER JOIN studentaccount sa ON 
                    sa.studentID = egmas.studentID
                INNER JOIN 
                    `groups` g ON 
                    g.id = egmsb.groups_id
                INNER JOIN program p ON
                    p.id = g.properties ->> '$.programId'
                INNER JOIN student_program_account spa ON 
                    spa.current_program_id = p.id AND 
                    spa.current_batch_id = egmsb.groups_id AND 
                    spa.student_id = egmas.studentID  AND
                    spa.properties->>'$.academicStatus' IN ('ACTIVE','COMPLETED')
                LEFT JOIN ec_redistribution_applied_student_details erasd ON
                    erasd.studentID = egmas.studentID
                WHERE 
                    p.course_type_id = '$request->courseTypeId' AND g.properties ->> '$.startYear' = '$request->admissionYear' AND egmas.isConfirmed = 1";
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    public function getGraceMarkPercent($batch, $categoryList){
        $categories = [];
        foreach($categoryList as $category){
            $categories[$category->categoryID]->categoryId = $category->categoryID;
            $categories[$category->categoryID]->categoryName = $category->categoryName;
            $categories[$category->categoryID]->levelSelectCount = $category->levelSelectCount;
            $categories[$category->categoryID]->percentageLimit = $category->percentageLimit;
            $categories[$category->categoryID]->level[$category->levelId]->levelId = $category->levelId;
            $categories[$category->categoryID]->level[$category->levelId]->levelName = $category->levelName;
            $categories[$category->categoryID]->level[$category->levelId]->levelLimit = $category->levelLimit;
            $categories[$category->categoryID]->level[$category->levelId]->isSelected = 0;
            $positions = json_decode($category->positions);
            $hasPosition = 0;
            if($positions){
                $hasPosition = 1;
            }
            $categories[$category->categoryID]->level[$category->levelId]->hasPosition = $hasPosition;
    
            $categories[$category->categoryID]->level[$category->levelId]->positions = $positions;
        }
        $categoryDetails = json_decode( $this->utf8ize($batch->applied_events ));
        foreach($categoryDetails as $catId  => $category){
            // $categories[$catId]->eventSelected = $category;
            foreach( $category as $key =>$catVal){
                $categories[$catId]->level[$catVal->levelId]->eventSelected[$key] = $catVal;
            }
        }
        $totalPercent = 0;
        foreach( $categories as $cat){
            $categoryLimit = $cat->percentageLimit;
            $levelTotal = 0;
            foreach( $cat->level as $level){
                $levelLimit = $level->levelLimit;
                $positionTotal = 0;
                foreach( $level->eventSelected as $eventSelected){
                    if( $level->hasPosition){
                        $positionId = $eventSelected->positionId;
                        $percentageDetails = array_filter(array_map(function ($obj) use ($positionId) {
                            if($obj->id == $positionId){
                                return $obj->percentage;
                            }
                        }, $level->positions));
                        $percentage = current($percentageDetails);
                        $positionTotal += $percentage;
                    }
                    else{
                        $positionTotal += $levelLimit;
                    }
                }
                if($levelLimit){
                    $levelTotal += $positionTotal < $levelLimit? $positionTotal : $levelLimit;
                }
                else{
                    $levelTotal += $positionTotal;
                }
            }
            if($categoryLimit){
                $totalPercent += $levelTotal < $categoryLimit? $levelTotal : $categoryLimit;
            }
            else{
                $totalPercent += $levelTotal;
            }
        }
        $totalPercent =  $totalPercent < 25 ?  $totalPercent : 25;
        return $totalPercent;
    }
    
    # json invalid char decode php #
    /* Use it for json_encode some corrupt UTF-8 chars
     * useful for = malformed utf-8 characters possibly incorrectly encoded by json_encode
     */
     //use example :- $categoryDetails = json_decode( utf8ize($batch->applied_events ));
     public function utf8ize($mixed)
     {
         if (is_array($mixed)) {
             foreach ($mixed as $key => $value) {
                 $mixed[$key] = $this->utf8ize($value);
             }
         } elseif (is_string($mixed)) {
             return mb_convert_encoding($mixed, "UTF-8", "UTF-8");
         }
         return $mixed;
     }
    /**
     * @param $request
     */
    public function getConsoliidatedMarksCardData($request)
    {
        $request = $this->realEscapeObject($request);
        
        try {
            $whereQuery = "";
            if(!empty($request->studentId)) {
                $studentIdString = is_array($request->studentId) ? implode(",",$request->studentId) : $request->studentId;
                $whereQuery .= " AND ecsmd.student_id IN ($studentIdString";
            }
            if(!empty($request->consoliderExternalSubjectsOnly)) {
                $whereQuery .= " AND caps.properties ->> '$.isExternal' = 1 ";
            }
            $query = "SELECT
                ecsmd.student_id AS studentId,
                ecsmd.groups_id AS groupsId,
                atm.id AS termId,
                atm.name AS termName,
                ecsmd.cm_academic_paper_subjects_id AS paperSubjetId,
                ecsmd.mark_details AS markDetails,
                ecsmd.mark_history AS markHistory,
                ecsmd.no_of_chances_taken AS noOfChancesTaken,
                ecsmd.total_mark AS totalMarkObtained,
                ecsmd.class,
                ecsmd.grade,
                ecsmd.failed_status AS failedStatus,
                s.code AS code,
                s.name AS name,
                caps.properties ->> '$.syllabusName' AS syllabusName,
                caps.properties ->> '$.isInternal' as isInternal,
                caps.properties ->> '$.isExternal' as isExternal,
                caps.properties ->> '$.externalMaxMark' as externalMaxMark,
                caps.properties ->> '$.internalMaxMark' as internalMaxMark,
                ecsmd.mark_details ->> '$.externalMark' AS externalMark,
                IF(caps.properties ->> '$.classType' = 'THEORY',1,0) AS isTheory,
                caps.properties ->> '$.classType' as classType,
                sc.subjectcatID AS categoryId,
                sc.subjectcatName AS categoryName,
                sc.subjectcatPriority AS categoryPriority,
                sc.subjectcatCode AS subjectCategoryCode,
                sc.parentID AS categoryParentId,
                sc.use_bring_value AS useBringValue,
                g.id as groupId,
                esmd.failed_status AS semesterFailedStatus,
                cc.categoryCode
            FROM
                ec_consolidated_subject_mark_details ecsmd
            INNER JOIN student_program_account spa
                ON spa.student_id =  ecsmd.student_id
               INNER JOIN `groups` g ON
                g.id = ecsmd.groups_id 
            INNER JOIN cm_academic_paper_subjects caps ON
                caps.id = ecsmd.cm_academic_paper_subjects_id
            INNER JOIN cm_academic_paper cap ON
                cap.id = caps.cm_academic_paper_id
            INNER JOIN cm_syllabus_academic_term_settings csats ON
                csats.id = cap.cm_syllabus_academic_term_settings_id
            INNER JOIN academic_term atm ON
                atm.id = csats.academic_term_id
            INNER JOIN ec_semester_mark_details esmd ON
                esmd.academic_term_id = csats.academic_term_id AND esmd.groups_id = g.id AND esmd.student_id = ecsmd.student_id
            INNER JOIN v4_ams_subject s ON
                s.id = caps.ams_subject_id
            LEFT JOIN subject_category sc ON
                sc.subjectcatID = caps.properties->>'$.subjectTypeId'
            LEFT JOIN categoryCode cc ON
                cc.subject_category_id = caps.properties->>'$.subjectTypeId'
                AND cc.subject_category_id = sc.subjectcatID
                AND cc.course_type_id = CAST(g.properties->>'$.courseTypeId' AS CHAR)
            WHERE
                1 = 1 AND ecsmd.is_active = 1
            $whereQuery";
            $subjectsMarkDetails = $this->executeQueryForList($query);
            $student = [];
           foreach($subjectsMarkDetails as $subject){
                $subject->markDetails = json_decode($subject->markDetails);
                $subject->markHistory = json_decode($subject->markHistory);
                $subject->examMonthYear = $subject->markDetails->latestExamMonth."/".$subject->markDetails->latestExamYear;
                $subject->isAbsent = $subject->markDetails->attendanceStatus == "PRESENT" ? 0 : 1;
                $subject->isInternalFailed = $subject->markDetails->internalResultStatus == "PASSED" ? 0 : 1;
                $subject->isFailed = $subject->failedStatus == "PASSED" ? 0 : 1;
                $subject->internalMark = $subject->markDetails->internalMark;
                $subject->creditPoint = round($subject->markDetails->credit * $subject->markDetails->gradePoint, 2);
                $subject->RSI = substr($subject->markDetails->latestExamType,0,1);
                $subject->priority = $subject->markDetails->priority;
                $student[$subject->studentId]->semMarks[$subject->termId]->subject[$subject->paperSubjetId] = $subject;
                $student[$subject->studentId]->groupId = $subject->groupId;
                $student[$subject->studentId]->semMarks[$subject->termId]->semName = $subject->termName;
                $student[$subject->studentId]->semMarks[$subject->termId]->externalMaxMark 
                += $subject->externalMaxMark;
                $student[$subject->studentId]->semMarks[$subject->termId]->isFailed = $subject->semesterFailedStatus == "PASSED" ? 0 : 1;
            }
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        return $student;
    } 
    public function distributeStudentGraceMark($graceMarkStudent){
        try {
            $graceMarkStudent =  (object)$graceMarkStudent;
            $semPercentage = $graceMarkStudent->sem;
            $graceMarkStudent->consoliderExternalSubjectsOnly = 1;
            $studentMarkDetails = $this->getConsoliidatedMarksCardData($graceMarkStudent);
            
            if (!empty($studentMarkDetails)) {    
                $remainingSemesterGraceMark = 0; 
                foreach ($studentMarkDetails as $studentId => $student) {
                    ksort($student->semMarks);
                    foreach($student->semMarks as $semId =>$sem){
                        $percentageForSemester = $semPercentage[$semId];
                        if(!$percentageForSemester &&  !$remainingSemesterGraceMark ){
                            continue;
                        }
                        $graceMarkForSemester = 0;
                        $externalMaxMark = $sem->externalMaxMark;
                        if($percentageForSemester){
                            $graceMarkForSemester = round(($percentageForSemester / 100) * $externalMaxMark);
                        }
                        $sem->percentageForSemester = $percentageForSemester;
                        $sem->graceMarkForSemester = $graceMarkForSemester;
                        $sem->previousSemExcessMark = $remainingSemesterGraceMark;
                        $graceMarkForSemester += $remainingSemesterGraceMark;
                        $sem->totalGraceMarkForSemester = $graceMarkForSemester;
                        $equalDistMark = floor($graceMarkForSemester / count($sem->subject));
                        $excessMark = $graceMarkForSemester % count($sem->subject);
                        $registrationRequest = new \stdClass();
                        $registrationRequest->groupId = $student->groupId;
                        $registrationRequest->type = "SUPPLEMENTARY";
                        $registrationRequest->termId = $semId;
                        $registrationRequest->limit = 2;
                        $supplyIds = ExamRegistrationService::getInstance()->getExamRegistrationOfABatchByRequest ( $registrationRequest );
                        $supplyIds = array_slice($supplyIds,0,2);
                        if (count($supplyIds) >= 2){
                            $sem->isCompleted = 1;
                            $sem->chancesTaken = 3;
                        }
                        else{
                            $sem->chancesTaken = count($supplyIds) ? count($supplyIds) + 1 : 1;
                        }
                        foreach ($sem->subject as $sub) {
                            $subjectmarkHistory = [];
                            $sub->isFailed = $sub->failedStatus == "PASSED" ? 0 : 1;
                            foreach ($sub->markHistory as $supplyMarksHistory) {
                                $subjectmarkHistoryObj = new \stdClass();
                                $subjectmarkHistoryObj->examMarkType = $supplyMarksHistory->examMarkType;
                                $subjectmarkHistoryObj->examRegId = $supplyMarksHistory->examRegistrationId;
                                $subjectmarkHistoryObj->examId = $supplyMarksHistory->examId;
                                $subjectmarkHistoryObj->mark = $supplyMarksHistory->externalMark;
                                $subjectmarkHistoryObj->examMonth = $supplyMarksHistory->examMonth;
                                if( $supplyMarksHistory->graceMark ){
                                    return 2;
                                }
                                $subjectmarkHistoryObj->examYear = $supplyMarksHistory->examYear;
                                $subjectmarkHistoryObj->assessmentId = $supplyMarksHistory->assessmentId;
                                $subjectmarkHistoryObj->oeExamId = $supplyMarksHistory->oeExamId;
                                $subjectmarkHistoryObj->attendanceStatus = $supplyMarksHistory->attendanceStatus;
                                $subjectmarkHistoryObj->isAbsent = $supplyMarksHistory->attendanceStatus == "PRESENT" ? 0 : 1;
                                $subjectmarkHistoryObj->resultStatus = $supplyMarksHistory->resultStatus;
                                $subjectmarkHistoryObj->examName = $supplyMarksHistory->examName;
                                if( $supplyMarksHistory->examMarkType == "REGULAR" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[1] = $subjectmarkHistoryObj;
                                }
                                else if( $supplyMarksHistory->examMarkType == "IMPROVEMENT" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[2] = $subjectmarkHistoryObj;
                                }
                                else{
                                    foreach ($supplyIds as $supplyId) {
                                        $sub->chancesTaken ++;
                                        if($supplyId->examRegistrationId == $supplyMarksHistory->examRegistrationId){
                                            $subjectmarkHistory[$sub->chancesTaken] = $subjectmarkHistoryObj;
                                        }
                                    }
                                }
                            }
                            $sub->subjectMarkHistory = $subjectmarkHistory;
                        }
                        foreach ($sem->subject as $sub) {
                            if(($sub->externalMark ) > $sub->externalMaxMark){
                                $excessMark +=  $equalDistMark;
                                continue;
                            }
                            if(($sub->externalMark + $equalDistMark) > $sub->externalMaxMark){
                                $diff = $sub->externalMaxMark - $sub->externalMark;
                                $excessMark +=  $equalDistMark - $diff;
                                $sub->graceMark = $diff;
                                continue;
                            }
                            $sub->graceMark = $equalDistMark;
                        }
                        if($excessMark){
                            $countOfSubject = count($sem->subject);
                            $flag = 1;
                            while($flag == 1){
                                if(!$excessMark){
                                    break;
                                }
                                $equalDistMark = floor($excessMark / count($sem->subject));
                                if($equalDistMark){
                                    $excessMark = $excessMark % count($sem->subject);
                                }
                                uasort($sem->subject, function ($a, $b) {
                                    return $a->externalMark > $b->externalMark;
                                });
                                $completeFag = 0;
                                if($equalDistMark){
                                    foreach ($sem->subject as $sub) {
                                        // if(!$excessMark){
                                        //     $flag = 0;
                                        //     break;
                                        // }
                                        if(($sub->externalMark + $sub->graceMark) >= $sub->externalMaxMark){
                                            $excessMark +=  $equalDistMark;
                                            continue;
                                        }
                                        if((($sub->externalMark + $sub->graceMark + $equalDistMark) > $sub->externalMaxMark)){
                                            $diff = $sub->externalMaxMark - ($sub->externalMark + $sub->graceMark);
                                            $excessMark +=  $equalDistMark - $diff;
                                            $sub->graceMark += $diff;
                                            continue;
                                        }
                                        $sub->graceMark += $equalDistMark;
                                    }
                                   
                                }
                                if($excessMark){
                                    foreach ($sem->subject as $sub) {
                                        if(!$excessMark){
                                            $flag = 0;
                                            break;
                                        }
                                        if((($sub->externalMark + $sub->graceMark + 1) > $sub->externalMaxMark)){
                                            $completeFag++;
                                            continue;
                                        }
                                        $sub->graceMark += 1;
                                        $excessMark -= 1;
                                    }
                                    if( $completeFag == $countOfSubject){
                                        $flag = 0;
                                    }
                                }
                                // $remainingSemesterGraceMark = $excessMark;
                                // $sem->excessGraceMark = $remainingSemesterGraceMark;
                            }
                        }
                        if($sem->isFailed){
                            foreach ($sem->subject as $sub) {
                                if( $sub->isFailed && !$sub->isInternalFailed && !$sub->isAbsent){
                                    $requiredGraceMark = $this->totalMarkNeededtoPass($sub, $student->groupId);
                                    if(!$requiredGraceMark){
                                        $sub->isFailed = 0;
                                        $sub->isGraceMarkPartially = 0;
                                        $subjectMarkNeeded = $this->totalMarkNeededtoPass($sub, $student->groupId);
                                        $sub->isGraceMarkPartially = 1;
                                        $sub->excessMark = $sub->graceMark - $subjectMarkNeeded;
                                        continue;
                                    }
                                    $externalMinimumRequired= (5/100) * $sub->externalMaxMark; 
                                    if ($externalMinimumRequired > $sub->externalMark){
                                        $sub->isNotApplicable = 1;
                                    }
                                }
                                elseif(!$sub->isFailed){
                                    $sub->excessMark = $sub->graceMark;
                                }
                            }
                            uasort($sem->subject, function ($a, $b) {
                                return $a->externalPercent < $b->externalPercent;
                            });
                            foreach ($sem->subject as $sub) {
                                if( $sub->isFailed && !$sub->isInternalFailed && !$sub->isAbsent && !$sub->isNotApplicable && $sub->isExternal){
                                    $requiredGraceMark = $this->totalMarkNeededtoPass($sub, $student->groupId);
                                    // $requiredGraceMark = ceil($requiredGraceMark);
                                    $remaingGracing = $requiredGraceMark;
                                    $deductedGracing = 0;
                                    // if($excessMark >= $requiredGraceMark){
                                    //     $sub->graceMark += $requiredGraceMark ;
                                    //     $excessMark -= $requiredGraceMark;
                                    //     $sub->graceMarkNeeded = 1;
                                    //     continue;
                                    // }
                                    // else{
                                    //     $deductedGracing += $excessMark;
                                    //     $remaingGracing -= $excessMark;
                                    //     $excessMark = 0;
                                    // }
                                    $totalExcesMarkArray = array_map(function ($obj) {
                                        return $obj->excessMark;
                                    }, $sem->subject);
                                    $totalExcesMark = array_sum($totalExcesMarkArray);
                                    if( $totalExcesMark <  $requiredGraceMark){
                                        continue;
                                    }
                                    if(!$sub->isInternalFailed && !$sub->isAbsent ){
                                        uasort($sem->subject, function ($a, $b) {
                                            return $a->externalMark < $b->externalMark;
                                        });
                                        foreach ($sem->subject as $graceSub) {
                                            if(!$remaingGracing || $graceSub->isFailed || $graceSub->graceMarkNeeded || $graceSub->isNotApplicable){
                                                continue;
                                            }
                                            if ($graceSub->isGraceMarkPartially){
                                                if ($graceSub->excessMark >= $remaingGracing){
                                                    $deductedGracing += $remaingGracing;
                                                    $graceSub->graceMark = $graceSub->graceMark - $remaingGracing ;
                                                    $graceSub->excessMark = $graceSub->excessMark - $remaingGracing ;
                                                    $remaingGracing = 0;
                                                }
                                                else{
                                                    $graceSub->graceMark = $graceSub->graceMark - $graceSub->excessMark;
                                                    $remaingGracing -= $graceSub->excessMark;
                                                    $deductedGracing += $graceSub->excessMark;
                                                    $graceSub->excessMark = 0;
                                                }
                                            }
                                            else{
                                                if ($graceSub->graceMark >= $remaingGracing){
                                                    $deductedGracing += $remaingGracing;
                                                    $graceSub->graceMark = $graceSub->graceMark - $remaingGracing ;
                                                    $graceSub->excessMark = $graceSub->excessMark - $remaingGracing ;
                                                    $remaingGracing = 0;
                                                }
                                                else{
                                                    $remaingGracing -= $graceSub->graceMark;
                                                    $deductedGracing += $graceSub->graceMark;
                                                    $graceSub->graceMark = 0;
                                                    $graceSub->excessMark = 0;
                                                }
                                            }
                                        }
                                        $sub->graceMark += $deductedGracing ;
                                        $sub->graceMarkNeeded = 1;
                                    }
                                }
                            }
                        }
                        $remainingSemesterGraceMark = $excessMark;
                        $sem->excessGraceMark = $remainingSemesterGraceMark;
                        $previousSem = $semId;
                    }
                    if($remainingSemesterGraceMark){
                        krsort($student->semMarks);
                        // uasort($student->semMarks, function ($a, $b) {
                        //     return $a->semId < $b->semId;
                        // });
                        foreach($student->semMarks as $semId =>$sem){
                            if($previousSem == $semId || !$remainingSemesterGraceMark){
                                continue;
                            }
                            $equalDistMark = floor($remainingSemesterGraceMark / count($sem->subject));
                            $excessMark = $remainingSemesterGraceMark % count($sem->subject);
                            if( $equalDistMark){
                                foreach ($sem->subject as $sub) {
                                    if(($sub->externalMark + $sub->graceMark + $equalDistMark) > $sub->externalMaxMark){
                                        $diff = $sub->externalMaxMark - ($sub->externalMark + $sub->graceMark);
                                        $excessMark +=  $equalDistMark - $diff;
                                        $sub->graceMark += $diff;
                                        continue;
                                    }
                                    $sub->graceMark += $equalDistMark;
                                    $sem->previousSemExcessMark += $equalDistMark;
                                    $sem->totalGraceMarkForSemester += $equalDistMark;
                                }
                            }
                            if($excessMark){
                                $flag = 1;
                                while($flag == 1){
                                    if(!$excessMark){
                                        break;
                                    }
                                    uasort($sem->subject, function ($a, $b) {
                                        return $a->externalMark > $b->externalMark;
                                    });
                                    $equalDistMark = floor($excessMark / count($sem->subject));
                                    if($equalDistMark){
                                        $excessMark = $excessMark % count($sem->subject);
                                    }
                                    uasort($sem->subject, function ($a, $b) {
                                        return $a->externalMark > $b->externalMark;
                                    });
                                    $completeFag = 0;
                                    if($equalDistMark){
                                        foreach ($sem->subject as $sub) {
                                            if((($sub->externalMark + $sub->graceMark + $equalDistMark) > $sub->externalMaxMark) || !$excessMark){
                                                $diff = $sub->externalMaxMark - ($sub->externalMark + $sub->graceMark);
                                                $excessMark +=  $equalDistMark - $diff;
                                                $sub->graceMark += $diff;
                                                continue;
                                            }
                                            $sub->graceMark += $equalDistMark;
                                            $sem->previousSemExcessMark += $equalDistMark;
                                            $sem->totalGraceMarkForSemester += $equalDistMark;
                                        }
                                    }
                                    if($excessMark){
                                        $countOfSubject = count($sem->subject);
                                        foreach ($sem->subject as $sub) {
                                            if(!$excessMark){
                                                $flag = 0;
                                                break;
                                            }
                                            if((($sub->externalMark + $sub->graceMark + 1) > $sub->externalMaxMark) || !$excessMark){
                                                $completeFag++;
                                                continue;
                                            }
                                            $sub->graceMark += 1;
                                            $excessMark -= 1;
                                            $sem->previousSemExcessMark += 1;
                                            $sem->totalGraceMarkForSemester += 1;
                                           
                                        }
                                        if( $completeFag == $countOfSubject){
                                            $flag = 0;
                                        }
                                    }
                                }
                            }
                            $remainingSemesterGraceMark = $excessMark;
                        }
                    }
                    ksort($student->semMarks);
                    foreach($student->semMarks as $semId =>$sem){
                        foreach ($sem->subject as $sub) {
                            $sub->externalMinimum = (5/100) * $sub->externalMaxMark; 
                            if( $sub->isFailed && !$sub->isInternalFailed && !$sub->isAbsent || $sub->isGraceMarkPartially ){
                                $requiredGraceMark = $this->totalMarkNeededtoPass($sub, $student->groupId);
                                $sub->excessMark = 0;
                                if(!$requiredGraceMark){
                                    $sub->isFailed = 0;
                                    $sub->isGraceMarkPartially = 0;
                                    $subjectMarkNeeded = $this->totalMarkNeededtoPass($sub, $student->groupId);
                                    $sub->isGraceMarkPartially = 1;
                                    $sub->excessMark = $sub->graceMark - $subjectMarkNeeded;
                                    continue;
                                }
                            }
                            elseif(!$sub->isFailed){
                                $sub->excessMark = $sub->graceMark;
                            }
                        }
                    }
                    //save DISTRIBUTION
                    $this->saveMarkDistribution($student);
                }
            }
        } catch ( \Exception $e ) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
    public function carryForwardStudentGraceMark($graceMarkStudent){
        try {
            $graceMarkRequest = new \stdClass();
            $graceMarkStudent =  (object)$graceMarkStudent;
            $semPercentage = $graceMarkStudent->sem;
            $graceMarkStudent->consoliderExternalSubjectsOnly = 1;
            $studentMarkDetails = $this->getConsoliidatedMarksCardData($graceMarkStudent);
            $graceMarkFound = 0;
            if (!empty($studentMarkDetails)) {    
                $remainingSemesterGraceMark = 0; 
                foreach ($studentMarkDetails as $studentId => $student) {
                    ksort($student->semMarks);
                    foreach($student->semMarks as $semId =>$sem){
                        $graceMarkRequest = new \stdClass();
                        $graceMarkRequest->studentId =  $graceMarkStudent->studentId;
                        $graceMarkRequest->termId =  $semId;
                        $semesterGraceDetails = $this->getSemesterGraceMarkDistribution($graceMarkRequest)[0];
                      
                        if($semesterGraceDetails->isCompleted){
                            $sem->isDistributed = 1;
                            continue;
                        }
                        $registrationRequest = new \stdClass();
                        $registrationRequest->groupId = $student->groupId;
                        $registrationRequest->type = "SUPPLEMENTARY";
                        $registrationRequest->termId = $semId;
                        $registrationRequest->limit = 2;
                        $supplyIds = ExamRegistrationService::getInstance()->getExamRegistrationOfABatchByRequest ( $registrationRequest );
                        if (count($supplyIds) >= 2){
                            $sem->isCompleted = 1;
                            $sem->chancesTaken = 3;
                        }
                        else{
                            $sem->chancesTaken = count($supplyIds) ? count($supplyIds) + 1 : 1;
                        }
                        foreach ($sem->subject as $sub) {
                            $graceMarkRequest = new \stdClass();
                            $graceMarkRequest->studentId =  $graceMarkStudent->studentId;
                            $graceMarkRequest->termId =  $semId;
                            $graceMarkRequest->paperSubjetId =  $sub->paperSubjetId;
                            $subjectGraceDetails = $this->getSubjectGraceMarkDistribution($graceMarkRequest)[0];
                            $sub->graceMark = $subjectGraceDetails->graceMark;
                            $sub->excessMark = $subjectGraceDetails->excessMark;
                            if($subjectGraceDetails->no_of_chances_taken == 3){
                                $sub->isAlreadyApplied = 1;
                                continue;
                            }
                            $sem->isCompleted = 0;
                            $sem->chancesTaken = 0;
                            $subjectmarkHistory = [];
                            $sub->isFailed = $sub->failedStatus == "PASSED" ? 0 : 1;
                            foreach ($sub->markHistory as $supplyMarksHistory) {
                                $subjectmarkHistoryObj = new \stdClass();
                                $subjectmarkHistoryObj->examMarkType = $supplyMarksHistory->examMarkType;
                                $subjectmarkHistoryObj->examRegId = $supplyMarksHistory->examRegistrationId;
                                $subjectmarkHistoryObj->examId = $supplyMarksHistory->examId;
                                $subjectmarkHistoryObj->mark = $supplyMarksHistory->externalMark;
                                $subjectmarkHistoryObj->examMonth = $supplyMarksHistory->examMonth;
                                $subjectmarkHistoryObj->examYear = $supplyMarksHistory->examYear;
                                $subjectmarkHistoryObj->assessmentId = $supplyMarksHistory->assessmentId;
                                $subjectmarkHistoryObj->oeExamId = $supplyMarksHistory->oeExamId;
                                $subjectmarkHistoryObj->attendanceStatus = $supplyMarksHistory->attendanceStatus;
                                $subjectmarkHistoryObj->isAbsent = $supplyMarksHistory->attendanceStatus == "PRESENT" ? 0 : 1;
                                $subjectmarkHistoryObj->resultStatus = $supplyMarksHistory->resultStatus;
                                $subjectmarkHistoryObj->examName = $supplyMarksHistory->examName;
                                if( $supplyMarksHistory->graceMark ){
                                    $graceMarkFound = 1;
                                }
                                if( $supplyMarksHistory->examMarkType == "REGULAR" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[1] = $subjectmarkHistoryObj;
                                }
                                else if( $supplyMarksHistory->examMarkType == "IMPROVEMENT" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[2] = $subjectmarkHistoryObj;
                                }
                                else{
                                    foreach ($supplyIds as $supplyId) {
                                        $sub->chancesTaken ++;
                                        if($supplyId->examRegistrationId == $supplyMarksHistory->examRegistrationId){
                                            $subjectmarkHistory[$sub->chancesTaken] = $subjectmarkHistoryObj;
                                        }
                                    }
                                }
                            }
                            $sub->subjectMarkHistory = $subjectmarkHistory;
                        }
                        $excessMark = 0;
                        if($remainingSemesterGraceMark){
                            $excessMark += $remainingSemesterGraceMark;
                        }
                        foreach ($sem->subject as $sub) {
                            if(($sub->externalMark + $sub->graceMark) > $sub->externalMaxMark){
                                $diff = $sub->externalMaxMark - $sub->externalMark;
                                $excessMark +=  $sub->graceMark - $diff;
                                $sub->graceMark = $diff;
                                continue;
                            }
                            else{
                                continue;
                            }
                            // $sub->graceMark = $equalDistMark;
                        }
                        if($excessMark){
                            $equalDistMark = floor($excessMark / count($sem->subject));
                            if($equalDistMark){
                                $excessMark = $excessMark % count($sem->subject);
                            }
                            uasort($sem->subject, function ($a, $b) {
                                return $a->externalMark > $b->externalMark;
                            });
                            if($equalDistMark){
                                foreach ($sem->subject as $sub) {
                                    if((($sub->externalMark + $sub->graceMark + $equalDistMark) > $sub->externalMaxMark) || !$excessMark){
                                        $excessMark += $equalDistMark;
                                        continue;
                                    }
                                    $sub->graceMark += $equalDistMark;
                                }
                            }
                            if($excessMark){
                                foreach ($sem->subject as $sub) {
                                    if((($sub->externalMark + $sub->graceMark + 1) > $sub->externalMaxMark) || !$excessMark){
                                        continue;
                                    }
                                    $sub->graceMark += 1;
                                    $excessMark -= 1;
                                }
                            }
                            // $remainingSemesterGraceMark = $excessMark;
                            // $sem->excessGraceMark = $remainingSemesterGraceMark;
                        }
                        $remainingSemesterGraceMark = $excessMark;
                        // $sem->excessGraceMark = $remainingSemesterGraceMark;
                        // $previousSem = $semId;
                    }
                    if ( !$graceMarkFound ){
                        return 2;
                    }
                    ksort($student->semMarks);
                    foreach($student->semMarks as $semId =>$sem){
                        foreach ($sem->subject as $sub) {
                            $sub->externalMinimum = (5/100) * $sub->externalMaxMark; 
                            if( $sub->isFailed && !$sub->isInternalFailed && !$sub->isAbsent || $sub->isGraceMarkPartially ){
                                $requiredGraceMark = $this->totalMarkNeededtoPass($sub, $student->batchId);
                                $sub->excessMark = 0;
                                if(!$requiredGraceMark){
                                    $sub->isFailed = 0;
                                    $sub->isGraceMarkPartially = 0;
                                    $subjectMarkNeeded = $this->totalMarkNeededtoPass($sub, $student->batchId);
                                    $sub->isGraceMarkPartially = 1;
                                    $sub->excessMark = $sub->graceMark - $subjectMarkNeeded;
                                    continue;
                                }
                            }
                            elseif(!$sub->isFailed){
                                $sub->excessMark = $sub->graceMark;
                            }
                        }
                    }
                    //save 
                    $this->saveCarryForwardedMarkDistribution($student);
                }
            }
        } catch ( \Exception $e ) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
    public function redistributeStudentGraceMark($graceMarkStudent){
        try {
            $graceMarkRequest = new \stdClass();
            $graceMarkStudent =  (object)$graceMarkStudent;
            $semPercentage = $graceMarkStudent->sem;
            $graceMarkStudent->consoliderExternalSubjectsOnly = 1;
            $studentMarkDetails = $this->getConsoliidatedMarksCardData($graceMarkStudent);
            $totalRequiredPassMark = 0;
            $totalExcessMark = 0;
            $error = 0;
            $graceMarkFound = 0;
            if (!empty($studentMarkDetails)) {    
                $remainingSemesterGraceMark = 0; 
                foreach ($studentMarkDetails as $studentId => $student) {
                    ksort($student->semMarks);
                    foreach($student->semMarks as $semId =>$sem){
                        $registrationRequest = new \stdClass();
                        $registrationRequest->groupId = $student->groupId;
                        $registrationRequest->type = "SUPPLEMENTARY";
                        $registrationRequest->termId = $semId;
                        $registrationRequest->limit = 2;
                        $supplyIds = ExamRegistrationService::getInstance()->getExamRegistrationOfABatchByRequest ( $registrationRequest );
                        foreach ($sem->subject as $sub) {
                            $subjectmarkHistory = [];
                            $sub->isFailed = $sub->failedStatus == "PASSED" ? 0 : 1;
                            foreach ($sub->markHistory as $supplyMarksHistory) {
                                $subjectmarkHistoryObj = new \stdClass();
                                $subjectmarkHistoryObj->examMarkType = $supplyMarksHistory->examMarkType;
                                $subjectmarkHistoryObj->examRegId = $supplyMarksHistory->examRegistrationId;
                                $subjectmarkHistoryObj->examId = $supplyMarksHistory->examId;
                                $subjectmarkHistoryObj->mark = $supplyMarksHistory->externalMark;
                                $subjectmarkHistoryObj->examMonth = $supplyMarksHistory->examMonth;
                                $subjectmarkHistoryObj->examYear = $supplyMarksHistory->examYear;
                                $subjectmarkHistoryObj->assessmentId = $supplyMarksHistory->assessmentId;
                                $subjectmarkHistoryObj->oeExamId = $supplyMarksHistory->oeExamId;
                                $subjectmarkHistoryObj->attendanceStatus = $supplyMarksHistory->attendanceStatus;
                                $subjectmarkHistoryObj->isAbsent = $supplyMarksHistory->attendanceStatus == "PRESENT" ? 0 : 1;
                                $subjectmarkHistoryObj->resultStatus = $supplyMarksHistory->resultStatus;
                                $subjectmarkHistoryObj->examName = $supplyMarksHistory->examName;
                                if( $supplyMarksHistory->graceMark ){
                                    $graceMarkFound = 1;
                                }
                                if( $supplyMarksHistory->examMarkType == "REGULAR" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[1] = $subjectmarkHistoryObj;
                                }
                                else if( $supplyMarksHistory->examMarkType == "IMPROVEMENT" ){
                                    $sub->chancesTaken ++;
                                    $subjectmarkHistory[2] = $subjectmarkHistoryObj;
                                }
                                else{
                                    foreach ($supplyIds as $supplyId) {
                                        $sub->chancesTaken ++;
                                        if($supplyId->examRegistrationId == $supplyMarksHistory->examRegistrationId){
                                            $subjectmarkHistory[$sub->chancesTaken] = $subjectmarkHistoryObj;
                                        }
                                    }
                                }
                            }
                            $sub->subjectMarkHistory = $subjectmarkHistory;
                            $sub->requiredPassMark = $this->totalMarkNeededtoPass($sub, $student->batchId);
                            $graceMarkRequest = new \stdClass();
                            $graceMarkRequest->studentId =  $graceMarkStudent->studentId;
                            $graceMarkRequest->termId =  $semId;
                            $graceMarkRequest->paperSubjetId =  $sub->paperSubjetId;
                            $graceMarkDetails = $this->getSubjectGraceMarkDistribution($graceMarkRequest)[0];
                            $sub->graceMark = $graceMarkDetails->graceMark;
                            $sub->oldGraceMark = $graceMarkDetails->graceMark;
                            $sub->isExternalOnlyTaken = 1;
                            $requiredPassMark = $this->totalMarkNeededtoPass($sub, $student->batchId);
                            $sub->excessMark = $sub->graceMark - $requiredPassMark;
                            $sub->excessMark = $sub->excessMark < 0 ? 0 : $sub->excessMark;
                            // $sub->excessMark = $graceMarkDetails->excessMark;
                            $totalExcessMark +=  $sub->excessMark;
                            $totalRequiredPassMark +=  $sub->requiredPassMark;
                            $externalMinimum = (5/100) * $sub->externalMaxMark; 
                            $studentExternalMark = $sub->externalMark - $sub->graceMark;
                            // if($sub->isAbsent){
                            //     return ResultHandler::fault("Not eligible for redistribution");
                            // }
                            if($studentExternalMark < $externalMinimum){
                                $error = 1;
                            }
                            if($sub->classType == "PRACTICAL" && $sub->isFailed){
                                $error = 1;
                            }
                        }
                    }
                    if ( !$graceMarkFound ){
                        return 2;
                    }
                    if($totalExcessMark < $totalRequiredPassMark){
                        return 1;
                    }
                    if(!$totalRequiredPassMark || $error == 1){
                        return 1;
                    }
                    $remainingPassMark = $totalRequiredPassMark;
                    foreach($student->semMarks as $semId =>$sem){
                        foreach ($sem->subject as $sub) {
                            if(!$remainingPassMark){
                                break;
                            }
                            if($sub->excessMark){
                                if($sub->excessMark < $remainingPassMark){
                                    $remainingPassMark -= $sub->excessMark;
                                    $sub->graceMark -= $sub->excessMark;
                                    $sub->excessMark = 0;
                                }
                                else{
                                    $sub->excessMark -= $remainingPassMark;
                                    $sub->graceMark -= $remainingPassMark;
                                    $remainingPassMark = 0;
                                }
                            }
                        }
                    }
                    foreach($student->semMarks as $semId =>$sem){
                        foreach ($sem->subject as $sub) {
                            if($sub->isFailed){
                                $sub->graceMark += $sub->requiredPassMark;
                                $sub->excessMark = 0;
                            }
                        }
                    }
        
                    $this->saveRedistributionMarkDetails($student);
        
                }
            }
        } catch ( \Exception $e ) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
    public function totalMarkNeededtoPass ( $subject, $groupId) {
        $schemeType = "PERCENTAGE";
        $passPercentConfig = GradeSchemeService::getInstance()->getSubjectPassCriteriaByAcademicPaperSubject($subject->paperSubjetId, $schemeType);
        $searchRequest = new \stdClass();
        $searchRequest->groupId = $groupId;;
        $searchRequest->academicTermId = $subject->termId;
        $searchRequest->academicPaperSubjectId = $subject->paperSubjetId;
        $subjectGradeSchemeArray = GradeSchemeService::getInstance()->getAllSubjectGradeSchemesByRequest($searchRequest);
        $gradeDetails = current($subjectGradeSchemeArray)->grades;
        $maxGradePercent = $gradeDetails[0]->rangeTo;
        $searchRequest->requestType = "SEMESTER";
        $semesterGradeSchemeArray = GradeSchemeService::getInstance()->getAllSubjectGradeSchemesByRequest($searchRequest);
        $semesterGradeDetails = current($semesterGradeSchemeArray)->grades;
        $maxSemesterGradePercent = $semesterGradeDetails[0]->rangeTo;
        $considerOverallPassCriteriaOnly = 0;
        $internalPassCriteria = $externalPassCriteria = $overallPassCriteria = $aggregatePassCriteria = null;
        if ($passPercentConfig->internalPassCriteria) {
            $internalPassCriteria = (float) $passPercentConfig->internalPassCriteria;
        }
        if ($passPercentConfig->externalPassCriteria) {
            $externalPassCriteria = (float) $passPercentConfig->externalPassCriteria;
        }
        if ($passPercentConfig->overallPassCriteria) {
            $overallPassCriteria = (float) $passPercentConfig->overallPassCriteria;
        }
        if($subject->isFailed || ($subject->isGraceMarkPartially)){
            $studentExternalMark = $subject->externalMark + $subject->graceMark;
        }
        else{
            $studentExternalMark = $subject->externalMark;
        }
        if($subject->isExternalOnlyTaken){
            $studentExternalMark = $subject->externalMark - $subject->graceMark;
        }
    
        $isFailed = 0;
        if ($subject->isInternal) {
            $studentExamTotal = round($subject->internalMark);
            $examTotal = $subject->internalMaxMark;
            if (!empty ($internalPassCriteria)) {
                $internalPercent = $subject->internalMaxMark ? (100 * $subject->internalMark / $subject->internalMaxMark) : 0;
                if ( $considerOverallPassCriteriaOnly == 0 ) {
                    $isFailed = $internalPassCriteria <= $internalPercent ? $isFailed : 1;
                    $isInternalFailed = $internalPassCriteria <= $internalPercent ? 0 : 1;
                }
            }
        }
        if ($subject->isExternal) {
            $studentExamTotal += round($studentExternalMark);
            $examTotal += $subject->externalMaxMark;
            if (!empty ($externalPassCriteria)) {
                    $externalPercent = $subject->externalMaxMark ? (100 * $studentExternalMark / $subject->externalMaxMark) : 0;
                if ( $considerOverallPassCriteriaOnly == 0 ) {
                    $isFailed = $externalPassCriteria <= $externalPercent ? $isFailed : 1;
                    $isExternalFailed = $externalPassCriteria <= $externalPercent ? 0 : 1;
                    if($isExternalFailed){
                        $externalPassMark = ($externalPassCriteria / 100)*$subject->externalMaxMark;
                        $externalRequired = $externalPassMark - $studentExternalMark;
                        $externalRequired =  $externalRequired < 0 ? 0 : $externalRequired;
                    }
                }
            }
        }
    
        if (!empty ($overallPassCriteria)) {
            $overallPercent = $examTotal ? 100 * $studentExamTotal / $examTotal : 0;
            $isFailed = $overallPassCriteria <= $overallPercent ? $isFailed : 1;
            $isOverAllFailed = $overallPassCriteria <= $overallPercent ? $isFailed : 1;
            if($isOverAllFailed){
                $overallPassMark = ($overallPassCriteria / 100)*$examTotal;
                $overallRequired = $overallPassMark - $studentExamTotal;
                $overallRequired =  $overallRequired < 0 ? 0 : $overallRequired;
            }
        }
        /**
         * $maxGradePercent is used so that, we get the percentage in 'out of' the values in the db 
         * ie, 6, 10 or 100, different values for different colleges for different colleges...
         */
        if ( $isFailed ) {
            $percentageObtained = 0;
            $semesterGradePercentObtained = 0;
        }
        else {
            $percentageObtained = $maxGradePercent * $studentExamTotal / $examTotal;
            $percentageObtained = round($percentageObtained, 2);
            /**
             * In colleges like SJCC semester grade percentage is in out of 10 not 100
             * So we have to convert the student percent to out of 10
             */
            $semesterGradePercentObtained = $maxSemesterGradePercent * $studentExamTotal / $examTotal;
            $semesterGradePercentObtained = round($semesterGradePercentObtained, 2);
        }
        $grade = $this->getGradeByPercentage($percentageObtained, $gradeDetails);
    
        if (!empty ($grade)) {
            if ($grade->failStatus == 1) {
                $isFailed = 1;
            }
        }
        if(!$isFailed){
            return 0;
        }
        $totalNeeded = $externalRequired <  $overallRequired ?  $overallRequired : $externalRequired;
        $totalNeeded = ceil($totalNeeded);
        return $totalNeeded;
    }
    public function getGradeByPercentage($percentage, $gradeDetails)
    {
        foreach ($gradeDetails as $grade) {
            if ($grade->rangeFrom <= $percentage && $grade->rangeTo >= $percentage) {
                return $grade;
            }
        }
        return null;
    }
    public function saveMarkDistribution($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            foreach($student->semMarks as $semId =>$sem){
                foreach ($sem->subject as $sub) {
                    if($sub->graceMark){
                        if(!$sub->isNotApplicable){
                            foreach ($sub->subjectMarkHistory as $subjectMarkHistory) {
                                if( $sub->externalMinimum <= $subjectMarkHistory->mark){
                                    $graceObj = new ExamUserMarkRequest();
                                    $sub->graceMark = $sub->graceMark ? $sub->graceMark : NULL;
                                    $graceObj->studentId = $sub->studentId;
                                    $graceObj->assessmentId = $subjectMarkHistory->assessmentId;
                                    $graceObj->oeExamsId = $subjectMarkHistory->oeExamId;
                                    $graceObj->valuationType = "GRACEMARK";
                                    $graceObj->markObtained = $sub->graceMark;
                
                                    // for high lighting edit changes in import mark
                                    $editRequest = new \stdClass();
                                    $editRequest->groupId = $sub->groupId;
                                    $editRequest->studentId = $sub->studentId;
                                    $editRequest->isDirty = 1;
                                    $editRequest->staffId = $GLOBALS['userId'];
                                    $editHistoryLog[] = $editRequest;
                
                                    $graceObj->valuationType = "GRACEMARK";
                                    $studentGraceMarkArray[] = $graceObj;
                                }
                            }
                        }
                        $this->saveSubjectGraceMarkDetails($sub);
                    }
                }
                $sem->studentId = $sub->studentId;
                $sem->termId =  $sub->termId;
                $this->saveSemesterGraceMarkDetails($sem);
            }
            if(! empty($studentGraceMarkArray)){
                ExamUserMarkService::getInstance()->saveExamUserTotalMark($studentGraceMarkArray);
            }
            if(! empty($editHistoryLog)){
                StudentsOverAllMarkReportService::getInstance()->insertStudentEditStatus($editHistoryLog);
            }
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /**
     * save subject grace mark
     * @throws ExamControllerException
     */
    public function saveSubjectGraceMarkDetails($request) 
    {    
        $request = $this->realEscapeObject($request);
        $subjectMarkHistory = json_encode($request->subjectMarkHistory);
        $sql = "INSERT INTO ec_subject_gracemark_details (studentID,academic_term_id,cm_academic_paper_subjects_id,graceMark,mark_details,excessMark,no_of_chances_taken) VALUES ('$request->studentId','$request->termId','$request->paperSubjetId','$request->graceMark','$subjectMarkHistory','$request->excessMark','$request->chancesTaken') ON DUPLICATE KEY UPDATE graceMark = VALUES(graceMark), mark_details = VALUES(mark_details), excessMark = VALUES(excessMark), no_of_chances_taken = VALUES(no_of_chances_taken)";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
    
    /**
     * save subject grace mark
     * @throws ExamControllerException
     */
    public function saveSemesterGraceMarkDetails($request) 
    {    
        $request = $this->realEscapeObject($request);
        $isExist = $this->getSemesterGraceMarkDistribution($request);
        if( $isExist ){
            $sql = "UPDATE ec_semester_gracemark_details set no_of_chances_taken ='$request->chancesTaken',isCompleted='$request->isCompleted' WHERE studentID = $request->studentId AND academic_term_id = '$request->termId'";
        }
        else{
            $sql = "INSERT INTO ec_semester_gracemark_details (studentID,academic_term_id,semester_mark,addon_mark,total_mark,excess_mark,no_of_chances_taken,isCompleted,percentage_for_semester) VALUES ('$request->studentId','$request->termId','$request->graceMarkForSemester','$request->previousSemExcessMark','$request->totalGraceMarkForSemester','$request->excessGraceMark','$request->chancesTaken', '$request->isCompleted','$request->percentageForSemester')";
        }
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * get subject graceMark distribution
     * @throws ExamControllerException
     */
    public function getSemesterGraceMarkDistribution($request) 
    {    
        $request = $this->realEscapeObject($request);
        $condition = ""; 
        if ($request->termId){
            $condition .=" AND academic_term_id = $request->termId";
        }
        $sql = "SELECT studentID FROM ec_semester_gracemark_details WHERE studentID = $request->studentId $condition";
        
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
        /**
     * get subject graceMark distribution
     * @throws ExamControllerException
     */
    public function getSubjectGraceMarkDistribution($request) 
    {    
        $request = $this->realEscapeObject($request);
        $condition = ""; 
        if ($request->termId){
            $condition .=" AND academic_term_id = '$request->termId'";
        }
        if ($request->paperSubjetId){
            $condition .=" AND cm_academic_paper_subjects_id = '$request->paperSubjetId'";
        }
        $sql = "SELECT cm_academic_paper_subjects_id, graceMark, excessMark, no_of_chances_taken FROM ec_subject_gracemark_details WHERE studentID = '$request->studentId$condition";
        
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /*
    * save grace mark carry forward
    * @param student
    * @throws ExamControllerException
    */
   public function saveCarryForwardedMarkDistribution($student) 
   {    
       $student = $this->realEscapeObject($student);
       try {
           foreach($student->semMarks as $semId =>$sem){
               if($sem->isDistributed){
                   continue;
               }
               foreach ($sem->subject as $sub) {
                   if($sub->graceMark){
                       if(!$sub->isNotApplicable){
                           foreach ($sub->subjectMarkHistory as $subjectMarkHistory) {
                               if( $sub->externalMinimum <= $subjectMarkHistory->mark){
                                    $graceObj = new ExamUserMarkRequest();
                                    $sub->graceMark = $sub->graceMark ? $sub->graceMark : NULL;
                                    $graceObj->studentId = $sub->studentId;
                                    $graceObj->assessmentId = $subjectMarkHistory->assessmentId;
                                    $graceObj->oeExamsId = $subjectMarkHistory->oeExamId;
                                    $graceObj->valuationType = "GRACEMARK";
                                    $graceObj->markObtained = $sub->graceMark;
                
                                    // for high lighting edit changes in import mark
                                    $editRequest = new \stdClass();
                                    $editRequest->groupId = $sub->groupId;
                                    $editRequest->studentId = $sub->studentId;
                                    $editRequest->isDirty = 1;
                                    $editRequest->staffId = $GLOBALS['userId'];
                                    $editHistoryLog[] = $editRequest;
                
                                    $graceObj->valuationType = "GRACEMARK";
                                    $studentGraceMarkArray[] = $graceObj;
                               }
                           }
                       }
                       $this->saveSubjectGraceMarkDetails($sub);
                   }
               }
               $sem->studentId = $sub->studentId;
               $sem->termId =  $sub->termId;
               $this->saveSemesterGraceMarkDetails($sem);
            }
            if(! empty($studentGraceMarkArray)){
                ExamUserMarkService::getInstance()->saveExamUserTotalMark($studentGraceMarkArray);
            }
            if(! empty($editHistoryLog)){
                StudentsOverAllMarkReportService::getInstance()->insertStudentEditStatus($editHistoryLog);
            }
       } catch (\Exception $e) {
           throw new ExamControllerException($e->getCode(),$e->getMessage());
       }
       
   }
    /*
    * un distribute grace mark
    * @param student
    * @throws ExamControllerException
    */
    public function unDistributeStudentGraceMark($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            $this->deleteSubjectGraceMarkDetails($student);
            $this->deleteSemesterGraceMarkDetails($student);
            $this->deleteRedistributionGraceMarkDetails($student);
            $this->deleteRedistributionGraceMarkAppliedDetails($student);
          
            $graceObj = new ExamUserMarkRequest();
            $graceObj->studentId = $student->studentId;
            $graceObj->valuationType = "GRACEMARK";
            ExamUserMarkService::getInstance()->deleteExamUserMarkOfStudentByValuationType($graceObj);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /*
    * delete semester grace mark
    * @param student
    * @throws ExamControllerException
    */
    public function deleteSemesterGraceMarkDetails($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            $sql = "DELETE FROM ec_semester_gracemark_details WHERE studentID = '$student->studentId'";
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /*
    * delete subject grace mark
    * @param student
    * @throws ExamControllerException
    */
    public function deleteSubjectGraceMarkDetails($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            $sql = "DELETE FROM ec_subject_gracemark_details WHERE studentID = '$student->studentId'";
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    
    /*
    * delete redistribution grace mark
    * @param student
    * @throws ExamControllerException
    */
    public function deleteRedistributionGraceMarkDetails($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            $sql = "DELETE FROM ec_gracemark_redistribution WHERE studentID = '$student->studentId'";
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /*
    * delete redistribution grace mark applied details
    * @param student
    * @throws ExamControllerException
    */
    public function deleteRedistributionGraceMarkAppliedDetails($student) 
    {    
        $student = $this->realEscapeObject($student);
        try {
            $sql = "UPDATE ec_redistribution_applied_student_details SET isApplied = 0 WHERE studentID = '$student->studentId'";
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
    /**
     * get grace mark redistribution students
     * @param $searchRequest 
     * @return $response 
     */
    public function getAllGraceMarkReDistributionStudents($searchRequest) {
        $searchRequest = $this->realEscapeObject($searchRequest);
        try
        {
            $batchList = $this->getAllGraceMarkDistributionStudentList($searchRequest);
            $students = [];
            foreach($batchList as $batch){
                $students[$batch->studentID]->id = $batch->id;
                $students[$batch->studentID]->studentId = $batch->studentID;
                $students[$batch->studentID]->regNo = $batch->regNo;
                $students[$batch->studentID]->studentName = $batch->studentName;
                $students[$batch->studentID]->semesters = $batch->semesters;
                $students[$batch->studentID]->endDate = $batch->redistributionApplnEndDate;
                $students[$batch->studentID]->startDate = $batch->redistributionApplnStartDate;
            }
        }
        catch (\Exception $e)
        {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        return $students;
    }
    /**
     * save redistribution grace mark
     * @param student
     * @throws ExamControllerException
     */
    public function saveRedistributionMarkDetails($student) 
    {    
        $student = $this->realEscapeObject($student);
        $staffId = $_SESSION['adminID'];
        try {
            foreach($student->semMarks as $semId =>$sem){
                foreach ($sem->subject as $sub) {
                    if($sub->graceMark != $sub->oldGraceMark){
                        foreach ($sub->subjectMarkHistory as $subjectMarkHistory) {
                            $graceObj = new ExamUserMarkRequest();
                            $sub->graceMark = $sub->graceMark ? $sub->graceMark : NULL;
                            $graceObj->studentId = $sub->studentId;
                            $graceObj->assessmentId = $subjectMarkHistory->assessmentId;
                            $graceObj->oeExamsId = $subjectMarkHistory->oeExamId;
                            $graceObj->valuationType = "GRACEMARK";
                            $graceObj->markObtained = $sub->graceMark;
        
                            // for high lighting edit changes in import mark
                            $editRequest = new \stdClass();
                            $editRequest->groupId = $sub->groupId;
                            $editRequest->studentId = $sub->studentId;
                            $editRequest->isDirty = 1;
                            $editRequest->staffId = $GLOBALS['userId'];
                            $editHistoryLog[] = $editRequest;
        
                            $graceObj->valuationType = "GRACEMARK";
                            $studentGraceMarkArray[] = $graceObj;
                        }
                        $this->saveSubjectGraceMarkDetails($sub);
                        $this->saveSubjectGraceMarkRedistributionDetails($sub);
                    }
                }
            }
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
        
    }
     /**
     * save subject grace mark redistribution details
     * @throws ExamControllerException
     */
    public function saveSubjectGraceMarkRedistributionDetails($request) 
    {    
        $request = $this->realEscapeObject($request);
        $staffId = $GLOBALS['userId'];
        $sql = "INSERT INTO ec_gracemark_redistribution (studentID,academic_term_id,cm_academic_paper_subjects_id,graceMark,oldGraceMark,created_by) VALUES ('$request->studentId','$request->termId','$request->paperSubjetId','$request->graceMark','$request->oldGraceMark','$staffId') ON DUPLICATE KEY UPDATE graceMark = VALUES(graceMark), oldGraceMark = VALUES(oldGraceMark)";
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ExamControllerException($e->getCode(),$e->getMessage());
        }
    }
   
}