// Path: utils/src/main/java/co/flyver/utils/CapacityQueue.java
// public class CapacityQueue<E> extends LinkedBlockingQueue<E> {
//         private int limit;
// 
//         public CapacityQueue(int limit) {
//             this.limit = limit;
//         }
// 
//         @Override
//         public boolean add(E e) {
//             boolean added = super.add(e);
//             while(added && size() > limit) {
//                 super.remove();
//             }
//             return added;
//         }
//     }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/exceptions/NoSuchTopicException.java
// public class NoSuchTopicException extends Exception {
//     public NoSuchTopicException(String detailMessage) {
//         super(detailMessage);
//     }
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/exceptions/ProducerAlreadyRegisteredException.java
// public class ProducerAlreadyRegisteredException extends Exception {
//     public ProducerAlreadyRegisteredException(String detailMessage) {
//         super(detailMessage);
//     }
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/interfaces/FlyverMQCallback.java
// public interface FlyverMQCallback {
//     /**
//      * Called every time a producer is registered to the message queue
//      * Used to notify components for new producers that they might be interested in
//      * @param topic String, the topic of the messages sent by the producer
//      */
//     public void producerRegistered(String topic);
// 
//     /**
//      * Called every time a producer is unregistered or replaced from the system
//      * Used to notify components that a producer has disappeared, so they should unregister
//      * for it's messages
//      * @param topic String, the topic of the messages of the unregistered producer
//      */
//     public void producerUnregistered(String topic);
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/interfaces/FlyverMQConsumer.java
// public interface FlyverMQConsumer {
//     /**
//      * Data recieved callback for the consumer.
//      * Called when a message with the associated topic
//      * for the consumer is received in the message queue
//      * @param message SimpleMQMessage data container
//      */
//     public void dataReceived(FlyverMQMessage message);
// 
//     /**
//      * Consumer unregister hook
//      * Called when the consumer is removed from the message queue
//      */
//     public void unregistered();
// 
//     //TODO: clarify if consumers need onPause/onResume functionallity
//     public void paused();
//     public void resumed();
// }


import android.util.Log;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import co.flyver.utils.CapacityQueue;
import co.flyver.utils.flyverMQ.exceptions.NoSuchTopicException;
import co.flyver.utils.flyverMQ.exceptions.ProducerAlreadyRegisteredException;
import co.flyver.utils.flyverMQ.interfaces.FlyverMQCallback;
import co.flyver.utils.flyverMQ.interfaces.FlyverMQConsumer;
    /**
     * Register an object, implementing the SimpleMQCallback interface
     * which is used to monitor changes in the producers registration and deregistration
     * from the components
     *
     * @param callback SimpleMQCallback, implementing onRegistered and onUnregistered methods
     * @return this, as to allow chaining
     */
    public FlyverMQ producersStatusCallback(FlyverMQCallback callback) {
        registeredComponentCallbacks.add(callback);
        return this;
    }

    /**
     * Register an Object implementing the SimpleMQProducer interface to a topic
     * All messages by this producer are enqueued for later processing
     *
     * @param producer       Class implementing SimpleMQProducer interface
     * @param topic          String defining the topic of the producer
     * @param removeExisting Set to true to remove previously registered producer for the topic
     * @return this, to allow chaining
     * @throws ProducerAlreadyRegisteredException - Throws the already registered exception if a producer is already registered,
     *                                            and the removeExisting flag is set to false
     */
    public FlyverMQ registerProducer(FlyverMQProducer producer, String topic, boolean removeExisting) throws ProducerAlreadyRegisteredException {
        if (topicExists(topic) && !removeExisting) {
            throw new ProducerAlreadyRegisteredException(REGISTEREDMSG.concat(topic));
        }
        if (topicExists(topic)) {
            try {
// Path: utils/src/main/java/co/flyver/utils/CapacityQueue.java
// public class CapacityQueue<E> extends LinkedBlockingQueue<E> {
//         private int limit;
// 
//         public CapacityQueue(int limit) {
//             this.limit = limit;
//         }
// 
//         @Override
//         public boolean add(E e) {
//             boolean added = super.add(e);
//             while(added && size() > limit) {
//                 super.remove();
//             }
//             return added;
//         }
//     }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/exceptions/NoSuchTopicException.java
// public class NoSuchTopicException extends Exception {
//     public NoSuchTopicException(String detailMessage) {
//         super(detailMessage);
//     }
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/exceptions/ProducerAlreadyRegisteredException.java
// public class ProducerAlreadyRegisteredException extends Exception {
//     public ProducerAlreadyRegisteredException(String detailMessage) {
//         super(detailMessage);
//     }
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/interfaces/FlyverMQCallback.java
// public interface FlyverMQCallback {
//     /**
//      * Called every time a producer is registered to the message queue
//      * Used to notify components for new producers that they might be interested in
//      * @param topic String, the topic of the messages sent by the producer
//      */
//     public void producerRegistered(String topic);
// 
//     /**
//      * Called every time a producer is unregistered or replaced from the system
//      * Used to notify components that a producer has disappeared, so they should unregister
//      * for it's messages
//      * @param topic String, the topic of the messages of the unregistered producer
//      */
//     public void producerUnregistered(String topic);
// }
// 
// Path: utils/src/main/java/co/flyver/utils/flyverMQ/interfaces/FlyverMQConsumer.java
// public interface FlyverMQConsumer {
//     /**
//      * Data recieved callback for the consumer.
//      * Called when a message with the associated topic
//      * for the consumer is received in the message queue
//      * @param message SimpleMQMessage data container
//      */
//     public void dataReceived(FlyverMQMessage message);
// 
//     /**
//      * Consumer unregister hook
//      * Called when the consumer is removed from the message queue
//      */
//     public void unregistered();
// 
//     //TODO: clarify if consumers need onPause/onResume functionallity
//     public void paused();
//     public void resumed();
// }


// Path: utils/src/main/java/co/flyver/utils/flyverMQ/FlyverMQ.java
import android.util.Log;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import co.flyver.utils.CapacityQueue;
import co.flyver.utils.flyverMQ.exceptions.NoSuchTopicException;
import co.flyver.utils.flyverMQ.exceptions.ProducerAlreadyRegisteredException;
import co.flyver.utils.flyverMQ.interfaces.FlyverMQCallback;
import co.flyver.utils.flyverMQ.interfaces.FlyverMQConsumer;

    /**
     * Register an object, implementing the SimpleMQCallback interface
     * which is used to monitor changes in the producers registration and deregistration
     * from the components
     *
     * @param callback SimpleMQCallback, implementing onRegistered and onUnregistered methods
     * @return this, as to allow chaining
     */
    public FlyverMQ producersStatusCallback(FlyverMQCallback callback) {
        registeredComponentCallbacks.add(callback);
        return this;
    }

    /**
     * Register an Object implementing the SimpleMQProducer interface to a topic
     * All messages by this producer are enqueued for later processing
     *
     * @param producer       Class implementing SimpleMQProducer interface
     * @param topic          String defining the topic of the producer
     * @param removeExisting Set to true to remove previously registered producer for the topic
     * @return this, to allow chaining
     * @throws ProducerAlreadyRegisteredException - Throws the already registered exception if a producer is already registered,
     *                                            and the removeExisting flag is set to false
     */
    public FlyverMQ registerProducer(FlyverMQProducer producer, String topic, boolean removeExisting) throws ProducerAlreadyRegisteredException {
        if (topicExists(topic) && !removeExisting) {
            throw new ProducerAlreadyRegisteredException(REGISTEREDMSG.concat(topic));
        }
        if (topicExists(topic)) {
            try {
                unregisterProducer(topic);