/*---------------------------------------------------------------------------
File:         			HelpWindowHTML.java
Package:                        JFLAP Version 3.1
Author:			        Eric Gramond
Modified:			Ted Hung 7/10/99
                                
Description of Contents:	Contains class HelpWindowHTML and HelpData.
				
--------------------------------------------------------------------------*/

/* 
 * Susan H. Rodger, Magda Procopiuc, Octavian Procopiuc, Eric Gramond, Ted Hung
 * Computer Science Department
 * Duke University
 * August 1999
 * Supported by National Science Foundation DUE-9596002, DUE-9555084,
 *  and DUE-9752583
 *
 * Copyright (c) 1999
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the author.  The name of the author may not be used to
 * endorse or promote products derived from this software without
 * specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

package flap;

import java.awt.*;
import java.util.*;
import java.net.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;


/**
 *  This is the default help window. Provide it with an application name and it will
 *  bring up help for the application.
 *  Requires: a series of files called applicationName0.html, applicationName1.html...
 *  each help file should contain a topic name as the first line in the form
 *  of an html comment:  <!--TOPIC: topicname-->
 *
 * It is recommended that the help files and icon image be arhived in a jar file but
 * not necessary. If not they must be located somewhere within the classpath.
 *
 * The help window is by default hidden. Simply call setVisible to make it appear.
 * closing the window only makes it invisible again, so keeping one help window
 * around while the program runs is simple to do.
 * The setCurrentTopic function allows picking the topic from outside the window 
 * easily by indicating the desired topic name.
 * 
 */

public class HelpWindowHTML extends HelpWindow implements ItemListener, ActionListener
{

    private JEditorPane myTextArea;
    private Label myTopicLabel;
    private JScrollPane myScrollPane;
    private Button myCloseButton;
    private Button myNextButton;
    private Button myPreviousButton;
    private java.awt.List   myList;
    private Panel myTopicPanel;
    private Panel myTopPanel;
    private ScrollPane myTopScrollPane;


    private Vector myHelpData;
    private int    numHelpTopics; 
    private Vector myHistory;
    private int    myHistoryLocation;
    

