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

import at.ac.tuwien.sbc.valesriegler.common.OrderId;
import at.ac.tuwien.sbc.valesriegler.common.Util;
import at.ac.tuwien.sbc.valesriegler.pizzeria.PizzeriaAgent;
import at.ac.tuwien.sbc.valesriegler.types.DeliveryGroupData;
import at.ac.tuwien.sbc.valesriegler.types.GroupData;
import at.ac.tuwien.sbc.valesriegler.types.GroupState;
import at.ac.tuwien.sbc.valesriegler.types.Table;
import at.ac.tuwien.sbc.valesriegler.xvsm.spacehelpers.SpaceAction;
import org.mozartspaces.core.MzsConstants.RequestTimeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class PizzeriaAgentXVSM extends AbstractXVSMConnector {
	private static final Logger log = LoggerFactory.getLogger(PizzeriaAgentXVSM.class);
	
	public PizzeriaAgentXVSM(int port) {
		super(port);
		tableAssignedContainer = useContainer(Util.TABLE_ASSIGNED) ;
		freeTablesContainer = useContainer(Util.FREE_TABLES);
		orderDeliveredContainer = useContainer(Util.ORDER_COMPLETE) ;
		preparedPizzasContainer = useContainer(Util.DELIVER_PIZZAS);
		paymentDoneContainer = useContainer(Util.PAYMENT_DONE) ;
		orderTakenContainer = useContainer(Util.ORDER_TAKEN);
		assignTableContainer = useContainer(Util.ASSIGN_TABLE);
        pizzeriaInfoContainer = useContainer(Util.PIZZERIA_INFO);
        deliveryOrderTakenContainer = useContainer(Util.DELIVERY_ORDER_TAKEN);
        pizzeriaTableContainer = useContainer(Util.PIZZERIA_TABLE);
        pizzeriaGroupContainer = useContainer(Util.PIZZERIA_GROUP);
        preparedDeliveryPizzasContainer = useContainer(Util.DELIVER_DELIVERY_PIZZAS);
        pizzeriaDeliveryContainer = useContainer(Util.PIZZERIA_DELIVERY);

    }

    public void listenForTablesUpdates() {
        getDefaultBuilder("listenForTablesUpdates").setLookaround(true).setCref(pizzeriaTableContainer).setSpaceAction(new SpaceAction() {
            @Override
            public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {

                final List<Table> tables = castEntries(entries);

                final ArrayList<Table> occupiedTables = new ArrayList<Table>();
                for (Table table : tables) {
                    if(! table.isFree()) occupiedTables.add(table);
                }

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        PizzeriaAgent.getInstance().getTablesModel().addItems(tables);
                        PizzeriaAgent.getInstance().getGroupModel().removeGroupsFromTables(occupiedTables);
                    }
                });
            }
        }).createSpaceListenerImpl();
    }

    public void listenForGroupUpdates() {
        getDefaultBuilder("listenForGroupUpdates").setLookaround(true).setCref(pizzeriaGroupContainer).setSpaceAction(new SpaceAction() {
            @Override
            public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
                final List<GroupData> groups = castEntries(entries);
                final List<GroupData> waitingGroups = getWaitingGroups(groups);
                final List<GroupData> orderedGroups = getOrderedGroups(groups);

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        PizzeriaAgent.getInstance().getGroupModel().addItems(waitingGroups);
                        PizzeriaAgent.getInstance().getOrdersModel().addItems(orderedGroups);
                    }
                });

            }
        }).createSpaceListenerImpl();
    }

    public void listenForDeliveryUpdates() {
         getDefaultBuilder("listenForDeliveryUpdates").setLookaround(true).setCref(pizzeriaDeliveryContainer).setSpaceAction(new SpaceAction() {
            @Override
            public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
                final List<DeliveryGroupData> groups = castEntries(entries);

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        PizzeriaAgent.getInstance().getDeliveryOrdersModel().addItems(groups);
                    }
                });

            }
        }).createSpaceListenerImpl();
    }

    public void sendFreeTablesToContainer(List<Table> tables) {
		sendItemsToContainer(tables, freeTablesContainer, RequestTimeout.DEFAULT, null);
		sendItemsToContainer(tables, pizzeriaTableContainer, RequestTimeout.DEFAULT, null);
	}

    private List<GroupData> getOrderedGroups(List<GroupData> groups) {
        final ArrayList<GroupData> orderedGroups = new ArrayList<GroupData>();
        for (GroupData group : groups) {
            if(group.getState() != GroupState.WAITING) {
                orderedGroups.add(group);
            }
        }
        return orderedGroups;
    }

    public void initializeOrderId() {
        sendItemsToContainer(Arrays.asList(new OrderId(0)), pizzeriaInfoContainer, RequestTimeout.DEFAULT, null);
    }

    public void notifyGroupAgent() {
        sendItemsToContainer(Arrays.asList(new PizzeriaRegistration(port)), useContainerOfSpaceWithPort(Util.GROUP_AGENT_INFO, Util.GROUP_AGENT_PORT), RequestTimeout.DEFAULT, null);
    }

    private List<GroupData> getWaitingGroups(List<GroupData> groups) {
        final ArrayList<GroupData> waitingGroups = new ArrayList<GroupData>();
        for (GroupData group : groups) {
            if (group.getState() == GroupState.WAITING) {
                waitingGroups.add(group);
            }

        }
        return waitingGroups;
    }
}
