import java.io.*;
import java.util.*;

//import BufferLoad;
//import BlankText;
//import TextTool;
//import StringArray;
//import Html;
//import DocumentElement;

/**
 *  This type is a list written in some document. In the
 *  current implementation the class can parse some text
 *  which is written in a 'wiki' style syntax. That is,
 *  the text uses basic markers to delimit the beginning of
 *  the list and its elements.
 *  
 *
 *  @see ListItem
 *  @author http://bumble.sf.net
 */
 
  
public class PlainList extends Object implements DocumentElement
{
  //--------------------------------------------
  private static String NEWLINE = System.getProperty("line.separator");
  //--------------------------------------------
  private boolean isGood;
  //--------------------------------------------
  private String errors;
  //--------------------------------------------
  private String title;
  //--------------------------------------------
  private int listType;
  //--------------------------------------------
  private Vector listItems;
  //--------------------------------------------
  private Date startTime;
  //--------------------------------------------
  private Date finishTime;
  //--------------------------------------------
  public static String INDICATOR = "   ";
  //--------------------------------------------
  public static String[] startTokens =
   {" u- ", " o- ", " 1- "};
  //--------------------------------------------
  public static String TERMINATOR = NEWLINE+NEWLINE;
  //--------------------------------------------
  public static int UNORDERED = 1;
  //--------------------------------------------
  public static int ORDERED_ALPHABETIC = 2;
  //--------------------------------------------
  public static int ORDERED_NUMERIC = 3;
  //--------------------------------------------
  public static int ORDERED_ROMAN = 4;
  //--------------------------------------------
  
 
  public PlainList()
  {
    this.errors = "";
    this.listItems = new Vector();
    this.title = "";
    this.listType = UNORDERED;
  } 

