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 / 52
CRAP
0.00% covered (danger)
0.00%
0 / 1993
NbaCoPoService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 52
202050.00
0.00% covered (danger)
0.00%
0 / 1993
 __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 / 2
 getInstance
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 5
 getAssessmentTypeIdFromCode
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 getPseudoSubjectList
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 13
 getAssessmentTypeCodeFromId
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 14
 saveCoValuesForSubjectAssessments
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 deleteCoValuesOfSubjectAssessment
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 insertCoValuesForSubjectAssessments
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 savePoValuesForSubjectAssessments
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 8
 deletePoValuesOfSubjectAssessment
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 insertPoValuesForSubjectAssessments
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 getRulesForUniversityOrEndSemesterExamCoMapping
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 30
 calculatePoValuesFromCo
0.00% covered (danger)
0.00%
0 / 1
420.00
0.00% covered (danger)
0.00%
0 / 77
 deleteAllPOsOfAParticularAssessment
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 getAllCalculatedCosFromSubjectAssessmentTable
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 33
 calculateCoValuesForUniversityExam
0.00% covered (danger)
0.00%
0 / 1
342.00
0.00% covered (danger)
0.00%
0 / 80
 calculateCoValuesForEndSemesterExam
0.00% covered (danger)
0.00%
0 / 1
462.00
0.00% covered (danger)
0.00%
0 / 98
 calculateCoValuesForActivity
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 43
 calculateAssessmentCOsAndPOs
0.00% covered (danger)
0.00%
0 / 1
930.00
0.00% covered (danger)
0.00%
0 / 89
 getDescriptors
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 getDescriptorById
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getProgramOutcomeListByBatchId
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 6
 getProgramOutcomeListByDeptId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 calculateCoAttainmentValuesAndStoreItToTreeForStudentMarkEntryMethod
0.00% covered (danger)
0.00%
0 / 1
306.00
0.00% covered (danger)
0.00%
0 / 65
 calculateCoAttainmentValuesAndStoreItToTreeForStudentMarkEntryMethodForUniversity
0.00% covered (danger)
0.00%
0 / 1
240.00
0.00% covered (danger)
0.00%
0 / 63
 getMaximumCorrelationForCoursePoMatrix
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 getCoPoRelationMatrix
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 38
 getSubjectWiseCoListWithCoPoRelation
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 29
 createNewCoPoRelation
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 deleteAllCoPoRelationByCoId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 9
 deleteAllCoPoRelationByCoIdList
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 getPosAndJustificationDetails
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 19
 saveCoPoJustification
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 17
 getPosAndJustificationDetailsForPseudoSubject
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 32
 saveCoPoJustificationPseudoSubject
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 20
 calculateCoOfOnlineExam
0.00% covered (danger)
0.00%
0 / 1
506.00
0.00% covered (danger)
0.00%
0 / 124
 calculateCoOfPollsSurvey
0.00% covered (danger)
0.00%
0 / 1
462.00
0.00% covered (danger)
0.00%
0 / 121
 getAllOnlineExams
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 40
 getAllPollsSurvey
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 37
 getValidCos
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 11
 getPosByCoAndPo
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 10
 courseWiseAttainmentCalculation
0.00% covered (danger)
0.00%
0 / 1
4160.00
0.00% covered (danger)
0.00%
0 / 191
 courseWisePOAttainmentCalculation
0.00% covered (danger)
0.00%
0 / 1
2256.00
0.00% covered (danger)
0.00%
0 / 145
 constructSubjectAssessmentNodeAttainmentRequest
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 8
 saveCoValuesForSubjectAssessmentCourseWiseCalculetion
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 6
 deleteCoValuesOfSubjectAssessmentCourseWiseCalculation
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 insertCoValuesForSubjectAssessmentCourseWiseCalculetion
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 insertPoValuesForSubjectAssessmentCourseWiseCalculetion
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 15
 getAllCalculatedCourseWiseCosFromNodeCoValueTable
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 30
 courseWiseAttainmentCalculationForUniversity
0.00% covered (danger)
0.00%
0 / 1
2256.00
0.00% covered (danger)
0.00%
0 / 145
 calculateCoOfOnlineExamForSelectAllAnswerdAndMandatoryUnAswered
