/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
 * 
 * ludovic.apvrille AT enst.fr
 * 
 * This software is a computer program whose purpose is to allow the
 * edition of TURTLE analysis, design and deployment diagrams, to
 * allow the generation of RT-LOTOS or Java code from this diagram,
 * and at last to allow the analysis of formal validation traces
 * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
 * from INRIA Rhone-Alpes.
 * 
 * This software is governed by the CeCILL  license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 * 
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 * 
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 */





package tmatrix;

import sddescription.HMSC;
import sdtranslator.SDTranslationException;
import sdtranslator.SDTranslator;
import translator.*;
import ui.*;
import ui.req.Requirement;
import ui.req.RequirementDiagramPanel;
import ui.req.RequirementObserver;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

/**
 * Class RequirementModeling
 * Management of formal requirements
 * Creation: 11/08/2006
 * @version 1.0 11/08/2006
 * @author Ludovic APVRILLE
 */
public class RequirementModeling {
    protected static final String NOT_FORMAL = "Requirement is not a formal requirement";
    protected static final String TOO_MANY_VERIFY = "Observer is linked with too many verify connectors";
    protected static final String UNKNOWN_DIAGRAM_NAME = "is an unknown diagram";
    protected static final String BAD_FORMATTING = "Bad formal description";
    
    private List<Requirements> matrix;
    private List<CheckingError> errors, warnings;
    
    private MainGUI mgui;
    
