import java.io.*;
import java.util.*;

//import BufferLoad;

/**
 *  This type represents a chunk of text containing
 *  a question and answer section, known as an faq.
 *  The text is not 'marked up' particularly, or at least
 *  only in a minimalistic way.
 *
 *  @see FaqItem, Question, Answer
 *  @author http://bumble.sf.net
 */
 
  
public class FAQ extends Object
{
  //--------------------------------------------
  private static String NEWLINE = System.getProperty("line.separator");
  //--------------------------------------------
  private boolean isGood;
  //--------------------------------------------
  private String errors;
  //--------------------------------------------
  private String title;
  //--------------------------------------------
  private Vector faqItems;
  //--------------------------------------------
  private Date startTime;
  //--------------------------------------------
  private Date finishTime;
  //--------------------------------------------
  public static String INDICATOR = "[faq]";
  //--------------------------------------------
  public static String TERMINATOR = "[/faq]";

  public FAQ()
  {
    this.errors = "";
    this.faqItems = new Vector();
    this.title = "";
  } 

  //--------------------------------------------
  public FAQ(String sText)
  {
    this();
    this.loadData(sText);
  } 

  //--------------------------------------------
  /** return the number of milliseconds taken to load. */
  public long getLoadDuration()
  {
    if (this.finishTime == null) { return 0; }
    if (this.startTime == null) { return 0; }
    return this.finishTime.getTime() - this.startTime.getTime();
  } 

  //--------------------------------------------
  public void setTitle(String sTitle)
  {
    this.title = sTitle;
  }

  //--------------------------------------------
  public String getTitle()
  {
    return this.title;
  }

  //--------------------------------------------
  public void loadData(String sText)
  {

    this.startTime = new Date();
    this.isGood = this.isFAQ(sText);
    if (!this.isGood)
    {
      this.finishTime = new Date();
      return;
    }

    String sFaqContents =
      sText.trim().substring(FAQ.INDICATOR.length());
    StringReader srText = new StringReader(sFaqContents);

    int iCurrentCharacter = 0;
    StringBuffer sbText = new StringBuffer("");
    
    while (iCurrentCharacter != -1)
    {
      sbText.append((char)iCurrentCharacter);
      //-- System.out.println("sbText=" + sbText);

      if (FaqItem.isFaqItem(sbText.toString()))
      {
        //-- System.out.println("<found item>");
        this.faqItems.addElement(new FaqItem(sbText.toString()));
        //--
        //-- push the 'q:' back on the buffer since we are
        //--

        if (sbText.toString().endsWith(Question.INDICATOR))
        {
          sbText.setLength(0);
          sbText.append(Question.INDICATOR);
        }
        else
        {
          sbText.setLength(0);
        }
      } //-- if faqItem 

      try
      {
        iCurrentCharacter = srText.read();
      }
      catch (IOException e)
      {
        this.errors =
          "An IO Exception occurred while reading " + e;
        this.finishTime = new Date();
        return;
      }
    } //-- while

    srText.close();
    this.finishTime = new Date();

  } //-- m: loadData()

  //--------------------------------------------
  /** checks if this looks like an FAQ */
  public static boolean isFAQ(String sText)
  {
    if (sText.trim().length() == 0)
     { return false; }

    if (!sText.trim().startsWith(FAQ.INDICATOR))
      { return false; }

    if (!sText.trim().endsWith(FAQ.TERMINATOR))
      { return false; }

    return true;
  }

  //--------------------------------------------
  /** is there any data */
  public boolean isEmpty()
  {
    if (this.faqItems.size() == 0)
     { return true; }
    else
     { return false; }
  }
  
  //--------------------------------------------
  /** how many question and answers are there */
  public int countItems()
  {
    return this.faqItems.size();
  }


  //--------------------------------------------
  /** how many answers are there */
  public int countAnswers()
  {
    int iAnswers = 0;
    FaqItem fiCurrent = new FaqItem();

    Enumeration ii = faqItems.elements();
    while (ii.hasMoreElements())
    {
      fiCurrent = (FaqItem)ii.nextElement();
      if (fiCurrent.hasAnswer())
       { iAnswers++; }
    }
    return iAnswers;
  }

  //--------------------------------------------
  public String toString()
  {
    StringBuffer sbReturn = new StringBuffer("");
    FaqItem fiCurrent = new FaqItem();

    sbReturn.append(FAQ.INDICATOR);
    sbReturn.append(NEWLINE);

    Enumeration ii = faqItems.elements();
    while (ii.hasMoreElements())
    {
      fiCurrent = (FaqItem)ii.nextElement();      
      sbReturn.append(fiCurrent.toString());
      sbReturn.append(NEWLINE);
    }

    sbReturn.append(FAQ.TERMINATOR);

    return sbReturn.toString();
  }

