package com.gmscheduler.model;

import com.gmscheduler.model.Timeframe;
import com.gmscheduler.model.Schedule;
import com.gmscheduler.model.DatabaseManager;
import java.util.LinkedList;
import java.util.ListIterator;


/**
 * The Schedule Utility is the buisness logic for parsing schedules as well as finding busy times. 
 * The utility has two methods parseSchedule, which takes a preformatted string and returns a schedule,
 * and findTime which takes a constraint schedule and a linkedlist of busy time schedules.
 * @author Peter Deschere
 * @author Ashton Galya
 * @author Rebecca Beale
 * @author Jason Fillo
 * @version 1.2
 * @see com.gmscheduler.model.Timeframe
 * @see com.gmscheduler.model.Schedule
 * @see com.gmscheduler.model.Person
 * @see com.gmscheduler.model.DatabaseManager;
 */

public class ScheduleUtil {

	/**
	 * This method simply takes in the big list of times and days, breaks them apart and sends them to the parse method which handles the
       * actual parsing.  The results of the parse method are then added to a schedule object which is returned.
       * @param str is the big long list of times that a user submits.
       * @return a schedule object containing the parsed times from the string.
       */
	public Schedule parseSchedule(String str) {
		Schedule sched = new Schedule();
		String tempStr = new String();
		str = str.trim();
		// if passed a zero length str (or all whitespaces) just return the default schedule
		if (str.length()==0) { return sched;}
		
		if (!str.endsWith(",")) {str += ",";}
		
		int i;
				
		do  {
			if (str.indexOf(",")==-1) { i=str.length()-1;} else {i=(str.indexOf(",") - 1);}
			tempStr = str.substring(0,i+1);
			str = str.substring((str.indexOf(",") + 1));
			sched.add(parse(tempStr));
		} while (str.contains(","));
		
		return sched;
	}

	/**
	 * This method takes in a string formatted as " MWF XX:YYZZ-XX:YYZZ," and breaks it
	 * into its component parts: days, start time and end time.
	 * Once that is complete it converts the start and end times to military time and creates a
	 * Timeframe object which it then adds to a schedule object to be returned.
	 * @param str this is the formatted string as mentioned above.
	 * @return This returns a newly created list of Timeframes object 
	 */
	private LinkedList parse(String str) {
		//System.out.println(str);
		
		LinkedList lst = new LinkedList();
		
		//Trims the leading and trailing whitespace from the input string
		str = str.trim();
		//System.out.println(str);
		
		//Pulls the days out of a string formatted as " MWF XX:YYZZ-XX:YYZZ,"
		String days = str.substring(0, str.indexOf(" "));

        //These two if statements are to add saturday and sunday functionality
        if(days.contains("Sa") || days.contains("SA"))
        	days = days.substring(0, days.indexOf("S")) + "A" + days.substring(days.indexOf("S") + 2);
        if(days.contains("sa") || days.contains("sA"))
        	days = days.substring(0, days.indexOf("s")) + "A" + days.substring(days.indexOf("s") + 2);
        if(days.contains("Su") || days.contains("SU"))
        	days = days.substring(0, days.indexOf("S")) + "U" + days.substring(days.indexOf("S") + 2);
        if(days.contains("su") || days.contains("sU"))
        	days = days.substring(0, days.indexOf("s")) + "U" + days.substring(days.indexOf("s") + 2);
        char[] dayArray = days.toCharArray();
		
		
		//This section pulls the "XX:YYZZ-XX:YYZZ" 
		String times = str.substring(str.indexOf(" ")+1);
		times = times.trim();
		String startTime = times.substring(0, times.indexOf("-"));
		String endTime = times.substring((times.indexOf("-") + 1));
		//System.out.println(endTime);
		
		//This converts the start and end times to military time with fractional hours
		String milStartTime = convertTime(startTime);
		String milEndTime = convertTime(endTime);
		
		Timeframe tf;
		//This loop adds one timeframe object to the schedule to be returned.  Goes through by day
		for(int i = 0; i < dayArray.length; i++) {
			if(dayArray[i] == 'A') {
				tf = new Timeframe("Sa", milStartTime, milEndTime); } else 
			if(dayArray[i] == 'U') {
				tf = new Timeframe("Su", milStartTime, milEndTime); }
			else {
				tf = new Timeframe(new Character(dayArray[i]).toString(), milStartTime, milEndTime); }
			lst.add(tf);
		}
		
		return lst;
			
	}
	
	/**
	 * This method takes in a string formatted as "XX:YYZZ" and converts it to military time
	 * and fractional hours for ease of calculation.
	 * @param str the formatted string mentioned above
	 * @return returns a string in military hours and minutes as a fraction of an hour
	 */
	private String convertTime(String str) {
		//rids us of whitespace
		str = str.trim();
		
		//Grabs the AM or PM classifier for ease of military time conversion.
		String classify = str.substring((str.indexOf(":") + 3));
		//System.out.println(classify);
		
		str = str.substring(0, (str.indexOf(":") + 3));
		
		//Pulls out the minutes substring, converts it to a double, divides by 60 to get the
		//fractional hours and then uses the Double data type's toString() method to convert it
		//back to a string.
		Integer minut = new Integer(str.substring((str.indexOf(":") + 1)));
		String minute = minut.toString();
		
		if (minute.length()==1) {minute = "0" + minute;}
		
		Integer hour = new Integer(str.substring(0, str.indexOf(":")));
		if (classify.equals("pm") && hour!=12) {
			hour = hour + 12;
		}
		else if (classify.equals("am") && hour == 12) {
			hour = 0;
		}
		String milHours = hour.toString();
		return milHours + ":" + minute;
		
	}
	
	/**
	 * Finds the remaining free time from the free time constraint compared against the 
	 * busy time of all schedules.
	 * 
	 * @param freetime The original non-busy time in which to constrain all other busy times.
	 * @param schedules A linked list of <code>Schedule</code>s that are busy time. 
	 * @return A schedule of free time constrained by the original free time and the list of busy schedules.
	 */
	public Schedule findTime(Schedule freetime, LinkedList<Schedule> schedules) {
		// Iterate through the list of busy times and take the difference for each
		ListIterator busyit = schedules.listIterator();
		Schedule sched = new Schedule(freetime.getPerson(),freetime.getSchedule());
		do {
			sched.difference((Schedule)busyit.next());
		}
		while(busyit.hasNext());
		
		return sched;
	}
	
	/**
	 * Removes a <code>Timeframe</code> from a <code>Schedule</code>, also from the database.
	 * 
	 * @param s The schedule to remove the <code>Timeframe</code> from.
	 * @param t The <code>Timeframe</code> to be removed. 
	 * @return The original <code>Schedule</code> less the timeframe.
	 */
	public Schedule removeTimeframe(Schedule s, Timeframe t) {
		dm.deleteTimeframe(t);
		s.removeTimeframe(t);
		return s;
	}
	
	private DatabaseManager dm = new DatabaseManager();
}