    /*
     *  constructs a help window for the appropriate application.
     */
    public HelpWindowHTML(String applicationName, Color background, boolean isApplet)
       throws Exception
    {
        super(isApplet);
	Enumeration e;
	HelpData hd;

	setBackground(background);
	
	try
	{
	   myTextArea = new JEditorPane("text/html", "");
	}
	catch(NoClassDefFoundError err)
	{
           throw new Exception("Only Available in JDK 1.2");
	}
        myTextArea.setEditable(false);
	myTextArea.setBackground(Color.white);
	readInFiles(applicationName);
	
	setTitle(applicationName + " Help");

	Panel p2 = new Panel(new BorderLayout());
	try
	{   
	    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
	}
	catch (Exception exc)
	{
	}

	JScrollPane sp = new JScrollPane(
	   JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
	   JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
        sp.setPreferredSize(new Dimension(500, 450));
        sp.setViewportView(myTextArea);
	p2.add(sp, "Center");
	myScrollPane = sp;

	myTopicLabel = new Label("Welcome to "+ applicationName + " Help" , Label.CENTER);
	p2.add(myTopicLabel, "North");

	add(p2, "Center");

	p2 = new Panel(new FlowLayout());
	
	myCloseButton = new Button("Close");
	myCloseButton.addActionListener(this);
	p2.add(myCloseButton);

	p2.add(new Label("     "));  //just a filler

	myPreviousButton = new Button("<<");
	myPreviousButton.addActionListener(this);
	myPreviousButton.setEnabled(false);
	p2.add(myPreviousButton);

	myNextButton = new Button(">>");
	myNextButton.addActionListener(this);
	myNextButton.setEnabled(false);
	p2.add(myNextButton);
        myTopPanel = new Panel(new BorderLayout());
	myTopPanel.add(p2, "South");

	myList = new java.awt.List(numHelpTopics);
	ScrollPane sp2 = new ScrollPane();
	myTopScrollPane = sp2;
	sp2.add(myList);
	myTopPanel.add(sp2, "Center");
	add(myTopPanel, "West");
	pack();
	FontMetrics fm = myList.getGraphics().getFontMetrics();
	int longItem = 10;
	for(e = myHelpData.elements(); e.hasMoreElements(); )
	{
      	    hd = (HelpData) e.nextElement();
	    myList.add(hd.myTopic);
            if(fm.stringWidth(hd.myTopic) > longItem)
               longItem = fm.stringWidth(hd.myTopic);
	}
	myList.setBackground(Color.white);
	myList.setForeground(Color.black);
        pack();
	sp2.setSize(longItem + 10 + sp2.getInsets().left +
	   + sp2.getInsets().right + sp2.getVScrollbarWidth(), 450);
	myList.addItemListener(this);

	//get the default icon if the appropriate icon doesnt exist
	URL iconName = this.getClass().getResource(applicationName+"Help.gif");
	if(iconName == null) 
	    iconName = this.getClass().getResource("HelpIcon.gif");
	if(iconName== null)
	    System.out.println("Warning: help window icon missing!");
	else {
	    Toolkit t = Toolkit.getDefaultToolkit();
	    setIconImage(t.getImage(iconName));
	}  
	setCurrentTopic("Overview");

	addWindowListener(  new WindowAdapter() {
	    public void windowClosing(WindowEvent ev) {
		setVisible(false);
	    }
	} );

	String temp = myTopicLabel.getFont().getName();
	int sty = myTopicLabel.getFont().getStyle();
	int size = myTopicLabel.getFont().getSize();
	myTopicLabel.setFont(new Font(temp, sty, size*2));
	pack();
    }

    /**
     * reads in all the data files and gets ready to display them
     */
    private void readInFiles(String applicationName)
    {
       int counter = 0;
       URL fullName;
       String fileName = applicationName + counter++ + ".html";
       InputStream input;
       myHelpData = new Vector();
       myHistory = new Vector();
       myHistoryLocation = -1;
       BufferedReader myReader = null;

       if(isApplet)
       {
          //repeat until an exception occurs: There must be a better way
          while(true)
          {
      	     try
             {
                URLConnection uc = new URL(Params._e_codebase +
                   "flap/" +
                   fileName).openConnection();
	        myReader = new BufferedReader(new InputStreamReader(uc.getInputStream()));
             }
	     catch(MalformedURLException e)
             {
                numHelpTopics = counter -1;
                return;
             }
	     catch(IOException e)
             {
                numHelpTopics = counter -1;
                return;
             }

             try
             {
                String line = myReader.readLine();
                myHelpData.addElement(
                   new HelpData(Params._e_codebase +
                   "flap/" +
                   fileName, line));
                fileName = applicationName + counter++ + ".html";
             }
             catch(IOException e)
             {
                numHelpTopics = counter -1;
                return;
             }
          }
       }
       else
       {
          while((fullName = this.getClass().getResource(fileName)) != null)
          {
             String s = null;
             URL helpURL = null;

             try 
             {
                if(fullName.getContent() instanceof InputStream)
                {
                    input = (InputStream) fullName.getContent();
                    myReader = new BufferedReader(new InputStreamReader(input));
                    String b = myReader.readLine();
                    myHelpData.addElement(new HelpData(fileName, b));    
                }
            }
            catch (IOException h)
            {
               System.out.println(h.getMessage());
            }
            fileName = applicationName + counter++ + ".html";
          }
          numHelpTopics = counter -1;
       }
    }


    /**
     * sets the current topic with a simple string. This should make it easy
     * to call this from the outside.
     */
    public void setCurrentTopic(String topicName)
    {
	Enumeration e;
	HelpData hd;

        if(topicName == null)
           return;

	String temp;
	String temp2;
	for(e = myHelpData.elements(); e.hasMoreElements(); ) {
	    hd = (HelpData) e.nextElement();
	    temp = hd.myTopic;
	    temp2 = topicName;
	    //deal with Windows and Unix difference in linefeed values
	    if(temp.charAt(temp.length() - 1) == '-')
		temp = temp.substring(0, temp.length() - 1);
	    if(temp2.charAt(temp2.length() - 1) == '-')
		temp2 = temp2.substring(0, temp2.length() - 1);
	    if(temp.trim().equals(temp2.trim()))
	    {
	        String s = null;
		URL helpURL = null;
	        try
		{
		    helpURL = this.getClass().getResource(hd.myFilename);
	        }
		catch (Exception except1)
		{
		    System.err.println("Couldn't create help URL: " + s);
	        }

		try
		{
		  myTextArea.setPage(helpURL);
		}
		catch (IOException except2)
		{
		  System.err.println("Attempted to read a bad URL: " + helpURL);
		}

		int loca = 0;
		while(loca < myList.getItemCount())
		{
		   if(myList.getItem(loca).trim().equals(hd.myTopic.trim()))
		   {
		     myList.select(loca);
		     break;
		   }
		   loca++;
		}

		myScrollPane.getVerticalScrollBar().setValue(0);

		myTopicLabel.setText(hd.myTopic);
		
		// reset the scrollpane
		int totheight = myList.getSize().height;
		int indexes = myList.getItemCount();
		int oneIndex = totheight/indexes;
		int finalPos =oneIndex*loca+oneIndex/2-myTopScrollPane.getSize().height/2;
		finalPos = Math.max(finalPos, 0);
		finalPos = Math.min(finalPos, totheight-myTopScrollPane.getSize().height);
		myTopScrollPane.setScrollPosition(0, finalPos);
		myScrollPane.validate();
		return;
	      }
	  }
	  myTextArea.setText("topic " + topicName + " not found");
      }

    /**
     * detects if the list has been updated
     */
    public void itemStateChanged(ItemEvent e) {
	
	if(e.getSource() instanceof java.awt.List)
        {
	    java.awt.List b = (java.awt.List) e.getSource();
	    String name = b.getSelectedItem();
            if(name == null)
               return;
	    setCurrentTopic(name);
	    if(myHistory.size() > myHistoryLocation+1)
		myHistory.setSize(myHistoryLocation+1);
	    myHistory.addElement( new Integer(b.getSelectedIndex()));
	    myHistoryLocation++;
	    if(myHistory.size() > 1)
		myPreviousButton.setEnabled(true);
	    myNextButton.setEnabled(false);
	}
    }

    /**
     * checks for the buttons
     */
    public void actionPerformed(ActionEvent e) {
	if(e.getSource() == myCloseButton)
	    setVisible(false);
	else if(e.getSource() == myPreviousButton) {
	    myHistoryLocation--;
	    Integer loc = (Integer) myHistory.elementAt(myHistoryLocation);
	    int loca = loc.intValue();
	    if(myHistoryLocation == 0)
		myPreviousButton.setEnabled(false);
	    myNextButton.setEnabled(true);
	    myList.select(loca);
	    setCurrentTopic(myList.getItem(loca));
	}
	else if(e.getSource() == myNextButton) {
	    myHistoryLocation++;
	    if(myHistoryLocation == myHistory.size()-1)
		myNextButton.setEnabled(false);
	    myPreviousButton.setEnabled(true);
	    Integer loc = (Integer) myHistory.elementAt(myHistoryLocation);
	    int loca = loc.intValue();
	    myList.select(loca);
	    setCurrentTopic(myList.getItem(loca));
	}

    }

    /**
     * returns a string that identifies what type of help window it is
     */
    public String getType()
    {
       return "HTML";
    }
    
}

/**
 * storage class. This holds the topic and information data obtained from
 * a help file's content
 */
class HelpData
{
    public String myFilename;
    /**
     * the name of this topic
     */
    public String myTopic;
   
    /**
     * constructor. parse the file into data and topic and figure out rows and 
     * maximum width.
     */ 
    public HelpData(String filename, String fileContents)
    {
        myFilename = filename;

	//topic is a meta tag in the form: <!--TOPIC: topicname-->
	if(fileContents.length() >= 11 && fileContents.substring(0, 11).equals("<!--TOPIC: "))
	{
	   myTopic = fileContents.substring(11, fileContents.length() - 3);
	}
	else
	{
	   myTopic = "";
	}
    }
}