  //--------------------------------------------
  public String printHtml()
  {
    StringBuffer sbReturn = new StringBuffer("");
    return this.printHtml(true);
  }

  //--------------------------------------------
  public String printHtml(boolean bIncludeIndex)
  {

    StringBuffer sbReturn = new StringBuffer("");
    Enumeration ii;
    FaqItem fiCurrent = new FaqItem();
    int iIndex;
    iIndex = 1;

    sbReturn.append("<h3>");
    sbReturn.append(this.getTitle());
    sbReturn.append("</h3>");

    if (bIncludeIndex)
    {
      sbReturn.append("<a name='toc'></a>");
      sbReturn.append(NEWLINE);
      sbReturn.append("<ul class='faq-index'>");
      sbReturn.append(NEWLINE);
      ii = faqItems.elements();
      while (ii.hasMoreElements())
      {
        fiCurrent = (FaqItem)ii.nextElement();      
        sbReturn.append("<li class='faq-index-item'>");
        sbReturn.append("<a href='#" + iIndex + "'>");
        sbReturn.append(fiCurrent.getQuestion().getContents());
        sbReturn.append(Question.TERMINATOR);
        sbReturn.append("</a>");
        sbReturn.append("</li>");
        sbReturn.append(NEWLINE);
        iIndex++;
      }
      sbReturn.append("</ul>");
      sbReturn.append(NEWLINE);

    } //-- if

    sbReturn.append("<dl class='faq'>");
    sbReturn.append(NEWLINE);

    iIndex = 1;
    ii = faqItems.elements();
    while (ii.hasMoreElements())
    {
      if (bIncludeIndex)
      {
        sbReturn.append(NEWLINE);
        sbReturn.append("<a name='" + iIndex + "'>");
      }

      fiCurrent = (FaqItem)ii.nextElement();      
      sbReturn.append(fiCurrent.printHtml());

      if (bIncludeIndex)
      {
        sbReturn.append("</a>");
      }

      sbReturn.append(NEWLINE);
      sbReturn.append(NEWLINE);

      iIndex++;
    }

    sbReturn.append("</dl>");
    sbReturn.append("<a href='#toc'>(top)</a>"); 
    return sbReturn.toString();
  }

  //--------------------------------------------
  public String printReport()
  {
    StringBuffer sbReturn = new StringBuffer("");
    sbReturn.append("");
    sbReturn.append(NEWLINE);
    sbReturn.append("Faq title        >");
    sbReturn.append(this.getTitle());
    sbReturn.append(NEWLINE);
    sbReturn.append("Number of items  >");
    sbReturn.append(this.countItems());
    sbReturn.append(NEWLINE);
    sbReturn.append("Number of answers>");
    sbReturn.append(this.countAnswers());
    sbReturn.append(NEWLINE);
    sbReturn.append("Load time        >");
    sbReturn.append(this.getLoadDuration());
    sbReturn.append(NEWLINE);
    sbReturn.append("last data good   >");
    sbReturn.append(this.isGood);
    sbReturn.append(NEWLINE);
    sbReturn.append("Faq is empty     >");
    sbReturn.append(this.isEmpty());
    sbReturn.append(NEWLINE);
    sbReturn.append("error messages   >");
    sbReturn.append(this.errors);
    sbReturn.append(NEWLINE);
    return sbReturn.toString();
  }

  //--------------------------------------------
  public String print()
  {
    StringBuffer sbReturn = new StringBuffer("");
    return this.toString();
  }


  //--------------------------------------------
  /** a main method for testing */
  public static void main(String[] args) throws Exception
  {

    StringBuffer sbUsageMessage = new StringBuffer("");
    sbUsageMessage.append("test usage: java FAQ faq-file [all]");
    sbUsageMessage.append(NEWLINE);

    if (args.length == 0)
    {	    
      System.out.println(sbUsageMessage);
      System.exit(-1);
    }


    StringBuffer sbTest = new StringBuffer("");
    sbTest.append(NEWLINE);

    if (args.length == 2)
    {
      System.out.println("Using data");
      System.out.println(NEWLINE);
      System.out.println(BufferLoad.loadBuffer(args[0]));
    }

    FAQ faqTest = new FAQ(BufferLoad.loadBuffer(args[0]));
    System.out.println(faqTest.printHtml());

    if (args.length == 2)
    {
      System.out.println(NEWLINE);
      System.out.println(faqTest.toString());
      System.out.println(NEWLINE);
      System.out.println(faqTest.printReport());
    }
  } //-- main()
  
} //-- FAQ class






