<?php
namespace local_treestudyplan\local;

use Exception;

class gradegenerator {
    private $table = [];

    private static $loremipsum = [
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
        "Etiam scelerisque ligula porttitor velit sollicitudin blandit.",
        "Praesent laoreet nisi id lacus laoreet volutpat.",
        "Donec rutrum tortor tempus lectus malesuada, ut pretium eros vehicula.",
        "Phasellus vulputate tortor vehicula mauris porta ultricies.",
        "Ut et lacus sit amet nisl facilisis elementum.",
        "Vestibulum ut mauris ac justo tincidunt hendrerit.",
        "Fusce congue nulla quis elit facilisis malesuada.",
        "Aenean ornare eros placerat ipsum fringilla, sed imperdiet felis imperdiet.",
        "Ut malesuada risus ultricies arcu dapibus, quis lobortis eros maximus.",
        "Nam ullamcorper dolor ac est tristique, vel blandit tortor tristique.",
        "Quisque quis lorem vitae leo lobortis posuere.",
        "Nulla ac enim consectetur, rhoncus eros sed, malesuada enim.",
        "Vestibulum lobortis lacus ac dolor pulvinar, gravida tincidunt dolor bibendum.",
        "Maecenas fringilla urna eget sem bibendum, non lacinia lorem tempus.",
        "Nullam quis metus sagittis, pharetra orci eget, ultrices nunc.",
        "Morbi et ante at ipsum sodales porta.",
        "Morbi vel neque in urna vestibulum vestibulum eu quis lectus.",
        "Nam consequat dolor at enim vestibulum, ac gravida nisl consequat.",
        "Phasellus ac libero vestibulum, vulputate tellus at, viverra dui.",
        "Vivamus venenatis magna a nunc cursus, eget laoreet velit malesuada.",
        "Cras fermentum velit vitae tellus sodales, vulputate semper purus porta.",
        "Cras ultricies orci in est elementum, at laoreet erat tempus.",
        "In non magna et lorem sagittis sollicitudin sit amet et est.",
        "Etiam vitae augue ac turpis volutpat iaculis a vitae enim.",
        "Integer pharetra quam ac tortor porta dignissim.",
        "Pellentesque ullamcorper neque vitae ligula rhoncus accumsan.",
        "Nullam in lectus sit amet est faucibus elementum vitae vel risus.",
        "Aenean vehicula libero ut convallis blandit.",
        "Aenean id mi facilisis, tristique enim vel, egestas lorem.",
        "Mauris suscipit dui eget neque gravida, vel pellentesque leo gravida.",
        "Quisque quis elit at velit maximus viverra ultricies in nisi.",
        "Vivamus et orci nec magna hendrerit egestas sed quis arcu.",
        "Suspendisse semper tortor sed justo iaculis volutpat.",
        "Praesent interdum dolor nec ultricies imperdiet.",
        "Vivamus tristique justo quis tellus commodo, at faucibus justo auctor.",
        "Praesent pharetra tellus vel nunc mattis pharetra.",
        "Cras a dui quis arcu rutrum ullamcorper sit amet et sem.",
        "Aenean porttitor risus ac enim tempor posuere.",
        "Mauris bibendum augue ac vehicula mattis.",
        "Vestibulum nec justo vehicula, euismod enim sed, convallis magna.",
        "Praesent ultrices elit vitae velit dignissim dignissim.",
        "Curabitur vehicula velit vitae tortor consequat consectetur sit amet at leo.",
        "Sed lobortis neque a magna facilisis aliquam.",
        "Phasellus a libero in sem aliquam varius.",
        "Mauris tincidunt ligula a risus efficitur euismod.",
        "Sed pharetra diam ac neque tempus convallis.",
        "Donec at ipsum elementum ex hendrerit laoreet mollis non elit.",
        "Praesent eu arcu sollicitudin, fermentum tellus at, blandit dolor.",
        "Curabitur in lectus consequat, bibendum ligula vitae, semper lacus.",
        "Aenean eu risus non sem pretium dictum.",
        "Praesent nec risus vestibulum quam venenatis tempor.",
        "Nullam rhoncus ex a quam egestas, eu auctor enim lobortis.",
        "Nam luctus ante id lacus scelerisque, quis blandit ante elementum.",
    
    ];

    private function generatedfeedback(){
        if(file_exists("/usr/games/fortune")){
            // get a fortune if it is available
            return shell_exec("/usr/games/fortune -n 160 -e disclaimer literature science pratchett wisdom education");
        } else {
            // get a random loremipsum string
            return self::$loremipsum[rand(0,count(self::$loremipsum)-1)];
        }
    }


    public function __construct(){
        
    }

    public function addstudent(string $student){
        if(!array_key_exists($student,$this->table)){
            $this->table[$student] = [ 
                "intelligence" => rand(70,100),
                "endurance" => rand(70,100),
                "skills" => [],
            ];
        }
    }

    public function addskill(string $student, string $skill){
        $this->addstudent($student);
        if(!array_key_exists($skill,$this->table[$student]["skills"])){
            $int = $this->table[$student]["intelligence"];
            $end = $this->table[$student]["endurance"];
            $this->table[$student]["skills"][$skill] = [ 
                "intelligence" => min(100, $int + rand(-30,30)),
                "endurance" => min(100, $end + rand(-10,10)),
            ];
        }
    }

    // Below is mostly just for reference in the json file
    public function addUserNameInfo(string $student, $firstname,$lastname){
        $this->addstudent($student);
        $this->table[$student]["firstname"] = $firstname;
        $this->table[$student]["lastname"] = $lastname;
    }