0.00% covered (danger)
0.00%
0 / 1
506.00
0.00% covered (danger)
0.00%
0 / 125
<?php
namespace com\linways\core\ams\professional\service\nba;
use com\linways\base\hooks\LinwaysHooks;
use com\linways\core\ams\professional\util\CommonUtil;
use com\linways\core\ams\professional\service\BaseService;
use com\linways\core\ams\professional\service\BatchService;
use com\linways\core\ams\professional\service\nba\PoGroupService;
use com\linways\core\ams\professional\constant\nba\AssessmentType;
use com\linways\core\ams\professional\util\nba\NbaCoPoServiceUtil;
use com\linways\core\ams\professional\service\UniversityExamService;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\mapper\nba\NbaCoPoServiceMapper;
use com\linways\core\ams\professional\request\nba\SearchPoGroupRequest;
use com\linways\core\ams\professional\service\nba\ExtraActivitiesService;
use com\linways\core\ams\professional\dto\nba\NBASubjectAssessmentCoValue;
use com\linways\core\ams\professional\dto\nba\NBASubjectAssessmentPoValue;
use com\linways\core\ams\professional\request\nba\GetExtraActivityRequest;
use com\linways\core\ams\professional\constant\nba\AttainmentCalculationType;
use com\linways\core\ams\professional\request\GetGradePointOfStudentExamRequest;
use com\linways\core\ams\professional\service\StudentService;
use com\linways\core\ams\professional\service\SubjectService;
use com\linways\core\ams\professional\request\nba\GetAllSubjectAssessmentNodeRequest;
use com\linways\core\ams\professional\constant\SettingsConstants;
use com\linways\core\ams\professional\service\CommonService;
use com\linways\core\ams\professional\constant\nba\NbaMethod;
class NbaCoPoService extends BaseService
{
    // /Condition 1 - Presence of a static member variable
    private static $_instance = null;
    private $mapper = [];
    // /Condition 2 - Locked down the constructor
    private function __construct()
    {
        $this->mapper = NbaCoPoServiceMapper::getInstance()->getMapper();
    }
    // 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;
    }
    public function getAssessmentTypeIdFromCode($name)
    {
        $name = $this->realEscapeString($name);
        $assessmentType = null;
        $sql = "SELECT id from assessment_type WHERE code = '$name'";
        try {
            $assessmentType = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (!empty($assessmentType)) {
            return $assessmentType->id;
        }
        return null;
    }
    public function getPseudoSubjectList($hlndDeptId)
    {
        $hlndDeptId = $this->realEscapeString($hlndDeptId);
        $sql = "SELECT pseudosubjectID,subjectName,hdl_deptID from pseudosubjects where pseudosubjects.hdl_deptID = $hlndDeptId";
        try {
            $pseudoSubjectList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (!empty($pseudoSubjectList)) {
            return $pseudoSubjectList;
        }
        return null;
    }
    public function getAssessmentTypeCodeFromId($id)
    {
        $id = $this->realEscapeString($id);
        $assessmentType = null;
        $sql = "SELECT code from assessment_type WHERE id = '$id'";
        try {
            $assessmentType = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        if (!empty($assessmentType)) {
            return $assessmentType->code;
        }
        return null;
    }
    /**
     * To Do:
     * 1)Add update functionality
     * 2)There are many cases to be handled inorder to rewrite service as update...
     *         what happens when co mapping is deleted from an assessment
     *         what happens when an assessment is deleted altogether after a report 
     *         is calculated    
     *
     * @param [type] $assessmentCoList
     * @return void
     */
    public function saveCoValuesForSubjectAssessments($assessmentCoList)
    {
        if (empty($assessmentCoList)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN, 'Atleast 1 Co must be given');
        }
        $assessmentCo = $assessmentCoList[0];
        $this->deleteCoValuesOfSubjectAssessment($assessmentCo->assessmentId, $assessmentCo->assessmentTypeId, $assessmentCo->batchId, $assessmentCo->semId, $assessmentCo->subjectId);
        $this->insertCoValuesForSubjectAssessments($assessmentCoList);
    }
    private function deleteCoValuesOfSubjectAssessment($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId)
    {
        $sql = "";
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "DELETE FROM nba_subject_assessment_co_value WHERE assessment_id = '$assessmentId' AND assessment_type_id = '$assessmentTypeId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '$subjectId'";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * !!!Always Provide Assessments Of Same Type!!!
     *
     * @param NBASubjectAssessmentCoValue[] $assessmentCoList
     * @return void
     */
    private function insertCoValuesForSubjectAssessments($assessmentCoList)
    {
        $sql = "";
        $assessmentCoList = $this->realEscapeArray($assessmentCoList);
        $sql = "INSERT INTO `nba_subject_assessment_co_value` (`assessment_id`, `assessment_type_id`, `co_id`, `value`, `student_id`, `staff_id`, `batch_id`, `sem_id`, `subject_id`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`) VALUES ";
        $values = [];
        foreach ($assessmentCoList as $assessmentCo) {
            $values[] = "('$assessmentCo->assessmentId', '$assessmentCo->assessmentTypeId', '$assessmentCo->coId', '$assessmentCo->value', '$assessmentCo->studentId', '$assessmentCo->staffId', '$assessmentCo->batchId', '$assessmentCo->semId', '$assessmentCo->subjectId', '$assessmentCo->createdBy', UTC_TIMESTAMP(), '$assessmentCo->updatedBy', UTC_TIMESTAMP())";
        }
        $sql .= implode(',', $values);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * To Do:
     * 1)Add update functionality
     * 2)There are many cases to be handled inorder to rewrite service as update...
     *         what happens when co mapping is deleted from an assessment
     *         what happens when an assessment is deleted altogether after a report 
     *         is calculated    
     *
     * @param [type] $assessmentPoList
     * @return void
     */
    public function savePoValuesForSubjectAssessments($assessmentPoList)
    {
        if (empty($assessmentPoList)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_PO_ASSESSMENT_LIST_GIVEN, 'Atleast 1 Po must be given');
        }
        $assessmentPo = $assessmentPoList[0];
        $this->deletePoValuesOfSubjectAssessment($assessmentPo->assessmentId, $assessmentPo->assessmentTypeId, $assessmentPo->batchId, $assessmentPo->semId, $assessmentPo->subjectId);
        $this->insertPoValuesForSubjectAssessments($assessmentPoList);
    }
    private function deletePoValuesOfSubjectAssessment($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId)
    {
        $sql = "";
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "DELETE FROM nba_subject_assessment_po_value WHERE assessment_id = '$assessmentId' AND assessment_type_id = '$assessmentTypeId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '$subjectId'";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * !!!Always Provide Assessments Of Same Type!!!
     *
     * @param NBASubjectAssessmentPoValue[] $assessmentPoList
     * @return void
     */
    private function insertPoValuesForSubjectAssessments($assessmentPoList)
    {
        $sql = "";
        $assessmentPoList = $this->realEscapeArray($assessmentPoList);
        $sql = "INSERT INTO `nba_subject_assessment_po_value` (`assessment_id`, `assessment_type_id`, `po_id`, `value`, `student_id`, `staff_id`, `batch_id`, `sem_id`, `subject_id`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`) VALUES ";
        $values = [];
        foreach ($assessmentPoList as $assessmentPo) {
            $values[] = "('$assessmentPo->assessmentId', '$assessmentPo->assessmentTypeId', '$assessmentPo->poId', '$assessmentPo->value', '$assessmentPo->studentId', '$assessmentPo->staffId', '$assessmentPo->batchId', '$assessmentPo->semId', '$assessmentPo->subjectId', '$assessmentPo->createdBy', UTC_TIMESTAMP(), '$assessmentPo->updatedBy', UTC_TIMESTAMP())";
        }
        $sql .= implode(',', $values);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getRulesForUniversityOrEndSemesterExamCoMapping($batchId, $semId, $subjectId)
    {
        $sql = "";
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $responseList = [];
        $sql = "SELECT 
                    id,
                    co_id AS coId,
                    po_id AS poId,
                    value,
                    from_percent AS fromPercent,
                    to_percent AS toPercent,
                    distribution_type AS distributionType,
                    subject_id AS subjectId,
                    sem_id AS semId,
                    batch_id AS batchId,
                    staff_id AS staffId
                FROM
                    nba_university_exam_co_mapping_rules
                WHERE
                    subject_id = '$subjectId' AND batch_id = '$batchId'
                        AND sem_id = '$semId'";
        try {
            $responseList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $responseList;
    }
    /**
     * method to calculate po values of all students for a particular assessment
     * when an assessment is given.
     *
     * @param [int] $assessmentId
     * @param [int] $assessmentTypeId
     * @param [int] $batchId
     * @param [int] $semId
     * @param [int] $subjectId
     * @param [int] $createdBy
     * @return void
     */
    public function calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId)
    {
        $createdBy = null;
        try {
            $createdBy = $_SESSION['staffID'];
        } catch (\Exception $e) {
            error_log('SESSION[staffID] is not defined... in calculatePoValuesFromCo');
        }
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $nodeId = $this->realEscapeString($nodeId);
        if (empty($subjectId) || empty($batchId) || empty($semId) || empty($assessmentId) || empty($assessmentTypeId)) {
            throw new ProfessionalException(ProfessionalException::INSUFFICIENT_PARAMETERS, "Sorry! Couldn't calculate PO values...");
        }
        $this->deleteAllPOsOfAParticularAssessment($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId);
        $studentList = $this->getAllCalculatedCosFromSubjectAssessmentTable($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId);//result is mapped as student
        if (empty($studentList)) {
            return null;
        }
        $sql = "";
        $sql = "INSERT INTO `nba_subject_assessment_po_value` (`assessment_id`, `assessment_type_id`, `po_id`, `value`, `student_id`, `staff_id`, `batch_id`, `sem_id`, `subject_id`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`) VALUES ";
        foreach ($studentList as $student) {
            foreach ($student->poList as $po) {
                if (empty($po->coList)) {
                    continue;
                }
                $poValueInPercent = 0;
                $sumOfDescriptors = 0;
                $sumOfDescriptors = NbaCoPoServiceUtil::findSumOfCoDescriptors($po->coList);
                foreach ($po->coList as $co) {
                    $poValueInPercent += ($co->coContribution) * ($co->descriptorValue / $sumOfDescriptors);
                }
                $values[] = "('$assessmentId', '$assessmentTypeId', '$po->id', '$poValueInPercent', '$student->id', '$po->staffId', '$batchId', '$semId', '$subjectId', '$createdBy', UTC_TIMESTAMP(), '$createdBy', UTC_TIMESTAMP())";
            }
        }
        $sql .= implode(",", $values);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        $courseWisePoList = $this->getAllCalculatedCourseWiseCosFromNodeCoValueTable($nodeId, $batchId, $semId, $subjectId);//result is mapped as student
        if (empty($courseWisePoList)) {
            return null;
        }
        $sql = "";
        $sql = "INSERT INTO `nba_course_wise_node_po_value` (`node_id`, `po_id`, `value`, `staff_id`, `batch_id`, `sem_id`, `subject_id`, `createdBy`, `createdDate`, `updatedBy`, `updatedDate`) VALUES ";
        foreach ($courseWisePoList as $po) {
            if (empty($po->coList)) {
                continue;
            }
            $poValueInPercent = 0;
            $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
            if($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                $maxDescriptorValue = CoPoAttainmentService::getInstance()->getMaxDescriptorDetails();
                foreach ($po->coList as $co) {
                    $poValueInPercent += ($co->coContribution) * ($co->descriptorValue / $maxDescriptorValue->descriptorValue);
                }
                $poValueInPercent = $poValueInPercent/count($po->coList);
            }else{
                $sumOfDescriptors = 0;
                $sumOfDescriptors = NbaCoPoServiceUtil::findSumOfCoDescriptors($po->coList);
                foreach ($po->coList as $co) {
                    $poValueInPercent += ($co->coContribution) * ($co->descriptorValue / $sumOfDescriptors);
                }
            }
            $valuesCourseWise[] = "('$nodeId', '$po->id', '$poValueInPercent', '$po->staffId', '$batchId', '$semId', '$subjectId', '$createdBy', UTC_TIMESTAMP(), '$createdBy', UTC_TIMESTAMP())";
        }
        
        $sql .= implode(",", $valuesCourseWise);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    private function deleteAllPOsOfAParticularAssessment($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId)
    {
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $sql = "";
        $sql = "DELETE FROM nba_subject_assessment_po_value WHERE assessment_id = '$assessmentId'  AND assessment_type_id = $assessmentTypeId AND batch_id = $batchId AND sem_id = $semId AND subject_id = $subjectId";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * 
     *
     * @param [type] $assessmentId
     * @param [type] $assessmentTypeId
     * @param [type] $batchId
     * @param [type] $semId
     * @param [type] $subjectId
     * @return void
     */
    public function getAllCalculatedCosFromSubjectAssessmentTable($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId)
    {
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $sql = "SELECT 
                    cpr.nba_program_outcome_id AS poId,
                    cpr.nba_course_outcome_id AS coId,
                    sacv.student_id AS studentId,
                    sacv.staff_id as staffId,
                    sacv.value AS coContribution,
                    d.weightage
                FROM
                    nba_subject_assessment_co_value sacv
                        INNER JOIN
                    nba_co_po_relation cpr ON cpr.nba_course_outcome_id = sacv.co_id
                        INNER JOIN
                    nba_descriptor d ON d.id = cpr.nba_descriptor_id
                WHERE
                    sacv.assessment_id = '$assessmentId'
                        AND sacv.assessment_type_id = '$assessmentTypeId'
                        AND sacv.batch_id = '$batchId'
                        AND sacv.sem_id = '$semId'
                        AND sacv.subject_id = '$subjectId'";
        $responseList = [];
        try {
            $responseList = $this->executeQueryForList($sql, $this->mapper[NbaCoPoServiceMapper::GET_CO_VALUES_FOR_AN_ASSESSMENT]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $responseList;
    }
    public function calculateCoValuesForUniversityExam($examId, $batchId, $semId, $subjectId, $nodeId)
    {
        $createdBy = null;
        try {
            $createdBy = $_SESSION['staffID'];
        } catch (\Exception $e) {
            error_log('SESSION[staffID] is not defined... in calculateCoValuesForUniversityExam');
        }
        if (empty($examId)) {
            throw new ProfessionalException(ProfessionalException::INSUFFICIENT_PARAMETERS, "Exam details not provided. Couldn't calculate co for university exam.");
        }
        //Currently It Only uses data from university_studentgrade table, in future we may want to take actual marks from universityMarks Table.
        $examId = $this->realEscapeString($examId);
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $nodeId = $this->realEscapeString($nodeId);
        $assessmentTypeId = $this->getAssessmentTypeIdFromCode(AssessmentType::UNIVERSITY_EXAM);
        $examRulesOfUniversity = $this->getRulesForUniversityOrEndSemesterExamCoMapping($batchId, $semId, $subjectId);
        if (empty($examRulesOfUniversity)) {
            error_log("Couldn't calculate CO for given exam since there are no rules defined for this subjectId :$subject, semId:$semId, batchId:$batchId");
            return null;
        }
        if (!$examRulesOfUniversity[0]->coId && !$examRulesOfUniversity[0]->poId) {
            throw new ProfessionalException(ProfessionalException::DATA_EMPTY, "University Exam Rule Is Not Properly Defined.");
        }
        $mapToCo = $examRulesOfUniversity[0]->coId ? true : false;
        
        $getGradePointRequest = new GetGradePointOfStudentExamRequest ();
        $getGradePointRequest->examId = $examId;
        $getGradePointRequest->batchId = $batchId;
        $getGradePointRequest->semId = $semId;
        $getGradePointRequest->subjectId = $subjectId;
        $studentUniversityMarks = UniversityExamService::getInstance()->getGradePointsOfStudentsForAnExam($getGradePointRequest);
        if (empty($studentUniversityMarks)) {
            error_log("No Student Mark Records For UniversityExam With examId :$examId,subjectId :$subject, semId:$semId, batchId:$batchId");
            return null;
        }
        $assessmentList = [];
        //As of now we use average of the percentFrom and percentTo to
        //calculate co of a student
        foreach ($studentUniversityMarks as $studentMark) {
            foreach ($examRulesOfUniversity as $rule) {
                if (($studentMark->averagePercent >= $rule->fromPercent && $studentMark->averagePercent < $rule->toPercent) || ($studentMark->averagePercent == 100 && $rule->toPercent == 100)) {
                    if ($mapToCo) {
                        $nbaSubjectAssessmentValue = new NBASubjectAssessmentCoValue();
                    } else {
                        $nbaSubjectAssessmentValue = new NBASubjectAssessmentPoValue();
                    }
                    $nbaSubjectAssessmentValue->assessmentId = $examId;
                    $nbaSubjectAssessmentValue->assessmentTypeId = $assessmentTypeId;
                    if ($mapToCo) {
                        $nbaSubjectAssessmentValue->coId = $rule->coId;
                    } else {
                        $nbaSubjectAssessmentValue->poId = $rule->poId;
                    }
                    $nbaSubjectAssessmentValue->value = $studentMark->averagePercent;
                    $nbaSubjectAssessmentValue->studentId = $studentMark->studentId;
                    $nbaSubjectAssessmentValue->staffId = $createdBy;//Here staff is 
                    $nbaSubjectAssessmentValue->batchId = $studentMark->batchId;
                    $nbaSubjectAssessmentValue->semId = $studentMark->semId;
                    $nbaSubjectAssessmentValue->subjectId = $studentMark->subjectId;
                    $nbaSubjectAssessmentValue->createdBy = $createdBy;
                    $nbaSubjectAssessmentValue->updatedBy = $createdBy;
                    $assessmentList[] = $nbaSubjectAssessmentValue;
                }
            }
        }
        if(empty($assessmentList)){
            error_log("Couldn't calculate CO for given exam since there were no valid results for exam with examId:$examId, subjectId :$subject, semId:$semId, batchId:$batchId");
            return null;
        }
        if ($mapToCo) {
            $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculationForUniversity($assessmentList, $nodeId);
            $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
            $this->saveCoValuesForSubjectAssessments($assessmentList);
            $this->calculatePoValuesFromCo($examId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
        } else {
            $assessmentCo = $assessmentList[0];
            $this->deleteCoValuesOfSubjectAssessment($assessmentCo->assessmentId, $assessmentCo->assessmentTypeId, $assessmentCo->batchId, $assessmentCo->semId, $assessmentCo->subjectId);
            $this->savePoValuesForSubjectAssessments($assessmentList);
            $assessmentCourseWisePOList=$this->courseWisePOAttainmentCalculation($assessmentList, $nodeId);
            $this->insertPoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWisePOList);
        }
    }
    public function calculateCoValuesForEndSemesterExam($examId, $batchId, $semId, $subjectId, $nodeId)
    {
        $createdBy = null;
        try {
            $createdBy = $_SESSION['staffID'];
        } catch (\Exception $e) {
            error_log('SESSION[staffID] is not defined... in calculateCoValuesForEndSemesterExam');
        }
        if (empty($examId)) {
            throw new ProfessionalException(ProfessionalException::INSUFFICIENT_PARAMETERS, "Exam details not provided. Couldn't calculate co for end semester exam.");
        }
        $examId = $this->realEscapeString($examId);
        $subjectId = $this->realEscapeString($subjectId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $nodeId = $this->realEscapeString($nodeId);
        $assessmentTypeId = $this->getAssessmentTypeIdFromCode(AssessmentType::END_SEMESTER_EXAM);
        $examRulesOfEndSemester = $this->getRulesForUniversityOrEndSemesterExamCoMapping($batchId, $semId, $subjectId);
        if (empty($examRulesOfEndSemester)) {
            error_log("Couldn't calculate CO for given exam since there are no rules defined for this subjectId :$subject, semId:$semId, batchId:$batchId");
            return null;
        }
        if (!$examRulesOfEndSemester[0]->coId && !$examRulesOfEndSemester[0]->poId) {
            throw new ProfessionalException(ProfessionalException::DATA_EMPTY, "End Semester Exam Rule Is Not Properly Defined.");
        }
        $mapToCo = $examRulesOfEndSemester[0]->coId ? true : false;
        $studentEndSemesterExamMarks = UniversityExamService::getInstance()->getStudentEndSemesterExamMarks($examId, $batchId, $semId, $subjectId);
        if (empty($studentEndSemesterExamMarks)) {
            error_log("No Student Mark Records For end semester exam With examId :$examId,subjectId :$subjectId, semId:$semId, batchId:$batchId");
            return null;
        }
        $endSemesterExamMark = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_END_SEMESTER_MARK_SELECTION);
        if($endSemesterExamMark==NbaMethod::OBE_END_SEMESTER_MARK_NOT_NORMALIZED){
            try {
            $sql="SELECT 
                e.examTotalMarks, ims.maxInternalMarks
            FROM
                exam e
                    INNER JOIN
                internal_marks_settings ims ON ims.batchID = e.batchID
                    AND ims.semID = e.semID
                    AND ims.subjectID = e.subjectID
            WHERE
                examID = $examId";           
                $totalMark = $this->executeQueryForObject($sql);
            } catch (\Exception $e) {
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
            $combinedMaximumMarks= $totalMark->examTotalMarks+$totalMark->maxInternalMarks;
        }       
        
        $assessmentList = [];
        //As of now we use average of the percentFrom and percentTo to
        //calculate co of a student
        foreach ($studentEndSemesterExamMarks as $studentMark) {
            if($endSemesterExamMark!=NbaMethod::OBE_END_SEMESTER_MARK_NOT_NORMALIZED){
                $combinedMaximumMarks = (double) $studentMark->maxMark; 
            }
            $studentMark->totalMark= (((double) $studentMark->totalMark)/$combinedMaximumMarks)*100;
            foreach ($examRulesOfEndSemester as $rule) {
                if (($studentMark->totalMark >= $rule->fromPercent && $studentMark->totalMark < $rule->toPercent) || ($studentMark->totalMark == 100 && $rule->toPercent == 100)) {
                    if ($mapToCo) {
                        $nbaSubjectAssessmentValue = new NBASubjectAssessmentCoValue();
                    } else {
                        $nbaSubjectAssessmentValue = new NBASubjectAssessmentPoValue();
                    }
                    $nbaSubjectAssessmentValue->assessmentId = $examId;
                    $nbaSubjectAssessmentValue->assessmentTypeId = $assessmentTypeId;
                    if ($mapToCo) {
                        $nbaSubjectAssessmentValue->coId = $rule->coId;
                    } else {
                        $nbaSubjectAssessmentValue->poId = $rule->poId;
                    }
                    $nbaSubjectAssessmentValue->value = $studentMark->totalMark;
                    $nbaSubjectAssessmentValue->studentId = $studentMark->studentId;
                    $nbaSubjectAssessmentValue->staffId = $createdBy;//Here staff is 
                    $nbaSubjectAssessmentValue->batchId = $studentMark->batchId;
                    $nbaSubjectAssessmentValue->semId = $studentMark->semId;
                    $nbaSubjectAssessmentValue->subjectId = $studentMark->subjectId;
                    $nbaSubjectAssessmentValue->createdBy = $createdBy;
                    $nbaSubjectAssessmentValue->updatedBy = $createdBy;
                    $assessmentList[] = $nbaSubjectAssessmentValue;
                }
            }
        }
        if(empty($assessmentList)){
            error_log("Couldn't calculate CO for given exam since there were no valid results for exam with examId:$examId, subjectId :$subject, semId:$semId, batchId:$batchId");
            return null;
        }
        if ($mapToCo) {
            $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculation($assessmentList, $nodeId);
            $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
            $this->saveCoValuesForSubjectAssessments($assessmentList);
            $this->calculatePoValuesFromCo($examId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
        } else {
            $assessmentCo = $assessmentList[0];
            $this->deleteCoValuesOfSubjectAssessment($assessmentCo->assessmentId, $assessmentCo->assessmentTypeId, $assessmentCo->batchId, $assessmentCo->semId, $assessmentCo->subjectId);
            $this->savePoValuesForSubjectAssessments($assessmentList);
            $assessmentCourseWisePOList=$this->courseWisePOAttainmentCalculation($assessmentList, $nodeId);
            $this->insertPoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWisePOList);
        }
    }
    // wip
    public function calculateCoValuesForActivity($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId) {
        $request = new GetExtraActivityRequest();
        $request->subjectId = $this->realEscapeString($subjectId);
        $request->batchId   = $this->realEscapeString($batchId);
        $request->semId     = $this->realEscapeString($semId);
        $request->nodeId    = $this->realEscapeString($nodeId);
        $assessmentId       = $this->realEscapeString($assessmentId);
        $assessmentTypeId   = $this->realEscapeString($assessmentTypeId);
        $staffId = $_SESSION['staffID'];
        $activity = ExtraActivitiesService::getInstance()->getActivityById ( $assessmentId );
        $courseOutcomes = ExtraActivitiesService::getInstance()->getCoPercentageOfActivity ( $request, $assessmentId );
        if(empty($courseOutcomes)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN, "Couldn't calculate CO for activity - ".$activity->activity_name.", since there were no valid COs are mapped.");
        }
        $students = ExtraActivitiesService::getInstance()->getActivityStudentDetailsById ( $assessmentId , $batchId, $semId, $subjectId, $staffId);
        foreach ( $courseOutcomes as $co ) {
            foreach ( $students as $student ) {
                if ( $activity->use_in_co ) {
                    $nbaSubjectAssessmentValue = new NBASubjectAssessmentCoValue();
                } else {
                    $nbaSubjectAssessmentValue = new NBASubjectAssessmentPoValue();
                }
                $value = $student->isAttended == 1 ? 100 : 0;
                $nbaSubjectAssessmentValue->coId         = $co->co_id;
                $nbaSubjectAssessmentValue->value        = $value;
                $nbaSubjectAssessmentValue->semId        = $request->semId;
                $nbaSubjectAssessmentValue->staffId      = $staffId;
                $nbaSubjectAssessmentValue->batchId      = $request->batchId;
                $nbaSubjectAssessmentValue->studentId    = $student->studentID;
                $nbaSubjectAssessmentValue->subjectId    = $request->subjectId;
                $nbaSubjectAssessmentValue->createdBy    = $staffId;
                $nbaSubjectAssessmentValue->updatedBy    = $staffId;
                $nbaSubjectAssessmentValue->assessmentId = $assessmentId;
                $nbaSubjectAssessmentValue->assessmentTypeId = $assessmentTypeId;
                $assessmentList[] = $nbaSubjectAssessmentValue;
            }
        }
        if ( $activity->use_in_co ) {
            $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculation($assessmentList, $nodeId);
            $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
            $this->saveCoValuesForSubjectAssessments($assessmentList);
            $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
        }
    }
    /**
     * method to be called during tree traversal
     *
     * @param [type] $assessmentId
     * @param [type] $assessmentTypeId
     * @param [type] $batchId
     * @param [type] $semId
     * @param [type] $subjectId
     * @param [type] $nodeId
     * @return void
     */
    public function calculateAssessmentCOsAndPOs($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId)
    {
        if (empty($assessmentId) || empty($assessmentTypeId) || empty($batchId) || empty($semId) || empty($subjectId) || empty($nodeId)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS, 'Assessment details is empty');
        }
        $hooks = LinwaysHooks::getInstance();
        $assessmentType = $this->getAssessmentTypeCodeFromId($assessmentTypeId);
        $hookParams = [];
        $hookParams = ["assessmentId" => $assessmentId, "batchId" => $batchId, "semId" => $semId, "subjectId" => $subjectId, "nodeId" => $nodeId];
        switch ($assessmentType) {
            case AssessmentType::ASSIGNMENT:
                try {
                    $hooks->do_action('calculate_co_of_assignment', $hookParams);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
            case AssessmentType::EXAM:
                try {
                    $hooks->do_action('calculate_co_of_exam', $hookParams);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
            case AssessmentType::QUIZ:
                try {
                    $hooks->do_action('calculate_co_of_quiz', $hookParams);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
            case AssessmentType::UNIVERSITY_EXAM:
                try {
                    $this->calculateCoValuesForUniversityExam($assessmentId, $batchId, $semId, $subjectId, $nodeId);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                //Here We Dont calculate Po Values From Co Since For University Exam it can be directly mapped to PO.. Po calculation is done inside calculateCoValuesForUniversityExam service
                break;
            case AssessmentType::END_SEMESTER_EXAM:
                try {
                    $this->calculateCoValuesForEndSemesterExam($assessmentId, $batchId, $semId, $subjectId, $nodeId);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                //Here We Dont calculate Po Values From Co Since For End Semester Exam it can be directly mapped to PO.. Po calculation is done inside calculateCoValuesForEndSemesterExam service
                break;
            case AssessmentType::ONLINE_EXAM:
                try {
                    $coValueCalculationMethod = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_SELECT_QUESTIONS_IN_THE_ONLINE_EXAM_FOR_OBE_CALCULATION);
                    if($coValueCalculationMethod == NbaMethod::SELECT_ALL_ANSWERED_AND_MANDATORY_UNANSWERED_QUESTIONS ){
                        $this->calculateCoOfOnlineExamForSelectAllAnswerdAndMandatoryUnAswered($assessmentId, $batchId, $semId, $subjectId, $nodeId);
                    }else{
                        $this->calculateCoOfOnlineExam($assessmentId, $batchId, $semId, $subjectId, $nodeId);
                    }
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                //Here We Dont calculate Po Values From Co Since For End Semester Exam it can be directly mapped to PO.. Po calculation is done inside calculateCoValuesForEndSemesterExam service
                $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
                
            case AssessmentType::POLLS_SURVEY:
                try {
                    $this->calculateCoOfPollsSurvey($assessmentId, $batchId, $semId, $subjectId, $nodeId);
                } catch (\Exception $e) {
                    if ($e->getCode() != ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN) {
                        throw new ProfessionalException($e->getCode(), $e->getMessage());
                    }
                }
                //Here We Dont calculate Po Values From Co Since For End Semester Exam it can be directly mapped to PO.. Po calculation is done inside calculateCoValuesForEndSemesterExam service
                $this->calculatePoValuesFromCo($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
            
            case AssessmentType::ACTIVITY:
                $this->calculateCoValuesForActivity($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId, $nodeId);
                break;
            default:
                throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER, "Please provide a valid assessment type.");
        }
    }
    /**
     * Get all descriptors
     * @throws ProfessionalExcepton
     * @return Array $descriptors
     * @author Vishnu M
     */
    public function getDescriptors () {
        $descriptors = null;
        try {
            $sql = "SELECT id, descriptorName, descriptorDesc, weightage FROM nba_descriptor ORDER BY weightage DESC";
            $descriptors = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $descriptors;
    }
        /**
     * Get descriptor by id
     * @throws ProfessionalExcepton
     * @return Array $descriptors
     * @author Vishnu M
     */
    public function getDescriptorById ($id) {
        $descriptor = null;
        $id = $this->realEscapeString($id);
        try {
            $sql = "SELECT id, descriptorName, descriptorDesc, weightage FROM nba_descriptor WHERE id=$id";
            $descriptor = $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $descriptor;
    }
    /**
     * Undocumented function
     *
     * @param [type] $batchId
     * @return void
     */
    public function getProgramOutcomeListByBatchId($batchId, $includePo = true, $includePso = true){
        $poList = [];
        $batchId = $this->realEscapeString($batchId);
        
        $groupDetails = PoGroupService::getInstance()->getGroupDetailsByBatchId($batchId);
        $poList = PoGroupService::getInstance()->getPoListByGroupId($groupDetails->id, $includePo, $includePso);
        // //if there are no pos in group fall back to default
        // if(empty($poList)){
        //     $batchDetails = BatchService::getInstance()->getBatchDetailsById($batchId);
        //     $poList = $this->getProgramOutcomeListByDeptId($batchDetails->deptId);
        // }
        return $poList;
    }
    /**
     * Undocumented function
     *
     * @param integer $deptId
     * @return void
     */
    public function getProgramOutcomeListByDeptId($deptId){
        $sql = "";
        $deptId = $this->realEscapeString($deptId);
        $poList = [];
        
        $sql = "SELECT t1.id, t1.poCode, t1.poName, t1.poDesc, t1.order_no FROM nba_program_outcome  WHERE department_id = $deptId";
        try {
            $poList = $this->executeQueryForList($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $poList;
    }
    public function calculateCoAttainmentValuesAndStoreItToTreeForStudentMarkEntryMethod($request){
        $request = $this->realEscapeObject($request);
        
        try {
            $coList = NbaStudentMarkEntryMethodService::getInstance()->getCoWiseStudentListForAttainmentCalculation($request);
        } catch (\Exception $e) {
            
        }
        
        if(empty($coList)){
            return null;
        }
        try {
            $totalNumberOfStudents = BatchService::getInstance()->getBatchStudentCount($request->batchId);
        } catch (\Exception $e) {
            
        }
        if(empty($totalNumberOfStudents) || $totalNumberOfStudents == 0){
            return null;
        }
        
        $coAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($request->batchId, $request->semId, $request->subjectId);
        if (empty($coAttainmentRuleDetails)) {
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }
        $coAttainmentRule = $coAttainmentRuleDetails->rule;
        $coAttainmentRule->goals = CoPoAttainmentService::getInstance()->populateDescriptorValuesFromIds($coAttainmentRule->goals);
        if($coAttainmentRule->type != AttainmentCalculationType::NSTUDENT_NPERCENT){
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }
        foreach($coList as $co){
            $attainmentForAllAssessment = 0;
            foreach($co->assessmentTypeList->assessmentList as $assessment){
                $attainmentForQuestions = 0;
                foreach($assessment->questionList as $question){
                    $question->studentMarkList = CommonUtil::getPercentageValueForAnAttributeInObjectList($question->studentMarkList , $question->maxMark, "marks");
                    foreach($coAttainmentRule->goals as $goal){
                        $numberOfStudentsWithSpecifiedAttainment = CommonUtil::getNumberOfElementsInAnObjectListByComparingAnAttributeWithGivenValue($question->studentMarkList, "marksInPercentage", ">=", $goal->attain_percent);
                        $percentageOfStudentsWithSpecifiedAttainment = 0;
                        if($totalNumberOfStudents){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalNumberOfStudents)*100;
                        }
                        if($percentageOfStudentsWithSpecifiedAttainment >= $goal->student_percent){
                            if($goal->descriptor->weightage){
                                $attainmentForQuestions += $goal->descriptor->weightage;
                            }
                            break;
                        }
                    }
                }
                if(!empty($assessment->questionList)){
                    $attainmentForQuestions = $attainmentForQuestions/sizeof($assessment->questionList);
                }
                $attainmentForAllAssessment += $attainmentForQuestions;
            }
            if(!empty($co->assessmentTypeList->assessmentList)){
                $attainmentForAllAssessment = $attainmentForAllAssessment/sizeof($co->assessmentTypeList->assessmentList);
            }
            $coAttainment = new NBASubjectAssessmentCoValue();
            $coAttainment->coId = $co->id;
            $coAttainment->value = $attainmentForAllAssessment;
            $coAttainment->nodeId = $request->nodeId;
            $coAttainment->batchId = $request->batchId;
            $coAttainment->semId = $request->semId;
            $coAttainment->staffId = $request->staffId;
            $coAttainment->subjectId = $request->subjectId;
            $coAttainment->createdBy = $request->createdBy;
            $coAttainment->updatedBy = $request->updatedBy;
                
        
            NBAPOAttainmentTreeService::getInstance()->addSubjectLeafNodeCoValueDirectly($coAttainment);
        }
    }
    
    public function calculateCoAttainmentValuesAndStoreItToTreeForStudentMarkEntryMethodForUniversity($request){
        $request = $this->realEscapeObject($request);
        $coList = [];
        $allCourseOutcomeList =  [];
        $totalNumberOfStudents  = 0;
        try {
            $coList = NbaStudentMarkEntryMethodService::getInstance()->getCoWiseStudentListForAttainmentCalculation($request);
        } catch (\Exception $e) {
            $coList = []; 
        }
        if(empty($coList)){
            return null;
        }
        try{
            $allCourseOutcomeList = NbaCoService::getInstance()->getAllCosBySubjectIdBatchIdAndSemId($request->subjectId, $request->batchId, $request->semId);
        }catch(\Exception $e){
            $allCourseOutcomeList =  [];
        }
        if(empty($allCourseOutcomeList)){
            return null;
        }
        try {
            $totalNumberOfStudents = BatchService::getInstance()->getBatchStudentCount($request->batchId);
        } catch (\Exception $e) {
            
        }
        if(empty($totalNumberOfStudents) || $totalNumberOfStudents == 0){
            return null;
        }
        $coAttainmentRuleDetails = UniversityExamCoPoRuleService::getInstance()->getRulesForUniversityAttainment($request->batchId, $request->semId, $request->subjectId);
        if (empty($coAttainmentRuleDetails)) {
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }
        $coAttainmentRule = $coAttainmentRuleDetails->rule;
        $coAttainmentRule->slabs = CoPoAttainmentService::getInstance()->populateDescriptorValuesFromIds($coAttainmentRule->slabs);
        if($coAttainmentRule->type != AttainmentCalculationType::SLABBED_UNIVERSITY_AVERAGE){
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }
        $questionList = $coList[0]->assessmentTypeList->assessmentList[0]->questionList[0];
        $numberOfStudentsWithMoreThanUniversityAverage = CommonUtil::getNumberOfElementsInAnObjectListByComparingAnAttributeWithGivenValue($questionList->studentMarkList, "marks", ">=", $questionList->universityAverage);
        $percentageOfStudentsWithMoreThanUniversityAverage = 0;
        if($totalNumberOfStudents){
            $percentageOfStudentsWithMoreThanUniversityAverage = ($numberOfStudentsWithMoreThanUniversityAverage/$totalNumberOfStudents)*100;
        }
        $coAttainmentValue = 0;
        foreach($coAttainmentRule->slabs as $slab){
            if($percentageOfStudentsWithMoreThanUniversityAverage >= $slab->percent){
                $coAttainmentValue = $slab->descriptor->weightage?$slab->descriptor->weightage:0;
                break;
            }
        }
        foreach($allCourseOutcomeList as $co){
        
            $coAttainment = new NBASubjectAssessmentCoValue();
            $coAttainment->coId = $co->id;
            $coAttainment->value = $coAttainmentValue;
            $coAttainment->nodeId = $request->nodeId;
            $coAttainment->batchId = $request->batchId;
            $coAttainment->semId = $request->semId;
            $coAttainment->staffId = $request->staffId;
            $coAttainment->subjectId = $request->subjectId;
            $coAttainment->createdBy = $request->createdBy;
            $coAttainment->updatedBy = $request->updatedBy;
            
            NBAPOAttainmentTreeService::getInstance()->addSubjectLeafNodeCoValueDirectly($coAttainment);
        }
        
        
    }
    public function getMaximumCorrelationForCoursePoMatrix($poId,$batchId,$semId,$subjectId){
        $sql = "";
        $weightage = null;
        $poId = $this->realEscapeObject($poId);
        $batchId = $this->realEscapeObject($batchId);
        $semId = $this->realEscapeObject($semId);
        $subjectId = $this->realEscapeObject($subjectId);
        $sql = "SELECT MAX(nd.weightage) as weightage FROM nba_program_outcome po INNER JOIN nba_co_po_relation cpr ON cpr.nba_program_outcome_id = po.id INNER JOIN nba_course_outcome co ON co.id = cpr.nba_course_outcome_id INNER JOIN nba_descriptor nd ON nd.id = cpr.nba_descriptor_id WHERE po.id = '$poId' and co.batchID ='$batchId' and co.semID = '$semId' and co.subjectID = '$subjectId'  ";
        try {
            $weightage = $this->executeQueryForObject($sql)->weightage;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $weightage;
    }
     /**
     * Returns CO PO relation 
     *
     * @param RequestForAttainment $request
     * @return void
     */
    public function getCoPoRelationMatrix($request){
        $request = $this->realEscapeObject($request);
        $poList = [];
        $sql = "";
        $sql = "SELECT 
                    co.id AS coId,
                    co.code AS coCode,
                    po.id AS poId,
                    po.poCode,
                    po.poName,
                    po.department_id AS poDepartmentId,
                    ndesc.id AS descriptorId,
                    ndesc.descriptorName,
                    ndesc.weightage AS descriptorWeightage            
                FROM
                    nba_course_outcome co
                        INNER JOIN
                    nba_co_po_relation cpr ON co.id = cpr.nba_course_outcome_id
                        INNER JOIN
                    nba_program_outcome po ON po.id = cpr.nba_program_outcome_id
                        INNER JOIN
                    nba_descriptor ndesc ON cpr.nba_descriptor_id = ndesc.id
                WHERE
                    co.batchID = '$request->batchId' AND co.subjectID = '$request->subjectId'
                        AND co.semID = '$request->semId";
                if($request->isPSO == 0){
                    $sql .= " AND po.isPso = 0 ";
                }
                if( $request->isPSO == 1){
                    $sql .= " AND po.isPso = 1 ";
                }
                $sql .= "ORDER BY po.order_no";
                try{
                    $poList = $this->executeQueryForList($sql, $this->mapper[NbaCoPoServiceMapper::GET_CO_PO_RELATION_MATRIX]);
                }catch(\Exception $e){
                    throw new ProfessionalException($e->getCode(), $e->getMessage());
                }
                return $poList;
    }
    /**
     * get subject wise co list
     *
     * @param GetSubjectWiseCoListWithCoPoRelationRequest $request
     * @return void
     */
    public function getSubjectWiseCoListWithCoPoRelation($request){
        $request = $this->realEscapeObject($request);
        $sql = "SELECT
                    co.id as co_id,
                    co.code as co_code,
                    co.objective as co_objective,
                    co.description as co_description,
                    co.order_no as co_order_number,
                    co.subjectID as co_subjectId,
                    co.staffID as co_staffId,
                    co.batchID as co_batchId,
                    co.semID as co_semId,
                    cpr.id AS cpr_id,
                    cpr.nba_course_outcome_id AS cpr_coId,
                    cpr.nba_program_outcome_id AS cpr_poId,
                    cpr.nba_descriptor_id AS cpr_descriptor_id
                FROM
                    nba_course_outcome co
                        INNER JOIN
                    nba_co_po_relation cpr ON cpr.nba_course_outcome_id = co.id
                WHERE
                    co.subjectID = '$request->subjectId' AND co.batchID = '$request->batchId'
                        AND co.semID = '$request->semId' ORDER BY co.order_no";
        try{
            $coList = $this->executeQueryForList($sql, $this->mapper[NbaCoPoServiceMapper::GET_SUBJECT_WISE_CO_LIST_WITH_CO_PO_RELATION]);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $coList;
    }
    /**
     * Method to create new co po relation
     *
     * @param NbaCoPoRelation $coPoRelationList
     * @return void
     */
    public function createNewCoPoRelation($coPoRelationList){
        $coPoRelationList = $this->realEscapeArray($coPoRelationList);
        $sql = "";
        $values = [];
        $sql = "INSERT INTO `nba_co_po_relation` (`nba_course_outcome_id`, `nba_program_outcome_id`, `nba_descriptor_id`) VALUES ";
        foreach($coPoRelationList as $coPoRelation){
            $values[] = "('$coPoRelation->coId', '$coPoRelation->poId', '$coPoRelation->descriptorId')";
        }
        $sql .= implode(',', $values);
        try{
            $this->executeQuery($sql);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * Undocumented function
     *
     * @param [type] $coId
     * @return void
     */
    public function deleteAllCoPoRelationByCoId($coId){
        $coId = $this->realEscapeString($coId);
        $sql = "DELETE FROM nba_co_po_relation WHERE nba_course_outcome_id = '$coId'";
        try{
            $this->executeQuery($sql);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * function used for delete co-po relation of a list of COs
     *
     * @param [type] $coIdList
     * @return void
     */
    public function deleteAllCoPoRelationByCoIdList($coIdList){
        $coIdList = $this->realEscapeArray($coIdList);
        $ids = implode("','", $coIdList);
        $sql = "DELETE FROM nba_co_po_relation WHERE nba_course_outcome_id IN ('".$ids."')";
        try{
            $this->executeQuery($sql);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return true;
    }
    /**
     * function used for returns all pos and co-po justification Details of selected CO 
     *
     * @param [type] $coId
     * @return void
     */
    public function getPosAndJustificationDetails($coId){
        $coId = $this->realEscapeString($coId);
        $sql = "SELECT 
                    t1.id as poId, t1.poCode, t1.poName, t2.descriptorName, t1.order_no, t3.nba_co_po_justification as coPoJustification
                FROM
                    nba_program_outcome t1,
                    nba_descriptor t2,
                    nba_co_po_relation t3
                WHERE
                    t1.id = t3.nba_program_outcome_id
                        AND t2.id = t3.nba_descriptor_id
                        AND t3.nba_course_outcome_id = '$coId'
                ORDER BY t1.order_no ASC";
        try{
        $poList = $this->executeQueryForList($sql);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $poList;
    }
    public function saveCoPoJustification($poList,$coId){
        $poList = $this->realEscapeArray($poList);
        $coId = $this->realEscapeString($coId);
        foreach($poList as $po){
            $coPovalues[] = "('".$coId."','".$po['poId']."','".$po['justification']."')";     
        }
        $coPoValuesInsert = implode(',', $coPovalues);
        $sql = "INSERT INTO    nba_co_po_relation (nba_course_outcome_id,nba_program_outcome_id,nba_co_po_justification)
                VALUES 
                $coPoValuesInsert
                ON DUPLICATE KEY UPDATE 
                nba_co_po_justification = VALUES(nba_co_po_justification)";
        try{
            $this->executeQuery($sql);
        }catch(\Exception $e){
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
    }
    public function getPosAndJustificationDetailsForPseudoSubject($coIds){
        $coIds = $this->realEscapeArray($coIds);
        $poList = [];
        if(empty($coIds)){
            return $poList;
        }
        $coIdsForSearch = implode(',', $coIds);
        $sql="SELECT 
            npo.id as poId, npo.poCode, npo.poName, nd.descriptorName, npo.order_no as orderNo, ncpr.nba_co_po_justification as coPoJustification,nco.batchID as batchId,nco.semID as semId,npg.name as groupName,batches.batchName,npg.id as groupId,ncpr.nba_course_outcome_id as courseOutcomeId,ncpr.id as coPoRelationId,nd.id as descriptorId
        FROM
            nba_program_outcome npo
        INNER JOIN 
            nba_co_po_relation ncpr ON npo.id = ncpr.nba_program_outcome_id
        INNER JOIN 
            nba_descriptor nd ON nd.id = ncpr.nba_descriptor_id  
        INNER JOIN 
            nba_course_outcome nco ON nco.id = ncpr.nba_course_outcome_id 
        INNER JOIN 
            nba_po_group_to_batches_mapping npgbm ON npgbm.batch_id = nco.batchID
        INNER JOIN 
            nba_po_group npg ON npg.id = npgbm.nba_po_group_id
        INNER JOIN 
            batches  ON batches.batchID = nco.batchID
        WHERE
            ncpr.nba_course_outcome_id IN ($coIdsForSearch)
        ORDER BY npo.order_no ASC";
        try{
        $poList = $this->executeQueryForList($sql,$this->mapper[NbaCoPoServiceMapper::GET_CO_PO_JUSSTFICATION_DETAILS]);
        }catch(\Exception $e){
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $poList;
    }
    public function saveCoPoJustificationPseudoSubject($selectedCoMoreDetails){
        $selectedCoMoreDetails = $this->realEscapeArray($selectedCoMoreDetails);
       
        foreach($selectedCoMoreDetails as $group){
            foreach($group->batchList as $batch){
                foreach($batch->poList as $po){
                    $coPovalues[] = "('".$po->coPoRelation->coId."','".$po->id."','".$po->coPoRelation->coPoJustification."')";     
                }
            }
        }
        
        $coPoValuesInsert = implode(',', $coPovalues);
        $sql = "INSERT INTO    nba_co_po_relation (nba_course_outcome_id,nba_program_outcome_id,nba_co_po_justification)
                VALUES 
                $coPoValuesInsert
                ON DUPLICATE KEY UPDATE 
                nba_co_po_justification = VALUES(nba_co_po_justification)";
        try{
            $this->executeQuery($sql);
        }catch(\Exception $e){
                throw new ProfessionalException($e->getCode(), $e->getMessage());
            }
    }
    public function calculateCoOfOnlineExam($onlineExamId, $batchId, $semId, $subjectId, $nodeId)
    {
        $onlineExamId = $onlineExamId;
        $sql = "";
        $assessmentCOList = [];
        $assessmentTypeId = NbaCoPoService::getInstance()->getAssessmentTypeIdFromCode(AssessmentType::ONLINE_EXAM);
        $onlineExamId = trim(sql_real_escape_string($onlineExamId));
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $coValueCalculationMethod = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD);
        
        // $sql = "select batchName from batches where batchID=\"" . $batchID . "\"";
        // $result = sql_query($sql, $connect);
        // $row = sql_fetch_array($result);
        // $batchName = preg_replace('/\s+/', '', $row[0]);
        // $fileName = $batchName . "_" . date("d-m-Y", strtotime($date));
        // $fileName = preg_replace('/\s+/', '', $fileName);
        
        $result = StudentService::getInstance()->getAllStudentsByBatchIdSemIdSubjectId($batchId, $semId, $subjectId);
        $count = 1;
        $COcount = 0;
        $sql_count = "SELECT id, code, objective, order_no FROM nba_course_outcome WHERE batchID=\"" . $batchId . "\" and subjectID = \"" . $subjectId . "\" ORDER BY order_no ASC";
        $result_count = sql_query($sql_count, $connect);
        $COcount = sql_num_rows($result_count);
        $colspan = $COcount + 3;
        while ($row_count = sql_fetch_array($result_count)) {
            $nba_course_outcomes[$row_count['id']] = $row_count['code'];
        }
        $count = count($nba_course_outcomes);
        if (!$count) {
            return null;
        }
        $sbsIdDetails = SubjectService::getInstance()->getSbsDetailsByStaffId($batchId, $semId, $_SESSION['staffID'], $subjectId);
        $pseudoSubject = SubjectService::getInstance()->getPseudoSubjectBySbsId($sbsIdDetails->sbsID);
        if ( $pseudoSubject && $pseudoSubject->pseudosubjectID ) {
            $contexts[] = '"pseudoSubjectId":"'.$pseudoSubject->pseudosubjectID.'"';
        }else{
            if ( $batchId ) {
                $contexts[] = '"batchId":"'.$batchId.'"';
            }
            if ( $semId ) {
                $contexts[] = '"semId":"'.$semId.'"';
            }
            if ( $subjectId ) {
                $contexts[] = '"subjectId":"'.$subjectId.'"';
            }
        }
        $conditions .= " AND JSON_CONTAINS(oee.identifying_context, '{" . implode (",", $contexts ) . "}')";
        foreach ($result as  $student) {
            $denominatorValueArray=[];
            $nominatorValueArray=[];
            $studentId = $student->id;
            $sql_oe = "SELECT
            oee.id
            FROM
            oe_exams oee
                LEFT JOIN 
            oe_exam_user_mark oeum ON (oee.id = oeum.oe_exams_id AND oeum.user_id = '$studentId' AND oeum.user_type= 'STUDENT')
                
            WHERE oee.is_deleted = 0 AND oee.id= '$onlineExamId' AND ( oee.type = 'QUIZ' OR oee.type = 'EXAM_CONTROLLER' OR oee.type = 'OBE_MARK_ENTRY' )
            $conditions 
            GROUP BY oee.id";
            $oeExams = $this->executeQueryForList($sql_oe);
            foreach ($oeExams as $exam) {
                $oeExamId = $exam->id;
                $studentMarkList = NbaCoService::getInstance()->getCoDetailsOfOnlineExam($oeExamId, $studentId,$batchId,$semId,$subjectId);
                $validStudentQuestionIds=NbaCoService::getInstance()->getSectionWiseValidQuestionIdsForCoCalculationOfAStudentForOnlineExam($oeExamId,$studentId);
                
                if (!empty($studentMarkList)) {
                    $totalCoPercentList = NbaCoService::getInstance()->calculateTotalCOPercentsOnlineExam($validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList, $batchId, $semId, $subjectId);
                    foreach ($studentMarkList as $row_mark) {
                        $row_mark = (array)$row_mark;
                        if (!in_array($row_mark['oe_exam_questions_id'], $validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList)) {
                            continue;
                        }
                        $mark_obtained = $row_mark['markObtained'];
                        $staffId = $row_mark["created_by"];
                        $maxMark = $row_mark['mark'];
                        foreach($row_mark['cos'] as $coDetails){
                            $nba_course_outcome_id = $coDetails->coId;
                            $course_outcome_value = $coDetails->value;
                            $course_outcome_value = $course_outcome_value / 100;
                            //this is only for course wise type 2 calculation
                            if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                
                                $studentQuestionCoDetails = new NBASubjectAssessmentCoValue();
                                $value = (($mark_obtained / $maxMark) * ($course_outcome_value))*100;
                                $studentQuestionCoDetails->markCOPercentage = $value;
                                $studentQuestionCoDetails->studentId = $studentId;
                                $studentQuestionCoDetails->questionId = $row_mark['oe_exam_questions_id'];
                                $studentQuestionCoDetails->coId = $nba_course_outcome_id;
            
                                $assessmentStudentQuestionMarkCOList[] = $studentQuestionCoDetails;
                            }
                            if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                                $denominatorValue =($maxMark*($coDetails->value/100));
                                $denominatorValueArray[$nba_course_outcome_id] += $denominatorValue;
                                $nominatorValue =($mark_obtained*($coDetails->value/100));
                                $nominatorValueArray[$nba_course_outcome_id] += $nominatorValue;
                                
                            }else{
                                $per_percent = $totalCoPercentList[$nba_course_outcome_id] / 100;
                                $percentage = ($mark_obtained / $maxMark) * ($course_outcome_value);
                                $exactValue = ($percentage / $per_percent) * 100;
                                $CoArr[$studentId][$nba_course_outcome_id] += $exactValue;
                            }
                        }
                        
                    }
                    if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                        foreach ($nominatorValueArray as $coId => $nominatorValue) {
                            $CoArr[$studentId][$coId]= ($nominatorValue/$denominatorValueArray[$coId])*100;
                        }    
                    }
                }
            }
        }
        foreach ($CoArr as $studentId => $nbaCourseOutcomes) {
            foreach ($nbaCourseOutcomes as $coId => $coValue) {
                $nbaSubjectAssessmentCoValue = new NBASubjectAssessmentCoValue();
                $nbaSubjectAssessmentCoValue->assessmentId = $onlineExamId;
                $nbaSubjectAssessmentCoValue->assessmentTypeId = $assessmentTypeId;
                $nbaSubjectAssessmentCoValue->coId = $coId;
                $nbaSubjectAssessmentCoValue->value = $coValue;
                $nbaSubjectAssessmentCoValue->studentId = $studentId;
                $nbaSubjectAssessmentCoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
                $nbaSubjectAssessmentCoValue->batchId = $batchId;
                $nbaSubjectAssessmentCoValue->semId = $semId;
                $nbaSubjectAssessmentCoValue->subjectId = $subjectId;
                $nbaSubjectAssessmentCoValue->createdBy = $_SESSION['staffID'];
                $nbaSubjectAssessmentCoValue->updatedBy = $_SESSION['staffID'];
                $assessmentCOList[] = $nbaSubjectAssessmentCoValue;
            }
        }
        if (empty($assessmentCOList)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN, 'Atleast 1 Co must be given');
        }
        $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculation($assessmentCOList, $nodeId, $assessmentStudentQuestionMarkCOList);
        $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
        $this->saveCoValuesForSubjectAssessments($assessmentCOList);
    }
    public function calculateCoOfPollsSurvey($onlineExamId, $batchId, $semId, $subjectId, $nodeId)
    {
        $onlineExamId = $onlineExamId;
        $sql = "";
        $assessmentCOList = [];
        $assessmentTypeId = NbaCoPoService::getInstance()->getAssessmentTypeIdFromCode(AssessmentType::POLLS_SURVEY);
        $onlineExamId = trim(sql_real_escape_string($onlineExamId));
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $coValueCalculationMethod = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD);
        
        // $sql = "select batchName from batches where batchID=\"" . $batchID . "\"";
        // $result = sql_query($sql, $connect);
        // $row = sql_fetch_array($result);
        // $batchName = preg_replace('/\s+/', '', $row[0]);
        // $fileName = $batchName . "_" . date("d-m-Y", strtotime($date));
        // $fileName = preg_replace('/\s+/', '', $fileName);
        
        $result = StudentService::getInstance()->getAllStudentsByBatchIdSemIdSubjectId($batchId, $semId, $subjectId);
        $count = 1;
        $COcount = 0;
        $sql_count = "SELECT id, code, objective, order_no FROM nba_course_outcome WHERE batchID=\"" . $batchId . "\" and subjectID = \"" . $subjectId . "\" ORDER BY order_no ASC";
        $result_count = sql_query($sql_count, $connect);
        $COcount = sql_num_rows($result_count);
        $colspan = $COcount + 3;
        while ($row_count = sql_fetch_array($result_count)) {
            $nba_course_outcomes[$row_count['id']] = $row_count['code'];
        }
        $count = count($nba_course_outcomes);
        if (!$count) {
            return null;
        }
        $sbsIdDetails = SubjectService::getInstance()->getSbsDetailsByStaffId($batchId, $semId, $_SESSION['staffID'], $subjectId);
        $pseudoSubject = SubjectService::getInstance()->getPseudoSubjectBySbsId($sbsIdDetails->sbsID);
        if ( $pseudoSubject && $pseudoSubject->pseudosubjectID ) {
            $batchesAndSubject = '{"pseudoSubjectId":"'.$pseudoSubject->pseudosubjectID.'"}';
        }else{
            if ( $batchId && $subjectId) {
                $batchesAndSubject= '{"batchId":"'.$batchId.'","subjectId":"'.$subjectId.'"}';
            }
        }
        $batchesAndSubjects = [];
        $batchesAndSubjects[] = $batchesAndSubject;
        $identifyingContexts[] = '"batchAndSubjects":['.implode($batchesAndSubjects).']';
        $conditions .= " AND JSON_CONTAINS(oee.identifying_context, '{" . implode (",", $identifyingContexts) . "}')";
        
        foreach ($result as  $student) {
            $denominatorValueArray=[];
            $nominatorValueArray=[];
            $studentId = $student->id;
            $sql_oe = "SELECT
            oee.id
            FROM
            oe_exams oee
                LEFT JOIN 
            oe_exam_user_mark oeum ON (oee.id = oeum.oe_exams_id AND oeum.user_id = '$studentId' AND oeum.user_type= 'STUDENT')
                
            WHERE oee.is_deleted = 0 AND oee.id= '$onlineExamId' AND oee.type = 'POLLS_SURVEY'
            $conditions 
            GROUP BY oee.id";
            $oeExams = $this->executeQueryForList($sql_oe);
            foreach ($oeExams as $exam) {
                $oeExamId = $exam->id;
                $studentMarkList = NbaCoService::getInstance()->getCoDetailsOfOnlineExam($oeExamId, $studentId,$batchId,$semId,$subjectId);
                $validStudentQuestionIds=NbaCoService::getInstance()->getSectionWiseValidQuestionIdsForCoCalculationOfAStudentForOnlineExam($oeExamId,$studentId);
                
                if (!empty($studentMarkList)) {
                    $totalCoPercentList = NbaCoService::getInstance()->calculateTotalCOPercentsOnlineExam($validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList, $batchId, $semId, $subjectId);
                    foreach ($studentMarkList as $row_mark) {
                        $row_mark = (array)$row_mark;
                        if (!in_array($row_mark['oe_exam_questions_id'], $validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList)) {
                            continue;
                        }
                        $mark_obtained = $row_mark['markObtained'];
                        $staffId = $row_mark["created_by"];
                        $maxMark = $row_mark['mark'];
                        foreach($row_mark['cos'] as $coDetails){
                            $nba_course_outcome_id = $coDetails->coId;
                            $course_outcome_value = $coDetails->value;
                            $course_outcome_value = $course_outcome_value / 100;
                            //this is only for course wise type 2 calculation
                            if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                
                                $studentQuestionCoDetails = new NBASubjectAssessmentCoValue();
                                $value = (($mark_obtained / $maxMark) * ($course_outcome_value))*100;
                                $studentQuestionCoDetails->markCOPercentage = $value;
                                $studentQuestionCoDetails->studentId = $studentId;
                                $studentQuestionCoDetails->questionId = $row_mark['oe_exam_questions_id'];
                                $studentQuestionCoDetails->coId = $nba_course_outcome_id;
            
                                $assessmentStudentQuestionMarkCOList[] = $studentQuestionCoDetails;
                            }
                            if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                                $denominatorValue =($maxMark*($coDetails->value/100));
                                $denominatorValueArray[$nba_course_outcome_id] += $denominatorValue;
                                $nominatorValue =($mark_obtained*($coDetails->value/100));
                                $nominatorValueArray[$nba_course_outcome_id] += $nominatorValue;
                                
                            }else{
                                $per_percent = $totalCoPercentList[$nba_course_outcome_id] / 100;
                                $percentage = ($mark_obtained / $maxMark) * ($course_outcome_value);
                                $exactValue = ($percentage / $per_percent) * 100;
                                $CoArr[$studentId][$nba_course_outcome_id] += $exactValue;
                            }
                        }
                    }
                    if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                        foreach ($nominatorValueArray as $coId => $nominatorValue) {
                            $CoArr[$studentId][$coId]= ($nominatorValue/$denominatorValueArray[$coId])*100;
                        }    
                    }
                }
            }
        }
        foreach ($CoArr as $studentId => $nbaCourseOutcomes) {
            foreach ($nbaCourseOutcomes as $coId => $coValue) {
                $nbaSubjectAssessmentCoValue = new NBASubjectAssessmentCoValue();
                $nbaSubjectAssessmentCoValue->assessmentId = $onlineExamId;
                $nbaSubjectAssessmentCoValue->assessmentTypeId = $assessmentTypeId;
                $nbaSubjectAssessmentCoValue->coId = $coId;
                $nbaSubjectAssessmentCoValue->value = $coValue;
                $nbaSubjectAssessmentCoValue->studentId = $studentId;
                $nbaSubjectAssessmentCoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
                $nbaSubjectAssessmentCoValue->batchId = $batchId;
                $nbaSubjectAssessmentCoValue->semId = $semId;
                $nbaSubjectAssessmentCoValue->subjectId = $subjectId;
                $nbaSubjectAssessmentCoValue->createdBy = $_SESSION['staffID'];
                $nbaSubjectAssessmentCoValue->updatedBy = $_SESSION['staffID'];
                $assessmentCOList[] = $nbaSubjectAssessmentCoValue;
            }
        }
        if (empty($assessmentCOList)) {
            throw new ProfessionalException(ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN, 'Atleast 1 Co must be given');
        }
        $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculation($assessmentCOList, $nodeId, $assessmentStudentQuestionMarkCOList);
        $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
       $this->saveCoValuesForSubjectAssessments($assessmentCOList);
    }
    public function getAllOnlineExams($batchId, $subjectId, $semId){
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
            $sbsIdDetails = SubjectService::getInstance()->getSbsDetailsByStaffId($batchId, $semId, $_SESSION['staffID'], $subjectId);
            $pseudoSubject = SubjectService::getInstance()->getPseudoSubjectBySbsId($sbsIdDetails->sbsID);
            if ( $pseudoSubject && $pseudoSubject->pseudosubjectID ) {
                $contexts[] = '"pseudoSubjectId":"'.$pseudoSubject->pseudosubjectID.'"';
            }else{
                if ( $batchId ) {
                    $contexts[] = '"batchId":"'.$batchId.'"';
                }
                if ( $semId ) {
                    $contexts[] = '"semId":"'.$semId.'"';
                }
                if ( $subjectId ) {
                    $contexts[] = '"subjectId":"'.$subjectId.'"';
                }
            }
            // if ( $staffId ) {
            //     $contexts[] = '"staffId":"'.$staffId.'"';
            // }
            // if ( $subbatchId ) {
            //     if ( $userId ) {
            //         /**
            //          * If subbatchId is given then (In user side)
            //          * Fetch all exam with that subbatchId and also subbatchId = 0 (ALL)
            //          */
            //         $conditions .= " AND JSON_EXTRACT(oee.identifying_context, \"$.subbatchId\") IN (0, $subbatchId) ";
            //     }
            //     else {
            //         $contexts[] = '"subbatchId":"'.$subbatchId.'"';
            //     }
            // } else {
            //     $contexts[] = '"subbatchId":"0"';
            // }
            
            // if ( $userId ) {
            //     /**
            //      * If userId then 
            //      * List all unlocked exams
            //      */ 
            //     // $conditions .= " AND JSON_CONTAINS(oee.properties, '{\"isLocked\": false}')";
            //     // if ( $staffId ) {
            //     //     $contexts[] = '"staffId":"'.$staffId.'"';
            //     // }
            // }
            $conditions .= " AND JSON_CONTAINS(oee.identifying_context, '{" . implode (",", $contexts ) . "}')";
        try {
            $sql = "SELECT
                            oee.id,
                            oee.name,
                            oee.description,
                            oee.type,
                            oee.identifying_context,
                            oee.properties,
                            oee.user_type,
                            oee.is_deleted
                        FROM
                            oe_exams oee
                                
                        WHERE oee.is_deleted = 0 AND ( oee.type = 'QUIZ' OR oee.type = 'EXAM_CONTROLLER' OR oee.type = 'OBE_MARK_ENTRY' )
                        $conditions 
                        GROUP BY oee.id";
                        
                $exams = $this->executeQueryForList($sql);
            return $exams;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getAllPollsSurvey($batchId, $subjectId, $semId){
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
            $sbsIdDetails = SubjectService::getInstance()->getSbsDetailsByStaffId($batchId, $semId, $_SESSION['staffID'], $subjectId);
            $pseudoSubject = SubjectService::getInstance()->getPseudoSubjectBySbsId($sbsIdDetails->sbsID);
            
            if ( $pseudoSubject && $pseudoSubject->pseudosubjectID ) {
                $batchesAndSubject = '{"pseudoSubjectId":"'.$pseudoSubject->pseudosubjectID.'"}';
            }else{
                if ( $batchId && $subjectId) {
                    $batchesAndSubject= '{"batchId":"'.$batchId.'","subjectId":"'.$subjectId.'"}';
                }
            }
            $batchesAndSubjects = [];
            $batchesAndSubjects[] = $batchesAndSubject;
            $identifyingContexts[] = '"batchAndSubjects":['.implode($batchesAndSubjects).']';
            $conditions .= " AND JSON_CONTAINS(oee.identifying_context, '{" . implode (",", $identifyingContexts) . "}')";
        try {
            $sql = "SELECT
                            oee.id,
                            oee.name,
                            oee.description,
                            oee.type,
                            oee.identifying_context,
                            oee.properties,
                            oee.user_type,
                            oee.is_deleted
                        FROM
                            oe_exams oee
                                
                        WHERE oee.is_deleted = 0 AND oee.type = 'POLLS_SURVEY'
                        $conditions 
                        GROUP BY oee.id";
                        
                $exams = $this->executeQueryForList($sql);
            return $exams;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getValidCos($batchId,$subjectId){
        $sql_valid_COs = "SELECT nco.id,nco.code ,b.batchName,subjectName from 
        nba_course_outcome nco 
        LEFT JOIN batches b ON b.batchID =nco.batchID
        INNER JOIN subjects s ON s.subjectID = nco.subjectID
        WHERE nco.batchID =".$batchId."  and nco.subjectID=".$subjectId."   order by nco.order_no;";
        try {
            return $this->executeQueryForList($sql_valid_COs);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function getPosByCoAndPo($coId,$poId){
        $sql = "SELECT weightage
            FROM nba_co_po_relation copo
            INNER JOIN nba_descriptor nd ON copo.nba_descriptor_id = nd.id
            WHERE copo.nba_course_outcome_id = '".$coId."' AND copo.nba_program_outcome_id = $poId";
        try {
            return $this->executeQueryForObject($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    public function courseWiseAttainmentCalculation($assessmentStudentCOList, $nodeId, $assessmentStudentQuestionMarkCOList=null){
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $subjectCOs = NbaCoService::getInstance()->getAllCosBySubjectIdBatchIdAndSemId($_REQUEST['subjectId'], $_REQUEST['batchId'], $_REQUEST['semId']);
        $ruleForCalculation = true;
        if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_IN_TREE_NODE || $coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO) {
            $coAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId'], $nodeId, $ruleForCalculation);
        }else{
            $coAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId']);
        }
        $totalCOValues=[];
        $coAttainment=[];
        foreach ($assessmentStudentCOList as $studentCoDetails) {
            $studentDetails[$studentCoDetails->studentId] = $studentCoDetails->studentName;
            $studentDetailsCO[$studentCoDetails->studentId][$studentCoDetails->coId] = $studentCoDetails->value;
            $totalCOValues[$studentCoDetails->coId]+=sprintf("%01.2f",$studentCoDetails->value);
        }
        $totalStudentStrength = count($studentDetails);
        if (empty($coAttainmentRuleDetails)) {
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }else{
            $coAttainmentRule = $coAttainmentRuleDetails->rule;
            $coAttainmentType = $coAttainmentRule->type;
            $coAttainmentGoals = $coAttainmentRule->goals;
        }
        $maxDescriptorValue = CoPoAttainmentService::getInstance()->getMaxDescriptorDetails();
        if (empty($maxDescriptorValue)) {
            throw new ProfessionalException(ProfessionalException::DESCRIPTOR_VALUES_NOT_DEFINED, 'Please Make Sure Descriptor Values Are Defined');
        }
        $maxDescriptorValue = $maxDescriptorValue->descriptorValue;
        switch ($coAttainmentRule->type) {
            case AttainmentCalculationType::SIMPLE_AVERAGE:
                foreach($totalCOValues as $coId => $coTotal){
                    $coValue = 0;
                    if(count($totalStudentStrength)){
                        $coValue = $coTotal / $totalStudentStrength;
                        $coValue = ($coValue / 100) * $maxDescriptorValue;
                        $coAttainment[$coId] = $coValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::SLABBED_AVERAGE:
                foreach($totalCOValues as $coId => $coTotal){
                    $coValue = 0;
                    $didNotMatchToAnySlab = true;
                    if(count($totalStudentStrength)){
                        $coValue = $coTotal / $totalStudentStrength;
                        foreach ($coAttainmentRule->slabs as $slab) {
                            if (($coValue >= $slab->min->percent && $coValue < $slab->max->percent) || ($slab->min->percent == $slab->max->percent && $coValue == $slab->max->percent) || ($coValue == $slab->max->percent && $coValue == 100)) {
                                $didNotMatchToAnySlab = false;
                                if(($slab->max->percent - $slab->min->percent) == 0)
                                    $coValue = $slab->min->descriptor;
                                else 
                                    $coValue = $slab->min->descriptor + (($coValue - $slab->min->percent) / ($slab->max->percent - $slab->min->percent)); //coValue = min_range + (coValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out co to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnySlab){
                        $coValue = 0;
                        $coAttainment[$coId] = $coValue;    
                    }else{
                        // $coValue = round($coValue,0);
                        $coAttainment[$coId] = $coValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::NSTUDENT_NPERCENT:
                $coAttainmentRule->goals = CoPoAttainmentService::getInstance()->populateDescriptorValuesFromIds($coAttainmentRule->goals);
                $questionAttendedStudents =[];
                if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                    foreach ($assessmentStudentQuestionMarkCOList as $studentQuestionCoDetails) {
                        if(empty($questionAttendedStudents[$studentQuestionCoDetails->questionId])){
                            $questionAttendedStudents[$studentQuestionCoDetails->questionId]=1;
                        }else{
                            $questionAttendedStudents[$studentQuestionCoDetails->questionId] = $questionAttendedStudents[$studentQuestionCoDetails->questionId]+1;
                        }
                        $atleastOneStudentNotHaveAttainPercentage[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId] =0;
                        if($studentQuestionCoDetails->markCOPercentage >= $coAttainmentRule->goals[0]->attain_percent){
                            if(empty($questionAttendedStudentsHaveSpecifiedCoValue[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId])){
                                $questionAttendedStudentsHaveSpecifiedCoValue[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId]=1;
                            }else{
                                $questionAttendedStudentsHaveSpecifiedCoValue[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId] = $questionAttendedStudentsHaveSpecifiedCoValue[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId]+1;
                            }
                        }else{
                            $atleastOneStudentNotHaveAttainPercentage[$studentQuestionCoDetails->questionId][$studentQuestionCoDetails->coId] = 1;
                        }
                    }
                      
                    foreach($questionAttendedStudents as  $questionId => $attendedStudents){
                        foreach ( $subjectCOs as $co ) {
                            $percentageOfStudentScoredSpecifiedValue[$questionId][$co->id] = ($questionAttendedStudentsHaveSpecifiedCoValue[$questionId][$co->id]/$questionAttendedStudents[$questionId])*100;
                            foreach($coAttainmentRule->goals as $gIndex => $goal){
                                if($percentageOfStudentScoredSpecifiedValue[$questionId][$co->id]>=$goal->student_percent){
                                    $attainmentOfStudentScoredSpecifiedValue[$questionId][$co->id]= $goal->descriptor->weightage;
                                    break;
                                }else if($percentageOfStudentScoredSpecifiedValue[$questionId][$co->id]>0 || $atleastOneStudentNotHaveAttainPercentage[$questionId][$co->id]){
                                    $attainmentOfStudentScoredSpecifiedValue[$questionId][$co->id]= 0;
                                }
                            }
    
                        }
                    }
                    foreach ( $subjectCOs as $co ) {
                        $coUsedCount =0;
                        $sumOfCoAttainment =0;
                        foreach($questionAttendedStudents as  $questionId => $attendedStudents){
                            if($attainmentOfStudentScoredSpecifiedValue[$questionId][$co->id] || $attainmentOfStudentScoredSpecifiedValue[$questionId][$co->id] ===0){
                                $coUsedCount= $coUsedCount+1;
                                $sumOfCoAttainment = $sumOfCoAttainment + $attainmentOfStudentScoredSpecifiedValue[$questionId][$co->id];
                            }
                        }
                        if($coUsedCount>0){
                            $coAttainment[$co->id] = $sumOfCoAttainment/$coUsedCount;
                        }
                    }
                }else{
                    foreach ( $subjectCOs as $co ) {
                        $goalCount= count($coAttainmentRule->goals);
                        foreach($coAttainmentRule->goals as $gIndex => $goal){
                            $numberOfStudentsWithSpecifiedAttainment=0;
                            $percentageOfStudentsWithSpecifiedAttainment=0;
                            foreach ($studentDetails as $student_id => $studentName) {
                                if($studentDetailsCO[$student_id][$co->id] >= $goal->attain_percent){
                                    $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                                }
                            }
                            if($totalStudentStrength){
                                $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                                if($percentageOfStudentsWithSpecifiedAttainment >= $goal->student_percent && $percentageOfStudentsWithSpecifiedAttainment !=0){
                                    $coValue = $goal->descriptor->weightage;
                                    $coAttainment[$co->id] = $coValue;    
                                    break;
                                }
                            }
                        }
                    }
                }
            break;
            case AttainmentCalculationType::N_STUDENT_N_PERCENT_SLABBED_AVERAGE:
                foreach ( $subjectCOs as $co ) {
                    $goalCount= count($coAttainmentRule->goalsWithSlab);
                    foreach($coAttainmentRule->goalsWithSlab as $gIndex => $goal){
                        $numberOfStudentsWithSpecifiedAttainment=0;
                        $percentageOfStudentsWithSpecifiedAttainment=0;
                        foreach ($studentDetails as $student_id => $studentName) {
                            if($studentDetailsCO[$student_id][$co->id] >= $goal->thresholdMark){
                                $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                            }
                        }
                        $didNotMatchToAnyGoalsSlab = true;
                        if($totalStudentStrength){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                            if (($percentageOfStudentsWithSpecifiedAttainment >= $goal->min->percent && $percentageOfStudentsWithSpecifiedAttainment < $goal->max->percent) || ($goal->min->percent == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent) || ($percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == 100)) {
                                $didNotMatchToAnyGoalsSlab = false;
                                if(($goal->max->percent - $goal->min->percent) == 0)
                                    $coValue = $goal->min->descriptor;
                                else if($goal->max->descriptor == $goal->min->descriptor)
                                    $coValue = $goal->min->descriptor;
                                else 
                                    $coValue = $goal->min->descriptor + (($percentageOfStudentsWithSpecifiedAttainment - $goal->min->percent) / ($goal->max->percent - $goal->min->percent)); //coValue = min_range + (coValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out co to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnyGoalsSlab){
                        $coValue = 0;
                        $coAttainment[$co->id] = $coValue;    
                    }else{
                        // $coValue = round($coValue,0);
                        $coAttainment[$co->id] = $coValue;    
                    }
                }
            break;
        }
        $assessmentCourseWiseCoValue=[];
        foreach ($coAttainment as $coId => $coValue) {
            $nbaSubjectAssessmentCoValue = new NBASubjectAssessmentCoValue();
            $nbaSubjectAssessmentCoValue->assessmentId = $assessmentStudentCOList[0]->assessmentId;
            $nbaSubjectAssessmentCoValue->assessmentTypeId = $assessmentStudentCOList[0]->assessmentTypeId;
            $nbaSubjectAssessmentCoValue->coId = $coId;
            $nbaSubjectAssessmentCoValue->nodeId = $nodeId;
            if($coAttainmentRule->type == AttainmentCalculationType::NSTUDENT_NPERCENT && $coPoCourseWiseCalculationDisplayStyle!=NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                $nbaSubjectAssessmentCoValue->value = (int) $coValue;
            }else{
                $nbaSubjectAssessmentCoValue->value = (float) $coValue;
            }
            $nbaSubjectAssessmentCoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
            $nbaSubjectAssessmentCoValue->batchId = $assessmentStudentCOList[0]->batchId;
            $nbaSubjectAssessmentCoValue->semId = $assessmentStudentCOList[0]->semId;
            $nbaSubjectAssessmentCoValue->subjectId = $assessmentStudentCOList[0]->subjectId;
            $nbaSubjectAssessmentCoValue->createdBy = $_SESSION['staffID'];
            $nbaSubjectAssessmentCoValue->updatedBy = $_SESSION['staffID'];
            $assessmentCourseWiseCoValue[] = $nbaSubjectAssessmentCoValue;
        }
        return $assessmentCourseWiseCoValue;
        
    }
    public function courseWisePOAttainmentCalculation($assessmentStudentPOList, $nodeId){
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $subjectPOs = $this->getProgramOutcomeListByBatchId($_REQUEST['batchId']);
        $ruleForCalculation = true;
        if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_IN_TREE_NODE || $coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO) {
            $coPoAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId'], $nodeId, $ruleForCalculation);
        }else{
            $coPoAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId']);
        }
        $totalPOValues=[];
        $coPoAttainment=[];
        foreach ($assessmentStudentPOList as $studentCoDetails) {
            $studentDetails[$studentCoDetails->studentId] = $studentCoDetails->studentName;
            $studentDetailsPO[$studentCoDetails->studentId][$studentCoDetails->poId] = $studentCoDetails->value;
            $totalPOValues[$studentCoDetails->poId]+=sprintf("%01.2f",$studentCoDetails->value);
        }
        $totalStudentStrength = count($studentDetails);
        if (empty($coPoAttainmentRuleDetails)) {
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }else{
            $coPoAttainmentRule = $coPoAttainmentRuleDetails->rule;
            $coAttainmentType = $coPoAttainmentRule->type;
            $coAttainmentGoals = $coPoAttainmentRule->goals;
        }
        $maxDescriptorValue = CoPoAttainmentService::getInstance()->getMaxDescriptorDetails();
        if (empty($maxDescriptorValue)) {
            throw new ProfessionalException(ProfessionalException::DESCRIPTOR_VALUES_NOT_DEFINED, 'Please Make Sure Descriptor Values Are Defined');
        }
        $maxDescriptorValue = $maxDescriptorValue->descriptorValue;
        switch ($coPoAttainmentRule->type) {
            case AttainmentCalculationType::SIMPLE_AVERAGE:
                foreach($totalPOValues as $poId => $poTotal){
                    $poValue = 0;
                    if(count($totalStudentStrength)){
                        $poValue = $poTotal / $totalStudentStrength;
                        $poValue = ($poValue / 100) * $maxDescriptorValue;
                        $coPoAttainment[$poId] = $poValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::SLABBED_AVERAGE:
                foreach($totalPOValues as $poId => $poTotal){
                    $poValue = 0;
                    $didNotMatchToAnySlab = true;
                    if(count($totalStudentStrength)){
                        $poValue = $poTotal / $totalStudentStrength;
                        foreach ($coPoAttainmentRule->slabs as $slab) {
                            if (($poValue >= $slab->min->percent && $poValue < $slab->max->percent) || ($slab->min->percent == $slab->max->percent && $poValue == $slab->max->percent) || ($poValue == $slab->max->percent && $poValue == 100)) {
                                $didNotMatchToAnySlab = false;
                                if(($slab->max->percent - $slab->min->percent) == 0)
                                    $poValue = $slab->min->descriptor;
                                else 
                                    $poValue = $slab->min->descriptor + (($poValue - $slab->min->percent) / ($slab->max->percent - $slab->min->percent)); //poValue = min_range + (poValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out co to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnySlab){
                        $poValue = 0;
                        $coPoAttainment[$poId] = $poValue;    
                    }else{
                        // $poValue = round($poValue,0);
                        $coPoAttainment[$poId] = $poValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::NSTUDENT_NPERCENT:
                $coPoAttainmentRule->goals = CoPoAttainmentService::getInstance()->populateDescriptorValuesFromIds($coPoAttainmentRule->goals);
                foreach ( $subjectPOs as $po ) {
                    $goalCount= count($coPoAttainmentRule->goals);
                    foreach($coPoAttainmentRule->goals as $gIndex => $goal){
                        $numberOfStudentsWithSpecifiedAttainment=0;
                        $percentageOfStudentsWithSpecifiedAttainment=0;
                        foreach ($studentDetails as $student_id => $studentName) {
                            if($studentDetailsPO[$student_id][$po->id] >= $goal->attain_percent){
                                $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                            }
                        }
                        if($totalStudentStrength){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                            if($percentageOfStudentsWithSpecifiedAttainment >= $goal->student_percent && $percentageOfStudentsWithSpecifiedAttainment !=0){
                                $poValue = $goal->descriptor->weightage;
                                $coPoAttainment[$po->id] = $poValue;    
                                break;
                            }
                        }
                    }
                }
            break;
            case AttainmentCalculationType::N_STUDENT_N_PERCENT_SLABBED_AVERAGE:
                foreach ( $subjectPOs as $po ) {
                    $goalCount= count($coPoAttainmentRule->goalsWithSlab);
                    foreach($coPoAttainmentRule->goalsWithSlab as $gIndex => $goal){
                        $numberOfStudentsWithSpecifiedAttainment=0;
                        $percentageOfStudentsWithSpecifiedAttainment=0;
                        foreach ($studentDetails as $student_id => $studentName) {
                            if($studentDetailsPO[$student_id][$po->id] >= $goal->thresholdMark){
                                $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                            }
                        }
                        $didNotMatchToAnyGoalsSlab = true;
                        if($totalStudentStrength){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                            if (($percentageOfStudentsWithSpecifiedAttainment >= $goal->min->percent && $percentageOfStudentsWithSpecifiedAttainment < $goal->max->percent) || ($goal->min->percent == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent) || ($percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == 100)) {
                                $didNotMatchToAnyGoalsSlab = false;
                                if(($goal->max->percent - $goal->min->percent) == 0)
                                    $poValue = $goal->min->descriptor;
                                else if($goal->max->descriptor == $goal->min->descriptor)
                                    $poValue = $goal->min->descriptor;
                                else 
                                    $poValue = $goal->min->descriptor + (($percentageOfStudentsWithSpecifiedAttainment - $goal->min->percent) / ($goal->max->percent - $goal->min->percent)); //poValue = min_range + (coValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out po to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnyGoalsSlab){
                        $poValue = 0;
                        $coAttainment[$po->id] = $poValue;    
                    }else{
                        // $poValue = round($poValue,0);
                        $coAttainment[$po->id] = $poValue;    
                    }
                }
            break;
        }
        $assessmentCourseWisePoValue=[];
        foreach ($coPoAttainment as $poId => $poValue) {
            $nbaSubjectAssessmentPoValue = new NBASubjectAssessmentPoValue();
            $nbaSubjectAssessmentPoValue->assessmentId = $assessmentStudentPOList[0]->assessmentId;
            $nbaSubjectAssessmentPoValue->assessmentTypeId = $assessmentStudentPOList[0]->assessmentTypeId;
            $nbaSubjectAssessmentPoValue->poId = $poId;
            $nbaSubjectAssessmentPoValue->nodeId = $nodeId;
            $nbaSubjectAssessmentPoValue->value = (int) $poValue;
            if($coPoAttainmentRule->type == AttainmentCalculationType::NSTUDENT_NPERCENT){
                $nbaSubjectAssessmentPoValue->value = (int) $poValue;
            }else{
                $nbaSubjectAssessmentPoValue->value = (float) $poValue;
            }
            $nbaSubjectAssessmentPoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
            $nbaSubjectAssessmentPoValue->batchId = $assessmentStudentPOList[0]->batchId;
            $nbaSubjectAssessmentPoValue->semId = $assessmentStudentPOList[0]->semId;
            $nbaSubjectAssessmentPoValue->subjectId = $assessmentStudentPOList[0]->subjectId;
            $nbaSubjectAssessmentPoValue->createdBy = $_SESSION['staffID'];
            $nbaSubjectAssessmentPoValue->updatedBy = $_SESSION['staffID'];
            $assessmentCourseWisePoValue[] = $nbaSubjectAssessmentPoValue;
        }
        return $assessmentCourseWisePoValue;
        
    }
    
    
    public function constructSubjectAssessmentNodeAttainmentRequest($nodeId) {
        $subjectAssessmentNodeReq = new GetAllSubjectAssessmentNodeRequest();
        $subjectAssessmentNodeReq->subjectId = $_REQUEST['subjectId'];
        $subjectAssessmentNodeReq->batchId      = $_REQUEST['batchId'];
        $subjectAssessmentNodeReq->semId      = $_REQUEST['semId'];
        $subjectAssessmentNodeReq->staffId      = $_REQUEST['staffId'];
        $subjectAssessmentNodeReq->nodeId      = $nodeId;
        return $subjectAssessmentNodeReq;
    }
     /**
     * To Do:
     * 1)Add update functionality
     * 2)There are many cases to be handled inorder to rewrite service as update...
     *         what happens when co mapping is deleted from an assessment
     *         what happens when an assessment is deleted altogether after a report 
     *         is calculated    
     *
     * @param [type] $assessmentCoList
     * @return void
     */
    public function saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCoList)
    {
        if (!empty($assessmentCoList)) {
            $this->insertCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCoList);
        }
        $assessmentCo = $assessmentCoList[0];
        // $this->deleteCoValuesOfSubjectAssessmentCourseWiseCalculation($assessmentCo->assessmentId, $assessmentCo->assessmentTypeId, $assessmentCo->batchId, $assessmentCo->semId, $assessmentCo->subjectId);
    }
    private function deleteCoValuesOfSubjectAssessmentCourseWiseCalculation($assessmentId, $assessmentTypeId, $batchId, $semId, $subjectId)
    {
        $sql = "";
        $assessmentId = $this->realEscapeString($assessmentId);
        $assessmentTypeId = $this->realEscapeString($assessmentTypeId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "DELETE FROM nba_subject_assessment_co_value WHERE assessment_id = '$assessmentId' AND assessment_type_id = '$assessmentTypeId' AND batch_id = '$batchId' AND sem_id = '$semId' AND subject_id = '$subjectId'";
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * !!!Always Provide Assessments Of Same Type!!!
     *
     * @param NBASubjectAssessmentCoValue[] $assessmentCoList
     * @return void
     */
    private function insertCoValuesForSubjectAssessmentCourseWiseCalculetion($courseWiseCoList)
    {
        $sql = "";
        $courseWiseCoList = $this->realEscapeArray($courseWiseCoList);
        $sql = "INSERT INTO nba_course_wise_node_co_value (node_id, co_id, value, staff_id, batch_id, sem_id, subject_id, createdBy, createdDate, updatedBy, updatedDate) VALUES ";
        $values = [];
        foreach ($courseWiseCoList as $courseWiseCo) {
            $values[] = "('$courseWiseCo->nodeId', '$courseWiseCo->coId', '$courseWiseCo->value', '$courseWiseCo->staffId', '$courseWiseCo->batchId', '$courseWiseCo->semId', '$courseWiseCo->subjectId', '$courseWiseCo->createdBy', UTC_TIMESTAMP(), '$courseWiseCo->updatedBy', UTC_TIMESTAMP())";
        }
        $sql .= implode(',', $values);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * !!!Always Provide Assessments Of Same Type!!!
     *
     * @param NBASubjectAssessmentCoValue[] $assessmentCoList
     * @return void
     */
    private function insertPoValuesForSubjectAssessmentCourseWiseCalculetion($courseWisePoList)
    {
        $sql = "";
        $courseWisePoList = $this->realEscapeArray($courseWisePoList);
        $sql = "INSERT INTO nba_course_wise_node_po_value (node_id, po_id, value, staff_id, batch_id, sem_id, subject_id, createdBy, createdDate, updatedBy, updatedDate) VALUES ";
        $values = [];
        foreach ($courseWisePoList as $courseWisePo) {
            $values[] = "('$courseWisePo->nodeId', '$courseWisePo->poId', '$courseWisePo->value', '$courseWisePo->staffId', '$courseWisePo->batchId', '$courseWisePo->semId', '$courseWisePo->subjectId', '$courseWisePo->createdBy', UTC_TIMESTAMP(), '$courseWisePo->updatedBy', UTC_TIMESTAMP())";
        }
        $sql .= implode(',', $values);
        try {
            $this->executeQuery($sql);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
    }
    /**
     * 
     *
     * @param [type] $nodeId
     * @param [type] $batchId
     * @param [type] $semId
     * @param [type] $subjectId
     * @return void
     */
    public function getAllCalculatedCourseWiseCosFromNodeCoValueTable($nodeId, $batchId, $semId, $subjectId)
    {
        $nodeId = $this->realEscapeString($nodeId);
        $batchId = $this->realEscapeString($batchId);
        $semId = $this->realEscapeString($semId);
        $subjectId = $this->realEscapeString($subjectId);
        $sql = "SELECT 
                    cpr.nba_program_outcome_id AS poId,
                    cpr.nba_course_outcome_id AS coId,
                    ncwncv.staff_id as staffId,
                    ncwncv.value AS coContribution,
                    d.weightage
                FROM
                    nba_course_wise_node_co_value ncwncv
                        INNER JOIN
                    nba_co_po_relation cpr ON cpr.nba_course_outcome_id = ncwncv.co_id
                        INNER JOIN
                    nba_descriptor d ON d.id = cpr.nba_descriptor_id
                WHERE
                    ncwncv.node_id = '$nodeId'
                        AND ncwncv.batch_id = '$batchId'
                        AND ncwncv.sem_id = '$semId'
                        AND ncwncv.subject_id = '$subjectId'";
        $responseList = [];
        try {
            $responseList = $this->executeQueryForList($sql, $this->mapper[NbaCoPoServiceMapper::GET_CO_VALUES_FOR_AN_ASSESSMENT_FOR_COURSE_WISE_CALCULATION]);
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(), $e->getMessage());
        }
        return $responseList;
    }
    public function courseWiseAttainmentCalculationForUniversity($assessmentStudentCOList, $nodeId){
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $subjectCOs = NbaCoService::getInstance()->getAllCosBySubjectIdBatchIdAndSemId($_REQUEST['subjectId'], $_REQUEST['batchId'], $_REQUEST['semId']);
        $ruleForCalculation = true;
        if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_IN_TREE_NODE || $coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO) {
            $coAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId'], $nodeId, $ruleForCalculation);
        }else{
            $coAttainmentRuleDetails = CoPoAttainmentService::getInstance()->getRulesForCoAndPoAttainment($_REQUEST['batchId'], $_REQUEST['semId'], $_REQUEST['subjectId']);
        }
        $totalCOValues=[];
        $coAttainment=[];
        foreach ($assessmentStudentCOList as $studentCoDetails) {
            $studentDetails[$studentCoDetails->studentId] = $studentCoDetails->studentName;
            $studentDetailsCO[$studentCoDetails->studentId][$studentCoDetails->coId] = $studentCoDetails->value;
            $totalCOValues[$studentCoDetails->coId]+=sprintf("%01.2f",$studentCoDetails->value);
        }
        $totalStudentStrength = count($studentDetails);
        if (empty($coAttainmentRuleDetails)) {
            throw new ProfessionalException(ProfessionalException::ATTAINMENT_RULES_NOT_DEFINED, 'Please Define Co And Po Attainment rules...');
        }else{
            $coAttainmentRule = $coAttainmentRuleDetails->rule;
            $coAttainmentType = $coAttainmentRule->type;
            $coAttainmentGoals = $coAttainmentRule->goals;
        }
        $maxDescriptorValue = CoPoAttainmentService::getInstance()->getMaxDescriptorDetails();
        if (empty($maxDescriptorValue)) {
            throw new ProfessionalException(ProfessionalException::DESCRIPTOR_VALUES_NOT_DEFINED, 'Please Make Sure Descriptor Values Are Defined');
        }
        $maxDescriptorValue = $maxDescriptorValue->descriptorValue;
        switch ($coAttainmentRule->type) {
            case AttainmentCalculationType::SIMPLE_AVERAGE:
                foreach($totalCOValues as $coId => $coTotal){
                    $coValue = 0;
                    if(count($totalStudentStrength)){
                        $coValue = $coTotal / $totalStudentStrength;
                        $coValue = ($coValue / 100) * $maxDescriptorValue;
                        $coAttainment[$coId] = $coValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::SLABBED_AVERAGE:
                foreach($totalCOValues as $coId => $coTotal){
                    $coValue = 0;
                    $didNotMatchToAnySlab = true;
                    if(count($totalStudentStrength)){
                        $coValue = $coTotal / $totalStudentStrength;
                        foreach ($coAttainmentRule->slabs as $slab) {
                            if (($coValue >= $slab->min->percent && $coValue < $slab->max->percent) || ($slab->min->percent == $slab->max->percent && $coValue == $slab->max->percent) || ($coValue == $slab->max->percent && $coValue == 100)) {
                                $didNotMatchToAnySlab = false;
                                if(($slab->max->percent - $slab->min->percent) == 0)
                                    $coValue = $slab->min->descriptor;
                                else 
                                    $coValue = $slab->min->descriptor + (($coValue - $slab->min->percent) / ($slab->max->percent - $slab->min->percent)); //coValue = min_range + (coValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out co to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnySlab){
                        $coValue = 0;
                        $coAttainment[$coId] = $coValue;    
                    }else{
                        // $coValue = round($coValue,0);
                        $coAttainment[$coId] = $coValue;    
                    }
                }
            break;
    
            case AttainmentCalculationType::NSTUDENT_NPERCENT:
                $coAttainmentRule->goals = CoPoAttainmentService::getInstance()->populateDescriptorValuesFromIds($coAttainmentRule->goals);
                $questionAttendedStudents =[];
                foreach ( $subjectCOs as $co ) {
                    $goalCount= count($coAttainmentRule->goals);
                    foreach($coAttainmentRule->goals as $gIndex => $goal){
                        $numberOfStudentsWithSpecifiedAttainment=0;
                        $percentageOfStudentsWithSpecifiedAttainment=0;
                        foreach ($studentDetails as $student_id => $studentName) {
                            if($studentDetailsCO[$student_id][$co->id] >= $goal->attain_percent){
                                $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                            }
                        }
                        if($totalStudentStrength){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                            if($percentageOfStudentsWithSpecifiedAttainment >= $goal->student_percent && $percentageOfStudentsWithSpecifiedAttainment !=0){
                                $coValue = $goal->descriptor->weightage;
                                $coAttainment[$co->id] = $coValue;    
                                break;
                            }
                        }
                    }
                }
                
            break;
            case AttainmentCalculationType::N_STUDENT_N_PERCENT_SLABBED_AVERAGE:
                foreach ( $subjectCOs as $co ) {
                    $goalCount= count($coAttainmentRule->goalsWithSlab);
                    foreach($coAttainmentRule->goalsWithSlab as $gIndex => $goal){
                        $numberOfStudentsWithSpecifiedAttainment=0;
                        $percentageOfStudentsWithSpecifiedAttainment=0;
                        foreach ($studentDetails as $student_id => $studentName) {
                            if($studentDetailsCO[$student_id][$co->id] >= $goal->thresholdMark){
                                $numberOfStudentsWithSpecifiedAttainment =  $numberOfStudentsWithSpecifiedAttainment+1;
                            }
                        }
                        $didNotMatchToAnyGoalsSlab = true;
                        if($totalStudentStrength){
                            $percentageOfStudentsWithSpecifiedAttainment = ($numberOfStudentsWithSpecifiedAttainment/$totalStudentStrength)*100;
                            if (($percentageOfStudentsWithSpecifiedAttainment >= $goal->min->percent && $percentageOfStudentsWithSpecifiedAttainment < $goal->max->percent) || ($goal->min->percent == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent) || ($percentageOfStudentsWithSpecifiedAttainment == $goal->max->percent && $percentageOfStudentsWithSpecifiedAttainment == 100)) {
                                $didNotMatchToAnyGoalsSlab = false;
                                if(($goal->max->percent - $goal->min->percent) == 0)
                                    $coValue = $goal->min->descriptor;
                                else if($goal->max->descriptor == $goal->min->descriptor)
                                    $coValue = $goal->min->descriptor;
                                else 
                                    $coValue = $goal->min->descriptor + (($percentageOfStudentsWithSpecifiedAttainment - $goal->min->percent) / ($goal->max->percent - $goal->min->percent)); //coValue = min_range + (coValueInPercent - lower_range_slab)/ (higher_range_slab - lower_range_slab) This formula converts out co to descriptor range
                                break;
                            }
                        }
                    }
                    if($didNotMatchToAnyGoalsSlab){
                        $coValue = 0;
                        $coAttainment[$co->id] = $coValue;    
                    }else{
                        // $coValue = round($coValue,0);
                        $coAttainment[$co->id] = $coValue;    
                    }
                }
            break;
        }
        $assessmentCourseWiseCoValue=[];
        foreach ($coAttainment as $coId => $coValue) {
            $nbaSubjectAssessmentCoValue = new NBASubjectAssessmentCoValue();
            $nbaSubjectAssessmentCoValue->assessmentId = $assessmentStudentCOList[0]->assessmentId;
            $nbaSubjectAssessmentCoValue->assessmentTypeId = $assessmentStudentCOList[0]->assessmentTypeId;
            $nbaSubjectAssessmentCoValue->coId = $coId;
            $nbaSubjectAssessmentCoValue->nodeId = $nodeId;
            if($coAttainmentRule->type == AttainmentCalculationType::NSTUDENT_NPERCENT){
                $nbaSubjectAssessmentCoValue->value = (int) $coValue;
            }else{
                $nbaSubjectAssessmentCoValue->value = (float) $coValue;
            }
            $nbaSubjectAssessmentCoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
            $nbaSubjectAssessmentCoValue->batchId = $assessmentStudentCOList[0]->batchId;
            $nbaSubjectAssessmentCoValue->semId = $assessmentStudentCOList[0]->semId;
            $nbaSubjectAssessmentCoValue->subjectId = $assessmentStudentCOList[0]->subjectId;
            $nbaSubjectAssessmentCoValue->createdBy = $_SESSION['staffID'];
            $nbaSubjectAssessmentCoValue->updatedBy = $_SESSION['staffID'];
            $assessmentCourseWiseCoValue[] = $nbaSubjectAssessmentCoValue;
        }
        return $assessmentCourseWiseCoValue;
        
    }
    public function calculateCoOfOnlineExamForSelectAllAnswerdAndMandatoryUnAswered($onlineExamId, $batchId, $semId, $subjectId, $nodeId)
    {
        $onlineExamId = $onlineExamId;
        $sql = "";
        $assessmentCOList = [];
        $assessmentTypeId = NbaCoPoService::getInstance()->getAssessmentTypeIdFromCode(AssessmentType::ONLINE_EXAM);
        $onlineExamId = trim(sql_real_escape_string($onlineExamId));
        // $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        // $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_AND_DISPlAY_STYLE_IN_TREE_NODE);
        // $coValueCalculationMethod = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_BASE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS);
        
        $coPoCourseWiseCalculationDisplayStyle = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_PO_CALCULATION_DISPlAY_STYLE_IN_TREE_NODE);
        $coValueCalculationMethod = CommonService::getInstance()->getSettings(SettingsConstants::NBA, NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD);
        // $sql = "select batchName from batches where batchID=\"" . $batchID . "\"";
        // $result = sql_query($sql, $connect);
        // $row = sql_fetch_array($result);
        // $batchName = preg_replace('/\s+/', '', $row[0]);
        // $fileName = $batchName . "_" . date("d-m-Y", strtotime($date));
        // $fileName = preg_replace('/\s+/', '', $fileName);
        
        $result = StudentService::getInstance()->getAllStudentsByBatchIdSemIdSubjectId($batchId, $semId, $subjectId);
        $count = 1;
        $COcount = 0;
        $sql_count = "SELECT id, code, objective, order_no FROM nba_course_outcome WHERE batchID=\"" . $batchId . "\" and subjectID = \"" . $subjectId . "\" ORDER BY order_no ASC";
        $result_count = sql_query($sql_count, $connect);
        $COcount = sql_num_rows($result_count);
        $colspan = $COcount + 3;
        while ($row_count = sql_fetch_array($result_count)) {
            $nba_course_outcomes[$row_count['id']] = $row_count['code'];
        }
        $count = count($nba_course_outcomes);
        if (!$count) {
            return null;
        }
        $sbsIdDetails = SubjectService::getInstance()->getSbsDetailsByStaffId($batchId, $semId, $_SESSION['staffID'], $subjectId);
        $pseudoSubject = SubjectService::getInstance()->getPseudoSubjectBySbsId($sbsIdDetails->sbsID);
        if ( $pseudoSubject && $pseudoSubject->pseudosubjectID ) {
            $contexts[] = '"pseudoSubjectId":"'.$pseudoSubject->pseudosubjectID.'"';
        }else{
            if ( $batchId ) {
                $contexts[] = '"batchId":"'.$batchId.'"';
            }
            if ( $semId ) {
                $contexts[] = '"semId":"'.$semId.'"';
            }
            if ( $subjectId ) {
                $contexts[] = '"subjectId":"'.$subjectId.'"';
            }
        }
        $conditions .= " AND JSON_CONTAINS(oee.identifying_context, '{" . implode (",", $contexts ) . "}')";
        foreach ($result as  $student) {
            $denominatorValueArray=[];
            $nominatorValueArray=[];
            $studentId = $student->id;
            $sql_oe = "SELECT
            oee.id
            FROM
            oe_exams oee
                LEFT JOIN 
            oe_exam_user_mark oeum ON (oee.id = oeum.oe_exams_id AND oeum.user_id = '$studentId' AND oeum.user_type= 'STUDENT')
                
            WHERE oee.is_deleted = 0 AND oee.id= '$onlineExamId' AND ( oee.type = 'QUIZ' OR oee.type = 'EXAM_CONTROLLER' OR oee.type = 'OBE_MARK_ENTRY' )
            $conditions 
            GROUP BY oee.id";
            $oeExams = $this->executeQueryForList($sql_oe);
            foreach ($oeExams as $exam) {
                $oeExamId = $exam->id;
                $studentMarkList = NbaCoService::getInstance()->getCoDetailsOfOnlineExamForSelectAllAnswerdAndMandatoryUnAswered($oeExamId, $studentId,$batchId,$semId,$subjectId);
                $validStudentQuestionIds=NbaCoService::getInstance()->getSectionWiseValidQuestionIdsSelectAllAnswerdAndMandatoryUnAsweredForCoCalculationOfAStudentForOnlineExam($oeExamId,$studentId);
                
                if (!empty($studentMarkList)) {
                    $totalCoPercentList = NbaCoService::getInstance()->calculateTotalCOPercentsOnlineExam($validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList, $batchId, $semId, $subjectId);
                    foreach ($studentMarkList as $row_mark) {
                        $row_mark = (array)$row_mark;
                        if (!in_array($row_mark['oe_exam_questions_id'], $validStudentQuestionIds->nbaCourseOutcomeQuestionsIdList)) {
                            continue;
                        }
                        $mark_obtained = $row_mark['markObtained'];
                        $staffId = $row_mark["created_by"];
                        $maxMark = $row_mark['mark'];
                        foreach($row_mark['cos'] as $coDetails){
                            $nba_course_outcome_id = $coDetails->coId;
                            $course_outcome_value = $coDetails->value;
                            $course_outcome_value = $course_outcome_value / 100;
                            //this is only for course wise type 2 calculation
                            if ($coPoCourseWiseCalculationDisplayStyle==NbaMethod::OBE_CO_PO_CALCULATION_COURSE_WISE_DISPlAY_AND_CALCULATION_TWO){
                                $studentQuestionCoDetails = new NBASubjectAssessmentCoValue();
                                $value = (($mark_obtained / $maxMark) * ($course_outcome_value))*100;
                                $studentQuestionCoDetails->markCOPercentage = $value;
                                $studentQuestionCoDetails->studentId = $studentId;
                                $studentQuestionCoDetails->questionId = $row_mark['oe_exam_questions_id'];
                                $studentQuestionCoDetails->coId = $nba_course_outcome_id;
                                $assessmentStudentQuestionMarkCOList[] = $studentQuestionCoDetails;
                            }
                            if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                                $denominatorValue =($maxMark*($coDetails->value/100));
                                $denominatorValueArray[$nba_course_outcome_id] += $denominatorValue;
                                $nominatorValue =($mark_obtained*($coDetails->value/100));
                                $nominatorValueArray[$nba_course_outcome_id] += $nominatorValue;
                                
                            }else{
                                $per_percent = $totalCoPercentList[$nba_course_outcome_id] / 100;
                                $percentage = ($mark_obtained / $maxMark) * ($course_outcome_value);
                                $exactValue = ($percentage / $per_percent) * 100;
                                $CoArr[$studentId][$nba_course_outcome_id] += $exactValue;
                            }
                        }
                        
                    }
                    if ($coValueCalculationMethod==NbaMethod::OBE_CO_VALUE_CALCULATION_FROM_ASSESSMENTS_METHOD_TWO){
                        foreach ($nominatorValueArray as $coId => $nominatorValue) {
                            $CoArr[$studentId][$coId]= ($nominatorValue/$denominatorValueArray[$coId])*100;
                        }    
                    }
                }
            }
        }
        foreach ($CoArr as $studentId => $nbaCourseOutcomes) {
            foreach ($nbaCourseOutcomes as $coId => $coValue) {
                $nbaSubjectAssessmentCoValue = new NBASubjectAssessmentCoValue();
                $nbaSubjectAssessmentCoValue->assessmentId = $onlineExamId;
                $nbaSubjectAssessmentCoValue->assessmentTypeId = $assessmentTypeId;
                $nbaSubjectAssessmentCoValue->coId = $coId;
                $nbaSubjectAssessmentCoValue->value = $coValue;
                $nbaSubjectAssessmentCoValue->studentId = $studentId;
                $nbaSubjectAssessmentCoValue->staffId = $staffId ? $staffId : $_SESSION['staffID'];//Here staff is the one who enters  mark to students
                $nbaSubjectAssessmentCoValue->batchId = $batchId;
                $nbaSubjectAssessmentCoValue->semId = $semId;
                $nbaSubjectAssessmentCoValue->subjectId = $subjectId;
                $nbaSubjectAssessmentCoValue->createdBy = $_SESSION['staffID'];
                $nbaSubjectAssessmentCoValue->updatedBy = $_SESSION['staffID'];
                $assessmentCOList[] = $nbaSubjectAssessmentCoValue;
            }
        }
        if (empty($assessmentCOList)) {
            $this->deleteCoValuesOfSubjectAssessment($onlineExamId, $assessmentTypeId, $batchId, $semId, $subjectId);
            throw new ProfessionalException(ProfessionalException::EMPTY_CO_ASSESSMENT_LIST_GIVEN, 'Atleast 1 Co must be given');
        }
        $assessmentCourseWiseCOList=$this->courseWiseAttainmentCalculation($assessmentCOList, $nodeId, $assessmentStudentQuestionMarkCOList);
        $this->saveCoValuesForSubjectAssessmentCourseWiseCalculetion($assessmentCourseWiseCOList);
        $this->saveCoValuesForSubjectAssessments($assessmentCOList);
    }
    
}