/*
 * Copyright 2010, Haiku.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Clemens Zeidler <haiku@clemens-zeidler.de>
 */


#include "WindowStack.h"

#include <new>

#include <Window.h>

#ifndef HoG_GENODE
#include <ApplicationPrivate.h>
#include <MessengerPrivate.h>
#include <PortLink.h>
#include <ServerProtocol.h>

#include "StackAndTilePrivate.h"


using namespace BPrivate;
#else  // HoG_GENODE:
#	include <app/Messenger.h>
#endif  // ~HoG_GENODE


BWindowStack::BWindowStack(BWindow* window)
{
///later: SAT... probably won't happen any time soon?
#ifndef HoG_GENODE
	fLink = window->fLink;
#endif  // ~HoG_GENODE
}


BWindowStack::~BWindowStack()
{

}


status_t
BWindowStack::AddWindow(const BWindow* window)
{
	BMessenger messenger(window);
	return AddWindow(messenger);
}


status_t
BWindowStack::AddWindow(const BMessenger& window)
{
	return AddWindowAt(window, -1);
}


status_t
BWindowStack::AddWindowAt(const BWindow* window, int32 position)
{
	BMessenger messenger(window);
	return AddWindowAt(messenger, position);
}


status_t
BWindowStack::AddWindowAt(const BMessenger& , int32 position)
{
#ifndef HoG_GENODE
	_StartMessage(kAddWindowToStack);

	_AttachMessenger(window);
	fLink->Attach<int32>(position);

	int32 code = B_ERROR;
	if (fLink->FlushWithReply(code) != B_OK)
		return code;
#endif  // ~HoG_GENODE

	return B_OK;
}


status_t
BWindowStack::RemoveWindow(const BWindow* window)
{
	BMessenger messenger(window);
	return RemoveWindow(messenger);
}


status_t
BWindowStack::RemoveWindow(const BMessenger& window)
{
#ifndef HoG_GENODE
	_StartMessage(kRemoveWindowFromStack);
	_AttachMessenger(window);

	if (fLink->Flush() != B_OK)
		return B_ERROR;
#endif  // ~HoG_GENODE

	return B_OK;
}


status_t
BWindowStack::RemoveWindowAt(int32 position, BMessenger* window)
{
#ifndef HoG_GENODE
	_StartMessage(kRemoveWindowFromStackAt);
	fLink->Attach<int32>(position);

	int32 code = B_ERROR;
	if (fLink->FlushWithReply(code) != B_OK)
		return code;
#endif  // ~HoG_GENODE

	if (window == NULL)
		return B_OK;

	return _ReadMessenger(*window);
}


int32
BWindowStack::CountWindows()
{
#ifndef HoG_GENODE
	_StartMessage(kCountWindowsOnStack);

	int32 code = B_ERROR;
	fLink->FlushWithReply(code);
	if (code != B_OK)
		return -1;

	int32 count;
	if (fLink->Read<int32>(&count) != B_OK)
		return -1;

	return count;
#else  // HoG_GENODE
	return -1;
#endif  // ~HoG_GENODE
}


status_t
BWindowStack::WindowAt(int32 , BMessenger& messenger)
{
#ifndef HoG_GENODE
	_StartMessage(kWindowOnStackAt);
	fLink->Attach<int32>(position);

	int32 code = B_ERROR;
	fLink->FlushWithReply(code);
	if (code != B_OK)
		return code;

	return _ReadMessenger(messenger);
#else  // HoG_GENODE
	return -1;
#endif  // ~HoG_GENODE
}


bool
BWindowStack::HasWindow(const BWindow* window)
{
	BMessenger messenger(window);
	return HasWindow(messenger);
}


bool
BWindowStack::HasWindow(const BMessenger& window)
{
#ifndef HoG_GENODE
	_StartMessage(kStackHasWindow);
	_AttachMessenger(window);

	int32 code = B_ERROR;
	fLink->FlushWithReply(code);
	if (code != B_OK)
		return false;

	bool hasWindow;
	if (fLink->Read<bool>(&hasWindow) != B_OK)
		return false;
		
	return hasWindow;
#else  // HoG_GENODE
	return false;
#endif  // ~HoG_GENODE
}


status_t
BWindowStack::_AttachMessenger(const BMessenger& window)
{
#ifndef HoG_GENODE
	BMessenger::Private messengerPrivate(const_cast<BMessenger&>(window));
	fLink->Attach<port_id>(messengerPrivate.Port());
	fLink->Attach<int32>(messengerPrivate.Token());
	return fLink->Attach<team_id>(messengerPrivate.Team());
#else  // HoG_GENODE
	return -1;
#endif  // ~HoG_GENODE
}


status_t
BWindowStack::_ReadMessenger(BMessenger& window)
{
#ifndef HoG_GENODE
	port_id port;
	int32 token;
	team_id team;
	fLink->Read<port_id>(&port);
	fLink->Read<int32>(&token);
	status_t status = fLink->Read<team_id>(&team);
	if (status != B_OK)
		return status;
	BMessenger::Private messengerPrivate(window);
	messengerPrivate.SetTo(team, port, token);
#endif  // ~HoG_GENODE
	return B_OK;
}


status_t
BWindowStack::_StartMessage(int32 what)
{
#ifndef HoG_GENODE
	fLink->StartMessage(AS_TALK_TO_DESKTOP_LISTENER);
	fLink->Attach<int32>(kMagicSATIdentifier);
	fLink->Attach<int32>(kStacking);
	return fLink->Attach<int32>(what);
#else  // HoG_GENODE
	return -1;
#endif  // ~HoG_GENODE
}