    // reqs should contain only formal requirement
    public RequirementModeling(Vector<Requirement> reqs, RequirementDiagramPanel rdp, MainGUI _mgui) {
        mgui = _mgui;
        
        matrix = new LinkedList<Requirements>();
        errors = new LinkedList<CheckingError> ();
        warnings = new LinkedList<CheckingError> ();
        
        generateFirstMatrix(reqs, rdp);
        printMatrix();
        generateTURTLEModelings();
        generateFormalSpecification();
    }
    
    
    public void generateFirstMatrix(Vector<Requirement> reqs, RequirementDiagramPanel rdp) {
        Requirement r;
        int i, j;
        Requirements rs;
        Iterator<TGComponent> iterator;
        TGComponent tgc;
        int cpt;
        String tab[];
        RequirementObserver ro;
        
        for(i=0; i<reqs.size(); i++) {
            r = reqs.elementAt(i);
            if (!(r.isFormal())) {
                UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, NOT_FORMAL);
                ce.setTDiagramPanel(rdp);
                ce.setTGComponent(r);
                errors.add(ce);
            } else {
                // r is a formal requirement!
                // Search for all observers linked only to this formal requirement with a "verify" semantics
                iterator = rdp.getComponentList().listIterator();
                while(iterator.hasNext()) {
                    tgc = iterator.next();
                    if (tgc instanceof RequirementObserver) {
                        ro = (RequirementObserver)tgc;
                        cpt = rdp.nbOfVerifyStartingAt(tgc);
                        if (cpt > 1) {
                            UICheckingError ce = new UICheckingError(CheckingError.STRUCTURE_ERROR, TOO_MANY_VERIFY);
                            ce.setTDiagramPanel(rdp);
                            ce.setTGComponent(tgc);
                            errors.add(ce);
                        } else if ((cpt == 1) && (rdp.isLinkedByVerifyTo(tgc, r))) {
                            // Good observer!
                            // So ... parse all observed diagrams -> for the one found -> add a line in the matrix
                            //
                            tab = ro.getDiagramNames();
                            
                            for(j=0; j<tab.length; j++) {
                                //
                                rs = new Requirements();
                                rs.req = r;
                                rs.ro = ro;
                                rs.diagramName = tab[j];
                                matrix.add(rs);
                            }
                        }
                    }
                }
            }
        }
        
    }
    
    // For each (req,obs,diagram), a TURTLE modeling is generated
    public void generateTURTLEModelings() {
        Requirements reqs;
        Iterator<Requirements> iterator = matrix.listIterator();
        TURTLEPanel tp;
        //int sizee;
        
        while(iterator.hasNext()) {
            reqs = iterator.next();
            
            // Locate diagram
            tp = mgui.getTURTLEPanel(reqs.diagramName);
            
            if (tp == null) {
                UICheckingError ce = new UICheckingError(CheckingError.STRUCTURE_ERROR, reqs.diagramName + " " + UNKNOWN_DIAGRAM_NAME);
                ce.setTDiagramPanel(reqs.ro.getTDiagramPanel());
                ce.setTGComponent(reqs.ro);
                errors.add(ce);
            } else {
                //sizee = errors.size();
                buildTURTLEModelingFromTURTLEPanel(reqs, tp);
                /*if (errors.size() != sizee) {
                    
                }*/
                reqs.tm = updateTURTLEModeling(reqs.tm, reqs);
                reqs.tm.simplify();
            }
        }
        
    }
    
    // RT-LOTOS is used by default
    public void generateFormalSpecification() {
        Requirements reqs;
        Iterator<Requirements> iterator = matrix.listIterator();
        //TURTLEPanel tp;
        //CheckingError ce;
        
        while(iterator.hasNext()) {
            reqs = iterator.next();
            if (reqs.tm != null) {
                
                TURTLETranslator tt = new TURTLETranslator(reqs.tm);
                reqs.formalSpec = tt.generateRTLOTOS();
                warnings.addAll(tt.getWarnings());
            }
        }
    }
    
    public List<CheckingError> getCheckingErrors() {
        return errors;
    }
    
    public List<CheckingError> getWarnings() {
        return warnings;
    }
    
    public List<Requirements> getMatrix() {
        return matrix;
    }
    
    public void printMatrix() {
        
    }
    
    public int nbOfElements() {
        return matrix.size();
    }
    
    public Requirements getRequirements(int index) {
        return matrix.get(index);
    }
    
    public String toString() {
        Requirements reqs;
        Iterator<Requirements> iterator = matrix.listIterator();
        String ret = "";
        
        while(iterator.hasNext()) {
            reqs = iterator.next();
            ret += reqs.toString() + "\n";
        }
        
        return ret;
    }
    
    private void buildTURTLEModelingFromTURTLEPanel(Requirements reqs, TURTLEPanel tp) {
        TURTLEModeling tm;
    //    CorrespondanceTGElement listE;
        LinkedList<CheckingError> errorstmp;
        
        mgui.reinitCountOfPanels();
        
        if (tp instanceof AnalysisPanel) {
            HMSC h = null;
            AnalysisPanel ap = (AnalysisPanel)tp;
            AnalysisPanelTranslator apt = new AnalysisPanelTranslator(ap, mgui);
            
            try {
                h = apt.translateHMSC();
                apt.translateMSCs(h);  // -> sans doute une analysisSyntaxException ?
            } catch (AnalysisSyntaxException ase) {
                CheckingError ce = new CheckingError(CheckingError.STRUCTURE_ERROR, ase.getMessage());
                errors.add(ce);
                return;
            }
            
            
            SDTranslator sd = new SDTranslator(h);
            try {
                tm = sd.toTURTLEModeling();
            } catch (SDTranslationException e) {
                CheckingError ce = new CheckingError(CheckingError.STRUCTURE_ERROR, e.getMessage());
                errors.add(ce);
                return;
            }
            
            TURTLEModelChecker tmc = new TURTLEModelChecker(tm);
            errorstmp = tmc.syntaxAnalysisChecking();
            
            if ((errorstmp != null) && (errorstmp.size() > 0)){
                errors.addAll(errorstmp);
            }
            
            reqs.tm = tm;
        } else if (tp instanceof DesignPanel) {
            
            //MasterGateManager.reinitNameRestriction();
            DesignPanel dp = (DesignPanel)tp;
            // Builds a TURTLE modeling from diagrams
            
            DesignPanelTranslator dpt = new DesignPanelTranslator(dp);
            tm = dpt.generateTURTLEModeling();
            
            //tm.print();
            
       //     listE = dpt.getCorrespondanceTGElement();
            errors = dpt.getErrors();
            if ((errors != null) && (errors.size()>0)) {
                //
                return;
            }
            
            // modeling is built
            // Now check it !
            TURTLEModelChecker tmc = new TURTLEModelChecker(tm);
            errorstmp = tmc.syntaxAnalysisChecking();
            
            if ((errorstmp != null) && (errorstmp.size() > 0)){
                //
                errors.addAll(errorstmp);
            }
            
            reqs.tm = tm;
        }
    }
    
    public TURTLEModeling updateTURTLEModeling(TURTLEModeling tm, Requirements reqs) {
        // Get the requirements String
        String text = reqs.req.getText();
        //String s1, s2, s3;
        //int index1;
        String[] actions;
        
        //
        
        // BEFORE_T
        if (text.indexOf("BEFORE_T") != -1) {
            actions = extractInfo(reqs, text, "BEFORE_T", 2, 1);
            if (actions == null) {
                return tm;
            }
            return generateBeforeT(tm, reqs, actions, true);
            
            //LESS_T
        } else if (text.indexOf("LESS_T") != -1) {
            actions = extractInfo(reqs, text, "LESS_T", 2, 1);
            if (actions == null) {
                return tm;
            }
            return generateLessThan(tm, reqs, actions);
            
            //GREAT_T
        } else if (text.indexOf("GREAT_T") != -1) {
            actions = extractInfo(reqs, text, "GREAT_T", 2, 1);
            if (actions == null) {
                return tm;
            }
            return generateGreatThan(tm, reqs, actions);
            
            //BETWEEN
        } else if (text.indexOf("BETWEEN") != -1) {
            actions = extractInfo(reqs, text, "BETWEEN", 2, 2);
            if (actions == null) {
                return tm;
            }
            return generateBetween(tm, reqs, actions);
            
            // OUTSIDE
        } else if (text.indexOf("OUTSIDE") != -1) {
            actions = extractInfo(reqs, text, "OUTSIDE", 2, 2);
            if (actions == null) {
                return tm;
            }
            return generateOutside(tm, reqs, actions);
            
            // MEETS
        } else if (text.indexOf("MEETS") != -1) {
            actions = extractInfo(reqs, text, "MEETS", 2, 0);
            if (actions == null) {
                return tm;
            }
            return generateMeet(tm, reqs, actions);
            
            // BEFORE
        } else if (text.indexOf("BEFORE") != -1) {
            actions = extractInfo(reqs, text, "BEFORE", 2, 0);
            if (actions == null) {
                return tm;
            }
            return generateBefore(tm, reqs, actions);
            
            // STARTS
        } else if (text.indexOf("STARTS") != -1) {
            actions = extractInfo(reqs, text, "STARTS", 2, 0);
            if (actions == null) {
                return tm;
            }
            return generateMeet(tm, reqs, actions);
            
            // FINISHES
        } else if (text.indexOf("FINISHES") != -1) {
            actions = extractInfo(reqs, text, "FINISHES", 2, 0);
            if (actions == null) {
                return tm;
            }
            return generateMeet(tm, reqs, actions);
            
            // UNKNOWN FORMAL REQUIREMENT -> ERROR
        } else {
            addReqFormattingError(reqs);
        }
        return tm;
    }
    
    private String[] extractInfo(Requirements reqs, String text, String word, int action, int time) {
        int index1 = text.indexOf(word);
        String s1 = text.substring(0, index1) + text.substring(index1+word.length()+1, text.length());
        s1 = s1.trim();
        
        String [] actions = extractData(s1);
        //print(actions);
        if (actions.length != (action + time)) {
            addReqFormattingError(reqs);
            return null;
        }
        if ((action == 2) && (time == 2)) {
            if (analysisActionActionTimeTime(reqs, actions) == false) {
                return null;
            }
        } else if ((action == 2) && (time == 1)) {
            if (analysisActionActionTime(reqs, actions) == false) {
                return null;
            }
        }
        return actions;
    }
    
    private String[] extractData(String s) {
        return s.trim().split("((\\s)+(\\r)*(\\n)*)+");
    }
    
    public void addReqFormattingError(Requirements reqs) {
        UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ": " + BAD_FORMATTING);
        ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
        ce.setTGComponent(reqs.req);
        errors.add(ce);
    }
    
    public boolean analysisActionActionTime(Requirements reqs, String[] actions) {
        boolean ret = true;
        if (analysisAction(reqs, actions[0]) == false) {
            ret = false;
        }
        if (analysisAction(reqs, actions[1]) == false) {
            ret = false;
        }
        if (analysisTime(reqs, actions[2]) == false) {
            ret = false;
        }
        return ret;
    }
    
    public boolean analysisActionActionTimeTime(Requirements reqs, String[] actions) {
        boolean ret = true;
        if(analysisActionActionTime(reqs, actions) == false) {
            ret = false;
        }
        if (analysisTime(reqs, actions[3]) == false) {
            ret = false;
        }
        return ret;
    }
    
    public boolean analysisAction(Requirements reqs, String action) {
        if (reqs.tm.knownAction(action) == false) {
            UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ", action : " + action + " " + "is an unknown action");
            ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
            ce.setTGComponent(reqs.req);
            errors.add(ce);
            return false;
        }
        
        if (reqs.tm.hasSeveralTClasWithAction(action)) {
            UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ", action : " + action + " " + "belongs to more than one class");
            ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
            ce.setTGComponent(reqs.req);
            errors.add(ce);
            return false;
        }
        
        return true;
    }
    
    public boolean analysisTime(Requirements reqs, String time) {
        try {
            /*int i =*/ Integer.decode(time).intValue();
        } catch (NumberFormatException nfe) {
            UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ", value: " + time + " " + "is not a correct time value");
            ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
            ce.setTGComponent(reqs.req);
            errors.add(ce);
            return false;
        }
        return true;
    }
    
    public TURTLEModeling generateLessThan(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc0 = new ADJunction();
        //ADJunction junc1 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate actionfirst = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay(actions[2]);
        tlo0.setLatency("0");
        ADActionStateWithGate actionv = new ADActionStateWithGate(gv);
        
        ad.add(adc);
        ad.add(junc0);
        //ad.add(junc1);
        ad.add(actionfirst);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(actionv);
        
        
        ads.addNext(junc0);
        //junc0.addNext(junc1);
        //junc1.addNext(adc);
        junc0.addNext(adc);
        adc.addNext(actionfirst);
        adc.addGuard("[]");
        adc.addNext(action0);
        adc.addGuard("[]");
        actionfirst.addNext(junc0);
        action0.addNext(tlo0);
        tlo0.addNext(junc0);
        tlo0.addNext(actionv);
        
        
        // Modifying observed class: after each observed action, a call to an action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        
        // Managing criticality
        manageCriticality(tm, reqs, t, ad, actions, 2, actionv, junc0);
        
        return tm;
    }
    
    public TURTLEModeling generateGreatThan(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc0 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate actionfirst = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay(actions[2]);
        tlo0.setLatency("0");
        ADActionStateWithGate actionv = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        ad.add(adc);
        ad.add(junc0);
        ad.add(actionfirst);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(actionv);
        ad.add(stop);
        
        ads.addNext(junc0);
        junc0.addNext(adc);
        adc.addNext(actionfirst);
        adc.addGuard("[]");
        adc.addNext(action0);
        adc.addGuard("[]");
        actionfirst.addNext(junc0);
        action0.addNext(tlo0);
        tlo0.addNext(actionv);
        tlo0.addNext(junc0);
        actionv.addNext(stop);
        
        // Modifying observed class: after each observed action, a call to an action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        
        // Managing criticality
        manageCriticality(tm, reqs, t, ad, actions, 2, actionv, junc0); 
        
        return tm;
    }
    
    public TURTLEModeling generateBeforeT(TURTLEModeling tm, Requirements reqs, String[] actions, boolean useTimeInfo) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADJunction junc1 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADTLO tlo0 = new ADTLO(gaction1);
        if (useTimeInfo) {
            tlo0.setDelay(actions[2]);
        } else {
            tlo0.setDelay("1");
        }
        tlo0.setLatency("0");
        ADActionStateWithGate action2 = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        ad.add(junc1);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(action2);
        ad.add(stop);
        
        ads.addNext(junc1);
        junc1.addNext(action0);
        action0.addNext(tlo0);
        tlo0.addNext(junc1);
        tlo0.addNext(action2);
        action2.addNext(stop);
        
        // Modifying observed class: after each observed action, a call to a action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        return tm;
    }
    
    public TURTLEModeling generateBetween(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc0 = new ADJunction();
        ADJunction junc1 = new ADJunction();
        ADJunction junc2 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate actionfirst = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay(actions[2]);
        tlo0.setLatency("0");
        ADTLO tlo1 = new ADTLO(gaction1);
        tlo1.setDelay(deduct(actions[3],actions[2]));
        tlo1.setLatency("0");
        ADActionStateWithGate action2 = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        ad.add(adc);
        ad.add(junc0);
        ad.add(actionfirst);
        ad.add(junc1);
        ad.add(junc2);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(tlo1);
        ad.add(action2);
        ad.add(stop);
        
        ads.addNext(junc0);
        junc0.addNext(adc);
        adc.addNext(actionfirst);
        adc.addGuard("[]");
        adc.addNext(junc1);
        adc.addGuard("[]");
        actionfirst.addNext(junc0);
        junc1.addNext(action0);
        action0.addNext(tlo0);
        tlo0.addNext(junc2);
        tlo0.addNext(tlo1);
        tlo1.addNext(junc1);
        tlo1.addNext(junc2);
        junc2.addNext(action2);
        action2.addNext(stop);
        
        // Modifying observed class: after each observed action, a call to a action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        return tm;
    }
    
    public TURTLEModeling generateOutside(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc0 = new ADJunction();
        ADJunction junc1 = new ADJunction();
        
        ADActionStateWithGate actiona0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate actiona1 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate actionb0 = new ADActionStateWithGate(gaction1);
        ADActionStateWithGate actionb1 = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay(actions[2]);
        tlo0.setLatency("0");
        ADTLO tlo1 = new ADTLO(gaction1);
        tlo1.setDelay(deduct(actions[3],actions[2]));
        tlo1.setLatency("0");
        ADActionStateWithGate actionv = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        
        ads.addNext(junc0);
        junc0.addNext(adc);
        adc.addNext(actionb0);
        adc.addGuard("[]");
        adc.addNext(actiona1);
        adc.addGuard("[]");
        actionb0.addNext(actiona0);
        actiona0.addNext(junc0);
        actiona1.addNext(tlo0);
        tlo0.addNext(junc1);
        tlo0.addNext(tlo1);
        tlo1.addNext(actionv);
        tlo1.addNext(actionb1);
        actionv.addNext(stop);
        actionb1.addNext(junc1);
        junc1.addNext(junc0);
        
        ad.add(junc0);
        ad.add(junc1);
        ad.add(adc);
        ad.add(actiona0);
        ad.add(actiona1);
        ad.add(actionb0);
        ad.add(actionb1);
        ad.add(tlo0);
        ad.add(tlo1);
        ad.add(actionv);
        ad.add(stop);
        
        // Modifying observed class: after each observed action, a call to a action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        return tm;
    }
    
    public TURTLEModeling generateMeet(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc1 = new ADJunction();
        ADJunction junc2 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate action1 = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay("1");
        tlo0.setLatency("0");
        ADActionStateWithGate action2 = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        ad.add(adc);
        ad.add(junc1);
        ad.add(junc2);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(action2);
        ad.add(stop);
        
        ads.addNext(junc1);
        junc1.addNext(adc);
        adc.addNext(junc2);
        adc.addGuard("[]");
        adc.addNext(action0);
        adc.addGuard("[]");
        action1.addNext(junc1);
        action0.addNext(tlo0);
        tlo0.addNext(junc2);
        tlo0.addNext(action2);
        junc2.addNext(action1);
        action2.addNext(stop);
        
        // Modifying observed class: after each observed action, a call to a action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        return tm;
    }
    
    public TURTLEModeling generateBefore(TURTLEModeling tm, Requirements reqs, String[] actions) {
        // Creating TClass
        TClass t = new TClass("T__" + reqs.ro.getValue(), true);
        Gate gv = t.addNewGateIfApplicable(reqs.req.getViolatedAction());
        Gate gaction0 = t.addNewGateIfApplicable("obs__" + actions[0]);
        
        //
        Gate gaction1 = t.addNewGateIfApplicable("obs__" + actions[1]);
        
        // Making Activity diagram
        ActivityDiagram ad = new ActivityDiagram();
        ADStart ads = ad.getStartState();
        t.setActivityDiagram(ad);
        
        ADChoice adc = new ADChoice();
        ADJunction junc1 = new ADJunction();
        ADJunction junc2 = new ADJunction();
        ADActionStateWithGate action0 = new ADActionStateWithGate(gaction0);
        ADActionStateWithGate action1 = new ADActionStateWithGate(gaction1);
        ADTLO tlo0 = new ADTLO(gaction1);
        tlo0.setDelay("1");
        tlo0.setLatency("0");
        ADActionStateWithGate action2 = new ADActionStateWithGate(gv);
        ADStop stop = new ADStop();
        ad.add(adc);
        ad.add(junc1);
        ad.add(junc2);
        ad.add(action0);
        ad.add(tlo0);
        ad.add(action2);
        ad.add(stop);
        
        ads.addNext(junc1);
        junc1.addNext(adc);
        adc.addNext(junc2);
        adc.addGuard("[]");
        adc.addNext(action0);
        adc.addGuard("[]");
        action1.addNext(junc1);
        action0.addNext(tlo0);
        tlo0.addNext(action2);
        tlo0.addNext(junc2);
        junc2.addNext(action1);
        action2.addNext(stop);
        
        // Modifying observed class: after each observed action, a call to a action synchronized with the observer is performed
        ModifyTMTwoActions(tm, t, gaction0, gaction1, reqs, actions);
        return tm;
    }
    
    public void ModifyTMTwoActions(TURTLEModeling tm, TClass t, Gate gaction0, Gate gaction1, Requirements reqs, String[] actions) {
        int nb;
        
        TClass t0 = tm.getTClassWithAction(actions[0]);
        Gate g0 = t0.getGateByName(actions[0]);
        Gate g00 = t0.addNewGateIfApplicable("obs__" + actions[0]);
        nb = t0.duplicateCall(g0, g00);
        if ( nb > 1) {
            addWarningDuplicate(reqs, actions[0], t0);
        } else if (nb == 0) {
            addWarningNoCall(reqs, actions[0], t0);
        }
        
        TClass t1 = tm.getTClassWithAction(actions[1]);
        Gate g1 = t1.getGateByName(actions[1]);
        Gate g11 = t1.addNewGateIfApplicable("obs__" + actions[1]);
        nb = t1.duplicateCall(g1, g11);
        if ( nb > 1) {
            addWarningDuplicate(reqs, actions[1], t1);
        } else if (nb == 0) {
            addWarningNoCall(reqs, actions[1], t1);
        }
        
        // Modifying TURTLE Modeling
        tm.addTClass(t);
        tm.addSynchroRelation(t, gaction0, t0, g00);
        tm.addSynchroRelation(t, gaction1, t1, g11);
    }
    
    public void manageCriticality(TURTLEModeling tm, Requirements reqs, TClass t, ActivityDiagram ad, String[] actions, int nbActions,  ADComponent actionv, ADComponent tgc2) {
        
        if (reqs.req.getCriticality() == Requirement.LOW) {
            // LOW
            // If action is violated -> generate an error action an reloop on the observer
            
            actionv.addNext(tgc2);
            
        } else if (reqs.req.getCriticality() == Requirement.MEDIUM) {
            // MEDIUM
            // if action is violated -> generate an error action, preempt all objects concerned with observation, and stop
            
            ADStop adstop; 
            ADParallel adpar = new ADParallel();
            Vector<TClass> tclasses = new Vector<TClass>();
            Gate g, go;
            TClass to;
            ADActionStateWithGate action;
             
            ad.add(adpar);
            actionv.addNext(adpar);
             
            for(int i=0; i<nbActions; i++) {
                to = tm.getTClassWithAction(actions[i]);
                if (!tclasses.contains(to)) {
                    // add a action to preempt to
                    tclasses.add(to);
                    g = t.addNewGateIfApplicable("preempt__" + i);
                    go = to.addNewGateIfApplicable("preempted__by__" + reqs.ro.getValue());
                    action = new ADActionStateWithGate(g);
                    adstop = new ADStop();
                    
                    ad.add(action);
                    ad.add(adstop);
                    
                    adpar.addNext(action);
                    action.addNext(adstop);
                    
                    to.addTopPreemptOn(go);
                    tm.addSynchroRelation(t, g, to, go);
                }
            }
            
        } else {
            // HIGH
            // if action is violated, preempt all objects
            
            ADStop adstop; 
            ADParallel adpar = new ADParallel();
            Gate g, go;
            TClass to;
            ADActionStateWithGate action;
             
            ad.add(adpar);
            actionv.addNext(adpar);
            
            for(int i=0; i<tm.classNb(); i++) {
                to = tm.getTClassAtIndex(i);
                if (to != t) {
                    // Add an action to preempt to
                    g = t.addNewGateIfApplicable("preempt__" + i);
                    go = to.addNewGateIfApplicable("preempted__by__" + reqs.ro.getValue());
                    action = new ADActionStateWithGate(g);
                    adstop = new ADStop();
                    
                    ad.add(action);
                    ad.add(adstop);
                    
                    adpar.addNext(action);
                    action.addNext(adstop);
                    
                    to.addTopPreemptOn(go);
                    tm.addSynchroRelation(t, g, to, go);
                }
            }
        }
    }
    
    public void addWarningDuplicate(Requirements reqs, String action, TClass t0) {
        UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ", value: " + action + " is called more than one time in" + t0.getName());
        ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
        ce.setTGComponent(reqs.req);
        warnings.add(ce);
    }
    
    public void addWarningNoCall(Requirements reqs, String action, TClass t0) {
        UICheckingError ce = new UICheckingError(CheckingError.BEHAVIOR_ERROR, reqs.req.getValue() + ", value: " + action + " is never called in" + t0.getName());
        ce.setTDiagramPanel(reqs.req.getTDiagramPanel());
        ce.setTGComponent(reqs.req);
        warnings.add(ce);
    }
    
    public void print(String []actions) {
        for(int i=0; i<actions.length; i++) {
            
        }
    }
    
    public String deduct(String s1, String s2) {
        int i1 = Integer.decode(s1).intValue();
        int i2 = Integer.decode(s2).intValue();
        int i3 = i1 - i2;
        //
        return Integer.toString(i3);
    }
}