/*
 * 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 org.clipsmonitor.gui;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Stack;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter.HighlightPainter;
import org.clipsmonitor.clips.ClipsConsole;
import org.clipsmonitor.core.MonitorModel;
import org.clipsmonitor.monitor2015.AssistedLivingModel;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.awt.ActionID;
import org.openide.awt.ActionReference;
import org.openide.windows.TopComponent;
import org.openide.util.NbBundle.Messages;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(
        dtd = "-//org.clipsmonitor.gui//Console//EN",
        autostore = false
)
@TopComponent.Description(
        preferredID = "ConsoleTopComponent",
        //iconBase="SET/PATH/TO/ICON/HERE",
        persistenceType = TopComponent.PERSISTENCE_ALWAYS
)
@TopComponent.Registration(mode = "console", openAtStartup = true)
@ActionID(category = "Window", id = "org.clipsmonitor.gui.ConsoleTopComponent")
@ActionReference(path = "Menu/Window" /*, position = 333 */)
@TopComponent.OpenActionRegistration(
        displayName = "#CTL_ConsoleAction",
        preferredID = "ConsoleTopComponent"
)
@Messages({
    "CTL_ConsoleAction=Console",
    "CTL_ConsoleTopComponent=Console Window",
    "HINT_ConsoleTopComponent=This is a Console window"
})

