// ListTestInOneClass.java
//
// Tests ShortSequenceLinkedList.java
// Uses, in this folder:
//    ShortSequenceLinkedList.java
//    ShortSequenceLinkedListIterator.java
//    ConsoleInput.java


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

   public static final String GETNUMBERAT = "short getNumberAt(int index)";
   public static final String APPEND = "void append(short data)";
   public static final String INSERT = "void insert(int index, short data)";
   public static final String INDEXOF = "int indexOf(short data)";
   public static final String REMOVEELEMENTAT
                                 = "short removeElementAt(int index)";
   public static final String EQUALS = "boolean equals(Object other)";
   public static final String HASHCODE = "int hashCode()";
   public static final String BEGINITERATING
                         = "ShortSequenceLinkedListIterator beginIterating()";

   private static String[] options
                       = new String[] {"N", "A", "I", "J",
                                       "R", "E", "H", "B"};

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

   public static void main(String[] args)
   {
      System.out.println(introMessage());
      System.out.println("Linked list tester");

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

      runTestsRepeatedly();
   }  // method main

   private static void runTestsRepeatedly()
   {
      do  {   // Test both lists repeatedly
         runTests();
      } while ( askYesNo("Test the two lists again (and possibly"
                                + " create/destroy them first)?",
                         "Test again?") );
   }  // method runTestsRepeatedly

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

      for ( int i = 0; i < 2; i++ )
      {
         if ( lists[i] == null )
         {
            if ( askYesNo("Create new " + descriptors[i]
                                    + "?  (Otherwise, "
                                    + descriptors[i]
                                    + " is null.)",
                              "Instantiate " + descriptors[i] + "?") )
               lists[i] = new ShortSequenceLinkedList();
         }  // if
         else
         {
            if ( 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]) };

      displayResults(texts);

      for ( int i = 0; i < 2; i++ )
      {
         if ( lists[i] != null )
            if ( 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 = askWhichMethod();
      String result;

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

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

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

   private static String askWhichMethod()
   {
      System.out.println("Select a method to test.");
      System.out.println();
      System.out.println("   N - " + GETNUMBERAT);
      System.out.println("   A - " + APPEND);
      System.out.println("   I - " + INSERT);
      System.out.println("   J - " + INDEXOF);
      System.out.println("   R - " + REMOVEELEMENTAT);
      System.out.println("   E - " + EQUALS);
      System.out.println("   H - " + HASHCODE);
      System.out.println("   B - " + BEGINITERATING);
      System.out.println();

      String answer = ConsoleInput.askSelection(
                            "Enter your selection:",
                            options);

      // Mote:  The above statement ensures that
      // answer will indeed be one of the desired
      // options.

      switch ( answer.charAt(0) )
      {
         case 'N':  case 'n':  return GETNUMBERAT;
         case 'A':  case 'a':  return APPEND;
         case 'I':  case 'i':  return INSERT;
         case 'J':  case 'j':  return INDEXOF;
         case 'R':  case 'r':  return REMOVEELEMENTAT;
         case 'E':  case 'e':  return EQUALS;
         case 'H':  case 'h':  return HASHCODE;
         case 'B':  case 'b':  return BEGINITERATING;
         default:  throw new IllegalStateException(
                                  "Option unaccounted for.");
      }  // switch
   }  // method askWhichMethod

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

      try
      {
          int index =  Integer.parseInt(
                               ConsoleInput.ask(
                                            "Enter an index:"));
          short data = list.getNumberAt(index);
          return ("Tested: " + GETNUMBERAT
                             + lineBreak
                             + "The element at index " + index
                             + " is " + data + ".");
      }  // try
      catch ( RuntimeException re )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + GETNUMBERAT
                             + lineBreak
                             + re);
      }  // catch
   }  // method testGetNumberAt

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

      try
      {
          short data =  Short.parseShort(
                              ConsoleInput.ask(
                                           "Enter a data item:"));
          list.append(data);
          return ("Tested: " + APPEND
                             + lineBreak
                             + "Appended " + data + ".");
      }  // try
      catch ( RuntimeException re )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + APPEND
                             + lineBreak
                             + re);
      }  // catch
   }  // method testAppend

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

      try
      {
          int index =  Integer.parseInt(
                               ConsoleInput.ask(
                                            "Enter an index:"));
          short data =  Short.parseShort(
                              ConsoleInput.ask(
                                           "Enter a data item:"));
          list.insert(index, data);
          return ("Tested: " + INSERT
                             + lineBreak
                             + "Inserted " + data + " at index "
                             + index + ".");
      }  // try
      catch ( RuntimeException re )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + INSERT
                             + lineBreak
                             + re);
      }  // catch
   }  // method testInsert

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

      try
      {
          short data =  Short.parseShort(
                              ConsoleInput.ask(
                                           "Enter a data item:"));

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

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

      try
      {
          int index =  Integer.parseInt(
                               ConsoleInput.ask(
                                            "Enter an index:"));
          short data = list.removeElementAt(index);
          return ("Tested: " + REMOVEELEMENTAT
                             + lineBreak
                             + "Removed " + data + " at index "
                             + index + ".");
      }  // try
      catch ( RuntimeException re )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + 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: " + 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 )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + 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: " + HASHCODE
                             + lineBreak
                             + "Hash code is " + hashCode + ".");
      }  // try
      catch ( RuntimeException re )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + 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: " + 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 )
      {
         re.printStackTrace();
         return("Exception while testing:  "
                             + 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 boolean askYesNo(String question,
                                  String abbrevQuestion)
   {
      System.out.println(question);
      return ConsoleInput.askYesNo(abbrevQuestion);
   }  // method askYesNo

   private static void displayResults(String[] text)
   {
      System.out.println();
      for ( int i = 0; i < text.length; i++ )
         System.out.println(text[i]);
      System.out.println();
   }  // method displayResults
}  // class ListTestInOneClass