/*
 * Copyright 2006, Haiku.
 *
 * Copyright (c) 2002-2003 Matthijs Hollemans
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Matthijs Hollemans
 */
 
#include "debug.h"
#include <MidiEndpoint.h>
#include <MidiRoster.h>
#include "MidiRosterLooper.h"
#include "protocol.h"
 
 
const char*
BMidiEndpoint::Name() const
{
	const char* str = NULL;
 
	// It seems reasonable to assume that the pointer returned by
	// BString::String() can change when the string is modified,
	// e.g. to allocate more space. That's why we lock here too.
 
	if (LockLooper()) {
		str = fName.String();
		UnlockLooper();
	}
 
	return str;
}
 
 
void
BMidiEndpoint::SetName(const char* newName)
{
	if (newName == NULL) {
		WARN("SetName() does not accept a NULL name");
		return;
	}
	if (IsRemote()) {
		WARN("SetName() is not allowed on remote endpoints");
		return;
	}
	if (!IsValid())
		return;
 
	if (fName != newName) {
		BMessage msg;
		msg.AddString("midi:name", newName);
 
		if (SendChangeRequest(&msg) == B_OK) {
			if (LockLooper()) {
				fName.SetTo(newName);
				UnlockLooper();
			}
		}
	}
}
 
 
int32
BMidiEndpoint::ID() const
{
	return fId;
}
 
 
bool
BMidiEndpoint::IsProducer() const
{
	return !fIsConsumer;
}
 
 
bool
BMidiEndpoint::IsConsumer() const
{
	return fIsConsumer;
}
 
 
bool
BMidiEndpoint::IsRemote() const
{
	return !fIsLocal;
}
 
 
bool
BMidiEndpoint::IsLocal() const
{
	return fIsLocal;
}
 
 
bool
BMidiEndpoint::IsPersistent() const
{
	return false;
}
 
 
bool
BMidiEndpoint::IsValid() const
{
	if (IsLocal())
		return (ID() > 0);
 
	// remote endpoint
	return IsRegistered();
}
 
 
status_t
BMidiEndpoint::Release()
{
	int32 old = atomic_add(&fRefCount, -1);
 
	TRACE(("BMidiEndpoint::Release refCount is now %" B_PRId32, old - 1))
 
	if (old == 1) {
		// If the reference count of a local endpoint drops to zero, 
		// we must delete it. The destructor of BMidiLocalXXX calls
		// BMidiRoster::DeleteLocal(), which does all the hard work.
		// If we are a proxy for a remote endpoint, we must only be
		// deleted if that remote endpoint no longer exists.
 
		if (IsLocal() || !fIsAlive)
			delete this;
	} else if (old <= 0) {
		debugger("too many calls to Release()");
	}
 
	return B_OK;
}
 
 
status_t
BMidiEndpoint::Acquire()
{
#ifdef DEBUG
	int32 old = 
#endif
	atomic_add(&fRefCount, 1);
 
	TRACE(("BMidiEndpoint::Acquire refCount is now %" B_PRId32, old + 1))
 
	return B_OK;
}
 
 
status_t
BMidiEndpoint::SetProperties(const BMessage* properties_)
{
	if (properties_ == NULL) {
		WARN("SetProperties() does not accept a NULL message")
		return B_BAD_VALUE;
	} else if (IsRemote()) {
		WARN("SetProperties() is not allowed on remote endpoints");
		return B_ERROR;
	} else if (!IsValid())  {
		return B_ERROR;
	} else {
		BMessage msg;
		msg.AddMessage("midi:properties", properties_);
 
		status_t err = SendChangeRequest(&msg);
		if (err == B_OK) {
			if (LockLooper()) {
				*fProperties = *properties_;
				UnlockLooper();
			}
		}
 
		return err;
	}
}
 
 
status_t
BMidiEndpoint::GetProperties(BMessage* _properties) const
{
	if (_properties == NULL) {
		WARN("GetProperties() does not accept NULL properties")
		return B_BAD_VALUE;
	}
 
	if (LockLooper()) {
		*_properties = *fProperties;
		UnlockLooper();
	}
 
	return B_OK;
}
 
 
status_t
BMidiEndpoint::Register()
{
	if (IsRemote()) { 
		WARN("You cannot Register() remote endpoints");
		return B_ERROR; 
	}
	if (IsRegistered()) { 
		WARN("This endpoint is already registered");
		return B_OK; 
	}
	if (!IsValid()) 
		return B_ERROR;
 
	return SendRegisterRequest(true);
}
 
 
status_t
BMidiEndpoint::Unregister()
{
	if (IsRemote()) { 
		WARN("You cannot Unregister() remote endpoints");
		return B_ERROR; 
	}
	if (!IsRegistered()) { 
		WARN("This endpoint is already unregistered");
		return B_OK; 
	}
	if (!IsValid())
		return B_ERROR;
 
	return SendRegisterRequest(false);
}
 
 
BMidiEndpoint::BMidiEndpoint(const char* name_)
{
	TRACE(("BMidiEndpoint::BMidiEndpoint"))
 
	if (name_ != NULL)
		fName.SetTo(name_);
 
	fId           = 0;
	fRefCount     = 0;
	fIsLocal      = false;
	fIsRegistered = false;
	fIsAlive      = true;
	
	fProperties	= new BMessage();
}
 
 
BMidiEndpoint::~BMidiEndpoint()
{
	TRACE(("BMidiEndpoint::~BMidiEndpoint (%p)", this))
 
	if (fRefCount > 0) {
		debugger(
			"you should use Release() to dispose of endpoints; "
			"do not \"delete\" them or allocate them on the stack!");
	}
	delete fProperties;
}
 
//------------------------------------------------------------------------------
 
void BMidiEndpoint::_Reserved1() { }
void BMidiEndpoint::_Reserved2() { }
void BMidiEndpoint::_Reserved3() { }
void BMidiEndpoint::_Reserved4() { }
void BMidiEndpoint::_Reserved5() { }
void BMidiEndpoint::_Reserved6() { }
void BMidiEndpoint::_Reserved7() { }
void BMidiEndpoint::_Reserved8() { }
 
//------------------------------------------------------------------------------
 
status_t
BMidiEndpoint::SendRegisterRequest(bool registered)
{
	BMessage msg;
	msg.AddBool("midi:registered", registered);
 
	status_t err = SendChangeRequest(&msg);
	if (err == B_OK)  {
		if (LockLooper()) {
			fIsRegistered = registered; 
			UnlockLooper();
		}
	}
 
	return err;
}
 
 
status_t
BMidiEndpoint::SendChangeRequest(BMessage* msg)
{
	ASSERT(msg != NULL)
 
	msg->what = MSG_CHANGE_ENDPOINT;
	msg->AddInt32("midi:id", ID());
 
	BMessage reply;
	status_t err = BMidiRoster::MidiRoster()->SendRequest(msg, &reply);
	if (err != B_OK)
		return err;
 
	status_t res;
	if (reply.FindInt32("midi:result", &res) == B_OK)
		return res;
 
	return B_ERROR;
}
 
 
bool
BMidiEndpoint::IsRegistered() const
{
	// No need to protect this with a lock, because reading
	// and writing a bool is always an atomic operation.
 
	return fIsRegistered;
}
 
 
bool
BMidiEndpoint::LockLooper() const
{
	return BMidiRoster::MidiRoster()->fLooper->Lock();
}
 
 
void
BMidiEndpoint::UnlockLooper() const
{
	BMidiRoster::MidiRoster()->fLooper->Unlock();
}
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fIsConsumer, _reserved.