import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.io.*;
/** 
  readAssignments reads assigments from a scanner that got a list.
  Rewritten.
  @author Fred Kral
  @version 2.5
**/
/* Change Log:
   Fred Kral      2.51   1/19/2015   Finished (I hope) mending of the assignment fragments.
                                    Also, handle Fall semester dates together with Spring.
                                    Note: Still has bug in findValueString.

*/
/* Help:
   http://stackoverflow.com/questions/1474954/working-with-a-list-of-lists-in-java
*/


public class readAssignments2 {

   public static void readAssignments(Scanner sc, Person student, Semester semester) {
                  
      int saveYear = semester.getFirstDate().getYear();
      //System.out.println("readAssigments Year " + saveYear);
      
      
      /* Note: he assigment data can contain fragments 
         from an unfortunte line break */    
   
      
      /* Design:
         Make a list of lists of lines with the date the first line per list
         // read a line
         // if it is a date
         // while OUTER
           // while INNER
           //   read lines and store them in the List until it's another date
           // end while INNER
           // when it's another date, store the List with lines in listOfLists
         // end while OUTER
       */
            
      /* read a line, break if we are at the end of good input */
      String line = readGoodLine(sc);
      if (line == null) 
         System.exit(37);
      
      //boolean first = true;
      
      /* look for a date */
      plainDate firstDate = new plainDate(line, saveYear);
      if (! firstDate.getValidDate()) 
         return;
      /* read column headings that follow the date */
      if (! readColumnHeadings(sc))
         System.exit(47);
      
      /* List of lists: holds one list per day */
      ArrayList<ArrayList<String>> listOfDayLists = new ArrayList<ArrayList<String>>();
   
      /* Loop over bunches of assignments that begin with a date */
      while (line != null) {// outer while
      
         /* List for one day: the date, the assignment, and any fragments */
         ArrayList<String> dayList = new ArrayList<String>();
         
         dayList.add(line);// the date is added
      
         /* Loop over lines until find a date that is the next bunch of lines */
         while (true) {// inner while
            
            /* read a line, break if we are at the end of good input */
            line = readGoodLine(sc);
            if (line == null) 
               break;         
            
            /* look for a date */
            plainDate tDate = new plainDate(line, saveYear);
            if (tDate.getValidDate()) {
               /* read column headings that follow the date */
               if (! readColumnHeadings(sc))
                  System.exit(45);
               // current assignment is done, this is the next one
               // go back to the next dayList
               break;               
            }
            else {
               dayList.add(line);
            }
            
         } // end while inner
         
         listOfDayLists.add(dayList);
               
      }// end while outer
   
      boolean PRINTLINES = false;
      if (PRINTLINES) {
         int i = 0;
         for (ArrayList<String> dayList : listOfDayLists ) {
            i++;
            int j=0;
            System.out.println(" list of lists " + i + " ");
            for (String iLine : dayList) {
               j++;
               System.out.println("   list of lines " + j + " ");
               System.out.println("\"" + iLine + "\"");
            
            }
         }
      }// end print
      
      
      // new section of code  
      
      /* Use List of List to unpack the date, course, and assigment data */
      
      /* Note: he assigment data can contain fragments 
         from an unfortunte line break   
         This makes the design tricky. Maybe should have been recursive? 
       */
   
   
      /* Clusters of date/assignment(with course)/fragment with each beginng with course names */
      for (ArrayList<String> dayList : listOfDayLists ) {
      
         int nGotten = 0;
         plainDate savePDate = null;
         
         /** Read the date (first element). */
         if ( ! dayList.isEmpty() && dayList.size() > 0 ) {
            String dateLine = dayList.get(0);
            nGotten++;
            
            /* Sav the date for this group of assignments */
            /* If allowed, adjust for assignments that are from a prior calendar year (for debugging use) */
            /* Should probably have checked if the date is in range for the requested semester */
            boolean ALLOW_PREVIOUS_SEMESTER_PREVIOUS_YEAR = true;
            if (ALLOW_PREVIOUS_SEMESTER_PREVIOUS_YEAR) {
               plainDate trialPDate = new plainDate(dateLine, saveYear);
               int trialMonthNumber = trialPDate.getMonth();
               if (semester.getSemesterNumber() == 2 && trialMonthNumber >=7) {
                  savePDate = new plainDate(dateLine, saveYear - 1);// previous calendar year date
               } 
               else {
                  savePDate = new plainDate(dateLine, saveYear);
               }
            }
            else {
               savePDate = new plainDate(dateLine, saveYear);
            }
         }
         else {
            break; // should not happen
         }
                  
         /* Read the first assignment with course element (second overall) */
         String cLine = "";
         if ( ! dayList.isEmpty() && dayList.size() > 1 ) {
            cLine = dayList.get(1);
            nGotten++;
         
         }
         else {
            break; // should not happen
         }
         
         /* Is it a good course? */
         String[] partsC = cLine.split("\\t");
         if (partsC.length < 1) 
            break;
         if ( student.getCourseNumber (partsC[0]) <= 0 )
            break;
         
         //System.out.println("===== Before Loop ===============================");
         //System.out.printf("dayList size %s ", dayList.size());
         //System.out.println(savePDate.sysPrint(false) + " n = " + nGotten + " " + cLine);
                    
               
         boolean pendingAssignment = true; // an assignment that needs a rawList
                           
         /* find assignment: first line and fragments */
         while (true) { // find all assignment lines
            //System.out.println(" i " + nGotten + " " + savePDate.sysPrint(false));
            
            /* Course raw data list (for one course) */
            ArrayList<String> rawDataList = new ArrayList<String>();
         
            rawDataList.add(cLine);
            pendingAssignment = false;
         
            /* Read and add fragments until the next assignment first line */
            while (nGotten < dayList.size()) { // find fragments and new assignments
               //System.out.println("   j " + nGotten + " ");
            
            /* Read the next assignment element */
               String jLine = dayList.get( nGotten );
               nGotten++;
            
               /* Is it a good course? */
               String[] partsJ = jLine.split("\\t");
               if (partsJ.length < 1) 
                  break;
               if ( student.getCourseNumber (partsJ[0]) > 0) {
                  // got a course name so it's the end of fragments
                  cLine = jLine;
                  
                  pendingAssignment = true;
                  
                  //System.out.printf("Got Next course n=%d %s -- %s \n", nGotten, partsJ[0], jLine);
               
                  // go on to the next assignment
                  break;
               }
               else {
                  // got a fragment. Add it.
                  rawDataList.add(jLine);
                  
                  pendingAssignment = false;
               
                  
               }
            }// loop of fragments
            
            // land here if we're done with first lines and fragments
            
            boolean PRINTRAW = false;
            if (PRINTRAW) {
               System.out.println("---------------------------------");
               int j=0;
               for (String jLine : rawDataList) {
                  j++;
                  System.out.println("   raw data lines  " + j + " " + savePDate.sysPrint(false) + " " + savePDate.getYear());
                  System.out.println("Line " + j + ": \"" + jLine + "\"");
               }
            }// end print
            
            
            /* Store the assignment list */
            /*                           */
            
            /* Check that raw data is good */
            if ( rawDataList.isEmpty() || rawDataList.size() <= 0 ) 
               break; // should not happen
         
             /* Get the course name */
            String line1 = rawDataList.get(0); // element with course name added first
            String[] partsI = line1.split("\\t");
            if (partsI.length < 1) 
               break; // should not happen
                     
             /* Get the Course for this student */
            Course course = student.getCourse(partsI[0]);
            if (course == null)
               break; // should not happen
               
             /* Add the Assignment */
            //Assignment assignment = new Assignment(rawDataList, savePDate, course);
            Assignment assignment = parseRawData(mendedRawData(rawDataList), savePDate, course);
         
            course.addAssignment(assignment);
            
            //System.out.printf("Added assignment %s \n", partsI[0]);
           
            if (nGotten >= dayList.size() && ! pendingAssignment) 
               break;
              
         }// loop of all assignment lines
      }// loop of lists
      
      
      
      boolean PRINTASSIGNMENTS = true;
      if (PRINTASSIGNMENTS) {
         System.out.println("------------- Assignments added ------------");
         for (Course course : student.getCourses() ) {
            course.sysPrintAssignments();
            //System.out.println("-----");
            //course.sysPrintAssignmentsAll();
            //System.out.println("==========");
            //course.sysPrintAssignmentsRaw();
         
         }
         System.out.println("------------- Assignments end --------------");
         System.out.println();
      }
      
      
   }// END readAssignments
   

