import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

/**
 * Represents a Program of Study, a list of courses taken and planned, for an
 * individual student.
 * 
 * @author Lewis and Chase
 * @version 4.0
 */
public class ProgramOfStudy implements Iterable<Course>, Serializable
{
	private List<Course> list;
	
	/**
	 * Constructs an initially empty Program of Study.
	 */
	public ProgramOfStudy()
	{
		list = new LinkedList<Course>();
	}
	
	/**
	 * Adds the specified course to the end of the course list.
	 * 
	 * @param course the course to add
	 */
	public void addCourse(Course course)
	{
		if (course != null)
			list.add(course);
	}
	
	/**
	 * Finds and returns the course matching the specified prefix and number.
	 * 
	 * @param prefix the prefix of the target course
	 * @param number the number of the target course
	 * @return the course, or null if not found
	 */
	public Course find(String prefix, int number)
	{
		for (Course course : list)
			if (prefix.equals(course.getPrefix()) &&
					number == course.getNumber())
				return course;

		return null;
	}
	
	/**
	 * Adds the specified course after the target course. Does nothing if
	 * either course is null or if the target is not found.
	 * 
	 * @param target the course after which the new course will be added
	 * @param newCourse the course to add
	 */
	public void addCourseAfter(Course target, Course newCourse)
	{
		if (target == null || newCourse == null)
			return;
		
		int targetIndex = list.indexOf(target);
		if (targetIndex != -1)
			list.add(targetIndex + 1, newCourse);
	}

	/**
	 * Replaces the specified target course with the new course. Does nothing if
	 * either course is null or if the target is not found.
	 * 
	 * @param target the course to be replaced
	 * @param newCourse the new course to add
	 */
	public void replace(Course target, Course newCourse)
	{
		if (target == null || newCourse == null)
			return;
		
		int targetIndex = list.indexOf(target);
		if (targetIndex != -1)
			list.set(targetIndex, newCourse);
	}

	/**
	 * Creates and returns a string representation of this Program of Study.
	 * 
	 * @return a string representation of the Program of Study
	 */
	public String toString()
	{
		String result = "";
		for (Course course : list)
			result += course + "\n";
		return result;
	}
	
	/**
	 * Returns an iterator for this Program of Study.
	 * 
	 * @return an iterator for the Program of Study
	 */
	public Iterator<Course> iterator()
	{
		return list.iterator();
	}
	
	/**
	 * Saves a serialized version of this Program of Study to the specified
	 * file name.
	 * 
	 * @param fileName the file name under which the POS will be stored
	 * @throws IOException
	 */
	public void save(String fileName) throws IOException
	{
		FileOutputStream fos = new FileOutputStream(fileName); 
		ObjectOutputStream oos = new ObjectOutputStream(fos); 
		oos.writeObject(this); 
		oos.flush(); 
		oos.close(); 
	}

	/**
	 * Loads a serialized Program of Study from the specified file.
	 * 
	 * @param fileName the file from which the POS is read
	 * @return the loaded Program of Study
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public static ProgramOfStudy load(String fileName) throws IOException, ClassNotFoundException
	{
		FileInputStream fis = new FileInputStream(fileName);
		ObjectInputStream ois = new ObjectInputStream(fis);
		ProgramOfStudy pos = (ProgramOfStudy) ois.readObject();
		ois.close();
		
		return pos;
	}
}
