#ifndef PROCESSING_QUEUE_H
#define PROCESSING_QUEUE_H

#include <list>
#include <iostream>
#include "util.h"
#include "address.h"

using namespace std;

enum ProcessingType
{
    INTERNAL_TIMEOUT,
    EXTERNAL_WAIT
};

struct ProcessingElement {
    // The data to store
    Address address;

    // Is the process calculating or waiting for external calculation
    const ProcessingType processing_type;

    // If the process is done by external calculation, is_ready should
    // be true when the calculation is finished
    bool is_ready;

    // If the process is done by internal calculation, this represents
    // the current timeout.
    unsigned int latency;


    inline friend ostream& operator << ( ostream& os,  ProcessingElement const & v ) {
        if (v.processing_type == INTERNAL_TIMEOUT) {
            os << v.address << "(timeout=" << v.latency << ")";
        } else if (v.processing_type == EXTERNAL_WAIT) {
            os << v.address << "(extern waiting)";
        }
        return os;
    }
    
};

class ProcessingQueue {
    private:
        unsigned int max_size;
        unsigned int current_size;
        list<ProcessingElement> elements;

    public:
        ProcessingQueue(int size) {
            this->max_size = size;
            this->current_size = 0;
        }


        // Prints the content of the queue
        void print();

        // marks an external request as ready for being sent
        void mark_ready(Address &element);

        // insert a request for internal processing, with
        // specified timeout
        void insert(const Address addr, unsigned int latency);

        // insert a request for external processing.
        // will be updated by 
        void insert(const Address addr);

        Address* get_next_ready();

        bool is_empty();

        // Updates the timeout of all internal requests
        void update_time();
};

#endif

