<?php
class Verbraucher_extern extends IPSModule
{
    private $timerID;

    public function Create()
    {
        parent::Create();

        // Verbraucherspezifische Properties
        $this->RegisterPropertyString("Verbraucher_Liste", "[]");
        $this->RegisterPropertyInteger("Is_Peak", 0);
        $this->RegisterPropertyInteger("delta_power", 0);
        $this->RegisterPropertyInteger("Interval", 5); // Recheninterval

        // Variabeln für Kommunkation mit Manager
        $this->RegisterVariableInteger("Sperre_Prio", "Sperre_Prio");
        $this->RegisterVariableInteger("PV_Prio", "PV_Prio");
        $this->RegisterVariableBoolean("Idle", "Idle", "", 0);
        $this->RegisterVariableInteger("Aktuelle_Leistung", "Aktuelle_Leistung", "", 0);
        $this->RegisterVariableFloat("Bezogene_Energie", "Bezogene_Energie", "", 0);
        $this->RegisterVariableString("PowerSteps", "PowerSteps");
        $this->RegisterVariableInteger("Power", "Power");
        $this->RegisterVariableBoolean("Is_Peak_Shaving", "Is_Peak_Shaving");
        $this->RegisterVariableInteger("Leistung_Delta", "Leistung_Delta", "", 0);

        
        // Hilfsvariabeln für Idle zustand
        $this->RegisterPropertyInteger("IdleCounterMax", 2);
        $this->RegisterVariableInteger("IdleCounter", "IdleCounter", "", 0);
        $this->SetValue("IdleCounter", 0);

        // Initialisiere Idle
        $this->SetValue("Idle", true);

        $this->RegisterTimer("Timer_Do_UserCalc_Verb",$this->ReadPropertyInteger("Interval")*1000,"IPS_RequestAction(" .$this->InstanceID .', "Do_UserCalc", "");');

    }

    public function ApplyChanges()
    {
        parent::ApplyChanges();
        $this->SetTimerInterval("Timer_Do_UserCalc_Verb",$this->ReadPropertyInteger("Interval")*1000); 

    }

    public function RequestAction($Ident, $Value)
    {
        switch ($Ident) {
            
            case "SetAktuelle_Leistung":
                $this->SetValue("Power", (int)$Value);
                break;
    
            case "GetCurrentData":
                $this->SetValue("Is_Peak_Shaving", (bool)$Value);
                break;

            case "Do_UserCalc":
                $this->SetAktuelle_Leistung($this->GetValue("Power"));
                $this->GetCurrentData($this->GetValue("Is_Peak_Shaving"));
                break; 

            default:
                throw new Exception("Invalid Ident");
        }
    }


    private function berechneKombinationen(array $verbraucherListe){
        $kombinationen = [0];
             foreach ($verbraucherListe as $verbraucher) {
                
                if (GetValue($verbraucher['Read_Var']) == true) {
                    $tempListe = [];
                    if(empty($kombinationen)){
                        $kombinationen[] = $verbraucher['P_Nenn']; 
                    }else{
                        foreach ($kombinationen as $wert) {
                            $tempListe[] = $wert + $verbraucher['P_Nenn'];
                        }      
                    $kombinationen = array_merge($kombinationen, $tempListe);
                    }
                }
            }
            sort($kombinationen);
            return array_values(array_unique($kombinationen)); 
        }
    
        private function findCombinationRecursive($power, $values, $currentCombination, $startIndex, &$result) {
             if ($power == 0) {
                 $result = $currentCombination;
                 return true;
             }
             if ($power < 0) {
                 return false;
             }
             for ($i = $startIndex; $i < count($values); $i++) {
                 $currentCombination[] = $values[$i];
                 if ($this->findCombinationRecursive($power - $values[$i], $values, $currentCombination, $i + 1, $result)) {
                     return true;
                 }
                 array_pop($currentCombination);
             }
             return false;
        }
             

        private  function findCombination($power, $values) {
              $result = [];
              $found = $this->findCombinationRecursive($power, $values, [], 0, $result);
              return $found ? $result : null;
            }
            

    private function find($target, $values, $current, &$result) {
                if ($target == 0) {
                    $result[] = $current;
                    return;
                }
                if ($target < 0) {
                    return;
                }
                for ($i = 0; $i < count($values); $i++) {
                    $newValues = array_slice($values, $i + 1);
                $this->find($target - $values[$i], $newValues, array_merge($current, [$values[$i]]), $result);
            }
        }

        private function berechneInverseKombinationen()
        {
        $values = json_decode($this->GetValue("PowerSteps"));
        $result = [];
        
        $firstCombination = $this->findCombination($this->GetValue("Power"), json_decode($this->GetValue("PowerSteps"))); 
        
        //$this->find($this->GetValue("Power"), $values, [], $result);

        $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true);


        //$firstCombination = $result[0];

        foreach ($verbraucherListe as $verbraucher) {
            if (in_array($verbraucher['P_Nenn'], $firstCombination)) {
                RequestAction($verbraucher['Write_Var'], true);
            } else {
                RequestAction($verbraucher['Write_Var'], false);
            }
        }

        return $result;

        }
        
   
    public function SetAktuelle_Leistung(float $power) {
        $this->CheckIdle($power);
        $this->SetValue("Aktuelle_Leistung", $power);
        $this->SetValue("Bezogene_Energie", ($this->GetValue("Bezogene_Energie") + ($this->GetValue("Aktuelle_Leistung")*($this->ReadPropertyInteger("Interval")/3600))));

        $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true);

        $this->berechneInverseKombinationen();
        $this->SetValue("Leistung_Delta", GetValue($this->ReadPropertyInteger("delta_power")));
    }
 
    public function GetCurrentData(bool $Peak)
    {
        $this->SetValue("Is_Peak_Shaving", $Peak);
        RequestAction($this->ReadPropertyInteger("Is_Peak"), $Peak);

        $verbraucherListe = json_decode($this->ReadPropertyString("Verbraucher_Liste"), true);
        $kombinationen = $this->berechneKombinationen($verbraucherListe);
        $this->SetValue("PowerSteps", json_encode($kombinationen));
    }
    

    

    public function CheckIdle($power)
    {
        $lastpower = GetValue($this->GetIDForIdent("Aktuelle_Leistung"));
        if ($lastpower != $power) {
            $this->SetValue("Idle", false);
            $this->SetValue("IdleCounter",$this->ReadPropertyInteger("IdleCounterMax"));
        }
        $idleCounter = $this->GetValue("IdleCounter");
        if ($idleCounter > 0) {
            $this->SetValue("Idle", false);
            $this->SetValue("IdleCounter", $idleCounter - 1);
        } else {
            $this->SetValue("Idle", true);
        }
    }


}

?>