  //--------------------------------------------
  public PlainList(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 static boolean recognize(String sText)
  {
    if (TextTool.endsWithIgnoreCase(sText, PlainList.startTokens))
    {
      return true;
    }
    return false;
  }

  //--------------------------------------------
  public static String returnToken(String sText)
  {
    return EndText.getSuffix(sText, PlainList.startTokens);
  }

  //--------------------------------------------
  public void loadData(String sText)
  {

    this.startTime = new Date();
    this.isGood = this.isPlainList(sText);
    if (!this.isGood)
    {
      this.finishTime = new Date();
      return;
    }

    if (sText.toLowerCase().startsWith(" u- "))
    {
      this.listType = UNORDERED;
    }

    if (sText.toLowerCase().startsWith(" o- "))
    {
      this.listType = ORDERED_ALPHABETIC;
    }

    if (sText.toLowerCase().startsWith(" 1- "))
    {
      this.listType = ORDERED_NUMERIC;
    }

    StringReader srText = new StringReader(sText);

    int iCurrentCharacter = 0;
    StringBuffer sbText = new StringBuffer("");
    
    while (iCurrentCharacter != -1)
    {
      sbText.append((char)iCurrentCharacter);
      //--System.out.println("sbText=" + sbText);

      if (ListItem.isListItem(sbText.toString()))
      {
        //--System.out.println("<found item>");
        this.listItems.addElement(new ListItem(sbText.toString()));
      } 

      if (ListItem.recognize(sbText.toString()))
      {
        //--
        //-- push the ListItem token back on the buffer since we are
        //-- using the start token as the end token of the previous
        sbText.setLength(0);
        sbText.append(ListItem.INDICATOR);
      }

      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 the text looks like an PlainList */
  public static boolean isPlainList(String sText)
  {
    if (sText.trim().length() == 0)
     { return false; }

    if (!TextTool.startsWithIgnoreCase(sText, PlainList.startTokens))
    {
      //--System.out.println("start token not found");
      return false;
    }

    if (!BlankText.lastLineIsBlank(sText))
    {
      //--System.out.println("last line not blank");
      return false;
    }

    return true;
  }

  //--------------------------------------------
  /** is there any data */
  public boolean isEmpty()
  {
    if (this.listItems.size() == 0)
     { return true; }
    else
     { return false; }
  }
  
  //--------------------------------------------
  /** how many list items are there */
  public int countItems()
  {
    return this.listItems.size();
  }

  //--------------------------------------------
  public String toString()
  {
    StringBuffer sbReturn = new StringBuffer("");
    ListItem liCurrent = new ListItem();

    if (listItems.size() == 0)
    {
      return "";
    }

    sbReturn.append(PlainList.INDICATOR);
    sbReturn.append(NEWLINE);

    Enumeration ii = listItems.elements();

    if (this.listType == UNORDERED)
    {
      sbReturn.append(" u- ");
    }
    else if (this.listType == ORDERED_ALPHABETIC)
    {
      sbReturn.append(" o- ");
    }
    else if (this.listType == ORDERED_NUMERIC)
    {
      sbReturn.append(" 1- ");
    }

    //-- since the list and the listitem share their
    //-- start token it is not possible to just call
    //-- toString for the first listitem.
    //--
    liCurrent = (ListItem)ii.nextElement();      
    sbReturn.append(liCurrent.getContents());
    sbReturn.append(NEWLINE);

    while (ii.hasMoreElements())
    {
      liCurrent = (ListItem)ii.nextElement();      
      sbReturn.append(liCurrent.toString());
      sbReturn.append(NEWLINE);
    }

    sbReturn.append(PlainList.TERMINATOR);

    return sbReturn.toString();
  }

  //--------------------------------------------
  public String printHtml()
  {

    StringBuffer sbReturn = new StringBuffer("");
    Enumeration ii;
    ListItem liCurrent = new ListItem();
    int iIndex;
    iIndex = 1;

    if (!this.title.trim().equals(""))
    {
      sbReturn.append("<h3>");
      sbReturn.append(Html.encode(this.title));
      sbReturn.append("</h3>");
    }

    if (this.listType == UNORDERED)
    {
      sbReturn.append("<ul>");
    }
    else if (this.listType == ORDERED_ALPHABETIC)
    {
      sbReturn.append("<ol type='a'>");
    }
    else if (this.listType == ORDERED_NUMERIC)
    {
      sbReturn.append("<ol type='1'>");
    }

    sbReturn.append(NEWLINE);

    iIndex = 1;
    ii = listItems.elements();
    while (ii.hasMoreElements())
    {
      liCurrent = (ListItem)ii.nextElement();      
      sbReturn.append(liCurrent.printHtml());

      sbReturn.append(NEWLINE);
      iIndex++;
    }

    if (this.listType == UNORDERED)
    {
      sbReturn.append("</ul>");
    }
    else 
    {
      sbReturn.append("</ol>");
    }

    return sbReturn.toString();
  }

  //--------------------------------------------
  public String printReport()
  {
    StringBuffer sbReturn = new StringBuffer("");
    sbReturn.append("");
    sbReturn.append(NEWLINE);
    sbReturn.append("PlainList title  >");
    sbReturn.append(this.getTitle());
    sbReturn.append(NEWLINE);
    sbReturn.append("Number of items  >");
    sbReturn.append(this.countItems());
    sbReturn.append(NEWLINE);
    sbReturn.append("Type of list     >");
    sbReturn.append(this.listType);
    sbReturn.append(NEWLINE);
    sbReturn.append("Start tokens     >");
    sbReturn.append(NEWLINE);
    sbReturn.append(StringArray.display(this.startTokens));
    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("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 PlainList . ");
    sbUsageMessage.append(NEWLINE);

    if (args.length == 0)
    {	    
      System.out.println(sbUsageMessage);
      System.exit(-1);
    }


    StringBuffer sbTest = new StringBuffer("");
    sbTest.append(" 1- The first item");
    sbTest.append(NEWLINE);
    sbTest.append("  - The second item");
    sbTest.append(NEWLINE);
    sbTest.append("  - another point to make");
    sbTest.append(NEWLINE);
    sbTest.append("  - and another");
    sbTest.append(NEWLINE);
    sbTest.append("  - then go back");
    sbTest.append(NEWLINE);
    sbTest.append("  - finally");
    sbTest.append(NEWLINE);
    sbTest.append("  ");
    sbTest.append(NEWLINE);

    if (args.length == 2)
    {
      System.out.println("Using data");
      System.out.println(NEWLINE);
      System.out.println(sbTest.toString());
    }

    PlainList list = new PlainList(sbTest.toString());
    System.out.println(list.printHtml());

    if (args.length == 2)
    {
      System.out.println(NEWLINE);
      System.out.println(list.toString());
      System.out.println(NEWLINE);
      System.out.println(list.printReport());
    }
  } //-- main()
  
} //-- PlainList class