public final class ConsoleTopComponent extends TopComponent implements Observer,
        KeyListener ,  ActionListener{
    private String text;
    private String currentCmd;
    private String SearchMode;
    private ClipsConsole console;
    private MonitorModel model;
    private LinkedList<String> CmdHistory;
    private int MaxCmdHistory;
    private int ActualCmd;
    private HashMap<String, HighlightPainter > painters ;

    public ConsoleTopComponent() {
        initComponents();
        setName(Bundle.CTL_ConsoleTopComponent());
        setToolTipText(Bundle.HINT_ConsoleTopComponent());
        init();
    }

    private void init(){
        this.model = AssistedLivingModel.getInstance();
        console = ClipsConsole.getInstance();
        console.addObserver(this);
        model.addObserver(this);
        this.CmdHistory = new LinkedList<String>();
        this.MaxCmdHistory=20;
        this.ActualCmd=0;
        String [] deffind = new String []{"defrule","deftemplate","deffunction","defmodule", "deffacts"};
        ComboBoxRenderer comborender = new ComboBoxRenderer(deffind,this.SearchModeCombobox);
        SetPaneStyle();
        this.refreshAll();
        this.cleanWatch();
    }


    private void SetPaneStyle(){

        painters = new HashMap<String,HighlightPainter>();

        painters.put("[ERROR]", new DefaultHighlighter.DefaultHighlightPainter(Color.red));
        painters.put("[WARN]",  new DefaultHighlighter.DefaultHighlightPainter(Color.orange));
        painters.put("[INFO]",  new DefaultHighlighter.DefaultHighlightPainter(Color.green));
        painters.put("[CLIPS]", new DefaultHighlighter.DefaultHighlightPainter(Color.blue));
        painters.put("[INTERNAL]", new DefaultHighlighter.DefaultHighlightPainter(Color.cyan));


    }

    private void clear(){
        this.model = null;
        this.console = null;
        cleanWatch();
        setEditable(false);
        this.jTextPane1.setText("");
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel2 = new javax.swing.JPanel();
        infoCheckBox = new javax.swing.JCheckBox();
        clipsCheckBox = new javax.swing.JCheckBox();
        debugCheckBox = new javax.swing.JCheckBox();
        warnCheckBox = new javax.swing.JCheckBox();
        errorCheckBox = new javax.swing.JCheckBox();
        clearButton = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTextPane1 = new javax.swing.JTextPane();
        jPanel1 = new javax.swing.JPanel();
        FindButton = new javax.swing.JButton();
        SearchModeCombobox = new javax.swing.JComboBox();
        SearchText = new javax.swing.JTextField();
        RulesCheck = new javax.swing.JCheckBox();
        Watch = new javax.swing.JLabel();
        ActivationsCheck = new javax.swing.JCheckBox();
        FactsCheck = new javax.swing.JCheckBox();
        DeffunctionsCheck = new javax.swing.JCheckBox();
        FocusCheck = new javax.swing.JCheckBox();
        GenericFCheck = new javax.swing.JCheckBox();
        MessagesCheck = new javax.swing.JCheckBox();

        org.openide.awt.Mnemonics.setLocalizedText(infoCheckBox, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.infoCheckBox.text")); // NOI18N
        infoCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                infoCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(clipsCheckBox, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.clipsCheckBox.text")); // NOI18N
        clipsCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clipsCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(debugCheckBox, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.debugCheckBox.text")); // NOI18N
        debugCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                debugCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(warnCheckBox, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.warnCheckBox.text")); // NOI18N
        warnCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                warnCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(errorCheckBox, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.errorCheckBox.text")); // NOI18N
        errorCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                errorCheckBoxActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(clearButton, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.clearButton.text")); // NOI18N
        clearButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGap(0, 0, 0)
                .addComponent(infoCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(clipsCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(debugCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(warnCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(errorCheckBox)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(clearButton))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(infoCheckBox)
                .addComponent(clipsCheckBox)
                .addComponent(debugCheckBox)
                .addComponent(warnCheckBox)
                .addComponent(errorCheckBox)
                .addComponent(clearButton))
        );

        jTextPane1.setEditable(false);
        jTextPane1.setBackground(new java.awt.Color(230, 230, 230));
        jTextPane1.setText(org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.jTextPane1.text")); // NOI18N
        jTextPane1.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jTextPane1.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTextPane1FocusGained(evt);
            }
        });
        jTextPane1.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                jTextPane1KeyPressed(evt);
            }
            public void keyReleased(java.awt.event.KeyEvent evt) {
                jTextPane1KeyReleased(evt);
            }
            public void keyTyped(java.awt.event.KeyEvent evt) {
                jTextPane1KeyTyped(evt);
            }
        });
        jScrollPane1.setViewportView(jTextPane1);

        org.openide.awt.Mnemonics.setLocalizedText(FindButton, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.FindButton.text")); // NOI18N
        FindButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FindButtonActionPerformed(evt);
            }
        });

        SearchModeCombobox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
        SearchModeCombobox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                SearchModeComboboxActionPerformed(evt);
            }
        });

        SearchText.setText(org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.SearchText.text")); // NOI18N

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(0, 0, 0)
                .addComponent(SearchText)
                .addGap(0, 0, 0)
                .addComponent(SearchModeCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 0, 0)
                .addComponent(FindButton)
                .addGap(0, 0, 0))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(0, 0, 0)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(FindButton)
                    .addComponent(SearchModeCombobox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(SearchText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(0, 0, 0))
        );

        RulesCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(RulesCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.RulesCheck.text")); // NOI18N
        RulesCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                RulesCheckActionPerformed(evt);
            }
        });

        org.openide.awt.Mnemonics.setLocalizedText(Watch, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.Watch.text")); // NOI18N

        ActivationsCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(ActivationsCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.ActivationsCheck.text")); // NOI18N
        ActivationsCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                ActivationsCheckActionPerformed(evt);
            }
        });

        FactsCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(FactsCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.FactsCheck.text")); // NOI18N
        FactsCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FactsCheckActionPerformed(evt);
            }
        });

        DeffunctionsCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(DeffunctionsCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.DeffunctionsCheck.text")); // NOI18N
        DeffunctionsCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                DeffunctionsCheckActionPerformed(evt);
            }
        });

        FocusCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(FocusCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.FocusCheck.text")); // NOI18N
        FocusCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                FocusCheckActionPerformed(evt);
            }
        });

        GenericFCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(GenericFCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.GenericFCheck.text")); // NOI18N
        GenericFCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                GenericFCheckActionPerformed(evt);
            }
        });

        MessagesCheck.setFont(new java.awt.Font("Noto Sans", 0, 10)); // NOI18N
        org.openide.awt.Mnemonics.setLocalizedText(MessagesCheck, org.openide.util.NbBundle.getMessage(ConsoleTopComponent.class, "ConsoleTopComponent.MessagesCheck.text")); // NOI18N
        MessagesCheck.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                MessagesCheckActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1)
            .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addComponent(Watch)
                .addGap(6, 6, 6)
                .addComponent(RulesCheck)
                .addGap(6, 6, 6)
                .addComponent(FactsCheck)
                .addGap(6, 6, 6)
                .addComponent(FocusCheck)
                .addGap(6, 6, 6)
                .addComponent(ActivationsCheck)
                .addGap(6, 6, 6)
                .addComponent(DeffunctionsCheck)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(GenericFCheck)
                .addGap(6, 6, 6)
                .addComponent(MessagesCheck)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(0, 0, 0)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(RulesCheck)
                    .addComponent(Watch)
                    .addComponent(ActivationsCheck)
                    .addComponent(FactsCheck)
                    .addComponent(DeffunctionsCheck)
                    .addComponent(FocusCheck)
                    .addComponent(GenericFCheck)
                    .addComponent(MessagesCheck))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 226, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void jTextPane1KeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextPane1KeyTyped
        // Check if last line has been changed before "CLIPS> "
        if(!isCursorPositionValid()){
            try {
                this.updatePane();
            } catch (BadLocationException ex) {
            }
        }
    }//GEN-LAST:event_jTextPane1KeyTyped

    private void jTextPane1KeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextPane1KeyReleased
        // Check if last line has been changed before "CLIPS> "
        if(jTextPane1.isEditable() && isCursorPositionValid()){
            if(!evt.isControlDown() && !evt.isShiftDown() && evt.getKeyCode() == KeyEvent.VK_ENTER){
                // Submit command!

              String cmd = this.currentCmd;


                // save on CmdHistory
                if(CmdHistory.size()==this.MaxCmdHistory){
                    CmdHistory.removeLast();
                }

                CmdHistory.addFirst(cmd);
                this.ActualCmd=0;

                this.currentCmd = "";

                try {
                    this.append("> " + cmd);
                } catch (BadLocationException ex) {

                }

                boolean check = this.parenthesisChecker(cmd);
                if(check){

                    String res = model.evalComandLine(cmd);
                    if(res.length() > 0){
                        try {
                            this.append(res);
                        } catch (BadLocationException ex) {

                        }
                    }
                }
                else{

                console.error("Parenthesis checker fallito");
                }


            }
        }
    }//GEN-LAST:event_jTextPane1KeyReleased


    @SuppressWarnings("UnusedAssignment")
    private void jTextPane1KeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_jTextPane1KeyPressed
        ListIterator<String> cmd;
        String JPanelText= this.jTextPane1.getText();
        String promptString = this.console.getPrompt();
        int promptStart = JPanelText.lastIndexOf(promptString);
        int cmdStart = promptStart + promptString.length();
        String CleanCmd=JPanelText.substring(0, cmdStart);


        if(jTextPane1.isEditable() && isCursorPositionValid()){

                switch(evt.getKeyCode()){

                    case KeyEvent.VK_UP :
                       if(CmdHistory.size()>0){ // se c'è qualche elemento nella CmdHistory
                          if(ActualCmd>0 && ActualCmd<CmdHistory.size()-1){  // se ci sono più comando e non sono sugli estremi
                               String textCmd=CmdHistory.get(ActualCmd);
                               JPanelText= CleanCmd.concat(textCmd);
                               jTextPane1.setText(JPanelText);
                               this.setCursorPosition();
                               ActualCmd++;
                          }
                          else{
                               if(ActualCmd==0){  // primo elemento della command history
                                  String textCmd=CmdHistory.getFirst();
                                  JPanelText= CleanCmd.concat(textCmd);
                                  jTextPane1.setText(JPanelText);
                                  this.setCursorPosition();
                                  ActualCmd++;
                              }
                              else{ // ultimo elemento della command
                                  String textCmd=CmdHistory.getLast();
                                  JPanelText= CleanCmd.concat(textCmd);
                                  jTextPane1.setText(JPanelText);
                                  this.setCursorPosition();
                                  ActualCmd=CmdHistory.size()-2;
                              }
                          }
                       }
                       else{
                           JPanelText=CleanCmd.concat(" ");
                           this.jTextPane1.setText(JPanelText);
                           this.setCursorPosition();
                       }
                       break;

                    case KeyEvent.VK_DOWN:
                       if(CmdHistory.size()>0){
                           if(ActualCmd>0 && ActualCmd<CmdHistory.size()-1){
                               String textCmd=CmdHistory.get(ActualCmd);
                               JPanelText= CleanCmd.concat(textCmd);
                               this.jTextPane1.setText(JPanelText);
                               this.setCursorPosition();
                               ActualCmd--;

                          }
                          else{
                               if(ActualCmd==0){
                                  String textCmd=" ";
                                  JPanelText= CleanCmd.concat(textCmd);
                                  this.jTextPane1.setText(JPanelText);
                                  this.setCursorPosition();
                               }
                              else{
                                  String textCmd=CmdHistory.getLast();
                                  JPanelText= CleanCmd.concat(textCmd);
                                  this.jTextPane1.setText(JPanelText);
                                  this.setCursorPosition();
                                  ActualCmd--;
                               }
                          }
                       }
                       else{
                           JPanelText=CleanCmd.concat(" ");
                           jTextPane1.setText(JPanelText);
                           this.setCursorPosition();
                       }
                       break;
                    case KeyEvent.VK_LEFT_PARENTHESIS:
                        String tmp= jTextPane1.getText();
                        tmp +=")";
                        jTextPane1.setText(tmp);
                        break;
                   default :
                       break;
                }

                this.updateCmd();
           }
    }//GEN-LAST:event_jTextPane1KeyPressed

    private void jTextPane1FocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_jTextPane1FocusGained
        if(jTextPane1.isEditable()){
            this.setCursorPosition();
        }
    }//GEN-LAST:event_jTextPane1FocusGained

    private void infoCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_infoCheckBoxActionPerformed
        console.setLogInfo(infoCheckBox.isSelected());
    }//GEN-LAST:event_infoCheckBoxActionPerformed

    private void errorCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_errorCheckBoxActionPerformed
        console.setLogError(errorCheckBox.isSelected());
    }//GEN-LAST:event_errorCheckBoxActionPerformed

    private void clipsCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clipsCheckBoxActionPerformed
        console.setLogClips(clipsCheckBox.isSelected());
    }//GEN-LAST:event_clipsCheckBoxActionPerformed

    private void debugCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_debugCheckBoxActionPerformed
        console.setLogDebug(debugCheckBox.isSelected());
    }//GEN-LAST:event_debugCheckBoxActionPerformed

    private void warnCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_warnCheckBoxActionPerformed
        console.setLogWarn(warnCheckBox.isSelected());
    }//GEN-LAST:event_warnCheckBoxActionPerformed

    private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
        console.clear();
    }//GEN-LAST:event_clearButtonActionPerformed

  private void FindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FindButtonActionPerformed

      String cmd = "( pp" + SearchModeCombobox.getSelectedItem() + " " + SearchText.getText() + ")";

       boolean check = this.parenthesisChecker(cmd);
       if(check){

           String res = model.evalComandLine(cmd);
       }
       else{

       console.error("Parenthesis checker fallito");
     }
  }//GEN-LAST:event_FindButtonActionPerformed

  private void SearchModeComboboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_SearchModeComboboxActionPerformed

  }//GEN-LAST:event_SearchModeComboboxActionPerformed

  private void RulesCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_RulesCheckActionPerformed
     String cmd="";
    if(this.RulesCheck.isSelected()){
      cmd = "(watch rules)";          
    }
    else{
       cmd= "(unwatch rules)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_RulesCheckActionPerformed

  private void ActivationsCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ActivationsCheckActionPerformed
    String cmd="";
    if(this.ActivationsCheck.isSelected()){
      cmd = "(watch activations)";          
    }
    else{
       cmd= "(unwatch activations)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_ActivationsCheckActionPerformed

  private void DeffunctionsCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DeffunctionsCheckActionPerformed
    String cmd="";
    if(this.DeffunctionsCheck.isSelected()){
      cmd = "(watch deffunctions)";          
    }
    else{
       cmd= "(unwatch deffunctions)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_DeffunctionsCheckActionPerformed

  private void FocusCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FocusCheckActionPerformed
    String cmd="";
    if(this.FocusCheck.isSelected()){
      cmd = "(watch focus)";          
    }
    else{
       cmd= "(unwatch focus)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_FocusCheckActionPerformed

  private void GenericFCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_GenericFCheckActionPerformed
    String cmd="";
    if(this.GenericFCheck.isSelected()){
      cmd = "(watch generic-functions)";          
    }
    else{
       cmd= "(unwatch generic-functions)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_GenericFCheckActionPerformed

  private void FactsCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_FactsCheckActionPerformed
    String cmd="";
    if(this.FactsCheck.isSelected()){
      cmd = "(watch facts)";          
    }
    else{
       cmd= "(unwatch facts)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_FactsCheckActionPerformed

  private void MessagesCheckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_MessagesCheckActionPerformed
    String cmd="";
    if(this.MessagesCheck.isSelected()){
      cmd = "(watch messages)";          
    }
    else{
       cmd= "(unwatch messages)";
    }
    String res = model.evalComandLine(cmd);
  }//GEN-LAST:event_MessagesCheckActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox ActivationsCheck;
    private javax.swing.JCheckBox DeffunctionsCheck;
    private javax.swing.JCheckBox FactsCheck;
    private javax.swing.JButton FindButton;
    private javax.swing.JCheckBox FocusCheck;
    private javax.swing.JCheckBox GenericFCheck;
    private javax.swing.JCheckBox MessagesCheck;
    private javax.swing.JCheckBox RulesCheck;
    private javax.swing.JComboBox SearchModeCombobox;
    private javax.swing.JTextField SearchText;
    private javax.swing.JLabel Watch;
    private javax.swing.JButton clearButton;
    private javax.swing.JCheckBox clipsCheckBox;
    private javax.swing.JCheckBox debugCheckBox;
    private javax.swing.JCheckBox errorCheckBox;
    private javax.swing.JCheckBox infoCheckBox;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextPane jTextPane1;
    private javax.swing.JCheckBox warnCheckBox;
    // End of variables declaration//GEN-END:variables
    @Override
    public void componentOpened() {

    }

    @Override
    public void componentClosed() {

    }

    void writeProperties(java.util.Properties p) {
        // better to version settings since initial version as advocated at
        // http://wiki.apidesign.org/wiki/PropertyFiles
        p.setProperty("version", "1.0");
        // TODO store your settings
    }

    void readProperties(java.util.Properties p) {
        String version = p.getProperty("version");
        // TODO read your settings according to their version
    }

    private void append(String s) throws BadLocationException {
        append(s, Color.BLACK, false);
    }

    private void append(String s, Color c) throws BadLocationException {
        append(s,c,false);
    }


    private void append(String s, Color c, boolean bold) throws BadLocationException {
        if(this.text.length() > 0){
            this.text += "\n";
        }
        this.text += s;
        this.updatePane();
    }






    private void updatePane() throws BadLocationException{
        String newText = this.text;
        if(this.text.length() > 0){
            newText += "\n";
        }
        if(console.getActive()){
            newText += console.getPrompt() + currentCmd;
        }

        this.jTextPane1.setText(newText);
        this.setCursorPosition();

        /*
        if(newText!=null && newText.length()>0){
        Highlighter highlighter = jTextPane1.getHighlighter();

        paintPane("ERROR", newText,highlighter);
        paintPane("WARN", newText,highlighter);
        paintPane("INFO", newText,highlighter);
        paintPane("CLIPS", newText,highlighter);
        paintPane("INTERNAL", newText,highlighter);
        }
        */
    }

    private void refreshAll(){
        currentCmd = "";
        setEditable(console.getActive());
        infoCheckBox.setSelected(console.getLogInfo());
        clipsCheckBox.setSelected(console.getLogClips());
        debugCheckBox.setSelected(console.getLogDebug());
        warnCheckBox.setSelected(console.getLogWarn());
        errorCheckBox.setSelected(console.getLogError());
        try { resetText(); }
        catch (BadLocationException ex) {

        }
    }

    private void setCursorPosition(){
        this.jTextPane1.setCaretPosition(this.jTextPane1.getText().length());
    }

    private boolean isCursorPositionValid(){
        String currentText = this.jTextPane1.getText();
        String promptString = console.getPrompt();
        int promptStart = currentText.lastIndexOf(promptString);
        int cmdStart = promptStart + promptString.length();
        return promptStart > 0 && cmdStart-1 < this.jTextPane1.getCaretPosition();
    }

    @Override
    public void update(Observable o, Object arg) {
        String evt = (String)arg;
        if(o instanceof ClipsConsole){
            if(evt.equals("on")){
                setEditable(true);
            }
            else if(evt.equals("off")){
                setEditable(false);
            }
            else if (evt.equals("info on")) {
                infoCheckBox.setSelected(true);
                try {
                    resetText();
                }
                catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("info off")){
                infoCheckBox.setSelected(false);
                try {
                    resetText();
                }
                catch (BadLocationException ex) {       }

                }
            else if (evt.equals("clips on")) {
                clipsCheckBox.setSelected(true);
                try {
                    resetText();
                }
                catch (BadLocationException ex) {
                }
            }
            else if (evt.equals("clips off")){
                clipsCheckBox.setSelected(false);
                try {    resetText();
                } catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("debug on")) {
                debugCheckBox.setSelected(true);
                try {
                    resetText();
                }
                catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("debug off")){
                debugCheckBox.setSelected(false);
                try {
                    resetText();
                } catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("warn on")) {
                warnCheckBox.setSelected(true);
                try {
                    resetText();
                } catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("warn off")){
                warnCheckBox.setSelected(false);
                try {
                    resetText();
                } catch (BadLocationException ex) {

                }
            }
            else if (evt.equals("error on")) {
                errorCheckBox.setSelected(true);
                try {
                    resetText();
                }
                catch (BadLocationException ex) {
                }
            }
            else if (evt.equals("error off")){
                errorCheckBox.setSelected(false);
                try {
                    resetText();
                } catch (BadLocationException ex) {


                }
            }
            else if(evt.equals("log")){
                try {
                    this.append(console.getLastOutputText());
                } catch (BadLocationException ex) {

                }
            }
            else if(evt.equals("debug")) {
                try {
                    this.append(console.getLastOutputText(), Color.DARK_GRAY);
                } catch (BadLocationException ex) {

                }
            }
            else if(evt.equals("error")){
                try {
                    this.append(console.getLastOutputText(), Color.RED, true);
                } catch (BadLocationException ex) {
                }
            }
            else if(evt.equals("warn")){
                try {
                    this.append(console.getLastOutputText(), Color.ORANGE, true);
                } catch (BadLocationException ex) {

                }
            }
            else if(evt.equals("info")){
                String lastOutput = console.getLastOutputText();
                try {
                    this.append(lastOutput, Color.BLUE);
                } catch (BadLocationException ex) {

                }
            }
            else if(evt.equals("clips")){
                try {
                    this.append(console.getLastOutputText(), Color.GRAY);
                } catch (BadLocationException ex) {

                }
            }
            else if(evt.equals("clear")){
                try {
                    resetText();
                } catch (BadLocationException ex) {

                }
            }
            try {
                updatePane();
            } catch (BadLocationException ex) {

            }
        }
        else if(o instanceof MonitorModel){
            if(evt.equals("startApp")){
                init();
            }
            else if(evt.equals("clearApp")){
                clear();
            }
        }
    }

    private void updateCmd() {
        String currentText = this.jTextPane1.getText();
        String promptString = console.getPrompt();
        int promptStart = currentText.lastIndexOf(promptString);
        int cmdStart = promptStart + promptString.length();
        this.currentCmd = currentText.substring(cmdStart);
    }

    private void resetText() throws BadLocationException {
        this.text = console.getFullOutputText();
        updatePane();
    }

    private void setEditable(boolean editable) {
        if(editable){
            jTextPane1.setBackground(new Color(255,255,255));
        }
        else{
            jTextPane1.setBackground(new Color(230,230,230));
        }
        jTextPane1.setEditable(editable);
        clipsCheckBox.setEnabled(editable);
        debugCheckBox.setEnabled(editable);
        warnCheckBox.setEnabled(editable);
        errorCheckBox.setEnabled(editable);
        infoCheckBox.setEnabled(editable);
        SearchText.setEditable(editable);
        SearchModeCombobox.setEnabled(editable);
        FindButton.setEnabled(editable);
        ActivationsCheck.setEnabled(editable);
        RulesCheck.setEnabled(editable);
        FactsCheck.setEnabled(editable);
        DeffunctionsCheck.setEnabled(editable);
        GenericFCheck.setEnabled(editable);
        FocusCheck.setEnabled(editable);
        MessagesCheck.setEnabled(editable);
    }
    
    private void cleanWatch(){
        ActivationsCheck.setSelected(false);
        RulesCheck.setSelected(false);
        FactsCheck.setSelected(false);
        DeffunctionsCheck.setSelected(false);
        GenericFCheck.setSelected(false);
        FocusCheck.setSelected(false);
        MessagesCheck.setSelected(false);
    
    
    }

    @Override
    public void keyTyped(KeyEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void keyPressed(KeyEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void keyReleased(KeyEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }


   


    // controllo sulla corretta chiusura delle parentesi

    private boolean parenthesisChecker(String cmd){

        Stack<Character> par_stack = new Stack<Character>();
        char c ;

        // una stringa valida deve almeno avere la coppia di parentesi quindi stringa di
        // dimensione >=2

        if(cmd.length()==1){

            return false;
        }
        else{

            int firstParenthesis = cmd.indexOf("(");


            // i comandi clips devono necessariamente iniziare con il simbolo (
            if(firstParenthesis==-1){
                return false;
            }

            cmd=cmd.substring(firstParenthesis);

             // controllo il resto della stringa per la corretta sintassi
            for (int i=0 ; i<cmd.length();i++){

                c=cmd.charAt(i);

                if(c=='('){
                    par_stack.push(c);
                }
                if(c==')'){

                    if(par_stack.empty()){
                         return false;  // numero di parentisi chiusa maggiore di quelle aperte
                    }
                    else{
                        if(par_stack.peek()=='('){
                            par_stack.pop();
                        }
                        else{
                          return false;
                        }
                     }
                }
            }
            return par_stack.empty();
       }
  }
}
