#ifndef _HAVE_OSCROUTER_H
#define _HAVE_OSCROUTER_H

#include <osc/OscPacketListener.h>
#include <ip/UdpSocket.h>

#include <QtCore/QObject>
#include <QtCore/QSet>
#include <QtCore/QHash>
#include <QtCore/QMultiMap>
#include <QtCore/QString>
#include <QtCore/QThread>
#include <QMetaObject>

#include <QtNetwork/QUdpSocket>
#include <QtNetwork/QHostAddress>


#include <boost/bind.hpp>
#include <boost/function.hpp>

#include <iostream>

#include "OscMethod.h"

class OscRouter : public QThread {
    Q_OBJECT


    public:
        
        static const int default_port = 7000;

        OscRouter(int port=OscRouter::default_port);
        ~OscRouter();
        void run();

        int port() { return _port; }

    public slots:
        void addMethod(const QString& address, AbstractOscMethod* endpoint);
        void scheduleTimer();
        void readPending();
    protected:

        class bundle_schedule {
            public:
            const osc::ReceivedBundle* b;
            const QHostAddress* sender;
            int senderport;
        };



        virtual void dispatchMessage(const osc::ReceivedMessage* rmsg, const QHostAddress* sender, int senderport);
        virtual void dispatchBundle(const osc::ReceivedBundle* b, const QHostAddress*, int);

        void scheduledBundle(struct bundle_schedule*);

        /**
         * Does a simple regex test to see if the address is a pattern. 
         */
        bool addressIsPattern(const QString&) const;

        /**
         * Finds all legal endpoints matching the pattern
         */
        QSet<AbstractOscMethod*>* matchPattern(const QString&) const;

            
        /* cache of query adresses */
        QHash<QString, QSet<AbstractOscMethod*>* > addressCache;
        /* all legal endpoints */
        QHash<QString, AbstractOscMethod*> addresses;

        /* bundles scheduled for later, sorted by timestamp */
        QMultiMap<quint32, bundle_schedule*> schedule;

        QUdpSocket _sock;
        int _port;
}; //OscRouter

#endif //_HAVE_OSCROUTER_H