// ListTest.java
//
// Tests ShortSequenceLinkedList.java
// Uses, in this folder:
//    ShortSequenceLinkedList.java
//    ShortSequenceLinkedListIterator.java
//    ConsoleInput.java
//    ListTestUI.java
//    ListTestUIConsole.java
//    ListTestUIDialog.java
//    ListTestUIMixed.java
//
// To compile under Java 1.4 (and avoid warnings under 1.5), type:
//    javac -source 1.4 ListTest.java

public class ListTest
{
   final static String lineBreak
                         = System.getProperty(
                                     "line.separator");

   private static ListTestUI ui;

   private static ShortSequenceLinkedList list1;
   private static String descriptorList1;
   private static ShortSequenceLinkedList list2;
   private static String descriptorList2;

   public static void main(String[] args)
   {
      ui = selectUI(args);

      ui.displayAnnouncementMessage(introMessage(),
                                    "Linked list tester");

      list1 = list2 = null;
      descriptorList1 = "List 1";
      descriptorList2 =  "List 2";

      ui.runTestsRepeatedly();
   }  // method main

   public static void runTests()
   {
      ShortSequenceLinkedList[] lists = {list1, list2};
      String[] descriptors = { descriptorList1, descriptorList2 };

      for ( int i = 0; i < 2; i++ )
      {
         if ( lists[i] == null )
         {
            if ( ui.askYesNo("Create new " + descriptors[i]
                                    + "?  (Otherwise, "
                                    + descriptors[i]
                                    + " is null.)",
                              "Instantiate " + descriptors[i] + "?") )
               lists[i] = new ShortSequenceLinkedList();
         }  // if
         else
         {
            if ( ui.askYesNo("Forget " + descriptors[i]
                                    + " (replace with null)?",
                             "Set " + descriptors[i]
                                    + " to null?") )
               lists[i] = null;
         }  // else
      }  // for i

      String[] texts = { listInfo(lists[0], descriptors[0]),
                         listInfo(lists[1], descriptors[1]) };

      ui.displayResults(texts);

      for ( int i = 0; i < 2; i++ )
      {
         if ( lists[i] != null )
            if ( ui.askYesNo("Call one of " + descriptors[i]
                                 + "'s methods to test it?",
                             "Test " + descriptors[i] + "?") )
               testOneList( lists[i], descriptors[i],
                            lists[1-i], descriptors[1-i] );
      }  // for i

      list1 = lists[0];
      list2 = lists[1];
   }  // method runTests

   private static void testOneList(
                            ShortSequenceLinkedList listToTest,
                            String descriptorListToTest,
                            ShortSequenceLinkedList listOther,
                            String descriptorListOther)
   {
      // listOther may be null, but listToTest may not be null.
      assert ( listToTest != null ) : "listToTest is null.";

      String methodToTest = ui.askWhichMethod();
      String result;

      assert ( methodToTest != null )
             : "methodToTest == null";

      if ( methodToTest.equals(ListTestUI.GETNUMBERAT) )
         result = testGetNumberAt(listToTest);
      else if ( methodToTest.equals(ListTestUI.APPEND) )
         result = testAppend(listToTest);
      else if ( methodToTest.equals(ListTestUI.INSERT) )
         result = testInsert(listToTest);
      else if ( methodToTest.equals(ListTestUI.INDEXOF) )
         result = testIndexOf(listToTest);
      else if ( methodToTest.equals(ListTestUI.REMOVEELEMENTAT) )
         result = testRemoveElementAt(listToTest);
      else if ( methodToTest.equals(ListTestUI.EQUALS) )
         result = testEquals(listToTest, descriptorListToTest,
                             listOther, descriptorListOther);
      else if ( methodToTest.equals(ListTestUI.HASHCODE) )
         result = testHashCode(listToTest);
      else if ( methodToTest.equals(ListTestUI.BEGINITERATING) )
         result = testBeginIterating(listToTest);
      else
         throw new IllegalStateException("methodToTest="
                                         + methodToTest);

      String[] texts = new String[]{ (descriptorListToTest
                                               + ":  " + result
                                               + lineBreak),
                                      listInfo(listToTest,
                                               descriptorListToTest),
                                      listInfo(listOther,
                                               descriptorListOther) };
      ui.displayResults(texts);
   }  // method testOneList

