/*
 *  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; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 "Be.h"
#include <map>


namespace winBe {


// Global variables
uint32 nextLooperID = 0;
std::map<thread_id, BLooper*> threadLoopers;


} // namespace winBe


// _task0_
status_t BLooper::_task0_ (void *arg)
{
	return (reinterpret_cast<BLooper*>(arg))->Run ();
}


// constructor
BLooper::BLooper (const char *name, int32 priority, int32 port_capacity) :
BHandler (name),
fLooperID (winBe::nextLooperID++),
fQueue (0),
fLastMessage (0),
fMsgPort (0),
fAtomicCount (0),
fOwnerCount (0),
fOwner (0),
fInitPriority (0),
fPreferred (0),
fCommonFilters (0),
fTerminating (false),
fRunCalled (false)
{
	fLockSem = create_sem (1, B_EMPTY_STRING);
	fLooper = this;

	if (fLooperID == 0) // a bit dodgy - we should check if this is a BApplication*
		fTaskID = find_thread (B_EMPTY_STRING);
	else {
		fTaskID = spawn_thread (_task0_, name, B_LOW_PRIORITY, this);
	}

	winBe::threadLoopers.insert (std::make_pair (fTaskID, this));
}


// destructor								
BLooper::~BLooper ()
{
	delete_sem (fLockSem);
}


// Archive
status_t BLooper::Archive (BMessage *data, bool deep) const
{
	return 0;
}


void BLooper::DispatchMessage (BMessage *message, BHandler *handler)
{
	MessageReceived (message);
}


void BLooper::MessageReceived (BMessage *msg)
{
}


// Run
thread_id BLooper::Run ()
{
	winBe::debugMessage ("BLooper::Run");

	while (BMessage* message = reinterpret_cast<BMessage*>(winBe::getMessage ())) {
		if (message) {
			std::ostringstream str;
			str << "Received message '" << winBe::getMessageChars (message->what) << '\'';
			winBe::debugMessage (str.str ());

			DispatchMessage (message, NULL);
		}
	}

	return Thread ();
}


// Quit
void BLooper::Quit ()
{
	winBe::postQuitMessage (Thread ());
}


// QuitRequested
bool BLooper::QuitRequested ()
{
	return true;
}


BHandler* BLooper::ResolveSpecifier (BMessage *msg, int32 index, BMessage *specifier, int32 form, const char *property)
{
	return 0;
}


status_t BLooper::GetSupportedSuites (BMessage *data)
{
	return 0;
}


void BLooper::AddCommonFilter (BMessageFilter *filter)
{
}


bool BLooper::RemoveCommonFilter (BMessageFilter *filter)
{
	return false;
}


void BLooper::SetCommonFilterList (BList *filters)
{
}


status_t BLooper::Perform (perform_code d, void *arg)
{
	return 0;
}


BMessage* BLooper::ConvertToMessage (void *raw, int32 code)
{
	return 0;
}


// task_looper
void BLooper::task_looper ()
{
}


void BLooper::_ReservedLooper1 () {}
void BLooper::_ReservedLooper2 () {}
void BLooper::_ReservedLooper3 () {}
void BLooper::_ReservedLooper4 () {}
void BLooper::_ReservedLooper5 () {}
void BLooper::_ReservedLooper6 () {}


// Thread
thread_id BLooper::Thread () const
{
	return fTaskID;
}


// Lock
bool BLooper::Lock ()
{
	bool success = false;
	
	if (!IsLocked ()) {
		success = acquire_sem (fLockSem) == B_NO_ERROR ? true : false;
		if (success)
			fAtomicCount++;
	}

	return success;
}


// Unlock
void BLooper::Unlock ()
{
	if (release_sem (fLockSem) == B_NO_ERROR)
		fAtomicCount--;
}


// IsLocked
bool BLooper::IsLocked () const
{
	return fAtomicCount == 0 ? false : true;
}


// PostMessage
status_t BLooper::PostMessage (uint32 command)
{
	BMessage* message = new BMessage (command);
	PostMessage (message);
	delete message;
	return B_OK;
}


// PostMessage
status_t BLooper::PostMessage (BMessage *message)
{
	BMessage* messageCopy = new BMessage (*message);
	bool success = winBe::postMessage (Thread (), messageCopy, messageCopy->what);
	return success ? B_OK : B_ERROR;
}


// PostMessage
status_t BLooper::PostMessage (uint32 command, BHandler *handler, BHandler *reply_to)
{
	BMessage* message = new BMessage (command);
	PostMessage (message, handler, reply_to);
	delete message;
	return B_OK;
}


// PostMessage
status_t BLooper::PostMessage (BMessage *message, BHandler *handler, BHandler *reply_to)
{
	BMessage* messageCopy = new BMessage (*message);
	bool success = winBe::postMessage (Thread (), messageCopy, messageCopy->what);
	return success ? B_OK : B_ERROR;
}


BLooper* BLooper::LooperForThread (thread_id tid)
{
	BLooper* looper = 0;
	std::map<thread_id, BLooper*>::iterator i = winBe::threadLoopers.find (tid);
	if (i != winBe::threadLoopers.end ())
		looper = (*i).second;
	return looper;
}
