/*
   Tamot --- Task Modelling Editor
   Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
   (CSIRO), Australia. All rights reserved. 

   The Software, owned by CSIRO Australia, has been developed by the CSIRO 
   Intelligent Interactive Technology group. 
   For more information, please see http://www.cmis.csiro.au/iit/.

   Redistribution in source and binary forms, with or without modification, are not permitted.

   The Software is a beta-test version for internal research and evaluation purposes 
   by the Licensee. The Software is still at a development stage. 
   It has not undergone complete testing and may have inherent errors,
   bugs or deficiencies that can affect the operation of the Software. 

   We encourage your feedback and suggestions. Any bugs / suggestions found please email to
   Shijian.Lu@cmis.csiro.au and Thomas.Lo@cmis.csiro.au. 

   After you have signed the Beta-Test Software License Agreement with the CSIRO,
   CSIRO grants you a non-exclusive, non-transferable license to use it only for your 
   personal, non-commercial and lawful end use. Implied licenses are negated. 

   Warranty Disclaimer : 

   CSIRO supplies the Software on an "as is" basis and makes no warranties that use of
   the Software by the Licensee will not infringe any third party’s 
   Intellectual Property Rights nor that the Software will be of merchantable quality,
   or suitable for a particular purpose. CSIRO excludes all terms, conditions and
   warranties implied by custom, the general law or statute in relation to the
   Software.
*/

package taskModellingTool;

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.util.*;
import java.beans.*;
import java.net.URL;

import TV.*;


/**
 * A prototype frame for textview windows that is
 * copied and modified from ComponentInternalFrame.java.  
 *
 * Things to do:
 * * There is probably a better way to integrate this feature, I just
 *   don't know tamot well enough to do it.
 *
 * - kvlinden, 22Feb00
 */

public class TVInternalFrame extends JInternalFrame implements InternalFrameListener {
    protected static final int WIDTH=300;
    protected static final int HEIGHT=300;
    protected static final int INSETS_WIDTH=13;
    protected static final int INSETS_HEIGHT=50;
    protected static final int GRAPHICPANEL_WIDTH=WIDTH-INSETS_HEIGHT;
    protected static final int GRAPHICPANEL_HEIGHT=HEIGHT-INSETS_HEIGHT;
    
    protected static final int NB_FRAMES=7;
    
    private static int openFrameCount = 0;
    private static int openFrameCountModulo=0;
    private static final int xOffset = 30, yOffset = 30;
    
    protected GraphicPanel gpanel;
    protected String name;
    
    private JButton backButton;
    private JButton forwardButton;
    
    private JTextField urlField;
    private JEditorPane editorPane;
    private JLabel statusBar;
    
    private int pageCounter = 0;
    private TreeMap addressTreeMap = new TreeMap();    // Integer pageCounter (key), String html address (value)
    
    
    /**
     * Create a new frame with a new {@link GraphicPanel} inside.
     * <P><A HREF="../source/TVInternalFrame.html#TVInternalFrame">Source</A>
     */
    ///TVInternalFrame
    public TVInternalFrame(String name, String htmlPathName) {
        super(name, 
              true, //resizable
              true, //closable
              true, //maximizable
              true);//iconifiable
        
        String homeAddress = "file:///" + htmlPathName;
    
        openFrameCount++;
        openFrameCountModulo=(openFrameCount-1)%NB_FRAMES;
        this.name=name;
        //...Create the GUI and put it in the window...

        //...Then set the window size or call pack...
        setSize(WIDTH,HEIGHT);
        setPreferredSize(new Dimension(WIDTH,HEIGHT));
        //Insets i=getInsets();

        //Set the window's location.
        int locationX=xOffset*openFrameCountModulo;
        int locationY=yOffset*openFrameCountModulo;
        setLocation(locationX,locationY);
        

        // Now the text view stuff   - kvlinden, 10feb00
    
        // Set up our basic screen components, the editor pane, the
        // text field for URLs, and the label for status and link information
        JPanel buttonPanel = getButtonPanel();

        JPanel urlPanel = new JPanel();
        urlPanel.setLayout(new BorderLayout());
        
        urlPanel.add(buttonPanel, BorderLayout.WEST);
        
        urlField = new JTextField(homeAddress);
        urlPanel.add(urlField, BorderLayout.CENTER);
        
        statusBar = new JLabel(" ");
            
        // Here's the editor pane configuration.  It's important to make
        // the "setEditable(false)" call, otherwise our hyperlinks won't
        // work.  (If the text is editable, then clicking on a hyperlink
        // simply means that you want to change the text...not follow the
        // link.)
        editorPane = new JEditorPane();
        editorPane.setEditable(false);
        
        // Here's where we force the pane to use our new editor kit
        PatchedHTMLEditorKit patchedHtmlEditorKit = new PatchedHTMLEditorKit();
        
        // make a patched stylesheet & attach it to the patched kit
        PatchedStyleSheet patchedStyleSheet = new PatchedStyleSheet();  
        patchedHtmlEditorKit.setStyleSheet(patchedStyleSheet);          
    
        editorPane.setEditorKitForContentType("text/html", patchedHtmlEditorKit);
        displayNewUrlPage(homeAddress);
        
        JScrollPane scrollPane = new JScrollPane(editorPane);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);