   /** readGoodLine tests whether we are at the end of user input date (or file)
   @param sc which has  with user input or file data
   @return the next line in the file
    */
   public static String readGoodLine(Scanner sc) {
      
      /* There is still something weird about this logic, what to do about
         line after copyright and whether the user hits return or not 
         Perhaps there is a difference between (Mac) OS X, Windows 7, and IDEs. */
      
      if ( sc.hasNextLine() ) {
         String line = sc.nextLine();
         
         // End of assignments
         if (line.length() > 9 && line.substring(0, 9).equals("Copyright")) {
            System.out.println();
            System.out.println("HIT RETURN if you have not already done so.");
            if ( sc.hasNextLine() ) {
               sc.nextLine();// flush the next line if we have it
               //System.out.println("Removed last line");
            }
            System.out.println("----------- End reading -----------");
            return null;
         }
         else {
            //System.out.println("Good Line: " + line);
            return line;// good line
         }
      }
      else {
         System.out.println("========= end of input ===========");
         return null;// no more lines
      }
      
      
   }// END method
   
   public static boolean readColumnHeadings(Scanner sc){
   
      /* Scan past column headings */
      /* Assignment Type Description Files Value Result Comment Upload_Assignment */
      for (int i = 1; i <= 8; i++) {
         String ss = readGoodLine(sc);// here do not use String line
         if (ss == null) 
            return false;
      }
      
      return true;
   
   }


