<?php

namespace local_treestudyplan;
require_once($CFG->libdir.'/externallib.php');

abstract class aggregator {
    private const FALLBACK = "bistate";
    private static $mod_supported = [];

    public static function supported($mod){
        if(!array_key_exists($mod,self::$mod_supported)){
            self::$mod_supported[$mod] = class_exists(self::aggregator_name($mod));
        }
        return self::$mod_supported[$mod];
    }

    private static function aggregator_name($mod){
        return "\local_treestudyplan\\local\\aggregators\\{$mod}_aggregator";
    }

    public static function list(){
        // static list, since we'd need to implement a lot of static data for new aggregation methods anyway
        // and this is faster than any dynamic method.
        return [
            "core", # use moodle core completion
            "bistate", 
            "tristate", # deprecated
        ];
    }

    public static function create($mod,$configstr){
        if(self::supported($mod)){
            $ag_class = self::aggregator_name($mod);
            return new $ag_class($configstr);
        } else {
            throw new \InvalidArgumentException("Cannot find aggregator '{$mod}'");
        }
    }

    public static function createOrDefault($mod,$configstr){
        try {
            return self::create($mod,$configstr);
        }
        catch(\ValueError $x){
            return self::create(self::FALLBACK,"");
        }
    }
    
    private function __construct($configstr) {
        $this->initialize($configstr);
    }

    protected function initialize($configstr) {}

    public abstract function needSelectGradables();
    public abstract function isDeprecated();
    public abstract function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid);
    public abstract function aggregate_junction(array $completion, studyitem $studyitem, $userid);

    public abstract function grade_completion(gradeinfo $gradeinfo, $userid);

    // Aggregation method makes use of "required grades" in a course/module
    public abstract function useRequiredGrades();
    // Aggregation method makes use of 
    public abstract function useItemConditions();

    // Whether the aggregation method uses core_completion, or treestudyplan custom completion
    public function usecorecompletioninfo(){ 
        return false;
    }

    // Parameter editing functions - override in child class to implement parameter config for aggregation

    // Return the current configuration string
    public function config_string() {
        return "";
    }

    public static function basic_structure($value=VALUE_REQUIRED){
        return new \external_single_structure([
            "useRequiredGrades" => new \external_value(PARAM_BOOL, 'id of studyplan'),
            "useItemConditions" => new \external_value(PARAM_BOOL, 'name of studyplan'),
        ],"Aggregator requirements",$value);
    }

    public function basic_model(){
        return [ 
            "useRequiredGrades" => $this->useRequiredGrades(),
            "useItemConditions" => $this->useItemConditions(),
        ];
    }

    public static function list_structure($value=VALUE_REQUIRED){
        return  new \external_multiple_structure(new \external_single_structure([
            "id" => new \external_value(PARAM_TEXT, 'id of aggregator'),
            "name" => new \external_value(PARAM_TEXT, 'name of agregator'),
            "deprecated" => new \external_value(PARAM_BOOL, 'if method is deprecated'),
            "defaultconfig" => new \external_value(PARAM_TEXT, 'default config of agregator'),

        ],"Available aggregators",$value));
    }

    public static function list_model(){
        
        $list = [];
        foreach(self::list() as $agid){
            $a = self::create($agid,""); // create new one with empty config string
            $list[] = [
                'id' => $agid,
                'name' => get_string("{$agid}_aggregator_title","local_treestudyplan"),
                'deprecated' => $a->isDeprecated(),
                'defaultconfig' => $a->config_string(),
            ];
        }
        
        return $list;
    }


}