/*
 * Copyright (C) 1999-2006 <a href="mailto:adrian.paschke@gmx.de">Adrian Paschke</a>
 * 
 * The RBSLM Environment is part of the Rule Based Service Level Agreement (RBSLA)
 * framework, available at 
 * <a href=" http://ibis.in.tum.de/staff/paschke/rbsla/index.htm">RBSLA</a>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package rbsla.environment;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import org.apache.log4j.Logger;

import rbsla.eca.Daemon;
import rbsla.eca.KnowledgeDefinition;
import rbsla.wrapper.ProvaWrapper;
import rbsla.environment.dialogs.AddViewDialog;
import rbsla.environment.dialogs.ECARuleWindow;
import rbsla.environment.dialogs.InfoDialog;
import rbsla.environment.dialogs.OutputConsole;
import rbsla.environment.dialogs.ProvaConsole;
import rbsla.environment.view.ActThread;
import rbsla.environment.view.StatsActual;
import rbsla.environment.view.StatsAvalaibility;
import rbsla.environment.view.StatsQuery;
import rbsla.environment.view.ViewDialog;

/**
 * Main ECA Panel.
 */
public class ECAPanel extends JPanel implements ActionListener, ItemListener,
        KeyListener, MouseListener, MouseMotionListener
{

    public ProvaWrapper myProva;

    public Daemon startEcaDaemon = null;

    protected String buffer;

    public GridBagLayout mainLayout = new GridBagLayout();
    
    private GridLayout buttonLayout = new GridLayout(1,6);

    public static final Font XsmallFont = new Font("Helvetica", Font.PLAIN, 10);

    public static final Font smallFont = new Font("Helvetica", Font.PLAIN, 12);

    public static final Font largeFont = new Font("Helvetica", Font.PLAIN, 14);

    public static final Font largeBoldFont = new Font("Helvetica", Font.BOLD,
            14);

    public static final Font XlargeFont = new Font("Helvetica", Font.PLAIN, 16);

    // ...otherwise
    protected ECAWindow parentWindow;

    private Class thisClass = ECAPanel.class;

    
    
    //vector that contains the imported files
    private Vector impFiles = new Vector();
    
    
    // The button panel

    protected JPanel buttonPanel;

    protected JButton startButton;

    protected JButton reloadKnowledgeBaseButton;

    protected JButton stopButton;

    protected JButton addViewButton;

    protected JButton changeViewButton;

    protected JButton provaConsoleStartButton;

    // Left (content) side

    protected JPanel contentPanel;

    protected TextArea unEditableArea;

    protected TextArea outputArea;

    private static Logger logger = Logger.getLogger(ECAPanel.class);

    public ECAPanel(String[] args)
    {
        super();

        // create a new knowlege base instance
        try
        {
            myProva = new ProvaWrapper(new String[] { args[0] });
        } 
        catch (Exception ex)
        {
        	logger.fatal("The Prova file " + args[0] + " can not be loaded.",
                    ex);
        }
        StartViewDaemon.getInstance().reloadProva(myProva);

        // show panel
        panelInit();
    }

    private void panelInit()
    {

        // set background color
        Color mycolor = Color.lightGray;
        setBackground(mycolor);

        // set up all of the window crap

        setLayout(mainLayout);

           
        
        // The top button panel

        buttonPanel = new JPanel();
        buttonPanel.setLayout(buttonLayout);

        reloadKnowledgeBaseButton = new JButton("load knowlegde base");
        reloadKnowledgeBaseButton.setFont(XsmallFont);
        reloadKnowledgeBaseButton.addActionListener(this);
        buttonPanel.add(reloadKnowledgeBaseButton);

        startButton = new JButton("start");
        startButton.setFont(XsmallFont);
        startButton.addActionListener(this);
        buttonPanel.add(startButton);

        stopButton = new JButton("abort");
        stopButton.setFont(XsmallFont);
        stopButton.addActionListener(this);
        stopButton.setEnabled(true);
        buttonPanel.add(stopButton);

        provaConsoleStartButton = new JButton("console");
        provaConsoleStartButton.setFont(XsmallFont);
        provaConsoleStartButton.addActionListener(this);
        buttonPanel.add(provaConsoleStartButton);

        addViewButton = new JButton("add viewer");
        addViewButton.setFont(XsmallFont);
        addViewButton.addActionListener(this);
        buttonPanel.add(addViewButton);

        changeViewButton = new JButton("change viewer");
        changeViewButton.setFont(XsmallFont);
        changeViewButton.addActionListener(this);
        buttonPanel.add(changeViewButton);

        // add button panel
        add(buttonPanel);

        // The contentPanel content panel
        contentPanel = new JPanel();
        contentPanel.setLayout(mainLayout);
        //contentPanel.setSize(800,800);

        JTextArea unEditableArea = new JTextArea();
        unEditableArea.setEditable(false);
        unEditableArea.setFont(ECAPanel.smallFont);
        unEditableArea.setRows(40);
        unEditableArea.setColumns(70);
        contentPanel.add(unEditableArea, new ECAConstraints(0, 1, 1, 1, 1.0,
                1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
                new Insets(0, 0, 5, 0), 0, 0));

        add(contentPanel, new ECAConstraints(0, 1, 1, 2, 3.0, 1.0,
                GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH,
                new Insets(5, 5, 5, 0), 0, 0));

        // register to receive the various events
        addKeyListener(this);
        addMouseListener(this);

        setVisible(true);
        this.requestFocus();
    }

    public void setParent(Component comp)
    {
        synchronized (comp.getTreeLock())
        {
            while ((comp != null) && !(comp instanceof JFrame))
                comp = comp.getParent();
        }
        parentWindow = (ECAWindow) comp;
    }

    public void setParentTitle(String title)
    {

        parentWindow.setTitle(title);
    }

    public static void centerDialogOnScreen(JDialog dialog)
    {
        Dimension size = dialog.getSize();
        Dimension screenSize = dialog.getToolkit().getScreenSize();
        dialog.setLocation((((screenSize.width - size.width) / 2)),
                (((screenSize.height - size.height) / 2)));
    }

    public static void centerDialog(Frame frame, JDialog dialog)
    {
        // Center dialogs on any Frame
        Dimension size = dialog.getSize();
        Dimension parentSize = frame.getSize();
        Point parentLocation = frame.getLocationOnScreen();
        if ((parentSize.width <= size.width)
                || (parentSize.height <= size.height))
            // If this window is bigger than the parent window,
            // place it at the same coordinates as the parent.
            dialog.setLocation(parentLocation.x, parentLocation.y);
        else
            // Otherwise, place it centered within the parent window.
            dialog
                    .setLocation(
                            (((parentSize.width - size.width) / 2) + parentLocation.x),
                            (((parentSize.height - size.height) / 2) + parentLocation.y));
    }

    public void centerDialog(JDialog dialog)
    {

        centerDialog(parentWindow, dialog);
    }

    public void reloadKnowledgeBase()
    {

        JFileChooser provaFileChooser = new JFileChooser();
        provaFileChooser.showOpenDialog(this);
        File provaFile = provaFileChooser.getSelectedFile();
        String provaFileName = "resource/" + provaFile.getName();

        //prova file should be saved in resource directory

        try
        {
            // create a new knowlege base instance
            myProva = new ProvaWrapper(new String[] { provaFileName });

            // reload prova
            StartViewDaemon.getInstance().reloadProva(myProva);

            // set parent title with actual prova name
            this.setParentTitle("ECA Runtime Environment - "
                    + provaFile.getName() + "");

            //stop eca daemon
            stopEcaDaemon();

        } catch (Exception ex)
        {
            String errString = "The Prova file " + provaFileName
                    + " can not be loaded.";
            logger.fatal(errString, ex);
            new InfoDialog(parentWindow, "Info Dialog", false, errString, "OK");
        }

    }

    private void stopEcaDaemon()
    {

        // stop the eca daemon
        if (startEcaDaemon != null)
            startEcaDaemon.abort();

        // enable eca daemon start button
        startButton.setEnabled(true);

    }

    private void startEcaDaemon()
    {

        KnowledgeDefinition kdef = null;

        try
        {
            ProvaWrapper otherLoggingProvaWrapper = (ProvaWrapper)myProva.createChild();
            kdef = (KnowledgeDefinition)new SimpleSLA(otherLoggingProvaWrapper);

        } catch (Exception ex)
        {
            logger
                    .fatal(
                            "Can not find ActiveKnoledgeDefinition or class have wrong type.",
                            ex);

        }

        try
        {
            startEcaDaemon = new Daemon();
        } catch (Exception ex)
        {
            logger.fatal("Can not find Daemon or class have wrong type.", ex);
        }
       
       	startEcaDaemon.setActiveKnowledgeBase(kdef.defineKnowledge());

        new Thread(startEcaDaemon, "ECA_RUNTIME").start();

    }

    public void startEcaConsole()
    {

        try
        {
            // First Cache all Output
            new OutputConsole(parentWindow, myProva);

            // than start daemon
            startEcaDaemon();

        } catch (IOException ex)
        {
            logger.info("", ex);
        }

    }
    
    public void openRuleWindow()
    {
    	new ECARuleWindow(parentWindow);
    }

    public void provaConsoleStart()
    {

        new ProvaConsole(parentWindow, myProva);

    }

    public void actionPerformed(ActionEvent E)
    {
    	
        if (E.getSource() == reloadKnowledgeBaseButton)
        {
            reloadKnowledgeBase();
            return;
        }

        if (E.getSource() == startButton)
        {
            startEcaConsole();
            openRuleWindow();
            startButton.setEnabled(false);
            return;
        }

        if (E.getSource() == stopButton)
        {
            StartViewDaemon.getInstance().abort();
            return;
        }

        if (E.getSource() == addViewButton)
        {
            new AddViewDialog(parentWindow);
            return;
        }

        if (E.getSource() == changeViewButton)
        {
            ViewDialog childViewer = (ViewDialog) parentWindow
                    .getLastActivatedViewer();
            new AddViewDialog(parentWindow, childViewer);
            return;
        }

        if (E.getSource() == provaConsoleStartButton)
        {
            provaConsoleStart();
            return;
        }
    }
    
    
    public void keyPressed(KeyEvent E)
    {
    }

    public void keyReleased(KeyEvent E)
    {
    }

    public void keyTyped(KeyEvent E)
    {
    }

    public void mouseClicked(MouseEvent E)
    {
    }

    public void mouseEntered(MouseEvent E)
    {
    }

    public void mouseExited(MouseEvent E)
    {
    }

    public void mousePressed(MouseEvent E)
    {
    }

    public void mouseReleased(MouseEvent E)
    {
    }

    public void mouseDragged(MouseEvent E)
    {
    }

    public void mouseMoved(MouseEvent E)
    {
    }

    public void itemStateChanged(ItemEvent E)
    {
    }
    
    //events that are sent by the parent frame
    public void menuEvent(String cmd)
    {
    	if(cmd.equals(ECAConstraints._ADDRULES))
    	{
    		JFileChooser provaFileChooser = new JFileChooser();
            provaFileChooser.showOpenDialog(this);
            File provaFile = provaFileChooser.getSelectedFile();
            
            //if a file is selected, rules should be in the inc folder
            if(provaFile != null)
            {
            	String idTmp = provaFile.getAbsolutePath();
//            	String fileName = "./rules/inc/" + idTmp;
//            	File f = new File(fileName);
//            	System.out.print(f.exists());
            	String query = "update('" + idTmp + "')";;
//            	String query = "update('./rules/inc/" + idTmp + "')";
            	myProva.modKB(query);
            	//and save it to the vector
            	impFiles.add(idTmp);
            	parentWindow.updateMenu(impFiles);
            }
            
    	}
    	else if(cmd.equals(ECAConstraints._STATIC))
    	{
    		StatsAvalaibility statWin = new StatsAvalaibility();
    	}
    	else if(cmd.equals(ECAConstraints._ACTUAL))
    	{
    		StatsActual statsAct = new StatsActual();
    		ActThread act = new ActThread(statsAct);
    		act.start();
    	}
    	else if(cmd.equals(ECAConstraints._QUERY))
    	{
    		StatsQuery statQ = new StatsQuery();
    		/**
    		ProvaWrapper test2 = new ProvaWrapper("./rbsla/rules/ContractLog/bsp2/kb.prova");
    		//String q = "holdsAt(X, datetime(2006,3,1,0,0,0))";
    		String q = "happens(X, Y)";
    		ProvaResultSet rs = (ProvaResultSet)test2.consult(q);
    		if (rs.getException() != null) {
                System.out.println("Test fails with " + rs.getException());
             } else if (rs.numberOfResults() == 0) {
                // No solutions for this resultset
             }
             for( Iterator itr = rs.iterator(); itr.hasNext(); ) {
                Result r = (Result) itr.next();
                // The type of untyped variables is java.lang.Object
                Object o = r.getResult(Object.class, "Person");
                System.out.println("result=" + o);
             } 
             **/
    	}
    	else
    	{
    		String query = "remove('"+cmd+"')";
    		myProva.modKB(query);
    		impFiles.remove(cmd);
    		parentWindow.updateMenu(impFiles);
    	}
    }
}

class LogWriter extends Writer
{
    private static Logger logger = Logger.getLogger(ECAPanel.class);

    public LogWriter()
    {
    }

    public void write(char cbuf[], int off, int len) throws IOException
    {
        //logger.info(new String(cbuf, off, len));
    }

    public void close()
    {
    }

    public void flush()
    {
    }
}