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

import at.ac.tuwien.sbc.valesriegler.common.AbstractAction;
import at.ac.tuwien.sbc.valesriegler.cook.actions.DeliveryOrderInfo;
import at.ac.tuwien.sbc.valesriegler.driver.actions.OrderDeliveredInfo;
import at.ac.tuwien.sbc.valesriegler.group.AbstractGroupConnector;
import at.ac.tuwien.sbc.valesriegler.group.Group;
import at.ac.tuwien.sbc.valesriegler.group.GroupAgent;
import at.ac.tuwien.sbc.valesriegler.group.actions.*;
import at.ac.tuwien.sbc.valesriegler.types.DeliveryGroupData;
import at.ac.tuwien.sbc.valesriegler.waiter.actions.DeliverOrder;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jms.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

/**
 * This class handles the communication with other processes using JMS.
 *
 * @author jan
 */
public class JMSGroupConnector extends AbstractGroupConnector implements MessageListener {
    private static final Logger log = LoggerFactory.getLogger(JMSGroupConnector.class);
    private static HashMap<String, JMSGroupConnector> connectors = new HashMap<String, JMSGroupConnector>();

    public final String JMS_CONNECTSTRING;
    private Connection connection;

    public JMSGroupConnector(String address) {
        if (address == null)
            throw new IllegalArgumentException("Address may not be null!");
        JMS_CONNECTSTRING = address;
        init();
    }

    @Override
    public void init() {
        try {
            connection = new ActiveMQConnectionFactory(JMS_CONNECTSTRING).createConnection();
            connection.start();
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageConsumer consumer = session.createConsumer(session.createQueue("GroupConnector"));
            consumer.setMessageListener(this);
        } catch (JMSException e) {
            log.error("EXCEPTION!", e);
        }
    }

    @Override
    public void onMessage(Message msg) {
        try {
            msg.acknowledge();
            if (msg instanceof ObjectMessage) {
                ObjectMessage objMsg = (ObjectMessage) msg;
                Object obj = objMsg.getObject();

                if (obj instanceof TableResponse) {
                    TableResponse tablerresponse = (TableResponse) obj;
                    log.debug("Received: " + tablerresponse);
                    Group g = GroupAgent.getInstance().getGroupModel().getGroupByID(tablerresponse.getGroupdata().getId());
                    g.assignTable(tablerresponse.getTable(), tablerresponse.getWaiterId());
                    return;
                } else if (obj instanceof OrderResponse) {
                    OrderResponse orderresponse = (OrderResponse) obj;
                    log.debug("Received: " + orderresponse);
                    Group g = GroupAgent.getInstance().getGroupModel().getGroupByID(orderresponse.getGroupdata().getId());
                    g.orderReceived(orderresponse.getWaiterId());
                    return;
                } else if (obj instanceof DeliverOrder) {
                    DeliverOrder deliverorder = (DeliverOrder) obj;
                    log.debug("Received: " + deliverorder);
                    Group g = GroupAgent.getInstance().getGroupModel().getGroupByID(deliverorder.getGroupdata().getId());
                    g.deliverPizzas(deliverorder.getGroupdata().getOrder(), deliverorder.getWaiterId());
                    return;
                } else if (obj instanceof PayResponse) {
                    PayResponse payresponse = (PayResponse) obj;
                    log.debug("Received: " + payresponse);
                    Group g = GroupAgent.getInstance().getGroupModel().getGroupByID(payresponse.getGroupdata().getId());
                    g.payForPizzas(payresponse.getWaiterId());
                    return;

                } else if (obj instanceof DeliveryOrderResponse) {
                    DeliveryOrderResponse deliveryOrderResponse = (DeliveryOrderResponse) obj;
                    log.debug("Received: " + deliveryOrderResponse);
                    deliveryOrderResponse.getDeliveryGroupData().setWaiterIdOfOrder(deliveryOrderResponse.getWaiterId());
                    ArrayList<DeliveryGroupData> gd = new ArrayList<DeliveryGroupData>();
                    gd.add(deliveryOrderResponse.getDeliveryGroupData());
                    GroupAgent.getInstance().getDeliveryModel().addDeliveries(gd);
                    return;

                } else if (obj instanceof DeliveryOrderInfo) {
                    DeliveryOrderInfo deliveryOrderInfo = (DeliveryOrderInfo) obj;
                    log.debug("Received: " + deliveryOrderInfo);
                    ArrayList<DeliveryGroupData> gd = new ArrayList<DeliveryGroupData>();
                    gd.add(deliveryOrderInfo.getDeliveryGroupData());
                    GroupAgent.getInstance().getDeliveryModel().addDeliveries(gd);
                    return;

                } else if (obj instanceof OrderDeliveredInfo) {
                    OrderDeliveredInfo orderDeliveredInfo = (OrderDeliveredInfo) obj;
                    log.debug("Received: " + orderDeliveredInfo);
                    orderDeliveredInfo.getDeliveryGroupData().setDriverId(orderDeliveredInfo.getDriverId());
                    ArrayList<DeliveryGroupData> gd = new ArrayList<DeliveryGroupData>();
                    gd.add(orderDeliveredInfo.getDeliveryGroupData());
                    GroupAgent.getInstance().getDeliveryModel().addDeliveries(gd);

                    if (GroupAgent.getInstance().getDeliveryModel().hasFinished()) {
                        log.warn("Finished after {} seconds", (new Date().getTime() - GroupAgent.startTime.get()) / 1000);
                    }
                    return;
                }

            }
            log.warn("Unknown messagetype received!");
        } catch (JMSException e) {
            log.error("EXCEPTION!", e);
        }
    }