   /** 
    * mendedRawData - Join the fragments from the raw data together.
    * They are broken due to a couple of conditions.
    */
    /* Change log
         Fred        1.0   First version just returned the unmended string.
         Fred        2.0   Second version attempted to join lines after files and before A grades
         Fred        3.0   Third version is a rewrite and the first one that seems to work.
    */
   public static String mendedRawData(ArrayList<String> rawDataList){
      //mend string here
      
      boolean PRINTTABS = false;
      if (PRINTTABS) {
         for (int i = 0; i < rawDataList.size(); i++){
            System.out.println(rawDataList.get(i).replace("\t", "<TAB>"));
         }
      }
      
      /* Join fragments with tabs. */
      
      /* Mending issues:
      
         1) Filenames in part 4 (field 5) break next line without tabs.
         Common file name endings: .doc .docx, .pdf, 
         but not always (e.g. Anatomy 3.Phys_Unit2_Support.Movement_SkullHandout_NoteTakingGuide)
         
         2) Letter grades of A or A+ (A-?) (e.g. U.S. History) break the previous line, 
         but tab is intact from previous line.
         Reason: AddThis social bookmarking buttons.
         
      */
      String mend = "";
      if (rawDataList.size() <0) 
         return mend;
      
      
      /* This could be the only element: an unfragmented assignment for one coures for one day */
      mend = rawDataList.get(0);
      int nGotten = 1;
   
   
      if (rawDataList.size() < 1)
         return mend;
      
      /* Read data list elements */
      while (nGotten < rawDataList.size()) {
      
         //System.out.println("     .....while loop...... " + " nGotten = " + nGotten);
      
         // A grades
      
         /* Broken A grade */
         /* (due to social buttons) */
         /* I do this first even though it logically should come last. 
            I don't think it can interfere with other mending. */
         String previous = rawDataList.get(nGotten - 1);
         //System.out.println("Previous Value. Currently nGotten = " + nGotten);
         int findPrevious = findValueString(previous);
         
         String current = rawDataList.get(nGotten);
         nGotten++;
         //System.out.println("Current Value. Currently nGotten = " + nGotten);
      
         int findCurrent = findValueString(current);
         
         /* Grade of A and previous *was* a value of Letter Grades */
         if (current.length() >= 1) {
            if (current.substring(0,1).equals("A") && findPrevious == 3) {
            // tack it on
               mend = mend + ""  + current;
               continue;
            }
         }
         
         // long filenames
         
         /* If you find value itself after a line, there must be a file beforehand *
         /* Tack on with a tab, since tabs don't follow filenames */
         if (findCurrent >0) {
            mend = mend + "\t"  + current;
            continue;
         }
         else {
           // must be a file. put in a separator
            mend = mend + " AND "  + current;
         
         }
         
                  
      }//while
      
            
      //System.out.println("Mend: \"" + mend + "\"");
         
      return mend;
      
   }// END method mendedRawData
   
   
   /** findValueString classifies assigment scoring method, called Value.
        Return codes                        examples
       -1 no match
        1 "N points"                        5 points
        2 "N points (Mx)"                   75 points (7.5x)
        3 "Letter Grades (Mx)"              Letter Grades (1x)
        4 "Check (Mx)"                      Check (1x)
        5 "Complete/Incomplete (Mx)"        Complete/Incomplete (1x)
     */ 
     /* To Do / Ideas:
        It would be nice to have this code return the numbers (max, result, and weighted value
     */
   public static int findValueString(String rawDataField){
   
      int find = -1;
     
      if (rawDataField.indexOf("x)") < 0) {
         if (rawDataField.indexOf("1 point") ==0) find = 1;
         if (rawDataField.indexOf(" points") >=1) find = 1;
      
      }
      else {
         if (rawDataField.indexOf("1 point (") ==0) find = 2;
         if (rawDataField.indexOf(" points (") >=1) find = 2;
         //if (rawDataField.indexOf("Letter Grades (") >0) 
         //   System.out.println("rawDataField " + rawDataField.indexOf("Letter Grades (") + " " + rawDataField.length());
         /* Bug (shortcoming) */
         //   || condition depends on Letter Grades( being followed by 2x) or 1x)
         //   Perhaps require one and only one tab last, as well as a range of slots of Letter Grades in case
         //   the multiplyer is not an integer
         //  --> Idea: look for the pattern "x)\t" at the end of the string.
         if ( (rawDataField.indexOf("Letter Grades (") ==0) ||
              (rawDataField.indexOf("Letter Grades (") == rawDataField.length() - 15 - 1 - 3) )  // broken A
            find = 3;
      
         if (rawDataField.indexOf("Check (") ==0) find = 4;
         if (rawDataField.indexOf("Complete/Incomplete (") ==0) find = 5;
      } 
      
      //System.out.println("Value: " + find + " \"" + rawDataField + "\"");
      
      return find;
   } // END method findValueString
   
