import java.util.*;
import java.io.*;

/**
 * Class to test Playlist class
 * This class uses the many of the same commands as the PlaylistManager 
 * and does some additional tests
 * 
 * @author hasti
 *
 */
public class PlaylistTester {
	private static Playlist playlist;
	private static boolean checkCurrent = false, badCurrent = false;
	private static boolean checkIterNext = false, badIterNext = false;
	private static boolean checkHasNext = false;
	
	public static void main(String[] args) {
		Scanner in = null;
		if (args.length > 1){
			System.err.println("invalid command-line arguments");
			System.exit(1);
		}
		boolean useFile = args.length == 1;
		if (useFile) {
			File inFile = new File(args[0]);
			if (!inFile.exists() || !inFile.canRead()) {
			    System.err.println("Problem with input file!");
			    System.exit(1);
			 }
			try {
			 in = new Scanner(inFile);
			} catch (FileNotFoundException e) {
			    System.err.println("Problem with input file!");
			    System.exit(1);
			}
		}
		else
			in = new Scanner(System.in);
		
		playlist = new Playlist();
		
		/*
		 * Do a bunch of tests on empty playlist
		 */
		if (!(playlist instanceof CircularSequenceADT)) {
			error("Playlist doesn't implement CircularSequenceADT interface");
		}
		
		if (playlist.size() != 0)
			error("size incorrect for empty playlist");
		
		try {
			playlist.getCurrent();
			error("getCurrent on empty playlist did not throw exception");
		} catch (EmptySequenceException e) {
			// correct result
		} catch (Exception e) {
			error("getCurrent threw " + e.getClass().getName());
		}
		
		try {
			playlist.removeCurrent();
			error("removeCurrent on empty playlist did not throw exception");
		} catch (EmptySequenceException e) {
			// correct result
		} catch (Exception e) {
			error("removeCurrent threw " + e.getClass().getName());
		}
		
		try {
			playlist.forward();
		} catch (Exception e) {
			error("forward on empty playlist threw an exception");
		}
		
		try {
			playlist.back();
		} catch (Exception e) {
			error("back on empty playlist threw an exception");
		}
		
		/*
		 * Run the main loop
		 */
		boolean again = true;
		String msg;
		
		while (again) {
			System.out.print("enter command> ");
			String input = in.nextLine();
			if (useFile)
				System.out.println(input);
			char choice = input.charAt(0);

			switch (choice) {

			case 'd': 
				display();
				break;
				
			case '>':
				if (playlist.size() == 0)
					System.out.println("no messages");
				else {
					playlist.forward();
					currentContext();					
				}
				break;
				
			case '<':
				if (playlist.size() == 0)
					System.out.println("no messages");
				else {
					playlist.back();
					currentContext();	
				}
				break;
				
			case 'r':
				if (playlist.size() == 0) 
					System.out.println("no messages");
				else {
					int beforeSize = playlist.size();
					playlist.removeCurrent();
					if (playlist.size() != beforeSize - 1)
						error("removeCurrent doesn't correctly update size");
					if (playlist.size() == 0)
						System.out.println("no messages");
					else
						currentContext();	
				}
				break;
				
			case 'a':
				msg = extract(input);
				if (msg != null) {	
					int beforeSize = playlist.size();
					playlist.addAfter(msg);
					if (playlist.size() != beforeSize + 1)
						error("addAfter doesn't correctly update size");
					currentContext();	
				}
				else
					System.out.println("invalid command");
				break;
				
			case 'q': 
				System.out.println("quit");
				again = false;
				break;
				
			default:
				System.out.println("invalid command");
			}
		}
		if (useFile)
			in.close();
	}
	private static void error(String s) {
		System.out.println("Error: " + s);
	}
	private static String currString(Object ob) {
		String str = "";
		if (badCurrent)
			str = (String) ((DblListnode)ob).getData();
		else
			str = (String) ob;
	    return str;
	}
	private static String extract(String s) {
		String msg = null;
		if ( s.length() > 2 && s.charAt(1) == ' ' && s.charAt(2) != ' ' )
			msg = s.substring(2, s.length());
		return msg;
	}
	private static void currentContext() {
		if (playlist.size() < 1) {
			System.out.println("no songs");
			return;
		}
		
		Object current = playlist.getCurrent();
		if (!checkCurrent && current instanceof DblListnode) {
			error("getCurrent returns a list node");
			badCurrent = true;
		}
		checkCurrent = true;		
		
		if (playlist.size() > 2) {
			playlist.back();
			System.out.println(currString(playlist.getCurrent()));
			playlist.forward();
		}
		
		System.out.println("<< " + currString(playlist.getCurrent()) + " >>");
		
		if (playlist.size() > 1) {
			playlist.forward();
			System.out.println(currString(playlist.getCurrent()));
			playlist.back();
		}
	}

	private static void display() {
		if (playlist.size() == 0)
			System.out.println("no messages");
		else {
			Iterator iter = playlist.iterator();
			while (iter.hasNext()) {
				Object ob = iter.next();
				if (!checkIterNext && ob instanceof DblListnode) {
					error("Iterator next returns list node");
					badIterNext = true;
				}
				checkIterNext = true;
				if (badIterNext)
					System.out.println((String) ((DblListnode)ob).getData());
				else 
				    System.out.println((String) ob);
			}
			if (!checkHasNext) {
				try {
					iter.next();  // expect an exception
					error("Iterator next did not throw exception - check if called hasNext");
				} catch (NoSuchElementException e) {
					// expected result
				} catch (Exception e) {
					error("hasNext threw " + e.getClass().getName());
				}
				checkHasNext = true;
			}
		}
	}

}