    public function generateraw($student,$skill, $count )
    {
        $this->addskill($student,$skill);
        $int = $this->table[$student]["skills"][$skill]["intelligence"];
        $end = $this->table[$student]["skills"][$skill]["endurance"];

        $results = [];
        $gaveup = false;
        for($i=0; $i < $count; $i++){
            $r = new \stdClass;
            if($gaveup) {
                $r->done = !$gaveup;
            } else {
                $r->done = (rand(0, $end) > 20); // Determine if the assignment was done
            }
            if($r->done){
                $score = rand(0,$int) ;
                $r->result = ($score > 20); // determine if the assignment was successful
                if(!$r->result){
                    $r->failed = !($score > 10); 
                }
            } else {
                $r->result = false; // make sure a result property is always there
                $r->failed = true;
            }
            // Aways generate a little feedback
            $r->fb = $this->generatedfeedback();
            $results[] = $r;

            if(!$gaveup && $i >= 3) {
                // There is a slight chance the students with low endurance for this course will stop with this course's work entirely
                $gaveup = (rand(0,$end) < 15);
            }
        }
        return $results;
    }

    public function generate($student,$skill, array $gradeinfos ){
        global $DB;
        $table ="local_treestudyplan_gradecfg";

        $rlist = [];
        $gen = $this->generateraw($student,$skill, count($gradeinfos));

        for($i=0; $i < count($gradeinfos); $i++){
            $g = $gradeinfos[$i];
            $gi = $g->getGradeitem();
            $gr = $gen[$i];

            // First get the configured interpretation for this scale or grade
            $scale = $gi->load_scale();
            if( isset($scale)){
                $gradecfg = $DB->get_record($table,["scale_id"=>$scale->id]);
            }
            else if($gi->grademin == 0)
            {
                $gradecfg = $DB->get_record($table,["grade_points"=>$gi->grademax]);
            }
            else 
            {
                $gradecfg = null;
            }

            // next generate the grade
            if($gradecfg)
            {
                if(!$gr->done){
                    // INCOMPLETE
                    // fair chance of teacher forgetting to set incomplete to "no evidence"
                    $grade = 0;// $grade =  (rand(0,100) > 15)?max(1, $gradecfg->min_progress-1):"0";
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>"" ];
                }
                else if(!$gr->result){
                    $grade =  rand($gradecfg->min_progress, $gradecfg->min_completed -1 );
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>$gr->fb ];
                }
                else{
                    // COMPLETED
                    $r = (object)["gi" => $g, "grade" => rand( $gradecfg->min_completed, $gi->grademax ), "fb" =>$gr->fb ];
                }

                $r->gradetext = $r->grade;
                if( isset($scale)){
                    $scaleitems = $scale->load_items();
                    if($r->grade > 0){
                        $r->gradetext = trim($scale->get_nearest_item($r->grade));
                    } else {
                        $r->gradetext = "-";
                    }
                }
                
            }
            else if($gi->gradepass > 0)
            {
                if(!$gr->done){
                    // INCOMPLETe or FAILED
                    $grade =  rand(0, $gi->gradepass/2);
                    $r = (object)["gi" => $g, "grade" => $grade, "fb" =>($grade > 0)?$gr->fb:"" ];
                }
                else if(!$gr->result){
                    //PROGRESS
                    $r = (object)["gi" => $g, "grade" => rand( round($gi->gradepass/2), $gi->gradepass -1 ), "fb" =>$gr->fb ];
                }
                else{
                    // COMPLETED
                    $r = (object)["gi" => $g, "grade" => rand(  $gi->gradepass, $gi->grademax ), "fb" =>$gr->fb ];
                }
               
                $r->gradetext = $r->grade;
            }
            else {
                // Blind assumptions if nothing is provided
                // over 55% of range is completed
                // under 35% is not done
                $range = floatval($gi->grademax - $gi->grademin);

                if(!$gr->done){
                    // INCOMPLETe or FAILED
                    $grade =  rand(0, round($range * 0.35) - 1);
                    $r = (object)["gi" => $g, "grade" =>  $gi->grademin+$grade, "fb" =>($grade > 0)?$gr->fb:"" ];
                }
                else if(!$gr->result){
                    //PROGRESS
                    $r = (object)["gi" => $g, "grade" => $gi->grademin+rand(round($range * 0.35),round($range * 0.55) - 1 ), "fb" =>$gr->fb ];
                }
                else{
                    // COMPLETED
                    $r = (object)["gi" => $g, "grade" => $gi->grademin+rand(round($range * 0.55) , $range  ), "fb" =>$gr->fb ];
                }

                $r->gradetext = $r->grade;
            }

            $rlist[] = $r;
          
        }

        return $rlist;
    }

    public function getstats($student){
        return $this->table[$student];
    }
    public function serialize(): ?string{
        return json_encode([
            "table" => $this->table],JSON_PRETTY_PRINT);
    }

    public function unserialize(string $data): void {
        $o = json_decode($data,true);
        $this->table = $o["table"];
    }

    public function toFile(string $filename){
        $filename = self::expand_tilde($filename);
        file_put_contents($filename,$this->serialize());
    }

    public function fromFile(string $filename){
        $filename = self::expand_tilde($filename);
        if(file_exists($filename)){
            try{
                $json = file_get_contents($filename);
                $this->unserialize($json);
            } catch(Exception $x){
                cli_problem("ERROR loading from file");
                throw $x; // Throw X up again to show the output
            }
        }
    }

    private static function expand_tilde($path)
    {
        if (function_exists('posix_getuid') && strpos($path, '~') !== false) {
            $info = posix_getpwuid(posix_getuid());
            $path = str_replace('~', $info['dir'], $path);
        }
    
        return $path;
    }


}
