/**********************************************************************
 *
 * ResultBox.java -- a list of phrases in the Phind java interface
 *
 * Copyright 1997-2000 Gordon W. Paynter
 * Copyright 2000 The New Zealand Digital Library Project
 *
 * A component of the Greenstone digital library software
 * from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *********************************************************************/

/*********************************************************************

This class is used in the Phind java applet (Phind.java).

A ResultBox holds the results of a query to phindcgi.  They deal mostly
with the information content of the query, and have methods for parsing the
input into phrase and document items.  They have little do with display:
ResultBoxes are shown to the user through "ResultDisplay" panels, and are
drawn using "ResultCanvas" objects.

**********************************************************************/

package org.nzdl.gsdl.Phind;

import java.awt.Panel;
import java.awt.BorderLayout;
import java.awt.Scrollbar;

import java.awt.Label;
import java.awt.Event;

import java.net.*;
import java.applet.*;

import java.util.Vector;


public class ResultBox extends Panel {
    
    // Objects at a "higher" level than this one
    Phind phind;
    ResultDisplay display;

    // Surroundig objects
    ResultBox prev, next;

    // The components contained by this one.
    ResultCanvas c;
    ResultTitle t;
    Scrollbar s;
    Panel label;

    // The key identifying the phrase displayed, with its text and the
    // collection from which it is drawn
    String searchKey, searchPhrase, searchCollection;
    
    // The total frequency, expansion frequency, and document frequency
    // of the phrase
    int numberOfOccurances;
    int numberOfExpansions;
    int numberOfDocuments;
    int numberOfThesaurusLinks;

    // The number of phrases and documents retrieved, and the number of
    // times the user has requested more phrases or documents.
    int expansionsRetrieved;
    int documentsRetrieved;
    int thesaurusLinksRetrieved;
    int nextPhraseBlock;
    int nextDocumentBlock;
    int nextThesaurusLinkBlock;
    
    int mode;
    final int initMode = 0;
    public final int emptyMode = 1;
    final int loadingMode = 2;
    final int finishedMode = 3;

    String buffer;
    boolean finished;


    // Create a ResultBox
    // given details of the search that generated it.
    ResultBox(Phind p, String collect, String key, String phrase, ResultBox rb) {

	super();
	mode = initMode;

	phind = p;
	display = null;
	next = null;
	prev = rb;
	if (prev != null) prev.next = this;

	searchKey = key;
	searchPhrase = phrase;
	searchCollection = collect;

	numberOfOccurances = -1;
	numberOfExpansions = -1;
	numberOfDocuments = -1;
	numberOfThesaurusLinks = -1;

	expansionsRetrieved = 0;
	documentsRetrieved = 0;
	thesaurusLinksRetrieved = 0;

	nextPhraseBlock = 1;
	nextDocumentBlock = 1;
	nextThesaurusLinkBlock = 1;


	setLayout(new BorderLayout());

	s = new Scrollbar(Scrollbar.VERTICAL);
	disableScrollbar();
	add("East", s);

	c = new ResultCanvas(this);
	add("Center", c);

	t = new ResultTitle(this);
	add("North", t);

	buffer = "";
	finished = false;
	mode = emptyMode;
    }

    static String describeContents(String phrase, String c) {
	return( "\"" + phrase + "\" in " + c + ".");
    }

    String describeContents() {
	return( describeContents(searchPhrase, searchCollection) );
    }


    // Reset the contents of the box
    void resetBox( ) {
	buffer = "";
	finished = false;
	c.resetCanvas();
	disableScrollbar();
	mode = emptyMode;
    
	numberOfExpansions = -1;
	numberOfDocuments = -1;
	numberOfThesaurusLinks = -1;

	expansionsRetrieved = 0;
	documentsRetrieved = 0;
	thesaurusLinksRetrieved = 0;
    }

    void setStatus( String status ) {
	phind.setStatus(status);
    }

    void disableScrollbar() {
	if (s.isEnabled()) {
	    s.setValues(0, 1, 0, 1);
	    s.setLineIncrement(1);
	    s.setPageIncrement(1);
	    s.disable();
	}
    }

