/*
 * msghandler.cpp
 *
 * Copyright (C) 2001 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) 
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation (version 2 of the License)
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
#include <psconfig.h>

#include "util/sleep.h"
#include "net/message.h"
#include "net/messages.h"
#include "net/netbase.h"
#include "net/msghandler.h"
#include "csutil/scopedmutexlock.h"

#include "interface/subscriber.h"
#include "util/psconst.h"

class Client;

MsgHandler::MsgHandler()
{
    netbase = NULL;
    queue   = NULL;
    mutex = csMutex::Create (CS_MUTEX_RECURSIVE);
    thread = NULL;
}

MsgHandler::~MsgHandler()
{   
    if ( thread )
        thread->Stop ();

    if (queue) delete queue;
}

bool MsgHandler::Initialize(NetBase* nb, int queuelen)
{
    if (!nb) return false;
    netbase = nb;

    queue = new MsgQueue(queuelen);
    if (!netbase->AddMsgQueue(queue))
        return false;

    return true;
}

bool MsgHandler::StartThread()
{
    thread = csThread::Create (this);
    if (!thread->Start ())
        return false;

    return true;
}

bool MsgHandler::StopThread()
{
    stop_network = true;
    thread->Wait();
    thread = NULL;

    return true;
}


void MsgHandler::Publish(MsgEntry* me)
{
    csScopedMutexLock lock(mutex);

    netbase->LogMessages("R",me);

    bool handled = false;

    int mtype = me->GetType();

    for ( size_t x = 0; x < subscribers[mtype].Length(); x++ )
    {
        Client *client;
        me->Reset();
        if (subscribers[mtype][x]->subscriber->Verify(me,subscribers[mtype][x]->flags,client))
            subscribers[mtype][x]->subscriber->HandleMessage(me,client);
        handled = true;
    }

    if (!handled)
    {
        Debug3(LOG_ANY,me->clientnum,"Unhandled message received 0x%04X from %d",
               me->GetType() ,me->clientnum);
    }
}

bool MsgHandler::Subscribe(iNetSubscriber *subscriber, msgtype type,uint32_t flags)
{
    Subscription* p = new Subscription;

    p->subscriber = subscriber;
    p->type       = type;
    p->flags      = flags;

    csScopedMutexLock lock(mutex);
    if ( IsSubscribed(p) )
        delete p;
    else
        subscribers[type].Push(p);

    return true;
}

bool MsgHandler::Unsubscribe(iNetSubscriber *subscriber, msgtype type)
{
    csScopedMutexLock lock(mutex);

    for ( size_t x = 0; x < subscribers[type].Length(); x++ )
    {
        if (subscribers[type][x]->subscriber == subscriber)
        {
            subscribers[type].DeleteIndex(x);
            return true;
        }        
    }

    return false;
}


/*void MsgHandler::Run ()
{
    csRef<MsgEntry> msg;
    
    while(true)
    {
        msg = queue->GetWait();

        if (msg)
        {
            Publish(msg);
            // don't forget to release the packet
            // msg->DecRef();  csRef does automatically
        }
    }
    Error1("BUG! This should never happen!");
}
*/

bool MsgHandler::IsSubscribed( Subscription* sub )
{
    for ( size_t x = 0; x < subscribers[sub->type].Length(); x++ )
    {
        if (subscribers[sub->type][x]->subscriber == sub->subscriber)
        {
            return true;
        }        
    }

    return false;
}