      /** parseRawData new creates a new assignment that does not need to be parsed by Assignment */
   public static Assignment parseRawData(String rawData, plainDate pDate, Course course) {
   
      String[] parts = rawData.split("\\t");
            
      boolean PRINTPARTS=false;
      if (PRINTPARTS) {
         if (parts.length >= 1) {
            for (int i = 0; i<parts.length; i++) {
               System.out.println("Parts " + i + " " + parts[i]); 
            }
         }
      }
      
      
      int pLen = parts.length;
      if (pLen >= 2) {
         String assignmentName = "";
         String type = "";
         String description = "";
         String files = "";
         String value = "";
         String result = "";
         String comment = "";
         String upload = "";
      
         // Make sense of different parts of a raw assignment String
         // COURSE Assignment Type Description Files Value Result Comment Upload_Assignment
         
         //if (pLen >0) courseName = course.getCourseTitle();
         if (pLen >1) assignmentName = parts[1];
         if (pLen >2) type = parts[2];
         if (pLen >3) description = parts[3];
         if (pLen >4) files = parts[4];
         if (pLen >5) value = parts[5];
         if (pLen >6) result = parts[6];
         if (pLen >7) comment = parts[7];
         if (pLen >8) upload = parts[8];
         
         
         return new Assignment(rawData, pDate, course,
                      assignmentName,
                      type,
                      description,
                      files,
                      value,
                      result,
                      comment,
                      upload);   
      }
      else {
         return null; // length of raw string has to be a minimum
      }
      
      
   }// END method parseRawData


}// END class