import java.awt.*;
import java.awt.event.*;
import java.awt.datatransfer.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
import javax.swing.text.html.HTMLDocument;

/**
  * The GUI for the Wedgi application, this is where most of the
  * functionality lies.  This GUI supports multiple text areas
  * through which the user can navigate.  Cut and Paste between
  * java applications is supported.
  * <P>
  * The current version reads files or URLs, but isn't threaded so
  * can block on URLs
  *
  * @author Owen Astrachan
  * @version 0.8
  */

public class WedgiGui extends JFrame implements KeyListener
{
    public WedgiGui(Controller con)
    {
	myController = con;
	getContentPane().setLayout(new BorderLayout());
	setDefaultCloseOperation(EXIT_ON_CLOSE);
	
	myWedgeNames = new Vector();
	myWedges     = new HashMap();
	addKeyListener(this);
	

	// the layout for this application is a card layout
	// to support multiple TextAreas (WedgiTexts) at the top
	// of the frame, the bottom of the frame contains buttons
	// and a message box
	
	myPanel = new JPanel(myLayout = new CardLayout());
	myPanel.setPreferredSize(new Dimension(WIDTH,HEIGHT));
	try{
	    myWedge = new WedgiText("file:help.txt");
	}
	catch (IOException io){
	    System.out.println("trouble " + io);
	}
	myPanel.add(myWedge,"default");
	myCurrentName = "default";
	getContentPane().add(myPanel,BorderLayout.CENTER);

	makeMenus();

	// make the button/message area panel

	JPanel p = new JPanel(new BorderLayout());   // for buttons and messages
	myText = new JTextField();                  // for messages
	p.add(myText,BorderLayout.SOUTH);
	p.add(makeButtons(),BorderLayout.NORTH);
	
	getContentPane().add(p,BorderLayout.SOUTH);
	
	pack();
	setVisible(true);
    }

    /**
      * make previous and next buttons
      * @return a panel with the buttons in it
      */
    
    private JPanel makeButtons()
    {
	JButton next = new JButton("next>");
	next.addActionListener(
	    new ActionListener()
	    {
                public void actionPerformed(ActionEvent e)
                {
		    nextDisplay();
		}
	    });
	JButton previous = new JButton("<prev ");
	previous.addActionListener(
	    new ActionListener()
	    {
		public void actionPerformed(ActionEvent e)
		{
		    previousDisplay();
		}
	    });
	JPanel bp = new JPanel();
	bp.add(previous);
	bp.add(next);

	return bp;
    }

    /**
      * make the menus for this application
      */
    private void makeMenus()
    {
	// make menubar with three menus: file, edit, windows
	
	JMenuBar bar = new JMenuBar();
	JMenu fileMenu = new JMenu("File");
	myWindows = new JMenu("Windows");
	myWindows.addSeparator();              // no stubby, empty menu
	
	bar.add(fileMenu);
	bar.add(makeEditMenu());
	bar.add(myWindows);
	
	this.setJMenuBar(bar);

	// make open sub menu, open from file or URL
	
	JMenu openMenu = new JMenu("Open");
	JMenuItem fileMI = new JMenuItem("File");	
	fileMI.addActionListener(new
				 ReadFileCommand(myController,this));
	JMenuItem urlMI = new JMenuItem("URL");
	urlMI.addActionListener(new
				ReadURLCommand(myController,this));

	JMenuItem quitMI = new JMenuItem("Quit");
	quitMI.addActionListener(Quitter.getInstance());
	
	openMenu.add(fileMI);
	openMenu.add(urlMI);
	fileMenu.add(openMenu);
	fileMenu.addSeparator();
	fileMenu.add(quitMI);
    }

    /**
      * make the edit menu
      */
    
    private JMenu makeEditMenu()
    {
	JMenu edit = new JMenu("Edit");

	// load up all the text actions so we can use cut/copy/paste
	
	Map actionmap = new HashMap();
	Action[] alist = myWedge.getActions();
	for(int k=0; k < alist.length; k++)
	{
	    Action a = alist[k];
	    actionmap.put(a.getValue(Action.NAME), a);
	}

	JMenuItem item;
	item = edit.add((Action)
			actionmap.get(DefaultEditorKit.copyAction));
	item.setText("copy");
	    
	edit.add((Action) actionmap.get(DefaultEditorKit.cutAction));
	edit.add((Action) actionmap.get(DefaultEditorKit.pasteAction));
	
	return edit;
    }


    /**
      * show a message to user, can be status, error, etc.
      * @param s is the message shown
      */
    
    public void showMessage(String s)
    {
	myText.setText(s);
    }