    @Override
    public void send(AbstractAction request) {
        try {
            if (request instanceof TableRequest) {
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer wantToSitAtTable = session.createProducer(session.createQueue("WantToSitAtTable"));
                wantToSitAtTable.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToSitAtTable.send(session.createObjectMessage(request));

                MessageProducer informPizzariaGui = session.createProducer(session.createQueue("PizzeriaConnector"));
                informPizzariaGui.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                informPizzariaGui.send(session.createObjectMessage(request));
                return;

            } else if (request instanceof OrderRequest) {
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer wantToOrder = session.createProducer(session.createQueue("WantToOrder"));
                wantToOrder.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToOrder.send(session.createObjectMessage(request));
                return;

            } else if (request instanceof PayRequest) {
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer wantToPay = session.createProducer(session.createQueue("WantToPay"));
                wantToPay.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToPay.send(session.createObjectMessage(request));
                return;

            } else if (request instanceof TableFree) {
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer wantToSitAtTable = session.createProducer(session.createQueue("TablesFree"));
                wantToSitAtTable.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToSitAtTable.send(session.createObjectMessage(request.getGroupdata().getTable()));

                MessageProducer wantToLeave = session.createProducer(session.createQueue("WantToLeave"));
                wantToLeave.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToLeave.send(session.createObjectMessage(request));

                MessageProducer informPizzariaGui = session.createProducer(session.createQueue("PizzeriaConnector"));
                informPizzariaGui.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                informPizzariaGui.send(session.createObjectMessage(request));
                session.close();
                return;

            } else if (request instanceof DeliveryOrderRequest) {
                Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                MessageProducer wantToPay = session.createProducer(session.createQueue("WantADelivery"));
                wantToPay.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                wantToPay.send(session.createObjectMessage(request));

                MessageProducer informPizzariaGui = session.createProducer(session.createQueue("PizzeriaConnector"));
                informPizzariaGui.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
                informPizzariaGui.send(session.createObjectMessage(request));
                session.close();
                return;
            }
        } catch (JMSException e) {
            log.error("EXCEPTION!", e);
        }
    }

    public static HashMap<String, JMSGroupConnector> getConnectors() {
        return connectors;
    }

    public static JMSGroupConnector getConnector(String key) {
        return connectors.get(key);
    }

    public Connection getConnection() {
        return connection;
    }

}