    // Are there displays previous to and after this?
    public boolean prevBoxExists () {
	return (prev != null);
    }
    public boolean nextBoxExists () {
	return (next != null);
    }

    
    // Look up a phrase
    // Phrase lookups are passed on to the Phind applet itself.
    void lookupPhrase(String key, String phrase, int queryMode) {
	buffer = "";
	finished = false;
	phind.searchForPhrase(this, key, phrase, queryMode);
	t.repaint();
    }

    public boolean handleEvent(Event event) {
	//    System.out.println("event: " + event.toString());
	if ( (event.target == s) && 
	     ( (event.id == Event.SCROLL_ABSOLUTE) ||
	       (event.id == Event.SCROLL_LINE_DOWN) ||
	       (event.id == Event.SCROLL_LINE_UP) ||
	       (event.id == Event.SCROLL_PAGE_DOWN) ||
	       (event.id == Event.SCROLL_PAGE_UP) ) ) {
	    c.repaint();
	    return true;
	} else {
	    return super.handleEvent(event);
	}
    }    


    // a new section of the byte stream is read
    void parseBytes(byte[] bytes) {
	mode = loadingMode;

	// update the buffer that holds the bytes read
	String input;
	try {
	    input = new String(bytes, new String("UTF8"));
	} catch (Exception e) {
	    System.err.println(e);
	    input = "";
	}
	buffer = buffer.concat(input);

	// Parse each line until there are no more lines to parse
	while(parseLine());

	if (finished) {
	    c.updateMarkers();
	    buffer = "";
	} else {
	    // We haven't finished, give some feedback about progress
	    setStatus("Connected to host, " + c.numberOfItems + " results read");
	}
    }

    // Parse a line of XML
    //
    // This isn't necessarily real XML.  We assume every tag begins and
    // ends on one line.  We read one line out of the buffer at a time,
    // then "add" them to the box with the addLine method.
    //
    // Return true if there is a another line here to parse, otherwise false.

    boolean parseLine() {

        // System.out.print("parseLine " + "(length " + buffer.length() + ")");
	String item;
	int eol = buffer.indexOf((int) '\n');

	// If there are no carriage returns, the line is incomplete
	if (eol == -1) {
	    return false;
	}

	// The </phinddata> tag concludes the dataset
	else if (buffer.startsWith("</phinddata>")) {
	    mode = finishedMode;
	    finished = true;
	    return false;
	}
	
	// The <expansion> tag
	else if (buffer.startsWith("<expansion ")) {
	    item = buffer.substring(0, eol);
	    buffer = buffer.substring(eol + 1);
	    addExpansionTag(item);
	    return true;
	}
 
	// The <document> tag
	else if (buffer.startsWith("<document ")) {
	    item = buffer.substring(0, eol);
	    buffer = buffer.substring(eol + 1);
	    addDocumentTag(item);
	    return true;
	}
 
	// The <thesaurus> tag
	else if (buffer.startsWith("<thesaurus ")) {
	    item = buffer.substring(0, eol);
	    buffer = buffer.substring(eol + 1);
	    addThesaurusTag(item);
	    return true;
	}
 
	// The <phinddata> tag introduces the dataset
	else if (buffer.startsWith("<phinddata ")) {
	    item = buffer.substring(0, eol);
	    buffer = buffer.substring(eol + 1);
	    addPhinddataTag(item);
	    return true;
	}

	// The <phinderror> tag contains an error message
	else if (buffer.startsWith("<phinderror")) {
	    item = buffer.substring(0, eol);
	    System.out.println("phind reported an error: " + item);
	    buffer = buffer.substring(eol + 1);
	    return true;
	}
 
	// Ignore the piece we've read
	item = buffer.substring(0, eol);
	// System.out.println("discarding: " + item);
	buffer = buffer.substring(eol + 1);
	return true;
    }
    


    // Add a phinddata tag
    //
    // Given a string containing an XML phinddata tag of the form:
    //   <phinddata id="35" text="FOREST" df="797" ef="134">
    // Read the expansion information from the tag
    //
    // Return true if successful, otherwise false.

