/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package HPalang;

import HPalang.Core.ActorType;
import HPalang.Core.CommunicationType;
import HPalang.Core.SoftwareActor;
import HPalang.Core.DelegationParameter;
import HPalang.Core.ContinuousExpressions.DifferentialEquation;
import HPalang.Core.DiscreteExpressions.BinaryExpression;
import HPalang.Core.DiscreteExpressions.BinaryOperators.*;
import HPalang.Core.DiscreteExpressions.VariableExpression;
import HPalang.Core.InstanceParameter;
import HPalang.Core.MessageHandler;
import HPalang.Core.Mode;
import HPalang.Core.ContinuousExpressions.Invarient;
import HPalang.Core.DiscreteExpressions.FalseConst;
import HPalang.Core.DiscreteExpressions.TrueConst;
import HPalang.Core.MainBlock;
import HPalang.Core.Message;
import HPalang.Core.PhysicalActor;
import HPalang.Core.PhysicalActorType;
import HPalang.Core.ModelDefinition;
import HPalang.Core.SoftwareActorType;
import HPalang.Core.Statement;
import HPalang.Core.Statements.AssignmentStatement;
import HPalang.Core.Statements.IfStatement;
import HPalang.Core.Variable;
import HPalang.Core.Variables.FloatVariable;
import HPalang.Core.Variables.RealVariable;
import static HPalang.Core.ModelCreationUtilities.*;
import HPalang.Core.SingleCommunicationRealVariablePool;
import HPalang.LTSGeneration.Labels.Guard;

/**
 *
 * @author Iman Jahandideh
 */
public class SingleBrakeModel
{

    public static final String Brake__brake_percent = "brake_percent";
    public static final String Brake__timer = "timer";
    public static final String Brake__increasing_brake = "IncreasingBrake";
    public static final String Brake__constant_brake = "ConstantBrake";
    public static final float Brake__period_const = 5f;
    public static final float Brake__brake_rate_const = 1f;
    



   
    public static ModelDefinition Create()
    {
        ModelDefinition definition = new ModelDefinition();
        
        PhysicalActorType brakeType = new PhysicalActorType("Brake");

        
        FillSkeletonForBrakeType(brakeType);
        
        FillFleshForBrakeType(brakeType);

        PhysicalActor brake_pedal = new PhysicalActor("brake", brakeType, 1);
    
        definition.AddActor(brake_pedal);
   
        
        definition.SetMainBlock(new MainBlock());
        
        definition.SetEventSystemVariablePoolSize(0);
        
        SingleCommunicationRealVariablePool globalPool = new SingleCommunicationRealVariablePool();
         

       
        definition.SetInitialGlobalVariablePool(globalPool);
        
        return definition;
    }
    
    private static void FillSkeletonForBrakeType(PhysicalActorType brakeType)
    {
        brakeType.AddVariable(new RealVariable(Brake__brake_percent));        
        brakeType.AddVariable(new RealVariable(Brake__timer));
        
        brakeType.AddMode(new Mode(Brake__increasing_brake));    
        brakeType.AddMode(new Mode(Brake__constant_brake));

        brakeType.SetInitialMode(brakeType.FindMode(Brake__increasing_brake));
    }
    
    private static void FillFleshForBrakeType(PhysicalActorType brakeType)
    {
        RealVariable brake_percent = (RealVariable) brakeType.FindVariable(Brake__brake_percent);
        RealVariable timer = (RealVariable) brakeType.FindVariable(Brake__timer);
        
        Mode increasingBrakeMode = brakeType.FindMode(Brake__increasing_brake);
        Mode constantBrakeMode = brakeType.FindMode(Brake__constant_brake);
                
        increasingBrakeMode.SetInvarient(new Invarient(
                CreateBinaryExpression(
                        CreateBinaryExpression(timer, "<=", Const(Brake__period_const)),
                        "&&",
                        CreateBinaryExpression(brake_percent, "<=", Const(100f)) )));
        
        increasingBrakeMode.SetGuard(new Guard(CreateBinaryExpression(
                        CreateBinaryExpression(timer, "==", Const(Brake__period_const)),
                        "||",
                        CreateBinaryExpression(brake_percent, "==", Const(100f)))));
        
        increasingBrakeMode.AddDifferentialEquation(new DifferentialEquation(timer, Const(1f)));
        increasingBrakeMode.AddDifferentialEquation(new DifferentialEquation(brake_percent, Const(Brake__brake_rate_const)));
        increasingBrakeMode.AddAction(CreateResetFor(timer));
        increasingBrakeMode.AddAction(new IfStatement(
                CreateBinaryExpression(brake_percent,"<",Const(100)),
                Statement.StatementsFrom(CreateModeChangeStatement(increasingBrakeMode)), 
                Statement.StatementsFrom(CreateModeChangeStatement(constantBrakeMode))
        ));
        
        constantBrakeMode.SetInvarient(new Invarient(CreateBinaryExpression(timer, "<=", Const(Brake__period_const))));
        constantBrakeMode.SetGuard(CreateGuard(timer, "==", Brake__period_const));
        
        constantBrakeMode.AddDifferentialEquation(new DifferentialEquation(timer, Const(1f)));
        constantBrakeMode.AddDifferentialEquation(new DifferentialEquation(brake_percent, Const(0)));
        constantBrakeMode.AddAction(CreateResetFor(timer));
        constantBrakeMode.AddAction(CreateModeChangeStatement(constantBrakeMode));
    }

}