        // and get the GUI components onto our content pane
        getContentPane().add(urlPanel, BorderLayout.NORTH);
        getContentPane().add(scrollPane, BorderLayout.CENTER);
        getContentPane().add(statusBar, BorderLayout.SOUTH);
        
        // and last but not least, hook up our event handlers
        // allow user to type the url and then press 'Enter' to try to display the HTML
        urlField.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                String address  = actionEvent.getActionCommand();
                
                displayNewUrlPage(address);
                updateButtonStatus();
            }
	    });
        
        editorPane.addHyperlinkListener(new SimpleLinkListener(this, editorPane, statusBar)); 
        updateButtonStatus();
    }

    private void displayNewUrlPage(String address) {
        try {
            URL url = new URL(address);
    
            displayNewUrlPage(url);
        }
        catch (Exception e) {
            statusBar.setText("Could not open the specified page : "+address);
        }
    }

    public void displayNewUrlPage(URL url) {
        try {
            String address = url.toString();
            
            //TMUtility.display("displayNewUrlPage : url",address);
            
            editorPane.setPage(url);
            
            if (urlField != null) {
                urlField.setText(address);
            }
            
            clearHistoryFromPageCounterOnwards();
            putToAddressTreeMap(address);
        }
        catch(Exception e) {
            statusBar.setText("Could not open page - "+url);
        }
    }

    private JPanel getButtonPanel() {
        JPanel result = new JPanel();
        
        result.setLayout(new FlowLayout(FlowLayout.LEADING));
        
        backButton    = new JButton("  Back  ");
        forwardButton = new JButton("Forward");
        
        result.add(backButton);
        result.add(forwardButton);

        result.add(new JLabel("    Address : "));
        
        addBackButtonListener(backButton);
        addForwardButtonListener(forwardButton);
        
        return result;
    }
    
    private void displayOldUrlPage(String address) {
        try {
            URL url = new URL(address);
    
            displayOldUrlPage(url);
        }
        catch (Exception e) {
            statusBar.setText("Could not open the specified page : "+address);
        }
    }

    public void displayOldUrlPage(URL url) {
        try {
            String address = url.toString();
            
            //TMUtility.display("displayOldUrlPage : url",address);
            
            editorPane.setPage(url);
            
            if (urlField != null) {
                urlField.setText(address);
            }
            
            //displayAddressTreeMapContents();
        }
        catch(Exception e) {
            statusBar.setText("Could not open page - "+url);
        }
    }

    private void addBackButtonListener(JButton backButton) {
        backButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                if (pageCounter > 1) {
                    pageCounter--;
                    String address = getUrlFromAddressTreeMap();
                    
                    displayOldUrlPage(address);
                    
                    updateButtonStatus();
                }
            }
        });
    }

    private void addForwardButtonListener(JButton forwardButton) {
        forwardButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                int lastPageCounter = getLastPageCounter();
                
                if (pageCounter < lastPageCounter) {
                    pageCounter++;
                    String address = getUrlFromAddressTreeMap();
                    
                    displayOldUrlPage(address);
                    
                    updateButtonStatus();
                }
            }
        });
    }

    public void updateButtonStatus() {
        int lastPageCounter = getLastPageCounter();
        
        if (pageCounter <= 1)
            backButton.setEnabled(false);
        else
            backButton.setEnabled(true);
        
        if (pageCounter >= lastPageCounter)
            forwardButton.setEnabled(false);
        else
            forwardButton.setEnabled(true);
    }
    
    private int getLastPageCounter() {
        int result = 0;
        
        if (addressTreeMap.size() == 0) return result;
        
        Integer iPageCounter = (Integer) addressTreeMap.lastKey();
        
        result = iPageCounter.intValue();
        
        return result;
    }
    
    private String getUrlFromAddressTreeMap() {
        String result = null;
        
        Integer iPageCounter = new Integer(pageCounter);
        
        if (addressTreeMap.containsKey(iPageCounter)) {
            result = (String) addressTreeMap.get(iPageCounter);
        }
        
        return result;
    }
    
    private void clearHistoryFromPageCounterOnwards() {
        int lastPageCounter = getLastPageCounter();
        
        for (int i=pageCounter+1; i<= lastPageCounter; i++) {
            Integer iPageCounter = new Integer(i);
            
            if (addressTreeMap.containsKey(iPageCounter)) {
                addressTreeMap.remove(iPageCounter);
            }
        }
    }
    
    private void putToAddressTreeMap(String url) {
        pageCounter++;
        
        Integer iPageCounter = new Integer(pageCounter);
        
        addressTreeMap.put(iPageCounter,url);
        
        displayAddressTreeMapContents();
    }

    private void displayAddressTreeMapContents() {
        TMUtility.displayLine(2);
        
        TMUtility.display("pageCounter = "+pageCounter);
        
        for (Iterator i=(addressTreeMap.keySet()).iterator();i.hasNext();) {
             Integer iPageCounter = (Integer) i.next();
             String address = (String) addressTreeMap.get(iPageCounter);
             
             TMUtility.display(iPageCounter+" : ["+address+"]");
        }
    }
    
    // The rest of the stuff from ComponentInternalFrame:

    /**
     * Required by InternalFrameListener.
     *<p>External Operations:
     *Manager.selectNode(<i>name of the frame</i>);
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameActivated">Source</A>
     */
    ///internalFrameActivated

    public void internalFrameActivated(InternalFrameEvent e){
    	Manager.desktop.currentFrame=name;
    	if (!(Manager.nodeSelectionVeto)&&(Manager.tree.isVisible())) Manager.selectNode(name);
    	Manager.nodeSelectionVeto=false;
    }

    /**
     * Required by InternalFrameListener but not used.
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameClosed">Source</A>
     */
    ///internalFrameClosed
    public void internalFrameClosed(InternalFrameEvent e) {}
    
    /**
     * Required by InternalFrameListener.
     *<p>External operations:
     *<ol> If this frame is already activated.
     *<li> Manager.openParentFrame(<i> current TreePath </i>)
     *<li> Manager.tree.collapsePath(<i> current TreePath </i>);
     *<li> Manager.select(<i>name of the frame</i>);
     *</ol>
     * <P><A HREF="internalFrameClosing">Source</A>
     */
    ///internalFrameClosing
    public void internalFrameClosing(InternalFrameEvent e) {
    	if (Manager.tree.isVisible())
    	    if (Manager.desktop.currentFrame==name) {
    	        TreePath treePath=Manager.fetchTreePath(name,Manager.tree);
                if (!(name.equals(Manager.ROOT_STRING))) Manager.openParentFrame(treePath);
                Manager.tree.collapsePath(treePath);
                Manager.select(treePath);
    	    }
    }
    
    /**
     * Required by InternalFrameListener but not used.
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameDeactivated">Source</A>
     */
    ///internalFrameDeactivated
    public void internalFrameDeactivated(InternalFrameEvent e) {}

    /**
     * Required by InternalFrameListener but not used.
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameDeiconified">Source</A>
     */
    ///internalFrameDeiconified
    public void internalFrameDeiconified(InternalFrameEvent e) {}

    /**
     * Required by InternalFrameListener but not used.
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameIconified">Source</A>
     */
    ///internalFrameIconified
    public void internalFrameIconified(InternalFrameEvent e) {}
    
    /**
     * Required by InternalFrameListener but not used.
     * <P><A HREF="../source/TVInternalFrame.html#internalFrameOpened">Source</A>
     */
    ///internalFrameOpened
    public void internalFrameOpened(InternalFrameEvent e) {}
    
    /**
     *Returns the name of the frame.
     * <P><A HREF="../source/TVInternalFrame.html#getName">Source</A>
     */
    ///getName
    public String getName() {
    	return name;
    }
    
    public static void resetCount() {
    	openFrameCount=0;
    	openFrameCountModulo=0;
    }
}