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

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


/**
 *  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.help, applicationName1.help...
 *            and a gif called applicationNameHelp.gif (optional)
 *  each help file should contain a topic name as the first line and the text contents
 *  of the help file after it.
 *
 * 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 HelpWindowText extends HelpWindow implements ItemListener, ActionListener
{
    private TextArea myTextArea;
    private Label myTopicLabel;
    private ScrollPane myScrollPane;
    private Button myCloseButton;
    private Button myNextButton;
    private Button myPreviousButton;
    private java.awt.List   myList;
    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 HelpWindowText(String applicationName, Color background, boolean isApplet)
    {
	super(isApplet);
	Enumeration e;
	HelpDataText hd;

	setBackground(background);
	setForeground(Color.black);
	this.setResizable(false);

	readInFiles(applicationName);
	
	setTitle(applicationName + " Help");

	Panel p2 = new Panel(new BorderLayout());
	ScrollPane sp = new ScrollPane();
	sp.setSize(500, 450);
	myTextArea = new TextArea("", 40, 40, TextArea.SCROLLBARS_NONE);
	myTextArea.setBackground(Color.white);
	myTextArea.setForeground(Color.black);
	myTextArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
	myTextArea.setEditable(false);
	sp.add(myTextArea);
	p2.add(sp, "Center");
	myScrollPane = sp;

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

	add(p2, "East");
	
	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);
	//add(p3, "South");
	myTopPanel = new Panel(new BorderLayout());
	myTopPanel.add(p2, "South");
	
	myList = new java.awt.List(numHelpTopics);
	sp = new ScrollPane();
	myTopScrollPane = sp;
	for(e = myHelpData.elements(); e.hasMoreElements(); )
	{
	    hd = (HelpDataText) e.nextElement();
	    myList.add(hd.myTopic);
	}
	sp.add(myList);
	myTopPanel.add(sp, "Center");
	add(myTopPanel, "West");
	myList.addItemListener(this);
	myList.setBackground(Color.white);
	myList.setForeground(Color.black);
	pack();

	int strLength = 10;
	int longstr = 10;
	FontMetrics fm = sp.getFontMetrics(sp.getFont());
	for(e = myHelpData.elements(); e.hasMoreElements(); )
        {
            hd = (HelpDataText) e.nextElement();
            if(fm.stringWidth(hd.myTopic) > strLength)
	    {
		strLength = fm.stringWidth(hd.myTopic);
	    }
	    if(hd.longest.length() > longstr)
		longstr = hd.longest.length();
        }
        sp.setSize(strLength + sp.getInsets().left +
		sp.getInsets().right + 2*sp.getVScrollbarWidth(), 450);

	fm = myTextArea.getFontMetrics(myTextArea.getFont());
	myScrollPane.setSize(fm.stringWidth("A") * longstr +
		    myScrollPane.getVScrollbarWidth() + 
                    myScrollPane.getInsets().left +
		    myScrollPane.getInsets().right, 450);


	//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);
	    }
	} );

	myScrollPane.addComponentListener( new ComponentAdapter() {
	    public void componentResized(ComponentEvent e)
	    {
		validate();
	    }
	});


	pack();
	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;
       String fileName = applicationName + counter++ + ".help";
       URL fullName;
       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();
                String b = "";
	        while(line != null)
                {
                   b += line + "\n";
                   line = myReader.readLine();
                }
                myHelpData.addElement(new HelpDataText(b));
                fileName = applicationName + counter++ + ".help";
             }
             catch(IOException e)
             {
                numHelpTopics = counter -1;
                return;
             }
          }
       }
       else
       {
           while((fullName = this.getClass().getResource(fileName)) != null)
           {
              try
              {
                 if(fullName.getContent() instanceof InputStream)
                 {
                    input = (InputStream) fullName.getContent();
                    myReader = new BufferedReader(new InputStreamReader(input));
                    String b = "";
                    String line = myReader.readLine();
                    while(line != null)
                    {
                       b += line + "\n";
                       line = myReader.readLine();
                    }
                    myHelpData.addElement(new HelpDataText(b));    
                 }
              }
              catch (IOException h) {
                 System.out.println(h.getMessage());
              }
              fileName = applicationName + counter++ + ".help";
           }
           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;
	HelpDataText hd;

        if(topicName == null)
           return;
	for(e = myHelpData.elements(); e.hasMoreElements(); )
        {
	    hd = (HelpDataText) e.nextElement();
	    if(hd.myTopic.trim().equals(topicName.trim()))
            {
		myTextArea.setRows(Math.max(25, hd.rows));
		FontMetrics fm = myTextArea.getFontMetrics(myTextArea.getFont());
		int result = fm.stringWidth(hd.longest);
		int result2 = fm.stringWidth("a");
		result = result/result2;
		myTextArea.setColumns(Math.max(40, result));
		myTextArea.setText(hd.myText);
		myScrollPane.setScrollPosition(0, 0);

		myTopicLabel.setText(hd.myTopic);

		int index = myList.getItemCount() - 1;

	        //find the index
	        while(index >= 0 && !myList.getItem(index).trim().equals(topicName.trim()))
		{
		   --index;
		}

	        int loca = myList.getSelectedIndex();
		if(index >= 0 && loca != index)
		{
		   myList.select(index);
		   loca = index;
		}

		// 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 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 "Text";
    }
    
}

/**
 * storage class. This holds the topic and information data obtained from
 * a help file's content
 */
class HelpDataText {

    /**
     * the actual help data
     */
    public String myText;
    /**
     * the name of this topic
     */
    public String myTopic;
    /** 
     * the number of rows in this help files
     */
    public int rows;
    /**
     * the widest line in this help file
     */
    public String longest;
   
    /**
     * constructor. parse the file into data and topic and figure out rows and 
     * maximum width.
     */ 
    public HelpDataText(String fileContents) {
	StringReader sr = new StringReader(fileContents);
	BufferedReader br = new BufferedReader(sr);
	String temp;
	longest = "";

	try {
	    myTopic = br.readLine();
	}
	catch(IOException h) {
	    myTopic = "";
	}
	myText = "";
	try {
	    temp = br.readLine();
	    while (temp != null) {
		if(longest.length() < temp.length())
		    longest = temp;
		myText += temp + "\n";
		temp = br.readLine();
		rows++;
	    }
	}
	catch(IOException h) {}
    }
}

