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

import at.ac.tuwien.sbc.valesriegler.common.Util;
import at.ac.tuwien.sbc.valesriegler.group.DeliveryGroup;
import at.ac.tuwien.sbc.valesriegler.group.GroupAgent;
import at.ac.tuwien.sbc.valesriegler.group.gui.DeliveryOverviewModel;
import at.ac.tuwien.sbc.valesriegler.types.DeliveryGroupData;
import at.ac.tuwien.sbc.valesriegler.types.GroupData;
import at.ac.tuwien.sbc.valesriegler.types.PizzaType;
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.*;
import java.util.concurrent.atomic.AtomicLong;

import static java.lang.String.valueOf;

public class GroupAgentXVSM extends AbstractXVSMConnector {
	private static final Logger log = LoggerFactory.getLogger(GroupAgentXVSM.class);

    private AtomicLong startTime = new AtomicLong();
	
	public GroupAgentXVSM() {
		super(Util.GROUP_AGENT_PORT);
        groupAgentInfoContainer = useContainer(Util.GROUP_AGENT_INFO);
	}
	
    public void listenForNewPizzerias() {
        getDefaultBuilder("groupAgentInfoContainer").setCref(groupAgentInfoContainer).setLookaround(true).setSpaceAction(new SpaceAction() {

            @Override
            public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
                final Set<String> pizzeriaIdentifiers = GroupAgent.getInstance().getPizzeriaIdentifiers();

                synchronized (pizzeriaIdentifiers) {
                    final List<PizzeriaRegistration> pizzeriaRegistrations = castEntries(entries);
                    final List<String> pizzeriaIds = new ArrayList<String>();
                    for (PizzeriaRegistration registration : pizzeriaRegistrations) {
                        final String pizzeriaId = valueOf(registration.pizzeriaSpacePort);
                        if (!pizzeriaIdentifiers.contains(pizzeriaId)) {
                            pizzeriaIds.add(pizzeriaId);
                            listenToPizzeria(pizzeriaId);
                        }
                    }

                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            pizzeriaIdentifiers.addAll(pizzeriaIds);
                        }
                    });
                }
            }
        }).createSpaceListenerImpl();

    }

    public void listenToPizzeria(String pizzeriaId) {
        final int port = Integer.parseInt(pizzeriaId);
        listenToGroupUpdates(port);
        listenToDeliveryUpdates(port);
    }

    private void listenToDeliveryUpdates(int port) {
        getDefaultBuilder().setCref(useContainerOfSpaceWithPort(Util.PIZZERIA_DELIVERY, port)).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() {
                        GroupAgent.getInstance().getDeliveryModel().addDeliveries(groups);
                    }
                });

                if (Util.runSimulation) {
                    boolean finished = GroupAgent.getInstance().getDeliveryModel().hasFinished();
                    if (finished) {
                        final long now = new Date().getTime();
                        final long difference = now - startTime.get();
                        log.info("Finished after {} seconds", difference / 1000);
                    }
                }
            }
        }).createSpaceListenerImpl();
    }

    private void listenToGroupUpdates(int port) {
        getDefaultBuilder().setCref(useContainerOfSpaceWithPort(Util.PIZZERIA_GROUP, port)).setSpaceAction(new SpaceAction() {
            @Override
            public void onEntriesWritten(List<? extends Serializable> entries) throws Exception {
                final List<GroupData> groups = castEntries(entries);

                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        GroupAgent.getInstance().getGroupModel().addGroupData(groups);
                    }
                });
            }
        }).createSpaceListenerImpl();
    }

    public void sendNewGroupsToSpace(List<GroupData> groupData, int pizzeriaSpacePort) {
        sendItemsToContainer(groupData, useContainerOfSpaceWithPort(Util.PIZZERIA_GROUP, pizzeriaSpacePort), RequestTimeout.DEFAULT, null);
        sendItemsToContainer(groupData, useContainerOfSpaceWithPort(Util.ASSIGN_TABLE, pizzeriaSpacePort), RequestTimeout.DEFAULT, null);
    }

    public void sendNewDeliveriesToSpace(List<DeliveryGroupData> groupData, int pizzeriaSpacePort) {
        sendItemsToContainer(groupData, useContainerOfSpaceWithPort(Util.PIZZERIA_DELIVERY, pizzeriaSpacePort), RequestTimeout.DEFAULT, null);
        sendItemsToContainer(groupData, useContainerOfSpaceWithPort(Util.PHONE_CALLS, pizzeriaSpacePort), RequestTimeout.DEFAULT, null);
    }

    public void runSimulation() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                List<PizzaType> pizzaTypes1 = Arrays.asList(PizzaType.CARDINALE, PizzaType.SALAMI, PizzaType.MARGHERITA, PizzaType.MARGHERITA);
                List<PizzaType> pizzaTypes2 = Arrays.asList(PizzaType.CARDINALE, PizzaType.SALAMI, PizzaType.MARGHERITA);
                List<PizzaType> pizzaTypes3 = Arrays.asList(PizzaType.SALAMI, PizzaType.MARGHERITA);

                final String pizzeria1 = "9874";
                final String pizzeria2 = "9875";
                List<DeliveryGroup> groups1 = GroupAgent.getInstance().createGroups(pizzaTypes1, pizzeria1, 4);
                List<DeliveryGroup> groups2 = GroupAgent.getInstance().createGroups(pizzaTypes2, pizzeria2, 3);
                List<DeliveryGroup> groups3 = GroupAgent.getInstance().createGroups(pizzaTypes3, pizzeria2, 2);

                final DeliveryOverviewModel deliveryModel = GroupAgent.getInstance().getDeliveryModel();
                deliveryModel.addItems(groups1);
                deliveryModel.addItems(groups2);
                deliveryModel.addItems(groups3);

                GroupAgent.getInstance().onDeliveryGroupsCreated(groups2);
                GroupAgent.getInstance().onDeliveryGroupsCreated(groups3);
                GroupAgent.getInstance().onDeliveryGroupsCreated(groups1);

                log.info("ATTENTION: Now let's wait 60 seconds!");

                try {
                    startTime.set(new Date().getTime());
                    Thread.sleep(60000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                log.info("ATTENTION: It's all over now!");
                notificationMgr.shutdown();

                deliveryModel.createStatistics();
            }
        }).start();
    }
}
