package pizza.presentation.clientserver;

import pizza.service.StudentService;
import pizza.service.ServiceException;
import pizza.domain.PizzaOrder;
import pizza.domain.PizzaSize;
import pizza.domain.Topping;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.TreeSet;
import java.util.TreeMap;

import pizza.config.PizzaSystemConfig;


// Student's user interface for order and status report.

public class TakeOrder {
	
	public static final String MENU_KEY = "m";
	public static final int NUM_OF_ATTEMPTS = 3;
	public static final int NO_MORE = -2;
	public static final String QUIT_KEY = "q"; 
	public static final int ERROR = -1;
	
	private StudentService studentService;
	private BufferedReader in;  // the user 
	
	public TakeOrder() {
		PizzaSystemConfig.configureServices();
		studentService = PizzaSystemConfig.getStudentService();
		in = new BufferedReader(new InputStreamReader(System.in));
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		TakeOrder orderTaker = new TakeOrder();
		try {
			while (orderTaker.executeCommand())  // loop until Q command
				;
			System.out.println("Thanks for visiting the pizza shop.");
		} catch (Exception e) {
			System.out.println("Error during command: "+e);
		} 
	}
	
	// execute one student command: O, S, or Q
	public boolean executeCommand() throws IOException {
		
		System.out.println("Possible Commands");
		System.out.println("O: Order");
		System.out.println("S: Status Report");
		System.out.println("Q: Quit");
		String command = PresentationUtils.readEntry(in, "Please Enter the Command");
		if (command.equalsIgnoreCase("O"))
			try {
				getTheOrder();
			} catch (ServiceException e) {
				System.out.println("Sorry, problem with inserting order: " + e);
			}
		else if (command.equalsIgnoreCase("S")) {
			String room = PresentationUtils.readEntry(in, "Enter the room number");
			try {
				List<PizzaOrder> report = studentService.getOrderStatus(Integer.parseInt(room));
				PresentationUtils.printOrderStatus(report, System.out);
			} catch (NumberFormatException e) {
				System.out.println("Invalid Input!");
			} catch (ServiceException e) {
				System.out.println("Sorry, problem with getting order status: "
						+ e);
			}
		} else if (command.equalsIgnoreCase("Q")) {
			return false;
		} else
			System.out.println("Invalid Command!");
		return true; // continue
	}
	
	public void getTheOrder() throws IOException, ServiceException {
		String roomNumStr = PresentationUtils.readEntry(in, "Please Enter the room Number");
		int roomNum = 0;
		if ((roomNum = checkNumInput(roomNumStr, PizzaSystemConfig.NUM_OF_ROOMS)) == ERROR) {
			System.out.println("Invalid Room Number");
			return;
		}
		listTheMenu();
		System.out.println("Size code: The number in front each size in Menu. ");
		List<PizzaSize> allSizes = studentService.getPizzaSizes();
		if (allSizes.size() == 0) {
			System.out.println("Sorry, no pizza sizes available (admin needs to add them)");
			return;
		}
			
		// set up map of id to name for menu
		Map<Integer,String> sizeTokens = new TreeMap<Integer, String>();
		for (PizzaSize s: allSizes){
			sizeTokens.put(s.getId(), s.getSizeName());
		}
	
		int sizeId = getEntry("Enter the size #", sizeTokens);
		if (sizeId < 0) {
			System.out.println("No size specified, please try again");
			return;
		}
		int currToppingId = 0;
		List<Topping> allToppings = studentService.getToppings();

		Map<Integer,String> toppingTokens = new TreeMap<Integer, String>();
		for (Topping t: allToppings){
			toppingTokens.put(t.getId(), t.getToppingName());
		}
		Set<Integer> chosenToppings = new TreeSet<Integer>();
		while (true) {
			currToppingId = getEntry("Enter Topping code, or " + QUIT_KEY
					+ " for no more Toppings",
					toppingTokens);
			if (currToppingId == NO_MORE)
				break;
			chosenToppings.add(currToppingId);
		}
		studentService.makeOrder(roomNum, sizeId, chosenToppings);
	}


	private int checkNumInput(String numStr, int maxBound) {
		int num = 0;
		try {
			num = Integer.parseInt(numStr);
			if (num > 0 && num <= maxBound)
				return num;
		} catch (NumberFormatException e) {
		}
		return ERROR;
	}

	private void listTheMenu() throws ServiceException {
		System.out.println("Basic Pizza: tomato sauce and cheese ");
		System.out.println("Additional toppings:");
		List<Topping> toppings = studentService.getToppings();
		for (Topping t: toppings)
			System.out.println("  Topping code:  " + t.getId()
					+ "  Topping name:  " + t.getToppingName());
		System.out.println("Sizes:");

		List<PizzaSize> sizes = studentService.getPizzaSizes();
		for (PizzaSize s: sizes)
			System.out.println("  Size code:  " + s.getId()
					+ "  Size name:  " + s.getSizeName());
	}
	
	// a primative menu handler: displays choices, gets choice from user
	private int getEntry(String promptMsg, Map<Integer, String> validEntrySet)
			throws IOException, ServiceException {
		int loop = 0;
		while (loop < NUM_OF_ATTEMPTS) {
			for (Integer id: validEntrySet.keySet()) {
					System.out.println("" + id + "  " + validEntrySet.get(id));
			}
			String entryLine = PresentationUtils.readEntry(in, promptMsg);
			if (entryLine.equalsIgnoreCase(QUIT_KEY))
				return NO_MORE;
			loop++;
			Integer num = -1;
			try {
				num = new Integer(entryLine); 
			} catch (NumberFormatException e) {
			}
			if (validEntrySet.get(num) != null)
				return num;	
			System.out.println("Wrong Entry!");
		}
		System.out.println("Invalid Entry after " + NUM_OF_ATTEMPTS + " attempts");
		return ERROR;
	}
}