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 / 56
CRAP
0.00% covered (danger)
0.00%
0 / 1931
InternalMarkService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 56
77006.00
0.00% covered (danger)
0.00%
0 / 1931
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 3
 __clone
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 getInstance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 4
 saveInternalMaskValue
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 17
 updateInternalMaskValue
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 24
 getAllInternalMaskValue
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getInternalMaskValueOfSubject
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 18
 deleteInternalMaskValue
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 23
 validateInternalMarkImportProcess
0.00% covered (danger)
0.00%
0 / 1
380.00
0.00% covered (danger)
0.00%
0 / 190
 checkMarkEnteredOrNot
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 26
 checkMarkEnteredDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 21
 getImportInternalMarkAutomationValidationStatus
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 45
 importInternalMark
0.00% covered (danger)
0.00%
0 / 1
210.00
0.00% covered (danger)
0.00%
0 / 86
 enterNormalizedMarkOfBatch
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 114
 approveNormalizedInternalMark
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 84
 copyNormalizedInternalMarkToExamController
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 74
 confirmImportedInternalMark
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 73
 setImportInternalMarkAutomationStatus
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 80
 validateAndImportInternalMark
0.00% covered (danger)
0.00%
0 / 1
156.00
0.00% covered (danger)
0.00%
0 / 67
 getImportAndValidationStatus
0.00% covered (danger)
0.00%
0 / 1
506.00
0.00% covered (danger)
0.00%
0 / 132
 setInternalImportAutomationDirtyFlag
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 44
 setNotificationEnableForSessionalExamMarkChange
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 12
 getMaxInternalMaxk
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 7
 getInternlMarksSubmitted
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 12
 getStudentsInternalMarksSubmitted
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 51
 saveInternalMarks
0.00% covered (danger)
0.00%
0 / 1
272.00
0.00% covered (danger)
0.00%
0 / 77
 allowOrBlockInternalMarkSubmitted
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 19
 getInternalExamMaxMark
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 17
 getMarkEnteredStudentCount
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 47
 getTotalNumberOfStudents
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 34
 checkPseudoSubject
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 getStudentByBatchSem
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 getInternalExamMark
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 20
 getStudentsInternalMarks
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 24
 confirmInternalSubmition
0.00% covered (danger)
0.00%
0 / 1
90.00
0.00% covered (danger)
0.00%
0 / 67
 getAttendanceRangeInDefineRule
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 23
 saveInternalMarkSubmitted
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 22
 assignStaffForInternalMarkEntry
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 getStaffAssignedForInternalMarkEntry
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 29
 deleteBatchFromInternalMarkEntryAssignedStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 updateInternalMarkEntryAssignedStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 updateInternalMarkEntryAssignedStaffDate
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 deleteStaffFromInternalMarkEntryAssignedStaff
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 updateInternalMarkByRequest
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 21
 getInternalMarkSubjectDetailsByRequest
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 28
 setInternalMarkSubmissionDatesSubjectwise
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 saveSupplyInternalMarks
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getStudentRegularSupplyInternalExamMarks
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 17
 deleteInternalMarksFromExamController
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 22
 copyNormalizedFinalInternalMarkToExamController
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 67
 getNormalizedInternalExamMaxMark
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 17
 setInternalMarkSettingsSubjectwise
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 12
 getInternalAbsentStatus
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 13
 getInternalMarksSubmittedSubjects
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getInternalMarksEnteredSubjects
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 insertToMarkSubmitted
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
<?php
namespace com\linways\core\ams\professional\service;
use com\linways\core\ams\professional\mapper\InternalMarkServiceMapper;
use com\linways\core\ams\professional\constant\StatusConstants;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\request\ImportInternalMarkRequest;
use com\linways\core\ams\professional\request\CalculateAssessmentRuleRequest;
use com\linways\core\ams\professional\request\GetRuleAssignedForABatchRequest;
use com\linways\core\ams\professional\logging\Events;
use com\linways\core\ams\professional\logging\AMSLogger;
use com\linways\core\ams\professional\queue\AMSTaskQueue;
use com\linways\core\ams\professional\logging\entities\ImportedInternalMark;
use com\linways\core\ams\professional\logging\entities\NormalizedMark;
use com\linways\core\ams\professional\service\AssessmentComponentRuleService;
use com\linways\core\ams\professional\dto\SettingsConstents;
use com\linways\core\ams\professional\service\CommonService;
class InternalMarkService extends BaseService
{
    private static $_instance = null;
    
    // /Condition 2 - Locked down the constructor
    private function __construct() {
        $this->mapper = InternalMarkServiceMapper::getInstance()->getMapper();
        $this->logger = AMSLogger::getLogger();
    }
    // Prevent any oustide instantiation of this class
    
    // /Condition 3 - Prevent any object or instance of that class to be cloned
    private function __clone() {
    }
    // Prevent any copy of this object
    
