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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import at.ac.tuwien.sbc.valesriegler.common.HasId;
import at.ac.tuwien.sbc.valesriegler.common.Util;
import at.ac.tuwien.sbc.valesriegler.group.actions.OrderRequest;
import at.ac.tuwien.sbc.valesriegler.group.actions.PayRequest;
import at.ac.tuwien.sbc.valesriegler.group.actions.TableFree;
import at.ac.tuwien.sbc.valesriegler.group.actions.TableRequest;
import at.ac.tuwien.sbc.valesriegler.group.jms.JMSGroupConnector;
import at.ac.tuwien.sbc.valesriegler.types.GroupData;
import at.ac.tuwien.sbc.valesriegler.types.GroupState;
import at.ac.tuwien.sbc.valesriegler.types.Order;
import at.ac.tuwien.sbc.valesriegler.types.OrderStatus;
import at.ac.tuwien.sbc.valesriegler.types.Table;

/**
 * class denoting a Group's will.
 * 
 * @author jan
 * 
 */
public class Group implements Runnable, HasId {
	private static final Logger log = LoggerFactory.getLogger(Group.class);
	private static int idNext = 0;

	private GroupData groupData;

	public Group() {
		groupData = new GroupData(++idNext);
	}

	public Group(Integer id) {
		groupData = new GroupData(id);
	}

	@Override
	public void run() {
		log.debug("Thread started for:" + this);
		try {
			if (!Util.runSimulation) {
				Thread.sleep((long) (Math.random() * 10000));
			}

			switch (groupData.getState()) {
				case NEW :
					// TODO : may not happen!
					break;
				case WAITING :
					JMSGroupConnector.getConnector(groupData.getPizzeriaId()).send(new TableRequest(groupData));
					break;
				case SITTING :
					groupData.getOrder().genId();
					JMSGroupConnector.getConnector(groupData.getPizzeriaId()).send(new OrderRequest(groupData));
					order();
					break;
				case ORDER_PENDING :
					break; // do nothing.
				case ORDERED :
					break; // do nothing.
				case EATING : // request bill.
					JMSGroupConnector.getConnector(groupData.getPizzeriaId()).send(new PayRequest(groupData));
					break;
				case PAY :// leave table
					JMSGroupConnector.getConnector(groupData.getPizzeriaId()).send(new TableFree(groupData));
					groupData.setState(GroupState.GONE);
					groupData.setTable(null);
					break;
				case GONE :
					break; // do nothing.
				default :
					break;
			}

		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void setGroupData(GroupData groupData) {
		this.groupData = groupData;
	}

	public GroupData getGroupData() {
		return groupData;
	}

	// lets go to the pizzaria.
	public void goGrabSomeFood() {
		log.debug("goGrabSomeFood(): " + this);
		groupData.setState(GroupState.WAITING);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
	}

	// get a table assigned by a waiter.
	public void assignTable(Table t, int waiterID) {
		groupData.setState(GroupState.SITTING);
		groupData.setTable(t);
		groupData.setTableWaiter(waiterID);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
		log.debug("assignTable(): " + this);
	}

	// ask the group to send their order.
	public void order() {
		groupData.setState(GroupState.ORDER_PENDING);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
		log.debug("order(): " + this);
	}

	// Waiter telling group he/she forwarded the order.
	public void orderReceived(int waiter) {
		groupData.setState(GroupState.ORDERED);
		groupData.getOrder().setStatus(OrderStatus.ORDERED);
		groupData.setOrderWaiter(waiter);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
		log.debug("orderReceived(): " + this);
	}

	// pizzas are here! nom nom nom
	public void deliverPizzas(Order order, int waiter) {
		groupData.setState(GroupState.EATING);
		groupData.setOrder(order);
		groupData.setServingWaiter(waiter);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
		log.debug("bringOrderedPizzas(): " + this);
	}

	// pay for the pizzas and leave
	public void payForPizzas(int waiter) {
		groupData.setState(GroupState.PAY);
		groupData.setPayingWaiter(waiter);
		GroupAgent.getInstance().getGroupModel().fireTableDataChanged();
		new Thread(this).start();
		log.debug("payForPizzas(): " + this);
	}

	@Override
	public int getId() {
		return groupData.getId();
	}
}