    /**
      * add a WedgiText to the GUI, the WedgiText source comes
      * a name, e.g., filename, URL
      * (name is final to facilitate use in nested, anonymous classes)
      *
      * @param name is the name of the source of the text
      * @param r is the reader that is the source of the text
      */
    
    public void addWedgi(final String name)
    {
	// make textarea, add to vector and to hashtable

	WedgiText wt = null;
	showMessage("loading "+name);

	try{
	    wt = new WedgiText(name);
	    wt.addHyperlinkListener(new Hyperactive(WedgiGui.this));
	    myWedgeNames.add(name);
	    myWedges.put(name,wt);
	    showMessage("done loading "+name);
	
	    // make a menuitem bound to this WedgiText
	
	    JMenuItem displayMI = new JMenuItem(name);
	    displayMI.addActionListener(
		new ActionListener()
		{
		    public void actionPerformed(ActionEvent e)
			{
			    showDisplay(name);
			}
		}
		);
	
	    myWindows.add(displayMI);
	
	    // add this Component to the card layout then show it
	
	    myPanel.add(new JScrollPane(wt),name);
	    showDisplay(name);	    
	}
	catch (IOException io){
	    showMessage("reading error: " + name);
	}
    }
    

    /**
      * show the previous WedgiText (in order loade)
      */
    
    public void previousDisplay()
    {
	if (myWedgeNames.size() == 0) return;     // no wedges loaded
	
	// set index to entry BEFORE currenet wedge name
	int index = myWedgeNames.indexOf(myCurrentName)-1;
	if (index == -1)
	{
	    index = myWedgeNames.size()-1;
	}
	showDisplay((String) myWedgeNames.get(index));
    }

    /**
      * show the next WedgiText (in order loade)
      */
    
    public void nextDisplay()
    {
	if (myWedgeNames.size() == 0) return;      // no wedges loaded
	
	// set index to entry AFTER current wedge name
	
	int index = myWedgeNames.indexOf(myCurrentName)+1;
	if (index == myWedgeNames.size())
	{
	    index = 0;
	}
	showDisplay((String) myWedgeNames.get(index));
    }

    public void showDisplay(String name)
    {
	myLayout.show(myPanel,name);
	showMessage("current: " + name);
	myCurrentName = name;
    }

    // KeyListener functions (currently don't work, focus problem?)
    
    public void keyPressed(KeyEvent e)
    {
	int keyCode = e.getKeyCode();
	if (keyCode == KeyEvent.VK_LEFT)
	{
	    previousDisplay();
	    e.consume();	    
	}
	else if (keyCode == KeyEvent.VK_RIGHT)
	{
	    nextDisplay();
	    e.consume();
	}

    }
    public void keyReleased(KeyEvent e){}
    public void keyTyped(KeyEvent e){}
	

    private Controller myController;    // the mediator between GUI/app
    private JTextField  myText;          // display for messages to user  
    private JPanel      myPanel;         // the panel for all WedgiTexts
    private JMenu       myWindows;       // menu added to as sources loaded
    private CardLayout myLayout;        // supports text navigation
    private Vector     myWedgeNames;    // names of all text sources
    private Map        myWedges;        // map of source names to WedgiText
    private WedgiText  myWedge;         // the initial TextArea (for sizing)
    private String     myCurrentName;   // name of current WedgiText
    private JMenuItem   myPaste;         // support enable/disable
    
    public static final int WIDTH;      // width of frame
    public static final int HEIGHT;     // height of frame

    static
    {
        WIDTH  = Toolkit.getDefaultToolkit().getScreenSize().width/3;
        HEIGHT = Toolkit.getDefaultToolkit().getScreenSize().height/2;
    }

    // find screen size, adjust app dimensions based on size
    
}

/**
 * code below taken from (adapted slightly)
 * http://java.sun.com/products/jfc/tsc/text/concurrency/HtmlExample.java
 */
class Hyperactive implements HyperlinkListener
{

    Hyperactive(WedgiGui wg)
    {
	myGui = wg;
    }
    /**
     * Notification of a change relative to a 
     * hyperlink.
     */
    public void hyperlinkUpdate(HyperlinkEvent e) {
	if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
	    JEditorPane html = (JEditorPane) e.getSource();
	    if (e instanceof HTMLFrameHyperlinkEvent) {
		HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;
		HTMLDocument doc = (HTMLDocument)html.getDocument();
		doc.processHTMLFrameHyperlinkEvent(evt);
	    } else {
		myGui.addWedgi(e.getURL().toString());
	    }
	}
    }
    private WedgiGui myGui;
}