    // /Condition 4 - Have a single globally accessible static method
    public static function getInstance() {
        if (! is_object ( self::$_instance )) // or if( is_null(self::$_instance) ) or if( self::$_instance == null )
            self::$_instance = new self ();
            
            return self::$_instance;
    }
    /**
     * Save internal mark mask value.
     * 
     * @param  $request
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function saveInternalMaskValue ( $request ) {
        $request = $this->realEscapeObject($request);
        $studentId = $request->studentId;
        $semId = $request->semId;
        $batchId = $request->batchId;
        $adminId = $request->adminId;
        $internalMarkMasks = $request->internalMarkMasks;
        try {
            foreach ($internalMarkMasks as $internalMarkMask) {
                $sql = "INSERT INTO `ec_internal_mark_mask_value` (`student_id`,`batch_id`,`sem_id`,`subject_id`,`mask_value`,`created_by`) VALUES ('$studentId', '$batchId', '$semId','".$internalMarkMask['subjectId']."','".$internalMarkMask['maskValue']."','$adminId')";
                $this->executeQuery($sql);
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return true;
    }
    /**
     * Update internal mark mask value.
     * 
     * @param  $request
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function updateInternalMaskValue ( $request, $internalMarkMask = "" ) {
        $request = $this->realEscapeObject($request);
        $internalMarkMask = $this->realEscapeArray($internalMarkMask);
        $studentId = $request->studentId;
        $semId = $request->semId;
        $batchId = $request->batchId;
        $adminId = $request->adminId;
        $internalMarkMasks = $request->internalMarkMasks;
        try {
            if ($internalMarkMask == "") {
                foreach ($internalMarkMasks as $internalMarkMask) {
                    $sql = "UPDATE ec_internal_mark_mask_value SET mask_value = '".$internalMarkMask['maskValue']."' , updated_by = '$adminId' WHERE student_id = '$studentId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '".$internalMarkMask['subjectId']."'";
                    $this->executeQuery($sql);
                }
            }
            else {
                $sql = "UPDATE ec_internal_mark_mask_value SET mask_value = '".$internalMarkMask['maskValue']."' , updated_by = '$adminId' WHERE student_id = '$studentId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '".$internalMarkMask['subjectId']."'";
                $this->executeQuery($sql);
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return true;
    }
    /**
     * Get all internal mark mask value.
     * 
     * @throws ProfessionalException
     * @return $internalMarkMasks list
     * @author anoop
     */
    public function getAllInternalMaskValue () {
        try {
            $sql = "SELECT student_id AS studentId,batch_id AS batchId,sem_id AS semId,subject_id AS subjectId, mask_value AS maskValue FROM ec_internal_mark_mask_value ";
            $internalMarkMasks = $this->executeQueryForList($sql);
            
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $internalMarkMasks;
    }
    /**
     * Get internal mark mask value of subjects of student in particular sem of particular batch.
     * 
     * @param  $request
     * @throws ProfessionalException
     * @return $internalMarkMasks list
     * @author anoop
     */
    public function getInternalMaskValueOfSubject ($studentId, $semId, $batchId, $subjectId = "") {
        $studentId = $this->realEscapeString($studentId);
        $semId = $this->realEscapeString($semId);
        $batchId = $this->realEscapeString($batchId);
        $subjectId = $this->realEscapeString($subjectId);
        $internalMarkMasks = [];
        $sql_subjectId = $subjectId == "" ? "" :" AND subject_id = $subjectId";
        try {
            $sql = "SELECT subject_id AS subjectId, mask_value AS maskValue FROM ec_internal_mark_mask_value WHERE  student_id = '$studentId' AND sem_id = '$semId' AND batch_id = '$batchId'$sql_subjectId";
            $internalMarkMaskValues = $this->executeQueryForList($sql);
            foreach ($internalMarkMaskValues as $internalMarkMaskValue) {
                $internalMarkMasks[$internalMarkMaskValue->subjectId] = $internalMarkMaskValue->maskValue;
            }
            
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $internalMarkMasks;
    }
    /**
     * Delete internal mark mask value.
     * 
     * @param  $request
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function deleteInternalMaskValue ( $request, $internalMarkMask = "" ) {
        $request = $this->realEscapeObject($request);
        $internalMarkMask = $this->realEscapeArray($internalMarkMask);
        $studentId = $request->studentId;
        $semId = $request->semId;
        $batchId = $request->batchId;
        $internalMarkMasks = $request->internalMarkMasks;
        try {
            if ($internalMarkMask == "") {
                foreach ($internalMarkMasks as $internalMarkMask) {
                    $sql = "DELETE FROM ec_internal_mark_mask_value WHERE student_id = '$studentId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '".$internalMarkMask['subjectId']."'";
                    $this->executeQuery($sql);
                }
            }
            else {
                $sql = "DELETE FROM ec_internal_mark_mask_value WHERE student_id = '$studentId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '".$internalMarkMask['subjectId']."'";
                $this->executeQuery($sql);
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return true;
    }
    /**
     * Validation for import internal mark to exam controller.
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @throws ProfessionalException
     * @return Object  of validation status $batches
     * @author anoop
     */
    public function validateInternalMarkImportProcess($importInternalMarkRequest) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $sqlCondition = "";
        try {
            if (!empty($importInternalMarkRequest->semId)) {
                $semIdString = implode(',',$importInternalMarkRequest->semId) ? implode(',',$importInternalMarkRequest->semId) : $importInternalMarkRequest->semId;
                $sqlCondition .= " AND sbsr.semID IN ($semIdString)";
            }
            else {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester given!");
            }
            if (!empty($importInternalMarkRequest->batchId)) {
                $batchIdString = implode(',',$importInternalMarkRequest->batchId) ? implode(',',$importInternalMarkRequest->batchId) : $importInternalMarkRequest->batchId;
                $sqlCondition .= " AND sbsr.batchID IN ($batchIdString)";
            }
            else {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid batch given!");
            }
            if (!empty($importInternalMarkRequest->subjectId)) {
                $subjectIdString = is_array($importInternalMarkRequest->subjectId) ? implode(',',$importInternalMarkRequest->subjectId) : $importInternalMarkRequest->subjectId;
                $sqlCondition .= " AND s.subjectID IN ($subjectIdString)";
            }
            $sql = "SELECT DISTINCT
                s.subjectID,
                s.isTheory,
                s.syllabusYear,
                b.batchID,
                sbsr.semID,
                esc.isInternal,
                ims.maxInternalMarks
            FROM
                subjects s
                    INNER JOIN
                sbs_relation sbsr ON sbsr.subjectID = s.subjectID
                    INNER JOIN
                batches b ON b.batchID = sbsr.batchID
                    INNER JOIN
                exam_subjectcredit esc ON esc.subjectID = s.subjectID
                    AND esc.subjectID = sbsr.subjectID
                    AND esc.semID = sbsr.semID
                    AND esc.batchID = b.batchID
                    AND esc.batchID = sbsr.batchID
                    LEFT JOIN
                internal_marks_settings ims ON ims.subjectID = s.subjectID
                    AND ims.subjectID = sbsr.subjectID
                    AND ims.subjectID = esc.subjectID
                    AND ims.semID = sbsr.semID
                    AND ims.semID = esc.semID
                    AND ims.batchID = b.batchID
                    AND ims.batchID = sbsr.batchID
                    AND ims.batchID = esc.batchID
            WHERE
                s.subjectID > 0 
                $sqlCondition";
            $subjects  = $this->executeQueryForList($sql);
            $batchwiseAssignedSubjectRules = [];
            $insertValidationStatusSqlValue = [];
            $batches = NULL;
            if (!empty($subjects)) {
                $getRuleAssignedForABatchRequest = new GetRuleAssignedForABatchRequest();
                foreach ($subjects as $subject) {
                    $validationParameterJSON = NULL;
                    $subjectValidateStatus = new \stdClass();
                    $subjectValidateStatus->id = $subject->subjectID;
                    
                    $batches [$subject->batchID]->subjects [$subject->subjectID] = new \stdClass();
                    $batches [$subject->batchID]->subjects [$subject->subjectID]->validation = true;
                    $validationParameterJSON ['status'] = '"status":true';
                    if (empty($batchwiseAssignedSubjectRules [$subject->batchID]) && !$batchwiseAssignedSubjectRules[$subject->batchID]->fetch) {
                        $getRuleAssignedForABatchRequest->batchId = $subject->batchID;
                        $getRuleAssignedForABatchRequest->semesterId = $subject->semID;
                        $batches [$subject->batchID]->validation = true;
                        $batchwiseAssignedSubjectRules [$subject->batchID]->fetch = true;
                        $batchwiseAssignedSubjectRules [$subject->batchID] = AssessmentComponentRuleService::getInstance()->getRuleAssignedForABatch($getRuleAssignedForABatchRequest);
                    }
                    // check subject have internal assessment
                    $validationParameterJSON ['internal'] = "";
                    if ((int)$subject->isInternal) {
                        $subjectValidateStatus->isInternal = new \stdClass();
                        $subjectValidateStatus->isInternal->status = true;
                        $subjectValidateStatus->isInternal->reason = "";
                        $validationParameterJSON ['internal'] = '"isInternal":true';
                        // check is set maximum mark for internal mark
                        if (!empty($subject->maxInternalMarks)) {
                            $subjectValidateStatus->isSetMaxMark = new \stdClass();
                            $subjectValidateStatus->isSetMaxMark->status = true;
                            $subjectValidateStatus->isSetMaxMark->reason = "";
                            
                            $validationParameterJSON ['internal'] .= ',"isSetMaxMark":true';
                        }
                        else {
                            $subjectValidateStatus->isSetMaxMark = new \stdClass();
                            $subjectValidateStatus->isSetMaxMark->status = false;
                            $subjectValidateStatus->isSetMaxMark->reason = "Max mark not entered";
                            
                            $batches [$subject->batchID]->subjects [$subject->subjectID]->validation = false;
                            $validationParameterJSON ['status'] = '"status":false';
                            $batches [$subject->batchID]->validation = false;
                            $validationParameterJSON ['internal'] .= ',"isSetMaxMark":false';
                        }
                    }
                    else{
                        $subjectValidateStatus->isInternal = new \stdClass();
                        $subjectValidateStatus->isInternal->status = false;
                        $subjectValidateStatus->isInternal->reason = "Not have internal mark";
                        $validationParameterJSON ['internal'] = '"isInternal":false';
                    }
                    $validationParameterJSON ['internal'] = '"internal":{'.$validationParameterJSON ['internal'].'}';
                    
                    // check internal mark calculating rules are defined
                    $validationParameterJSON ['rule'] = "";
                    if (!empty($batchwiseAssignedSubjectRules [$subject->batchID]->subjectWiseRule->{$subject->subjectID})) {
                        $subjectValidateStatus->isRuleDefined = new \stdClass();
                        $subjectValidateStatus->isRuleDefined->status = true;
                        $subjectValidateStatus->isRuleDefined->reason = "";
                         
                        $rulesJSON = NULL;
                        $ruleCriteriaJSON = NULL;
                        // check rule criterias are met 
                        // |-> 1. check internal marks of student entered for each exam type 
                        $examTypes = $batchwiseAssignedSubjectRules [$subject->batchID]->subjectWiseRule->{$subject->subjectID}->examTypes;
                        $ruleCriteriaJSON ['markEntry'] = "";
                        if (!empty($examTypes)) {
                            $ruleCriteriaJSONmarkEntry = NULL;
                            $isStudentMarkEntered = NULL;
                            $subjectValidateStatus->isMarkEntered = new \stdClass();
                            foreach ($examTypes as $examTypeId => $examType) {
                                $disableApproveExamMark = CommonService::getInstance()->getSettings(SettingsConstents::EXAM_CONTROLLER, SettingsConstents::DISABLE_APPROVE_EXAM_MARKS_FOR_SESSIONAL_MARKS);
                                if($disableApproveExamMark){
                                    $isStudentMarkEntered = $this->checkMarkEnteredDetails($subject->batchID, $subject->semID, $examTypeId, $subject->subjectID);
                                }
                                else{
                                    $isStudentMarkEntered = $this->checkMarkEnteredOrNot($subject->batchID, $subject->semID, $examTypeId, $subject->subjectID);
                                }
                               
                                if ($isStudentMarkEntered) {
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId} = new \stdClass();
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId}->status = true;
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId}->reason = "";
                                    
                                    $ruleCriteriaJSONmarkEntry [] = "\"$examTypeId\": {\"examTypeId\": $examTypeId,\"status\": true}";
                                }
                                else {
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId} = new \stdClass();
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId}->status = false;
                                    $subjectValidateStatus->isMarkEntered->{$examTypeId}->reason = "Mark not entered";
                                    $batches [$subject->batchID]->subjects [$subject->subjectID]->validation = false;
                                    $validationParameterJSON ['status'] = '"status":false';
                                    $batches [$subject->batchID]->validation = false;
                                    $ruleCriteriaJSONmarkEntry [] = "\"$examTypeId\": {\"examTypeId\": $examTypeId,\"status\": false}";
                                }
                            }
                            $validationParameterJSONexamTypeString = "";
                            $validationParameterJSONexamTypeString = implode(',',$ruleCriteriaJSONmarkEntry);
                            $ruleCriteriaJSON ['markEntry'] = '"markEntery":{'.$validationParameterJSONexamTypeString.'}';
                        }
                        else {
                            $subjectValidateStatus->isMarkEntered = new \stdClass();
                            $subjectValidateStatus->isMarkEntered->status = false;
                            $subjectValidateStatus->isMarkEntered->reason = "Exam type not defined";
                            
                            $batches [$subject->batchID]->subjects [$subject->subjectID]->validation = false;
                            $validationParameterJSON ['status'] = '"status":false';
                            $batches [$subject->batchID]->validation = false;
                            $ruleCriteriaJSON ['markEntry'] = '"markEntery":{}';
                        }
                        // TODO: add incoming rule crieteria validation eg:$ruleCriteriaJSON ['attendance'] = "{}"
                        $ruleCriteriaJSONstring = "";
                        $ruleCriteriaJSONstring = implode(',',$ruleCriteriaJSON);
                        $rulesJSON ['default'] = "";
                        $rulesJSON ['default'] .= '"isRuleDefined":true,"ruleCriteria":{'.$ruleCriteriaJSONstring.'}';
                    }
                    else{
                        $subjectValidateStatus->isRuleDefined = new \stdClass();
                        $subjectValidateStatus->isRuleDefined->status = false;
                        $subjectValidateStatus->isRuleDefined->reason = "Rule for internal mark calculation not defined";
                        
                        $batches [$subject->batchID]->subjects [$subject->subjectID]->validation = false;
                        $validationParameterJSON ['status'] = '"status":false';
                        $batches [$subject->batchID]->validation = false;
                        $rulesJSON ['default'] = '"isRuleDefined":false,"ruleCriteria":{}';
                    }
                    $rulesJSON ['default'] = '"default":{'.$rulesJSON ['default'].'}';;
                    // TODO: multiple rules for a subject (in case of sub-bathces: $rulesJSON['5'], 5 is subBatchId) 
                    $rulesJSONstring = "";
                    $rulesJSONstring = implode(',',$rulesJSON);
                    $validationParameterJSON ['rule'] = '"rule":{'.$rulesJSONstring.'}';
                    $validationParameterJSONstring = implode(',',$validationParameterJSON);
                    $validationParameterJSONstring = "{".$validationParameterJSONstring."}";
                    // values for batch_id, sem_id, subject_id, status, is_dirty, created_by
                    // TODO: set is_dirty = 0 if the triggers to update dirty flag are implimented
                    // $insertValidationStatusSqlValue [] = "($subject->batchID,$subject->semID,$subject->subjectID, '$validationParameterJSONstring',0,".$_SESSION ['adminId'].")";
                    $insertValidationStatusSqlValue [$subject->subjectID] = "($subject->batchID,$subject->semID,$subject->subjectID, '$validationParameterJSONstring',1,1)";
                    $batches[$subject->batchID]->subjects [$subject->subjectID]->subjectValidateStatus = $subjectValidateStatus;
                    $batches[$subject->batchID]->semId = $subject->semID;
                    $batches[$subject->batchID]->batchId = $subject->batchID;
                }
                $insertValidationStatusSqlValueString = implode(',',$insertValidationStatusSqlValue);
                // TODO: set is_dirty = 0 if the triggers to update dirty flag are implimented
                $insertValidationStatusSql = "INSERT INTO ec_subject_internal_mark_import_validated_status(batch_id, sem_id, subject_id, status, is_dirty, created_by) VALUES $insertValidationStatusSqlValueString ON DUPLICATE KEY UPDATE status = VALUES(status), is_dirty = 1, updated_by = VALUES(created_by)";
                $id  = $this->executeQuery($insertValidationStatusSql,true);
            }
            else {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"No subjects found!");
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $batches;
    }
    private function checkMarkEnteredOrNot($batchId, $semId, $examTypeId, $subjectId){
        try {
            $sql = "SELECT
                COUNT(markID) AS studentCount
            FROM
                student_marks sm
            INNER JOIN aprove_exam_marks aem ON
                aem.batchID = sm.batchID
                AND aem.semID = sm.semID
                AND aem.examId = sm.examID
            WHERE
                sm.batchID = $batchId
                AND sm.semID = $semId
                AND sm.examTypeID = $examTypeId
                AND sm.subjectID = $subjectId
                AND aem.isAproved = 1";
            $markList  = $this->executeQueryForObject($sql);
            if ($markList->studentCount < 1) {
                return false;
            }else {
                return true;
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    private function checkMarkEnteredDetails($batchId, $semId, $examTypeId, $subjectId){
        try {
            $sql = "SELECT
                COUNT(markID) AS studentCount
            FROM
                student_marks sm
            WHERE
                sm.batchID = $batchId
                AND sm.semID = $semId
                AND sm.examTypeID = $examTypeId
                AND sm.subjectID = $subjectId";
            $markList  = $this->executeQueryForObject($sql);
            if ($markList->studentCount < 1) {
                return false;
            }else {
                return true;
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * import internal mark to exam controller.
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @param  Methode validateInternalMarkImportProcess() $validatedBatches
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function getImportInternalMarkAutomationValidationStatus($importInternalMarkRequest) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $sql ="";
        $sqlCondition ="";
        $sqlMapper = NULL; 
        
        try {
            if (!$importInternalMarkRequest->batchId || !$importInternalMarkRequest->semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid request given for getiing status!");
            }
            if ($importInternalMarkRequest->batchSubjectGroupNeeded) {
                $sqlMapper = $this->mapper[InternalMarkServiceMapper::GET_VALIDATED_BATCHES_FOR_IMPORT_INTERNAL_MARK_AUTOMATION]; 
            }
            else{
                $sqlMapper = $this->mapper[InternalMarkServiceMapper::GET_VALIDATED_SUBJECT_FOR_IMPORT_INTERNAL_MARK_AUTOMATION]; 
            }
            if ($importInternalMarkRequest->subjectId) {
                $subjectIdString = is_array($importInternalMarkRequest->subjectId) ? implode(",",$importInternalMarkRequest->subjectId) : $importInternalMarkRequest->subjectId;
                $sqlCondition .= " AND subject_id IN ($subjectIdString)";
            }
            
            $batchIdString = is_array($importInternalMarkRequest->batchId) ? implode(",",$importInternalMarkRequest->batchId) : $importInternalMarkRequest->batchId;
            $semIdString = is_array($importInternalMarkRequest->semId) ? implode(",",$importInternalMarkRequest->semId) : $importInternalMarkRequest->semId;
            $sql = "SELECT
                simivs.id,
                simivs.batch_id,
                simivs.sem_id,
                simivs.subject_id,
                s.subjectName AS subjectCode,
                s.subjectDesc AS subjectName,
                simivs.status,
                simivs.is_dirty,
                simivs.notes
            FROM
                ec_subject_internal_mark_import_validated_status simivs
            INNER JOIN subjects s ON
                s.subjectID = simivs.subject_id
            WHERE
                batch_id IN ($batchIdString)
                AND sem_id IN ($semIdString)
                $sqlCondition";
            $batches  = $this->executeQueryForList($sql,$sqlMapper);
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $batches;
    }
    /**
     * import internal mark to exam controller.
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function importInternalMark($importInternalMarkRequest) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $studentInternalMarks = NULL;
        $importStatus = NULL;
        $response = new \stdClass();
        $response->reasons = [];
        global $COLLEGE_CODE;
        
        error_log("\nGlobal College Code --- ". $COLLEGE_CODE );
        error_log("\nCollege Code From Request --- ". $importInternalMarkRequest->COLLEGE_CODE );
        $COLLEGE_CODE = $importInternalMarkRequest->COLLEGE_CODE;
        $markEntryDetails = new \stdClass();
        $markEntryDetails->semId = $importInternalMarkRequest->semId;
        $markEntryDetails->batchId = $importInternalMarkRequest->batchId;
        $markEntryDetails->staffId = $importInternalMarkRequest->staffId;
        $markEntryDetails->subjectId = $importInternalMarkRequest->subjectId;
        $markEntryDetails->staffType = $importInternalMarkRequest->staffType;
        try {
            $importStatus = StatusConstants::FAILED;
            if (!$importInternalMarkRequest->batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$importInternalMarkRequest->semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$importInternalMarkRequest->subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$importInternalMarkRequest->staffId || !$importInternalMarkRequest->staffType) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            $calculateAssessmentRuleRequest = new CalculateAssessmentRuleRequest();
            $calculateAssessmentRuleRequest->batchId = $importInternalMarkRequest->batchId;
            $calculateAssessmentRuleRequest->semesterId = $importInternalMarkRequest->semId;
            $calculateAssessmentRuleRequest->subjectId = $importInternalMarkRequest->subjectId;
            $studentMarks = AssessmentComponentRuleService::getInstance()->calculateRuleForABatch($calculateAssessmentRuleRequest);
            foreach ($studentMarks['studentList'] as $student) {
                $studentMarkObj = new \stdClass();
                $studentMarkObj->studentId = $student->studentID;
                if($COLLEGE_CODE == "ASMPTN" || $COLLEGE_CODE == "IAGI"){
                    $studentMarkObj->marksObtained = round($student->internalMarkDetails['totalInternalMarks']);
                    $studentMarkObj->markNormalized = round($student->internalMarkDetails['totalInternalMarks']);
                }
                else{
                    $studentMarkObj->marksObtained = ceil($student->internalMarkDetails['totalInternalMarks']);
                    $studentMarkObj->markNormalized = ceil($student->internalMarkDetails['totalInternalMarks']);
                }
                $studentInternalMarks[] = $studentMarkObj;
            }
            
            $markEntryResponse = $this->enterNormalizedMarkOfBatch($studentInternalMarks,$markEntryDetails);
            $importStatus = StatusConstants::PARTIALLY_COMPLETED;
            
            $approveNormalizeId = $this->approveNormalizedInternalMark($markEntryDetails,true);
            
            $copyNormalizedMarkResponce = $this->copyNormalizedInternalMarkToExamController($markEntryDetails);
            
            $submitCopiedInternalMark = $this->confirmImportedInternalMark($markEntryDetails);
            $importStatus = StatusConstants::SUCCESS;
            
            $response->importStatus = $importStatus;
        }
        catch(\Exception $e) {
            
            $errorResponse = $e->getData();
            if ($importStatus === StatusConstants::FAILED && !$errorResponse) {
               if ($e->getCode() !== ProfessionalException::INVALID_PARAMETER) {
                   $reason = new \stdClass();
                   $reason->isSuccess = false;
                   $reason->message = "Calculation Failed";
                   $response->reasons[] = $reason;
                }
                else{
                    if (!$errorResponse) {
                        $reason = new \stdClass();
                        $reason->isSuccess = false;
                        $reason->message = "Server Error";
                        $response->reasons[] = $reason;
                    }
               }
            }
            else{
                $errorResponse = $e->getData();
                $response->reasons = $errorResponse->reasons;
            }
            $response->errorCode = $e->getCode();
            $response->errorMessage = $e->getMessage();
            // throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        $importStatusObj = new \stdClass();
        $importStatusObj->status = $importStatus;
        $importStatusObj->reasons = $response->reasons;
        $this->setImportInternalMarkAutomationStatus($markEntryDetails,$importStatusObj);
        return $response;
    }
    /**
     * save the normalized marks.
     * 
     * @param  $studentMarks
     * @param  $details
     * @throws ProfessionalException
     * @return $id
     * @author anoop
     */
    public function enterNormalizedMarkOfBatch($studentMarks, $details) {
        $details = $this->realEscapeObject($details);
        $studentMarks = $this->realEscapeArray($studentMarks);
        $semId = $details->semId;
        $batchId = $details->batchId;
        $staffId = $details->staffId;
        $subjectId = $details->subjectId;
        $staffType = $details->staffType;
        
        $sqlInsert = "";
        $sqlUpdate = "";
        $sqlInsertValueString = "";
        $sqlInsertValues = [];
        $studentMarksWithStudentId = NULL;
        
        try {
            if (empty($studentMarks)) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"No student mark!");
            }
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$staffId || !$staffType) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            foreach ($studentMarks as $studentMark) {
                $studentMarksWithStudentId[$studentMark->studentId] = $studentMark->marksObtained;
                $sqlInsertValues[] = "($batchId,$semId,$subjectId,$studentMark->studentId,$studentMark->marksObtained,$studentMark->markNormalized,$staffId,'$staffType',$staffId)";
                // $studentMark->markEntryIsSuccess = NULL;
                // $studentMark->errorCode = "";
                // $sqlInsertValueString = "";
                // $sqlInsertValueString = "($batchId,$semId,$subjectId,$studentMark->studentId,$studentMark->marksObtained,$studentMark->markNormalized,$staffId,'$staffType',$staffId)";
                // $sqlInsert = "INSERT INTO normalise_marks (batchID,semID,subjectID,studentID,marksObtained,normalisedMark,staffID,staff_type,created_by)
                // VALUES 
                //     $sqlInsertValueString";
                // $sqlUpdate = "UPDATE normalise_marks 
                //     SET
                //         marksObtained = $studentMark->marksObtained,
                //         normalisedMark = $studentMark->markNormalized,
                //         updated_by = $staffId
                //     WHERE batchID = $batchId
                //         AND semID = $semId
                //         AND subjectID = $subjectId
                //         AND studentID = $studentMark->studentId";
                // try {
                //     $id = $this->executeQueryForObject($sqlInsert,true);
                //     $studentMark->markEntryIsSuccess = true;
                //     $this->logger->info(Events::NORMALIZED_INTERNAL_MARK_ADDED,[
                //         "normalizedMark" => new NormalizedMark(["id" => $id]),
                //         "updatedByAdminID" => $staffId
                //     ]);
                // } catch(\Exception $e) {
                //     if ($e->getCode() == ProfessionalException::DUPLICATE_ENTRY) {
                //         try {
                //             $this->logger->info(Events::NORMALIZED_INTERNAL_MARK_UPDATED,[
                //                 "oldNormalizedMark" => new NormalizedMark(["id" => $id]),
                //                 "newNormlizedMark" => $studentMark->markNormalized
                //             ]);
                //             $this->executeQuery($sqlUpdate);
                //             $studentMark->markEntryIsSuccess = true;
                //         } catch(\Exception $e) {
                //             $studentMark->markEntryIsSuccess = false;
                //             $studentMark->errorCode = $e->getCode();
                //         }
                //     }
                //     else{
                //         $studentMark->markEntryIsSuccess = false;
                //         $studentMark->errorCode = $e->getCode();
                //     }
                // }
            }
            $sqlInsertValueString = implode(",",$sqlInsertValues);
            $sqlInsert = "INSERT INTO normalise_marks (batchID,semID,subjectID,studentID,marksObtained,normalisedMark,staffID,staff_type,created_by)
            VALUES 
                $sqlInsertValueString
            ON DUPLICATE KEY 
            UPDATE
                marksObtained = VALUES(marksObtained),
                normalisedMark = VALUES(normalisedMark),
                updated_by = VALUES(staffID)";
            $sqlSelectOldMark = "SELECT 
                batchID,
                studentID,
                examID,
                marksObtained,
                normalisedMark,
                subjectID,
                staffID,
                percentage,
                semID,
                examTypeID,
                staff_type,
                created_by,
                created_date,
                updated_by,
                updated_date
            FROM 
                normalise_marks 
            WHERE 
                batchID = $batchId
                AND semID = $semId
                AND subjectID = $subjectId";
                
            // fetch old marks and details
            $studentMarksOld = $this->executeQueryForList($sqlSelectOldMark);
            // insert newly calculated marks
            $this->executeQuery($sqlInsert);
            // log old mark in normalise_marks 
            foreach ($studentMarksOld as $studentMarkOld) {
                if ($studentMarksOld->marksObtained != $studentMarksWithStudentId[$studentMarkOld->studentID]) {
                    $this->logger->info(Events::NORMALIZED_INTERNAL_MARK_UPDATED,[
                        "batchID" => $studentMarkOld->batchID,
                        "studentID" => $studentMarkOld->studentID,
                        "oldNormalisedMark" => $studentMarkOld->normalisedMark,
                        "newMark" => $studentMarksWithStudentId[$studentMarkOld->studentID],
                        "subjectID" => $studentMarkOld->subjectID,
                        "staffID" => $studentMarkOld->staffID,
                        "percentage" => $studentMarkOld->percentage,
                        "semID" => $studentMarkOld->semID,
                        "examTypeID" => $studentMarkOld->examTypeID,
                        "staff_type" => $studentMarkOld->staff_type,
                        "updated_by" => $studentMarkOld->updated_by,
                    ]);
                }
                unset($studentMarksWithStudentId[$studentMarksOld->studentID]); // unset updated and not updated marks remaining studentIds will be new insert
            }
            $studentIds = implode(",",array_keys($studentMarksWithStudentId));
            $sqlSelectNewMark = $sqlSelectOldMark. " AND studentID IN($studentIds)";
            // fetch newly added marks and details
            $studentMarksNew = $this->executeQueryForList($sqlSelectNewMark);
            foreach ($studentMarksNew as $studentMarkNew) {
                // logs new marks
                $this->logger->info(Events::NORMALIZED_INTERNAL_MARK_ADDED,[
                    "batchID" => $studentMarkNew->batchID,
                    "studentID" => $studentMarkNew->studentID,
                    "examID" => $studentMarkNew->examID,
                    "normalisedMark" => $studentMarkNew->normalisedMark,
                    "subjectID" => $studentMarkNew->subjectID,
                    "staffID" => $studentMarkNew->staffID,
                    "percentage" => $studentMarkNew->percentage,
                    "semID" => $studentMarkNew->semID,
                    "examTypeID" => $studentMarkNew->examTypeID,
                    "staff_type" => $studentMarkNew->staff_type,
                    "created_by" => $studentMarkNew->created_by,
                    "created_date" => $studentMarkNew->created_date,
                ]);
            }
        }
        catch(\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Normalization Failed";
            $response->reasons[] = $reason;
            $response->studentMarks = $studentMarks;
            throw new ProfessionalException($e->getCode(),$e->getMessage(),$response);
        }
        return $studentMarks;
    }
    /**
     * set approve status of normalized marks entered.
     * @param  $details
     * @param  $isApprove
     * @param  $isPublish
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function approveNormalizedInternalMark($details, $isApprove = true,  $isPublish = true) {
        $details = $this->realEscapeObject($details);
        $isApprove = $this->realEscapeString($isApprove);
        $isPublish = $this->realEscapeString($isPublish);
        $semId = $details->semId;
        $batchId = $details->batchId;
        $staffId = $details->staffId;
        $subjectId = $details->subjectId;
        $staffType = $details->staffType;
        $publish = NULL;
        $approve = NULL;
        $sqlInsert = "";
        $sqlUpdate = "";
        
        $publish = $isPublish ? 1 : 0;
        $approve = $isApprove ? 1 : 0;
        try {
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$staffId || !$staffType) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            $sqlInsert = "INSERT INTO aprove_normalise_mark (batchID,semID,isAproved,staffID,subjectId,isPublished,createdBy,staff_type)
            VALUES 
                ($batchId,$semId,$approve,$staffId,$subjectId,$isPublish,$staffId,'$staffType')";
            $sqlUpdate = "UPDATE aprove_normalise_mark
            SET 
                isAproved = $approve,
                isPublished = $isPublish,
                updatedBy = $staffId
            WHERE
                batchID = $batchId
                AND semID = $semId
                AND subjectId = $subjectId";
            try {
                $id = $this->executeQuery($sqlInsert);
                $this->logger->info(Events::APPROVE_NORMALIZE_INTERNAL_MARK,[
                    "batchID" => $batchId,
                    "semID" => $semId,
                    "isAproved" => $approve,
                    "staffID" => $staffId,
                    "subjectId" => $subjectId,
                    "isPublished" => $isPublish,
                    "createdBy" => $staffId,
                    "staff_type" => $staffType
                ]);
            } catch(\Exception $e) {
                if ($e->getCode() == ProfessionalException::DUPLICATE_ENTRY) {
                    try {
                        $this->executeQuery($sqlUpdate);
                        $this->logger->info(Events::APPROVE_NORMALIZE_INTERNAL_MARK_UPDATED,[
                            "batchID" => $batchId,
                            "semID" => $semId,
                            "isAproved" => $approve,
                            "staffID" => $staffId,
                            "subjectId" => $subjectId,
                            "isPublished" => $isPublish,
                            "updatedBy" => $staffId,
                            "staff_type" => $staffType
                        ]);
                    } catch(\Exception $e) {
                        throw new ProfessionalException($e->getCode(),$e->getMessage());
                    }
                }
                else{
                    throw new ProfessionalException($e->getCode(),$e->getMessage());
                }
            }
        }
        catch(\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Normalization Failed";
            $response->reasons[] = $reason;
            throw new ProfessionalException($e->getCode(),$e->getMessage(),$response);
        }
        return $id;
    }
    /**
     * copy normalized marks entered to student internal marks.
     * @param  $details
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function copyNormalizedInternalMarkToExamController($details) {
        $details = $this->realEscapeObject($details);
        $semId = $details->semId;
        $staffId = $details->staffId;
        $batchId = $details->batchId;
        $subjectId = $details->subjectId;
        $sqlInsert = "";
        $sqlUpdate = "";
        try {
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$staffId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            // update existing mark
            $sqlUpdate = "UPDATE
                    internal_marks im
                INNER JOIN normalise_marks nm ON
                    nm.batchID = im.batchID
                    AND nm.semID = im.semID
                    AND nm.subjectID = im.subjectID
                    AND nm.studentID = im.studentID 
                SET
                    im.internalMarks = nm.marksObtained,
                    im.updated_by = $staffId
                WHERE
                    im.internalMarks <> nm.marksObtained
                    AND nm.semID = $semId
                    AND nm.batchID = $batchId
                    AND nm.subjectID = $subjectId";
            $this->logger->info(Events::IMPORT_NORMALIZED_MARK_TO_INTERNAL_MARKS,[
                "ImportedInternalMark" => new ImportedInternalMark([
                    "semId" => $semId,
                    "batchId" => $batchId,
                    "subjectId" => $subjectId
                    ])
            ]);
            $this->executeQuery($sqlUpdate);
            // copy internal marks values and ignore if mark exists
            $sqlInsert = "INSERT IGNORE
                INTO internal_marks(batchID,semID,studentID,subjectID,staffID,internalMarks,created_by)
                SELECT
                    batchID,
                    semID,
                    studentID,
                    subjectID,
                    $staffId,
                    marksObtained,
                    $staffId
                FROM
                    normalise_marks
                WHERE
                    semID = $semId
                    AND batchID = $batchId
                    AND subjectID = $subjectId";
            $this->executeQuery($sqlInsert,true);
        }
        catch(\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = true;
            $reason->message = "Normalization Completed";
            $response->reasons[] = $reason;
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Importing Failed";
            $response->reasons[] = $reason;
            throw new ProfessionalException($e->getCode(),$e->getMessage(),$response);
        }
    }
    /**
     * submit student internal marks copied from normalized marks.
     * @param  $details
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function confirmImportedInternalMark($details) {
        $details = $this->realEscapeObject($details);
        $semId = $details->semId;
        $staffId = $details->staffId;
        $batchId = $details->batchId;
        $subjectId = $details->subjectId;
        $staffType = $details->staffType;
        $sqlInsert = "";
        $sqlUpdate = "";
        try {
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$staffId || !$staffType) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            $sqlInsert = "INSERT INTO internal_marks_submitted(batchID,semID,subjectID,staffID,staffType,created_by)
                VALUES($batchId,$semId,$subjectId,$staffId,'$staffType',$staffId)";
            $sqlUpdate = "UPDATE internal_marks_submitted
            SET 
                updated_by = $staffId
            WHERE
                batchID = $batchId
                AND semID = $semId
                AND subjectID = $subjectId";
            try {
                $id = $this->executeQuery($sqlInsert);
                $this->logger->info(Events::SUBMIT_INTERNAL_MARKS,[
                    "batchID" => $batchId,
                    "semID" => $semId,
                    "staffID" => $staffId,
                    "subjectID" => $subjectId,
                    "created_by" => $staffId
                ]);
            } catch(\Exception $e) {
                if ($e->getCode() == ProfessionalException::DUPLICATE_ENTRY) {
                    try {
                        $this->executeQuery($sqlUpdate);
                        $this->logger->info(Events::SUBMIT_INTERNAL_MARKS_UPDATED,[
                            "batchID" => $batchId,
                            "semID" => $semId,
                            "staffID" => $staffId,
                            "subjectID" => $subjectId,
                            "updated_by" => $staffId
                        ]);
                    } catch(\Exception $e) {
                        throw new ProfessionalException($e->getCode(),$e->getMessage());
                    }
                }
                else{
                    throw new ProfessionalException($e->getCode(),$e->getMessage());
                }
            }
        }
        catch(\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = true;
            $reason->message = "Normalization Completed";
            $response->reasons[] = $reason;
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Importing Failed";
            $response->reasons[] = $reason;
            throw new ProfessionalException($e->getCode(),$e->getMessage(),$response);
        }
        return $id;
    }
    /**
     * Validate and import internal mark.
     * @param  $details
     * @param  $status
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function setImportInternalMarkAutomationStatus($details, $status) {
        $details = $this->realEscapeObject($details);
        $status = $this->realEscapeObject($status);
        $status = json_encode($status);
        // $status = $status; // As it is JSON we can't use real_escape_string
        $semId = $details->semId;
        $batchId = $details->batchId;
        $staffId = $details->staffId;
        $subjectId = $details->subjectId;
        
        $sqlInsert = "";
        $sqlUpdate = "";
        try {
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid subject!");
            }
            if (!$status) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid status!");
            }
            if (!$staffId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid Staff!");
            }
            $sqlInsert = "INSERT INTO ec_internal_mark_import_status(batch_id,sem_id,subject_id,status,created_by)
                VALUES($batchId,$semId,$subjectId,'$status',$staffId)";
            $sqlUpdate = "UPDATE ec_internal_mark_import_status
            SET
                status = '$status',
                is_dirty = 0,
                notes = NULL,
                updated_by = $staffId
            WHERE
                batch_id = $batchId
                AND sem_id = $semId
                AND subject_id = $subjectId";
            try {
                $id = $this->executeQuery($sqlInsert);
                $this->logger->info(Events::INTERNAL_MARKS_IMPORT_AUTOMATION,[
                    "batch_id" => $batchId,
                    "sem_id" => $semId,
                    "subject_id" => $subjectId,
                    "status" => $status,
                    "created_by" => $staffId
                ]);
            } catch(\Exception $e) {
                if ($e->getCode() == ProfessionalException::DUPLICATE_ENTRY) {
                    try {
                        $this->executeQuery($sqlUpdate);
                        $this->logger->info(Events::INTERNAL_MARKS_REIMPORT_AUTOMATION,[
                            "batch_id" => $batchId,
                            "sem_id" => $semId,
                            "subject_id" => $subjectId,
                            "status" => $status,
                            "updated_by" => $staffId
                        ]);
                    } catch(\Exception $e) {
                        throw new ProfessionalException($e->getCode(),$e->getMessage());
                    }
                }
                else{
                    throw new ProfessionalException($e->getCode(),$e->getMessage());
                }
            }
        }
        catch(\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = true;
            $reason->message = "Normalization Completed";
            $response->reasons[] = $reason;
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Importing Failed";
            $response->reasons[] = $reason;
            throw new ProfessionalException($e->getCode(),$e->getMessage(),$response);
        }
        return $id;
    }
    /**
     * import internal mark to exam controller.
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function validateAndImportInternalMark($importInternalMarkRequest) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $studentInternalMarks = NULL;
        $batchImportStatus = NULL;
        $response = new \stdClass();
        $sqlCondition = "";
        global $COLLEGE_CODE;
        
        try {
            if (!empty($importInternalMarkRequest->semId)) {
                $semIdString = is_array($importInternalMarkRequest->semId) ? implode(',',$importInternalMarkRequest->semId) : $importInternalMarkRequest->semId;
                $sqlCondition .= " AND sbsr.semID IN ($semIdString)";
            }
            else {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid semester given!");
            }
            if (!empty($importInternalMarkRequest->batchId)) {
                $batchIdString = is_array($importInternalMarkRequest->batchId) ? implode(',',$importInternalMarkRequest->batchId) : $importInternalMarkRequest->batchId;
                $sqlCondition .= " AND sbsr.batchID IN ($batchIdString)";
            }
            else {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid batch given!");
            }
            $invalidSubjectIds = [];
            $subjectImportInternalMarkRequest = new ImportInternalMarkRequest();
            $subjectImportInternalMarkRequest->semId = $importInternalMarkRequest->semId;
            $subjectImportInternalMarkRequest->batchId = $importInternalMarkRequest->batchId;
            $subjects  = $this->getImportAndValidationStatus($subjectImportInternalMarkRequest);
            foreach ($subjects as $subject) {
                if (!$subject->internalMarkImportAutomationStatus->status || $subject->internalMarkImportAutomationStatusIsDirty) {
                    $invalidSubjectIds[] = $subject->id;
                }
            }
            $subjectImportInternalMarkRequest->subjectId = $invalidSubjectIds;
            $validatedBatches = $this->validateInternalMarkImportProcess($subjectImportInternalMarkRequest);
            
            foreach ($validatedBatches as $batchId => $batch) {
                $getValidateAndImportStatusRequest = new ImportInternalMarkRequest();
                $getValidateAndImportStatusRequest->semId = $batch->semId;
                $getValidateAndImportStatusRequest->batchId = $batch->batchId;
                $batch->subjects = $this->getImportAndValidationStatus($getValidateAndImportStatusRequest);
                foreach ($batch->subjects as $subject) {
                    if ($subject->internalMarkImportAutomationStatus->status) {
                        $importValidatedInternalMarkRequest = new ImportInternalMarkRequest();
                        $importValidatedInternalMarkRequest->batchId = $batch->batchId;
                        $importValidatedInternalMarkRequest->semId = $subject->semId;
                        $importValidatedInternalMarkRequest->subjectId = $subject->id;
                        $importValidatedInternalMarkRequest->staffId = $importInternalMarkRequest->staffId;
                        $importValidatedInternalMarkRequest->staffType = $importInternalMarkRequest->staffType;
                        $importValidatedInternalMarkRequest->COLLEGE_CODE = $COLLEGE_CODE;
                        // $response = $this->importInternalMark($importValidatedInternalMarkRequest);
                        $importStatus = StatusConstants::PROCESSING;
                        $importStatusObj = new \stdClass();
                        $importStatusObj->status = $importStatus;
                        $importStatusObj->reasons = [];
                        $this->setImportInternalMarkAutomationStatus($importValidatedInternalMarkRequest,$importStatusObj);
                        
                        $taskQueue = new AMSTaskQueue();
                        $params    = ['className'  => 'com\linways\core\ams\professional\service\InternalMarkService',
                        'methodName'               => 'importInternalMark',
                            'methodParams'             => [$importValidatedInternalMarkRequest]];
                        $taskQueue->enqueue('EXECUTE SERVICE', $params);
                    }
                }
                $batch->subjects = $this->getImportAndValidationStatus($getValidateAndImportStatusRequest);
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $validatedBatches;
    }
     /**
     * import internal mark to exam controller.
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @param  Methode validateInternalMarkImportProcess() $validatedBatches
     * @throws ProfessionalException
     * @return boolean
     * @author anoop
     */
    public function getImportAndValidationStatus($importInternalMarkRequest) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $sql ="";
        $sqlCondition ="";
        
        try {
            if (!$importInternalMarkRequest->batchId || !$importInternalMarkRequest->semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid request given for getiing status!");
            }
            if ($importInternalMarkRequest->subjectId) {
                $subjectIdString = is_array($importInternalMarkRequest->subjectId) ? implode(",",$importInternalMarkRequest->subjectId) : $importInternalMarkRequest->subjectId;
                $sqlCondition .= " AND s.subjectID IN ($subjectIdString)";
            }
            
            $batchIdString = is_array($importInternalMarkRequest->batchId) ? implode(",",$importInternalMarkRequest->batchId) : $importInternalMarkRequest->batchId;
            $semIdString = is_array($importInternalMarkRequest->semId) ? implode(",",$importInternalMarkRequest->semId) : $importInternalMarkRequest->semId;
            $sql = "SELECT DISTINCT
                s.subjectID,
                s.subjectName AS subjectCode,
                s.subjectDesc AS subjectName,
                b.batchID,
                sbsr.semID,
                simivs.status AS validationStatus,
                simivs.is_dirty AS validationIsDirty,
                simivs.notes AS validationNotes,
                imis.status AS importStatus,
                imis.is_dirty AS importIsDirty,
                imis.notes AS importNotes,
                esc.isInternal
            FROM
                subjects s
                    INNER JOIN
                sbs_relation sbsr ON sbsr.subjectID = s.subjectID
                    INNER JOIN
                batches b ON b.batchID = sbsr.batchID
                    INNER JOIN
                exam_subjectcredit esc ON esc.subjectID = s.subjectID
                    AND esc.subjectID = sbsr.subjectID
                    AND esc.semID = sbsr.semID
                    AND esc.batchID = b.batchID
                    AND esc.batchID = sbsr.batchID
                    LEFT JOIN
                ec_subject_internal_mark_import_validated_status simivs ON  simivs.subject_id = s.subjectID
                    AND simivs.subject_id = esc.subjectID
                    AND simivs.batch_id = esc.batchID
                    AND simivs.batch_id = b.batchID
                    AND simivs.batch_id = sbsr.batchID
                    AND simivs.sem_id = esc.semID
                    AND simivs.sem_id = sbsr.semID
                    LEFT JOIN
                ec_internal_mark_import_status imis ON  imis.subject_id = s.subjectID
                    AND imis.subject_id = simivs.subject_id
                    AND imis.subject_id = esc.subjectID
                    AND imis.batch_id = simivs.batch_id
                    AND imis.batch_id = b.batchID
                    AND imis.batch_id = esc.batchID
                    AND imis.batch_id = sbsr.batchID
                    AND imis.sem_id = simivs.sem_id
                    AND imis.sem_id = sbsr.semID
                    AND imis.sem_id = esc.semID
            WHERE
                sbsr.batchID IN ($batchIdString)
                AND sbsr.semID IN ($semIdString)
                $sqlCondition";
            $subjects  = $this->executeQueryForList($sql,$this->mapper[InternalMarkServiceMapper::GET_SUBJECT_VALIDATION_AND_IMPORT_STATUS]);
            
            $ruleDefinedFor = "default"; // TODO: if custom rules are defined, then fetch value of $ruleDefinedFor from settings table
            // subject  validation status
            foreach ($subjects as $subject) {
                $subject->validationStatus->reasons = [];
                if ($subject->internalMarkImportAutomationStatus->status) {
                    $subject->validationStatus->status = true;
                    $subject->validationStatus->reasons[] = "Validated";
                }
                else if($subject->internalMarkImportAutomationStatus->status !== NULL){
                    $subject->validationStatus->status = false;
                    if ($subject->internalMarkImportAutomationStatus->internal->isInternal == true) {
                        $subject->internalValidation->status = false;
                        if (!$subject->internalMarkImportAutomationStatus->internal->isSetMaxMark) {
                            $subject->validationStatus->reasons[] = "Max mark not defined";
                        }
                        if (!$subject->internalMarkImportAutomationStatus->rule->{$ruleDefinedFor}->isRuleDefined) {
                            $subject->validationStatus->reasons[] = "Rule not defined";
                        }
                        else{
                            $examTypeNames = [];
                            foreach ($subject->internalMarkImportAutomationStatus->rule->{$ruleDefinedFor}->ruleCriteria->markEntery as $markEntery) {
                                if (!$markEntery->status) {
                                    $examTypeObj = ExamService::getInstance()->getExamTypeById($markEntery->examTypeId);
                                    $examTypeNames[$markEntery->examTypeId] = $examTypeObj->typeName;
                                }
                            }
                            if (!empty($examTypeNames)) {
                                $subject->validationStatus->reasons[] = "Mark not Entered For (".implode(", ",$examTypeNames).")";
                            }
                        }
                        $subject->validationStatus->reason = implode(", ",$subject->validationStatus->reasons);
                    }
                }
                else {
                    $subject->validationStatus->status = false;
                    $subject->validationStatus->reasons[] = "Not Validated for import";
                }
                if ($subject->importStatus === NULL) {
                    if ($subject->validationStatus->status) {
                        $subject->importStatus->status = "READY TO IMPORT";
                        $subject->importStatus->reason = [];
                    }
                    else {
                        $subject->importStatus->status = "NOT IMPORTED";
                        $subject->importStatus->reason = [];
                    }
                }
                else {
                    if ($subject->importIsDirty) {
                        $subject->importStatus->status = "RE IMPORT";
                        $dirtyReason = $subject->importNotes;
                        
                        if (!empty($dirtyReason->internalExamMarks)) {
                            $dirtyImportExamTypeNames = NULL;
                            foreach ($dirtyReason->internalExamMarks as $examTypeId => $internalExamMark) {
                                $examTypeObj = ExamService::getInstance()->getExamTypeById($examTypeId);
                                $dirtyImportExamTypeNames[$examTypeId] = $examTypeObj->typeName;
                            }
                            $importStatusReason = new \stdClass();
                            $importStatusReason->isSuccess = false;
                            $importStatusReason->message = "Mark changed For ".implode(", ",$dirtyImportExamTypeNames);
                            
                            $subject->importStatus->reasons[] = $importStatusReason;
                        }
                    }
                }
                
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
        return $subjects;
    }
    /**
     * set is_dirty of imported internal mark
     * 
     * @param  ImportInternalMarkRequest $importInternalMarkRequest
     * @param  $studentList
     * @throws ProfessionalException
     * @author anoop
    */
    public function setInternalImportAutomationDirtyFlag($importInternalMarkRequest, $examTypeId, $studentList) {
        $importInternalMarkRequest = $this->realEscapeObject($importInternalMarkRequest);
        $studentList = $this->realEscapeArray($studentList);
        $studentList = array_values($studentList);
        $sql = "";
        $sqlUpdate = "";
        $dirtyReasonJson = "";
        $dirtyReason = NULL;
        
        try {
            if (!$importInternalMarkRequest->batchId || !$importInternalMarkRequest->semId || !$importInternalMarkRequest->subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Invalid request given for getiing status!");
            }
            
            $sql = "SELECT                 
                is_dirty AS importIsDirty,
                notes AS importNotes
            FROM
                ec_internal_mark_import_status
            WHERE
                batch_id IN ($importInternalMarkRequest->batchId)
                AND sem_id IN ($importInternalMarkRequest->semId)
                AND subject_id IN ($importInternalMarkRequest->subjectId)";
            $subject  = $this->executeQueryForObject($sql);
            if (!empty($subject)) {
                if ($subject->importIsDirty) {
                    $dirtyReason = json_decode($subject->importNotes);
                }
                $dirtyReason->internalExamMarks->{$examTypeId}->examTypeId = $examTypeId;
                empty($dirtyReason->internalExamMarks->{$examTypeId}->students) ? ($dirtyReason->internalExamMarks->{$examTypeId}->students = $studentList) : array_merge($dirtyReason->internalExamMarks->{$examTypeId}->students, $studentList);
                $dirtyReasonJson = json_encode($dirtyReason);
    
                $sqlUpdate = "UPDATE
                ec_internal_mark_import_status
                SET
                    is_dirty = 1,
                    notes = '".$dirtyReasonJson."'
                WHERE
                    batch_id = $importInternalMarkRequest->batchId
                    AND sem_id = $importInternalMarkRequest->semId
                    AND subject_id = $importInternalMarkRequest->subjectId";
                $this->executeQuery($sqlUpdate);
            }
        }
        catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * Methode to set notification enable for sessional mark change
     * @param Object $notificationDetails
     */
    public function setNotificationEnableForSessionalExamMarkChange($notificationDetails) {
        $notificationDetails = $this->realEscapeObject($notificationDetails);
        try {
            $notificationJSON = CommonService::getInstance()->getSettings(SettingsConstents::EXAM_CONTROLLER, SettingsConstents::NOTIFICATION_ON_SESSIONAL_EXAM_MARK_CHANGE);
            $notification =  json_decode($notificationJSON);
            $notification->markChangeNotification = (int)$notificationDetails->markChangeNotification ? true : false;
            $notificationJSON = json_encode($notification);
            $sql = "UPDATE settings SET value = '$notificationJSON' WHERE type = \"".SettingsConstents::EXAM_CONTROLLER."\" AND name = \"".SettingsConstents::NOTIFICATION_ON_SESSIONAL_EXAM_MARK_CHANGE."\"";
            $this->executeQuery($sql);
        } catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
     /**
     * Get Max Internal Mark 
     * 
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author hijas
    */
    public function getMaxInternalMaxk($batchId, $semId, $subjectId) {
        try {
            $sql = " SELECT maxInternalMarks FROM internal_marks_settings WHERE batchID = $batchId AND semID = $semId AND subjectID = $subjectId ";
            return $this->executeQueryForObject($sql);
        } catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
     /**
     * Check entry in internal_marks_submitted
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
    */
    public function getInternlMarksSubmitted($batchId, $semId, $subjectId) {
        $condition = "";
        try {
            if($_SESSION['staffID']){
                $staffId = $_SESSION['staffID'];
                $condition .= " AND staffID IN($staffId) AND staffType = 'staff'";
            }
            $sql = "SELECT batchID,semID,subjectID,staffID from internal_marks_submitted WHERE batchID = $batchId AND semID = $semId AND subjectID = $subjectId $condition";
            return $this->executeQueryForObject($sql);
        } catch(\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * get studentList with internal marks
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getStudentsInternalMarksSubmitted($batchId,$semId,$subjectId, $subBatch)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $subBatch =$this->realEscapeArray($subBatch);
        if($subBatch){
            $sql = "SELECT distinct(subs.studentID),sa.studentName,sa.regNo,im.internalMarkID,s.subjectID,s.subjectName,s.subjectDesc,im.internalMarks,im.internalMarks as oldInternalMarks,im.isAbsent,sa.batchID,sa.rollNo,sf.staffID,sf.staffName
                        from sbs_relation sbs
                        left join subjects s
                            on s.subjectID='$subjectId
                        inner join subbatch_sbs ssbs
                            on ssbs.sbsID = sbs.sbsID
                        inner join    subbatch_student subs
                            on subs.subbatchID = ssbs.subbatchID
                        inner join studentaccount sa
                            on sa.studentID = subs.studentID
                            and sa.batchID = sbs.batchID
                            LEFT JOIN internal_marks im ON
                                im.batchID = sa.batchID
                                AND im.studentID = sa.studentID  
                                AND  im.subjectID ='$subjectId'
                                AND im.semID = '$semId'
                            LEFT JOIN staffaccounts sf ON sf.staffID = im.staffID
                            where sbs.batchID='$batchId'
                            and sbs.subjectID='$subjectId'
                            and sbs.semID='$semId'
                            ORDER BY sa.regNo ASC";
        }
        else{
            $sql = "SELECT  sa.studentID,sa.studentName,sa.regNo,sa.batchID,s.subjectID,s.subjectName,s.subjectDesc,im.internalMarks,im.internalMarks as oldInternalMarks,im.isAbsent,sa.rollNo,sf.staffID,sf.staffName
                            from  studentaccount sa
                                left join subjects s
                                    on s.subjectID='$subjectId'  
                                inner join batches ba 
                                    on  ba.batchID = sa.batchID
                                LEFT JOIN internal_marks im ON
                                    im.batchID = sa.batchID
                                    AND im.studentID = sa.studentID  
                                    AND  im.subjectID ='$subjectId'
                                    AND im.semID = '$semId'  
                                LEFT JOIN staffaccounts sf ON sf.staffID = im.staffID
                                where sa.batchID='$batchId
                                ORDER BY sa.regNo ASC";
        }
                try {
                    $students = $this->executeQueryForList($sql);
                } catch (\Exception $e) {
                    throw new ProfessionalException($e->getCode(), $e->getMessage());
                }
                return $students;
    }
    /**
     * save internal marks
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function saveInternalMarks($request)
    {
        $isExistSql="";
        $isExist="";
        $valueString="";
        $request = $this->realEscapeObject($request);
        $studentList = $request->studentList;
        $status = 0;
        foreach($studentList as $student){
            $student = (object) $student;
            //check whether entry exist
            $student->batchID = $student->batchID ? $student->batchID :$request->batchId;
            $student->semID = $student->semID ? $student->semID :$request->semId;
            $isExistSql = "SELECT internalMarkID,studentID
                                from internal_marks
                                where studentID='$student->studentID'
                                and batchID='$student->batchID'
                                and semID='$student->semID'
                                and subjectID='$request->subjectId'";
            try {
                $isExist = $this->executeQueryForObject($isExistSql);
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
            //set marks to 0 if absent 
            $student->internalMarks = (int) $student->isAbsent ? 0 : $student->internalMarks;
            //validate mark value update or insert
            if( is_numeric($student->internalMarks) && $student->internalMarks!="null" || (int) $student->isAbsent){
                //if exist update marks
                if ($isExist) {
                    $updateSql = "UPDATE internal_marks
                                SET internalMarks ='$student->internalMarks',
                                staffID ='$request->staffId',
                                updated_by='$request->staffId',
                                isAbsent = '$student->isAbsent'
                                where studentID='$student->studentID'
                                and batchID='$student->batchID'
                                and semID='$student->semID'
                                and subjectID='$request->subjectId'";
                    try {
                        $this->executeQueryForObject($updateSql);
                        $status=1;
                    } catch (\Exception $e) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                //else make insert values for new insert entry
                else {
                    if ($valueString) {
                        $valueString = $valueString . ",('$student->batchID','$student->semID','$student->studentID','$request->subjectId','$request->staffId','$student->internalMarks','$request->staffId','$student->isAbsent')";
                    } else {
                        $valueString = "('$student->batchID','$student->semID','$student->studentID','$request->subjectId','$request->staffId', '$student->internalMarks','$request->staffId','$student->isAbsent')";
                    }
                }
            }
            //end if
            //delete the entry if exist if edited mark is null or empty
            else{
                if ($isExist){
                    $deleteSql ="DELETE from internal_marks
                                where studentID='$student->studentID'
                                and batchID='$student->batchID'
                                and semID='$student->semID'
                                and subjectID='$request->subjectId'";
                    try {
                        $this->executeQueryForObject($deleteSql);
                        $status = 1;
                    } catch (\Exception $e) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
            }
            //end delete
            
        }
        //insert query
        if ($valueString) {
            $insertSql = "INSERT into internal_marks(batchID,semID,studentID,subjectID,staffID,internalMarks,created_by,isAbsent)
                                values $valueString";
            try {
                $this->executeQueryForObject($insertSql);
                $status = 1;
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
        }
        return $status;
    }
    /**
     * allow/block interanl mark submitted
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function allowOrBlockInternalMarkSubmitted($request)
    {
        $request = $this->realEscapeObject($request);
        $sql="";
        if($request->status==1){
            $sql = "INSERT into internal_marks_submitted(batchID,semID,subjectID,staffID,staffType,created_by) 
                                values('$request->batchId','$request->semId','$request->subjectId','$request->staffId','EXAM_CONTROLLER','$request->staffId')";
        }
        else{
            $sql = "DELETE from internal_marks_submitted
                                where batchID='$request->batchId'
                                and semID='$request->semId'
                                and subjectID='$request->subjectId'";
        }
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get interanl exam max mark
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getInternalExamMaxMark($batchId, $semId, $subjectId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "";
        $maxMark="";
        $sql = "SELECT internalSettingID,maxInternalMarks from internal_marks_settings
                                where batchID='$batchId'
                                and semID='$semId'
                                and subjectID='$subjectId'";
        try {
            $maxMark = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        
        return $maxMark;
        
    }
    /**
     * get getMarkEnteredStudentCount
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getMarkEnteredStudentCount($batchId, $semId, $subjectId,$subBatch)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $subBatch = $this->realEscapeArray($subBatch);
        $sql = "";
        $mark = "";
        if ($subBatch) {
            $sql="SELECT distinct (subs.studentID),sa.studentName,im.internalMarkID,im.internalMarks from sbs_relation sbs
                       inner join subbatch_sbs ssbs
                            on ssbs.sbsID = sbs.sbsID
                        inner join    subbatch_student subs
                            on subs.subbatchID = ssbs.subbatchID
                        inner join studentaccount sa
                            on sa.studentID = subs.studentID
                            and sa.batchID = sbs.batchID
                        inner join internal_marks im
                            on im.studentID=subs.studentID
                            and im.batchID='$batchId'
                            and im.semID='$semId'
                            and im.subjectID='$subjectId'
                        where sbs.batchID='$batchId'
                        and sbs.subjectID='$subjectId'
                        and sbs.semID='$semId'
                        ORDER BY sa.regNo ASC";
        }
        else{
            // $sql = "SELECT internalMarkID,internalMarks from internal_marks im
            //                     where im.batchID='$batchId'
            //                     and im.semID='$semId'
            //                     and im.subjectID='$subjectId'";
            $sql = "SELECT  sa.studentID,sa.studentName,sa.regNo,sa.batchID,im.internalMarks
                            from  studentaccount sa  
                                inner join batches ba 
                                    on  ba.batchID = sa.batchID
                                INNER JOIN internal_marks im ON
                                    im.batchID = sa.batchID
                                    AND im.studentID = sa.studentID  
                                    AND  im.subjectID ='$subjectId'
                                    AND im.semID = '$semId'  
                                where sa.batchID='$batchId
                                ORDER BY sa.regNo ASC";
        }
        try {
            $mark = $this->executeQueryForList($sql);
            $studCount = count($mark);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studCount;
    }
    /**
     * get getMarkEnteredStudentCount
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getTotalNumberOfStudents($batchId, $semId, $subjectId, $subBatch)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $subBatch = $this->realEscapeArray($subBatch);
        if ($subBatch) {
            $sql = "SELECT distinct(subs.studentID),sa.studentName from sbs_relation sbs
                        inner join subbatch_sbs ssbs
                            on ssbs.sbsID = sbs.sbsID
                        inner join    subbatch_student subs
                            on subs.subbatchID = ssbs.subbatchID
                        inner join studentaccount sa
                            on sa.studentID = subs.studentID
                            and sa.batchID = sbs.batchID
                        where sbs.batchID='$batchId'
                        and sbs.subjectID='$subjectId'
                        and sbs.semID='$semId'
                        ORDER BY sa.regNo ASC";
        } else {
            $sql = "SELECT  sa.studentID,sa.studentName
                            from  studentaccount sa  
                                inner join batches ba 
                                    on  ba.batchID = sa.batchID
                                where sa.batchID='$batchId
                                ORDER BY sa.regNo ASC";
        }
        try {
            $studentList = $this->executeQueryForList($sql);
            $studCount = count($studentList);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studCount;
    }
    /**
     * get checkPseudoSubject
     * @param  $staffDetails
     * @throws ProfessionalException
     * @author sibin
     */
    public function checkPseudoSubject($staffDetails)
    {
        $sbsIdString = "";
        $staffDetails = $this->realEscapeArray($staffDetails);
        foreach ($staffDetails as $staff) {
            if ($sbsIdString) {
                $sbsIdString = $sbsIdString . "$staff->sbsID";
            } else {
                $sbsIdString = "$staff->sbsID";
            }
        }
        $sql = "";
        $sql = "SELECT pseudosubsbsID,pseudosubjectID,sbsID
                        from pseudosubjects_sbs where sbsID in($sbsIdString)";
        try {
            $pseudoSubjectId = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $pseudoSubjectId;
    }
    /**
     * Check entry in internal_marks_submitted
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getStudentByBatchSem($batchId)
    {
        $batchId = $this->realEscapeString($batchId);
        try {
            $sql = "SELECT  sa.studentID,sa.regNo,sa.studentName,sa.rollNo
                            from  studentaccount sa  
                                inner join batches ba 
                                    on  ba.batchID = sa.batchID
                                where sa.batchID='$batchId
                                ORDER BY sa.regNo ASC";
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get interanl exam mark
     * @param  $batchID, $semId, $subjectId,$studentId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getInternalExamMark($batchId, $semId, $subjectId, $studentId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $studentId = $this->realEscapeString($studentId);
        $sql = "";
        $internalMark = "";
        $sql = "SELECT im.internalMarkID,im.internalMarks,ims.maxInternalMarks from internal_marks im
                INNER JOIN internal_marks_settings ims ON ims.batchID = im.batchID AND ims.semID = im.semID AND ims.subjectID = im.subjectID
                                where im.batchID='$batchId'
                                and im.semID='$semId'
                                and im.subjectID='$subjectId'
                                and im.studentID='$studentId'";
        try {
            $internalMark = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $internalMark;
    }
        /**
     * get studentList with internal marks
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getStudentsInternalMarks($batchId,$semId,$subjectId, $subBatch)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "SELECT  sa.studentID,sa.studentName,sa.regNo,sa.batchID,s.subjectID,s.subjectName,s.subjectDesc,im.internalMarks
                        from  studentaccount sa
                            left join subjects s
                                on s.subjectID='$subjectId'  
                            inner join batches ba 
                                on  ba.batchID = sa.batchID
                            LEFT JOIN internal_marks im ON
                                im.batchID = sa.batchID
                                AND im.studentID = sa.studentID  
                                AND  im.subjectID ='$subjectId'
                                AND im.semID = '$semId'  
                            where sa.batchID='$batchId
                            ORDER BY sa.regNo ASC";
        try {
            $students = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $students;
    }
    public function confirmInternalSubmition($batchId,$semId)
    {
        $batchId=$this->realEscapeString($batchId);
        $semId=$this->realEscapeString($semId);
        $subjectSubmitArray=[];
        $sql="SELECT
                    sr.subjectID 
                from
                    sbs_relation sr 
                    inner join
                    exam_subjectcredit es 
                    on (es.batchID = sr.batchID 
                    and es.semID = sr.semID 
                    and es.subjectID = sr.subjectID) 
                where
                    sr.batchID =$batchId 
                    and sr.semID =$semId 
                    and es.isInternal = 1";
        $sbsubjects = $this->executeQueryForList($sql);
        $query="select distinct
                    batchID,
                    semID,
                    subjectID,
                    staffID 
                from
                    internal_marks 
                where
                    batchID = '$batchId
                    and semID = '$semId'";
        $internalMarkEntered = $this->executeQueryForList($query);
        if(!empty($internalMarkEntered))
        {
            foreach ($internalMarkEntered as $intSubs)
            {
                $subjectSubmitArray[] = $intSubs->subjectID;
                $query1="select
                                * 
                            from
                                internal_marks_submitted 
                            where
                                batchID =$batchId 
                                and semID =$semId 
                                and subjectID =$intSubs->subjectID 
                                and staffID =$intSubs->staffID";
                $checkEntry = $this->executeQueryForList($query1);
                if(empty($checkEntry))
                {
                    $query="insert into internal_marks_submitted (batchID, semID, subjectID, staffID, staffType) values($intSubs->batchID,$intSubs->semID,$intSubs->subjectID,$intSubs->staffID,'staff')";
                    try{
                        $response2=$this->executeQuery($query,true);
                    }catch (\Exception $e)
                    {
                        throw new ProfessionalException($e->getCode(),$e->getMessage());
                    }
                }
            } 
        }
        $subjectNotEntered = [];
        foreach($sbsubjects as $subject){
            if(!in_array($subject->subjectID, $subjectSubmitArray)){
                $subjectNotEntered[] = $subject->subjectID;
            }
        }
        if(empty($sbsubjects) && empty($subjectSubmitArray)){
            return 2;
        }
        return $subjectNotEntered;
    }
    /**
     * get define rule attendance ranges values
     * @param  Integer $ruleID,$isSubjectSpecRule
     * @return Array $attendanceRange
     * @throws ProfessionalException
     */
    public function getAttendanceRangeInDefineRule($ruleID,$isSubjectSpecRule)
    {
        try {
            if($isSubjectSpecRule){
                $sql = "SELECT 
                    attn_range_from, attn_range_to, attendance_mark
                FROM
                    normalization_rule_subject_attendance
                WHERE
                    normalization_rule_subject_id = '$ruleID' ORDER BY attn_range_from ASC";
            }
            else{
                $sql = "SELECT 
                    attn_range_from, attn_range_to, attendance_mark
                FROM
                    normalization_rule_attendance
                WHERE
                    normalization_rule_id = '$ruleID' ORDER BY attn_range_from ASC";
            }
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
        /**
     * allow/block interanl mark submitted
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     */
    public function saveInternalMarkSubmitted($batchId, $semId, $subjectId, $staffId)
    {
        if(is_array($batchId)){
            $batchId = $this->realEscapeArray($batchId);
        }else{
            $batchId = $this->realEscapeString($batchId);
        }
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $staffId = $this->realEscapeString($staffId);
        $sql="";
        try {
            if(is_array($batchId)){
                foreach($batchId as $batch){
                    $sql = "INSERT into internal_marks_submitted(batchID,semID,subjectID,staffID,staffType,created_by) 
                                    values('$batch','$semId','$subjectId','$staffId','EXAM_CONTROLLER','$staffId') ON DUPLICATE KEY UPDATE staffID = VALUES(staffID)";
                    return $this->executeQueryForObject($sql);
                }
            }
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Assign staff for internal mark entry
     * @param  $batchID, $semId, $staffId, $startDate, $endDate
     * @throws ProfessionalException
     */
    public function assignStaffForInternalMarkEntry($batchId, $semId, $staffId, $startDate, $endDate)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $staffId = $this->realEscapeString($staffId);
        $startDate = $this->realEscapeString($startDate);
        $endDate = $this->realEscapeString($endDate);
        $sql="";
            $sql = "INSERT INTO assign_staff_internal_mark_entry(batchID,semID,adminID,startDate,endDate) VALUES('$batchId','$semId','$staffId','$startDate','$endDate')";
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * get staff for assigned internal mark entry
     * @param  $request
     * @throws ProfessionalException
     */
    public function getStaffAssignedForInternalMarkEntry($request)
    {
        $request = $this->realEscapeObject($request);
        $condition="";
        if($request->batchId){
            $condition .= " AND asime.batchID IN ($request->batchId)";
        }
        if($request->semId){
            $condition .= " AND asime.semID IN ($request->semId)";
        }
        if($request->adminID){
            $condition .= " AND asime.adminID IN ($request->adminID)";
        }
        $sql = "SELECT 
                    asime.id, asime.batchID, asime.semID, asime.adminID, asime.startDate, asime.endDate, bt.batchName, s.semName, ea.adminName 
                FROM 
                    assign_staff_internal_mark_entry asime 
                INNER JOIN 
                    batches bt ON(asime.batchID = bt.batchID) 
                INNER JOIN semesters s ON (asime.semID = s.semID) 
                INNER JOIN examcontroller_admin ea ON (asime.adminID = ea.adminID) 
                WHERE 
                    1=1 $condition
                    ORDER BY  asime.semID ASC";
        
        try {
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * delete batch from staff assigned for internal mark entry
     * @param  $id
     * @throws ProfessionalException
     */
    public function deleteBatchFromInternalMarkEntryAssignedStaff($id)
    {
        $id = $this->realEscapeString($id);
        $sql = "DELETE FROM assign_staff_internal_mark_entry WHERE id = $id";
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update batch from staff for internal mark entry
     * @param  $batch
     * @throws ProfessionalException
     */
    public function updateInternalMarkEntryAssignedStaff($batch)
    {
        $batch = $this->realEscapeObject($batch);
        $sql = "UPDATE assign_staff_internal_mark_entry SET startDate = '$batch->startDate', endDate = '$batch->endDate' WHERE id = $batch->id";
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
     /**
     * Update date of internal mark entry assigned staff
     * @param  $staff
     * @throws ProfessionalException
     */
    public function updateInternalMarkEntryAssignedStaffDate($staff)
    {
        $staff = $this->realEscapeObject($staff);
        $sql = "UPDATE assign_staff_internal_mark_entry SET startDate = '$staff->startDate', endDate = '$staff->endDate' WHERE adminID = $staff->adminId";
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
        /**
     * delete Staff from staff assigned for internal mark entry
     * @param  $adminId
     * @throws ProfessionalException
     */
    public function deleteStaffFromInternalMarkEntryAssignedStaff($adminId)
    {
        $adminId = $this->realEscapeString($adminId);
        $sql = "DELETE FROM assign_staff_internal_mark_entry WHERE adminID = $adminId";
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Update Internal mark
     * @param  $request
     * @throws ProfessionalException
     */
    public function updateInternalMarkByRequest($request)
    {
        $request = $this->realEscapeObject($request);
        $checkEntry = InternalMarkService::getInstance()->getInternalExamMark($request->batchId, $request->semId, $request->subjectId, $request->studentId);
        if($checkEntry){
            $sql = "UPDATE internal_marks
                    SET internalMarks ='$request->internalMark',
                    updated_by='$request->staffId'
                    where studentID='$request->studentId'
                    and batchID='$request->batchId'
                    and semID='$request->semId'
                    and subjectID='$request->subjectId'";
        }
        else{
            $sql = "INSERT into internal_marks(batchID,semID,studentID,subjectID,staffID,internalMarks,created_by) VALUES('$request->batchId', '$request->semId', '$request->studentId', '$request->subjectId', '$request->staffId', '$request->internalMark', '$request->staffId')";
        }
        
        try {
            return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * Get Internal mark subjects details by request
     * @param  $request
     * @throws ProfessionalException
     */
    public function getInternalMarkSubjectDetailsByRequest($request)
    {
        $request = $this->realEscapeObject($request);
        $subjectList=[];
        $condition = "";
        if ($request->batchId) {
            $condition .= " AND sbs.batchID IN ($request->batchId";
        }
        if ($request->semId) {
            $condition .= " AND sbs.semID IN ($request->semId";
        }
        if ($request->subjectId) {
            $condition .= " AND sbs.subjectID IN ($request->subjectId";
        }
        try {
            $sql = "SELECT distinct sbs.subjectID as subjectId,s.subjectName,s.subjectDesc,s.subjectPriority ,s.syllabusName,
                    IF(ims.fromDate='0000-00-00', '', ims.fromDate) as fromDate,IF(ims.toDate='0000-00-00','', ims.toDate) as toDate
                    FROM sbs_relation sbs
                    INNER JOIN subjects s ON s.subjectID = sbs.subjectID
                    LEFT JOIN internal_marks_settings ims ON ims.batchID = sbs.batchID AND ims.semID = sbs.semID AND ims.subjectID = sbs.subjectID
                    WHERE 1 = 1
                    $condition
                    ORDER BY s.subjectPriority";
            $subjectList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $subjectList;
    }
    /**
     * set Internal mark subjects wise dates
     * @param  $request
     * @throws ProfessionalException
     */
    public function setInternalMarkSubmissionDatesSubjectwise($request)
    {
        $request = $this->realEscapeObject($request);
        try {
            $sql = "INSERT INTO internal_marks_settings(batchID,semID,subjectID,fromDate,toDate)
                    VALUES($request->batchId,$request->semId,$request->subjectId,'$request->fromDate','$request->toDate')
                    ON DUPLICATE KEY UPDATE fromDate = VALUES(fromDate),toDate = VALUES(toDate)";
            $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * set Internal mark subjects wise dates
     * @param  $request
     * @throws ProfessionalException
     */
    public function saveSupplyInternalMarks($request)
    {
        $request = $this->realEscapeObject($request);
        $request->supplyInternalMarks = $request->supplyInternalMarks ? $request->supplyInternalMarks : 0;
        try {
            $sql = "INSERT INTO supply_internal_marks(studentId,subjectID,supplyExamRegId,marks,created_by)
                    VALUES($request->studentID,$request->subjectID,$request->exam_supplementary_id,$request->supplyInternalMarks,$request->createdBy)
                    ON DUPLICATE KEY UPDATE marks = VALUES (marks) ,updated_by = VALUES(created_by)";
            $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * get interanl exam mark
     * @param  $batchID, $semId, $subjectId,$studentId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getStudentRegularSupplyInternalExamMarks($request)
    {
        $request = $this->realEscapeObject($request);
        $sql = "";
        $internalMark = "";
        $sql = "SELECT im.internalMarkID,IF(im.internalMarks,im.internalMarks,0) as internalMarks,ims.maxInternalMarks,sim.marks as supplyInternalMarks from internal_marks_settings ims 
                LEFT JOIN internal_marks im ON im.batchID = ims.batchID AND im.semID = ims.semID AND im.subjectID = ims.subjectID AND im.studentID='$request->studentID'
                LEFT JOIN supply_internal_marks sim ON sim.studentId  = '$request->studentID' AND sim.subjectId = '$request->subjectID' AND sim.supplyExamRegId = '$request->exam_supplementary_id'
                                where ims.batchID='$request->batchID'
                                and ims.semID='$request->semId'
                                and ims.subjectID='$request->subjectID'";
        try {
            $internalMark = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $internalMark;
    }
    /**
     * delete internal marks from exam controller
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function deleteInternalMarksFromExamController($request)
    {
        $request = $this->realEscapeObject($request);
        $sql = $sqlDeleteSubmitted = "";
        if ($request->status == 1) {
            $sql = "DELETE from internal_marks
                                where batchID='$request->batchId'
                                and semID='$request->semId'
                                and subjectID='$request->subjectId'";
            $sqlDeleteSubmitted = "DELETE from internal_marks_submitted
                                where batchID='$request->batchId'
                                and semID='$request->semId'
                                and subjectID='$request->subjectId'";
        } else {
        }
        try {
            $this->executeQueryForObject($sql);
            $this->executeQueryForObject($sqlDeleteSubmitted);
            return true;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * copy normalized marks to student internal marks.
     * @param  $details
     * @throws ProfessionalException
     * @return boolean
     * @author sibin
     */
    public function copyNormalizedFinalInternalMarkToExamController($details)
    {
        $details = $this->realEscapeObject($details);
        $semId = $details->semId;
        $staffId = $details->staffId;
        $batchId = $details->batchId;
        $subjectId = $details->subjectId;
        $sqlInsert = "";
        $sqlUpdate = "";
        try {
            if (!$batchId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER, "Batch not valid!");
            }
            if (!$semId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER, "Invalid semester!");
            }
            if (!$subjectId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER, "Invalid subject!");
            }
            if (!$staffId) {
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER, "Invalid Staff!");
            }
            // update existing mark
            $sqlUpdate = "UPDATE
                    internal_marks im
                INNER JOIN normalise_marks nm ON
                    nm.batchID = im.batchID
                    AND nm.semID = im.semID
                    AND nm.subjectID = im.subjectID
                    AND nm.studentID = im.studentID 
                SET
                    im.internalMarks = nm.normalisedMark,
                    im.updated_by = nm.staffID
                WHERE
                    im.internalMarks <> nm.normalisedMark
                    AND nm.semID = $semId
                    AND nm.batchID = $batchId
                    AND nm.subjectID = $subjectId";
            $this->executeQuery($sqlUpdate);
            // copy internal marks values and ignore if mark exists
            $sqlInsert = "INSERT IGNORE
                INTO internal_marks(batchID,semID,studentID,subjectID,staffID,internalMarks,created_by)
                SELECT
                    batchID,
                    semID,
                    studentID,
                    subjectID,
                    staffID,
                    normalisedMark,
                    staffID
                FROM
                    normalise_marks
                WHERE
                    semID = $semId
                    AND batchID = $batchId
                    AND subjectID = $subjectId";
            $this->executeQuery($sqlInsert, true);
        } catch (\Exception $e) {
            $response = new \stdClass();
            $reason = new \stdClass();
            $reason->isSuccess = true;
            $reason->message = "Normalization Completed";
            $response->reasons[] = $reason;
            $reason = new \stdClass();
            $reason->isSuccess = false;
            $reason->message = "Importing Failed";
            $response->reasons[] = $reason;
            throw new ProfessionalException($e->getCode(), $e->getMessage(), $response);
        }
    }
    /**
     * get maximum mark from normaized internal max mark
     * @param  $batchID, $semId, $subjectId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getNormalizedInternalExamMaxMark($batchId, $semId, $subjectId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "";
        $maxMark = "";
        $sql = "SELECT max(normalisedMark) normalizedMaxMark from normalise_marks
                                where batchID='$batchId'
                                and semID='$semId'
                                and subjectID='$subjectId'";
        try {
            $maxMark = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $maxMark;
    }
    /* set Internal mark subjects wise settings
     * @param  $request
     * @throws ProfessionalException
     */
    public function setInternalMarkSettingsSubjectwise($request)
    {
        $request = $this->realEscapeObject($request);
        try {
            $sql = "INSERT INTO internal_marks_settings(batchID,semID,subjectID,maxInternalMarks)
                    VALUES($request->batchId,$request->semId,$request->subjectId,$request->maxMark)
                    ON DUPLICATE KEY UPDATE maxInternalMarks = VALUES(maxInternalMarks)";
            $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /* get Internal mark absent status
     * @param  $batchId $semId $subjectId $studentId
     * @throws ProfessionalException
     */
    public function getInternalAbsentStatus($batchId,$semId,$subjectId,$studentId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $studentId = $this->realEscapeString($studentId);
        $sql = "SELECT isAbsent AS studentInternalAbsent FROM internal_marks WHERE batchID = $batchId AND semID = $semId AND subjectID = $subjectId AND studentID = $studentId";
        try {
            $studentInternalAbsent = $this->executeQueryForObject($sql)->studentInternalAbsent;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $studentInternalAbsent;
    }
    /**
     * Check entry in internal_marks_submitted
     * @param  $batchID, $semId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getInternalMarksSubmittedSubjects($batchId,$semId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        try {
            $sql = "SELECT batchID,semID,subjectID,staffID FROM internal_marks_submitted WHERE batchID = $batchId AND semID = $semId";
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
      /**
     * Check entry in internal_marks
     * @param  $batchID, $semId
     * @throws ProfessionalException
     * @author sibin
     */
    public function getInternalMarksEnteredSubjects($batchId,$semId)
    {
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        try {
            $sql = "SELECT DISTINCT subjectID as subjectId,batchID as batchId,semID as semId,staffID as staffId FROM internal_marks WHERE batchID = $batchId AND semID = $semId";
            return $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * insert entry in internal_marks_submitted
     * @param  $batchID, $semId
     * @throws ProfessionalException
     * @author sibin
     */
    public function insertToMarkSubmitted($insertArray)
    {
        try {
                $insertStr = implode(",", $insertArray);
                $sql = "INSERT INTO internal_marks_submitted(batchID,semID,subjectID,staffID,staffType,created_by,unique_code) VALUES " . $insertStr . "";
                return $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
}