    boolean addPhinddataTag( String line ) {

	// System.out.println( "addExpansionListTag: " + line);

	String idStr = "", text = "", tfStr = "", efStr = "", dfStr = "", lfStr = "";
	int tf = 0, ef = 0, df = 0, lf = 0;

	// Break the tag down into its component parts
	int nextSplit;
       	while (line.length() > 0) {
	    line = line.trim();

	    // Read the phrase identifier
	    if (line.startsWith("id")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    idStr = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 
	    
	    // Read the total frequency
	    else if (line.startsWith("tf")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    tfStr = line.substring(0, nextSplit);
		    tf = Integer.valueOf(tfStr).intValue();
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 

	    // Read the text of the phrase
	    else if (line.startsWith("text")) {
		line = line.substring(6);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    text = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 

	    // Read the expansion frequency
	    else if (line.startsWith("ef")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    efStr = line.substring(0, nextSplit);
		    ef = Integer.valueOf(efStr).intValue();
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 

	    // Read the document frequency
	    else if (line.startsWith("df")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    dfStr = line.substring(0, nextSplit);
		    df = Integer.valueOf(dfStr).intValue();
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 

	    // Read the thesaurus link frequency
	    else if (line.startsWith("lf")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    lfStr = line.substring(0, nextSplit);
		    lf = Integer.valueOf(lfStr).intValue();
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("addExpansionListTag: error parsing: " + line);
 		}
	    } 

	    // Read and ignore some other tag
	    else {
		nextSplit = line.indexOf((int) ' ');
		if (nextSplit >= 1) {
		    line = line.substring(nextSplit + 1);
		} else {
		    line = "";
		}
	    }
	}

	// Add the data to the ResultBox
	searchKey = idStr;
	searchPhrase = text;
	numberOfOccurances = tf;
	numberOfExpansions = ef;
	numberOfDocuments = df;
	numberOfThesaurusLinks = lf;
	return true;
    }


    // Add an expansion tag
    //
    // Given a string containing an XML expansin tag of the form:
    //   <expansion num="3" id="8421" prefix="PEOPLE and" suffix="" tf="3" df="3"/>
    //   <expansion num="4" id="8696" prefix="" suffix="products" tf="3" df="3"/>
    // Create a new ResultItemPhrase for display
    //
    // Return true if successful, otherwise false.

    boolean addExpansionTag( String line ) {

	// System.out.println( "addExpansionTag: " + line + " (" + expansionsRetrieved + ")");

	String numStr = "", idStr = "", tfStr = "", dfStr = "", 
	    prefix = "", body = "", suffix = "";

	body = searchPhrase;

	// Break the tag down into its component parts
	line = line.substring(11);
	int nextSplit;
       	while (line.length() > 0) {
	    line = line.trim();

	    // Read the expansion number
	    if (line.startsWith("num")) {
		line = line.substring(5);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    numStr = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the phrase ID
	    else if (line.startsWith("id")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    idStr = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the prefix of the phrase
	    else if (line.startsWith("prefix")) {
		line = line.substring(8);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 0) {
		    prefix = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the suffix of the phrase
	    else if (line.startsWith("suffix")) {
		line = line.substring(8);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 0) {
		    suffix = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the frequency
	    else if (line.startsWith("tf")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    tfStr = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the document frequency
	    else if (line.startsWith("df")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    dfStr = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read some other tag
	    else {
		nextSplit = line.indexOf((int) ' ');
		if (nextSplit >= 1) {
		    line = line.substring(nextSplit + 1);
		} else {
		    line = "";
		}
	    }
	}
	
	// Create a new ResultItem and add it to the display
	ResultItemPhrase ri;
	if (phind.righttoleft) {
	  // swap suffix and prefix
	  ri = new ResultItemPhrase(idStr, tfStr, dfStr, suffix, body, prefix);
	} else {
	  ri = new ResultItemPhrase(idStr, tfStr, dfStr, prefix, body, suffix);
	}
	if (c.addResultItem(ri)) {
	    expansionsRetrieved++;
	    return true;
	}
	
	return false;
    }


    // Add an document tag
    //
    // Given a string containing an XML document tag of the form:
    //   <document num="2" hash="HASH424e64b811fdad933be69c" freq="1" title="CONTENTS"/>
    //   <document num="3" hash="HASH01f08efd8752ad54ca0a99cf" freq="1" title="Tree mixtures"/>
    //
    // Create a new ResultItemDocument for display
    //
    // Return true if successful, otherwise false.

    boolean addDocumentTag( String line ) {

	// System.out.println( "addDocumentTag: " + line + " (" + documentsRetrieved + ")");
	
	String num = "", hash = "", freq = "", title = "";
	line = line.substring(9);
	
	// Break the tag down into its component parts
	int nextSplit;
       	while (line.length() > 0) {
	    line = line.trim();

	    // Read the expansion number
	    if (line.startsWith("num")) {
		line = line.substring(5);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    num = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
 		}
	    } 

	    // Read the document OID hash
	    else if (line.startsWith("hash")) {
		line = line.substring(6);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    hash = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
 		}
	    } 

	    // Read the document frequency
	    else if (line.startsWith("freq")) {
		line = line.substring(6);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    freq = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
 		}
	    } 

	    // Read the title
	    else if (line.startsWith("title")) {
		line = line.substring(7);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    title = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addDocumentTag: error parsing: " + line);
 		}
	    } 

	    // Read some other tag or close the string off
	    else {
		nextSplit = line.indexOf((int) ' ');
		if (nextSplit >= 1) {
		    line = line.substring(nextSplit + 1);
		} else {
		    line = "";
		}
	    }
	}
	
	// Create a new ResultItem and add it to the display
	ResultItemDocument ri = new ResultItemDocument(hash, title, freq);
	
	if (c.addResultItem(ri)) {
	    documentsRetrieved++;
	    return true;
	}
	
	return false;
    }


    // Add a thesaurus tag
    //
    // Given a string containing an XML document tag of the form:
    //
    // <thesaurus num="3" id="36506" tf="0" df="0" type="RT" text="ANGLOPHONE AFRICA"/>
    // <thesaurus num="4" id="28724" tf="0" df="0" type="RT" text="FRANCOPHONE AFRICA"/>
    //
    // Create a new ResultItemLink for display
    //
    // Return true if successful, otherwise false.

    boolean addThesaurusTag( String line ) {
    
	// System.out.println( "addThesaurusTag: " + line + " (" + thesaurusLinksRetrieved + ")");

	String num = "", id = "", tf = "", df = "", type = "", text = "";
	line = line.substring(10);

	// Break the tag down into its component parts
	int nextSplit;
       	while (line.length() > 0) {
	    line = line.trim();

	    // Read the expansion number
	    if (line.startsWith("num")) {
		line = line.substring(5);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    num = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
 		}
	    } 

	    // Read the phrase ID
	    else if (line.startsWith("id")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    id = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
 		}
	    } 

	    // Read the phrase link type
	    else if (line.startsWith("type")) {
		line = line.substring(6);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    type = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
 		}
	    } 


	    // Read the phrase text
	    else if (line.startsWith("text")) {
		line = line.substring(6);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    text = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addThesaurusTag: error parsing: " + line);
 		}
	    } 

	    // Read the frequency
	    else if (line.startsWith("tf")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    tf = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 

	    // Read the document frequency
	    else if (line.startsWith("df")) {
		line = line.substring(4);
		nextSplit = line.indexOf((int) '"');
		if (nextSplit >= 1) {
		    df = line.substring(0, nextSplit);
		    line = line.substring(nextSplit + 1);
		} else {
		    System.err.println("ResultBox addExpansionTag: error parsing: " + line);
 		}
	    } 


	    // Read some other tag or close the string off
	    else {
		nextSplit = line.indexOf((int) ' ');
		if (nextSplit >= 1) {
		    line = line.substring(nextSplit + 1);
		} else {
		    line = "";
		}
	    }
	}
	
	// Create a new ResultItem and add it to the display
	ResultItemLink ri = new ResultItemLink(id, text, type, tf, df);

	if (c.addResultItem(ri)) {
	    thesaurusLinksRetrieved++;
	    return true;
	}
	
	return false;
    }
}




