package at.ac.tuwien.sbc.valesriegler.common;

import at.ac.tuwien.sbc.valesriegler.group.gui.GroupCreationDetailsRequest;
import at.ac.tuwien.sbc.valesriegler.types.HasOrder;
import at.ac.tuwien.sbc.valesriegler.types.Order;
import at.ac.tuwien.sbc.valesriegler.types.PizzaOrder;
import at.ac.tuwien.sbc.valesriegler.types.PizzaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.net.URI;
import java.util.*;
import java.util.List;

public abstract class Util {
    public static final Comparator<HasOrder> HAS_ORDER_COMPARATOR = new Comparator<HasOrder>() {
        @Override
        public int compare(HasOrder o1, HasOrder o2) {
            final int o1Id = o1.getOrder().getId();
            final int o2Id = o2.getOrder().getId();
//            if (o1Id == 0) {
//                if (o2Id > 0)
//                    return 1;
//            }
//            if (o2Id == 0) {
//                if (o1Id > 0)
//                    return 1;
//            }
            if (o1Id < o2Id)
                return -1;
            else if (o1Id > o2Id)
                return 1;
            else
                return 0;
        }
    };
    private static final Logger log = LoggerFactory.getLogger(Util.class);
	public static boolean useJMS = false;

	public static final String TABLE_ASSIGNED = "tables";
	public static final String ASSIGN_TABLE = "assignTable";
	public static final String TAKE_ORDER = "takeOrder";
	public static final String ORDER_TAKEN = "order";
	public static final String DELIVERY_ORDER_TAKEN = "deliverOrderTaken";
	public static final String DELIVER_PIZZAS = "deliverPizzas";
	public static final String DELIVER_DELIVERY_PIZZAS = "deliverDeliveryPizzas";
	public static final String DELIVER_DELIVERY_ORDER = "deliverDeliveryOrderContainer";
	public static final String PREPARE_PIZZAS = "preparePizzas";
	public static final String PREPARE_DELIVERY_PIZZAS = "prepareDeliveryPizzas";
	public static final String PIZZAS_IN_PROGRESS = "pizzasInProgress";
	public static final String ORDER_COMPLETE = "orderComplete";
	public static final String PAYMENT_REQUEST = "payment";
	public static final String FREE_TABLES = "freeTables";
	public static final String PAYMENT_DONE = "hasPaid";
	public static final String PIZZERIA_INFO = "pizzeriaInfo";
	public static final String PHONE_CALLS = "phoneCalls";
	public static final String GROUP_AGENT_INFO = "groupAgentInfo";
	public static final String PIZZERIA_GROUP = "pizzeriaGroupContainer";
	public static final String PIZZERIA_TABLE = "pizzeriaTableContainer";
	public static final String PIZZERIA_DELIVERY = "pizzeriaDeliveryContainer";

	public static final boolean runSimulation = false;

	public static final String NUMBER_DISPLAY_FORMAT = String.format("%%0%dd", 3);

	private static Random random = new Random();

	public static final long SPACE_TRANSACTION_TIMEOUT = 1500;

	public static final String SERVER_ADDR = "xvsm://localhost:%d";
	public static final int GROUP_AGENT_PORT = 9876;
	public static final int DELIVERY_CUSTOMERS_PORT = 9877;

	public static final String JMS_DELIVERY_DESTINATION = "tcp://localhost:61611?jms.prefetchPolicy.all=1";

	public static String getId(int id) {
		return (id != 0 && id != -1) ? String.valueOf(id) : "";
	}

	public static int getIntSafe(Integer nr) {
		return nr == null ? 0 : nr;
	}

	public static URI createURI(int port) {
		return URI.create(String.format(SERVER_ADDR, port));
	}

	public static <T extends HasId> Map<Integer, T> intoMapById(List<T> hasIds) {
		if (hasIds == null) {
			return Collections.emptyMap();
		}

		Map<Integer, T> myMap = new HashMap<Integer, T>();
		for (T hasId : hasIds) {
			myMap.put(hasId.getId(), hasId);
		}
		return myMap;
	}

	public static int getRandom(int min, int max) {
		return random.nextInt(max - min + 1) + min;
	}

	public static Tuple<Integer> parseIdAndSpacePort(String[] args, String usage) {
		if (args.length != 2) {
			throw new IllegalArgumentException(usage);
		}

		int parsedId = 0;
		int port = 0;
		try {
			parsedId = Integer.parseInt(args[0]);
			port = Integer.parseInt(args[1]);
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException(usage);
		}

		return new Tuple<Integer>(parsedId, port);
	}

	public static JTable createTableInTitledPanel(JPanel wrapperPanel, TableModel<?> model, String title) {
		JTable table = new JTable(model);
		wrapperPanel.setLayout(new GridBagLayout());
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.weightx = 1;
		c.weighty = 1;
		c.insets = new Insets(10, 10, 10, 10);
		c.fill = GridBagConstraints.BOTH;
		JScrollPane scrollPane = new JScrollPane(table);

		wrapperPanel.setBorder(new TitledBorder(title));
		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
		wrapperPanel.add(scrollPane, c);
		return table;
	}

	/**
	 * 
	 * @return A display string for PizzaTypes.
	 *         <p />
	 *         e.g. Cardinale, Cardinale, Margherita is displayed as "2xCARDINALE,1xMARGHERITA"
	 */
	public static String pizzaDisplay(List<PizzaOrder> list) {
		HashMap<PizzaType, Integer> pizzaCount = new HashMap<PizzaType, Integer>();
		for (PizzaOrder pizzaOrder : list) {
			PizzaType pizzaType = pizzaOrder.getPizzaType();
			if (pizzaCount.containsKey(pizzaType)) {
				pizzaCount.put(pizzaType, pizzaCount.get(pizzaType) + 1);
			} else
				pizzaCount.put(pizzaType, 1);
		}
		Set<PizzaType> pizzaTypes = pizzaCount.keySet();
		StringBuilder sb = new StringBuilder();

		boolean multiplePizzas = false;
		for (PizzaType pizzaType : pizzaTypes) {
			if (multiplePizzas)
				sb.append(", ");
			else
				multiplePizzas = true;

			sb.append(pizzaCount.get(pizzaType) + "x");
			sb.append(pizzaType.toString());
		}

		return sb.toString();
	}

	public static void handleSpaceErrorAndTerminate(Exception e) {
		log.error(e.getMessage());
		e.printStackTrace();
		System.exit(1);
	}

	public static Order createOrder(HasId group, GroupCreationDetailsRequest gc, boolean isDelivery) {
		List<PizzaOrder> pizzaOrders = new ArrayList<PizzaOrder>();
		for (PizzaType pt : gc.pizzaTypes) {
			final PizzaOrder pizzaOrder = new PizzaOrder(pt);
            pizzaOrder.setDeliveryPizza(isDelivery);
			pizzaOrders.add(pizzaOrder);
		}
		Order order = new Order(group, pizzaOrders);
		order.setNumberOfPizzas(order.getOrderedPizzas().size());

		return order;
	}
}