   private static String testGetNumberAt(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          int index = ui.askIndex();
          short data = list.getNumberAt(index);
          return ("Tested: " + ListTestUI.GETNUMBERAT
                             + lineBreak
                             + "The element at index " + index
                             + " is " + data + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.GETNUMBERAT
                             + lineBreak
                             + re);
      }  // catch
   }  // method testGetNumberAt

   private static String testAppend(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          short data = ui.askData();
          list.append(data);
          return ("Tested: " + ListTestUI.APPEND
                             + lineBreak
                             + "Appended " + data + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.APPEND
                             + lineBreak
                             + re);
      }  // catch
   }  // method testAppend

   private static String testInsert(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          int index = ui.askIndex();
          short data = ui.askData();
          list.insert(index, data);
          return ("Tested: " + ListTestUI.INSERT
                             + lineBreak
                             + "Inserted " + data + " at index "
                             + index + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.INSERT
                             + lineBreak
                             + re);
      }  // catch
   }  // method testInsert

   private static String testIndexOf(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          short data = ui.askData();
          int index = list.indexOf(data);
          return ("Tested: " + ListTestUI.INDEXOF
                             + lineBreak
                             + "Index of " + data + " is "
                             + index + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.INDEXOF
                             + lineBreak
                             + re);
      }  // catch
   }  // method testIndexOf

   private static String testRemoveElementAt(
                                  ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          int index = ui.askIndex();
          short data = list.removeElementAt(index);
          return ("Tested: " + ListTestUI.REMOVEELEMENTAT
                             + lineBreak
                             + "Removed " + data + " at index "
                             + index + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.REMOVEELEMENTAT
                             + lineBreak
                             + re);
      }  // catch
   }  // method testInsert

   private static String testEquals(ShortSequenceLinkedList listToTest,
                             String descriptorListToTest,
                             ShortSequenceLinkedList listOther,
                             String descriptorListOther)
   {
      assert ( listToTest != null ) : "listToTest is null.";

      try
      {
          boolean equal = listToTest.equals(listOther);
          String text = "Tested: " + ListTestUI.EQUALS
                             + lineBreak
                             + "Testing        "
                             + descriptorListToTest
                             + " (hash code "
                             + listToTest.hashCode() + ")"
                             + lineBreak
                             + "with parameter "
                             + descriptorListOther + " ";
          text += ( ( listOther == null )
                  ? ( "(null)." )
                  : ( "(hash code " + listOther.hashCode() + ")." ) );

          text += lineBreak + "The two lists "
                            + (equal ? "ARE" : "are NOT")
                            + " equal.";

          return text;
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.EQUALS
                             + lineBreak
                             + re);
      }  // catch
   }  // method testEquals

   private static String testHashCode(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          int hashCode = list.hashCode();
          return ("Tested: " + ListTestUI.HASHCODE
                             + lineBreak
                             + "Hash code is " + hashCode + ".");
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.HASHCODE
                             + lineBreak
                             + re);
      }  // catch
   }  // method testHashCode

   private static String testBeginIterating(ShortSequenceLinkedList list)
   {
      assert ( list != null ) : "list is null.";

      try
      {
          ShortSequenceLinkedListIterator iterator
                                           = list.beginIterating();
          String text = "Tested: " + ListTestUI.BEGINITERATING
                                   + lineBreak
                                   + "Below are the list's"
                                   + " contents, if any:"
                                   + lineBreak;

          while ( iterator.hasNext() )
              text = text + Short.toString(iterator.next())
                          + lineBreak;

          text = text + "End of iteration.";

          return text;
      }  // try
      catch ( RuntimeException re )
      {
         ui.displayErrorMessage(re);
         return("Exception while testing:  "
                             + ListTestUI.BEGINITERATING
                             + lineBreak
                             + re);
      }  // catch
   }  // method testBeginIterating

   private static String introMessage()
   {
      String intro = lineBreak
                     + "  This program allows you to test two linked "
                     + lineBreak
                     + "  lists repeatedly.  Each time, you will have"
                     + lineBreak
                     + "  the option of creating or destroying either"
                     + lineBreak
                     + "  or both lists if desired, and then calling"
                     + lineBreak
                     + "  a method on each list (if non-null).  (When"
                     + lineBreak
                     + "  you test the equals method, the parameter "
                     + lineBreak
                     + "  will be a reference to the other list.)"
                     + lineBreak;

      return intro;
   }  // method introMessage

   private static String listInfo(ShortSequenceLinkedList list,
                                  String listReferenceID)
   {
      String text = ( list == null )
                       ? (listReferenceID + " does not exist."
                               + " (The reference to "
                               + listReferenceID + " is null.)")
                       : (listReferenceID + ":   [" + list
                               + "]    length=" + list.getLength());
      return text;
   }  // method writeListsInfo

   private static ListTestUI selectUI(String[] args)
   {
      ListTestUI ui;
      String choice;

      if ( args.length >= 1
              && ( args[0].equalsIgnoreCase("C")
                     || args[0].equalsIgnoreCase("D")
                     || args[0].equalsIgnoreCase("M") ) )
         choice = args[0];
      else
      {
         System.out.println("Do you prefer console (C),"
                            + " dialog boxes (D), or"
                            + " mixed GUI/console (M)?");
         choice = ConsoleInput.askSelection(
                            "Enter your selection:",
                            new String[] {"C", "D", "M"} );
      }  // else

      switch ( choice.toUpperCase().charAt(0) )
      {
         case 'C':
            ui = new ListTestUIConsole();
            break;
         case 'D':
            ui = new ListTestUIDialog();
            break;
         case 'M':
            ui = new ListTestUIMixed();
            break;
         default:
            throw new AssertionError("choice=" + choice);
      }  // switch

      return ui;
   }  // method selectUI
}  // class ListTest