/*
 * Copyright 2009-2010, Philippe Houdoin, phoudoin@haiku-os.org. All rights reserved.
 * Copyright 2013-2016, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */
#include "TeamsWindow.h"
 
 
#include <new>
 
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
 
#include <Application.h>
#include <Button.h>
#include <File.h>
#include <FilePanel.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <ListView.h>
#include <Menu.h>
#include <MenuField.h>
#include <Path.h>
#include <Screen.h>
#include <ScrollView.h>
 
#include <AutoDeleter.h>
#include <AutoLocker.h>
 
#include "AppMessageCodes.h"
#include "SettingsManager.h"
#include "TargetHostInterface.h"
#include "TargetHostInterfaceRoster.h"
#include "TeamsListView.h"
 
 
enum {
	MSG_TEAM_SELECTION_CHANGED = 'tesc',
	MSG_CHOSE_CORE_FILE = 'chcf',
	MSG_SWITCH_TARGET_CONNECTION = 'stco'
};
 
 
TeamsWindow::TeamsWindow(SettingsManager* settingsManager)
	:
	BWindow(BRect(100, 100, 500, 250), "Teams", B_DOCUMENT_WINDOW,
		B_ASYNCHRONOUS_CONTROLS),
	fTargetHostInterface(NULL),
	fTeamsListView(NULL),
	fAttachTeamButton(NULL),
	fCreateTeamButton(NULL),
	fLoadCoreButton(NULL),
	fConnectionField(NULL),
	fCoreSelectionPanel(NULL),
	fSettingsManager(settingsManager),
	fListeners()
{
	team_info info;
	get_team_info(B_CURRENT_TEAM, &info);
	fCurrentTeam = info.team;
}
 
 
TeamsWindow::~TeamsWindow()
{
}
 
 
/*static*/ TeamsWindow*
TeamsWindow::Create(SettingsManager* settingsManager)
{
	TeamsWindow* self = new TeamsWindow(settingsManager);
 
	try {
		self->_Init();
	} catch (...) {
		delete self;
		throw;
	}
 
	return self;
}
 
 
void
TeamsWindow::Zoom(BPoint, float, float)
{
	BSize preferredSize = fTeamsListView->PreferredSize();
	ResizeBy(preferredSize.Width() - Bounds().Width(),
		0.0);
 
	// if the new size would extend us past the screen border,
	// move sufficiently to the left to bring us back within the bounds
	// + a bit of extra margin so we're not flush against the edge.
	BScreen screen;
	float offset = screen.Frame().right - Frame().right;
	if (offset < 0)
		MoveBy(offset - 5.0, 0.0);
}
 
 
void
TeamsWindow::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case MSG_DEBUG_THIS_TEAM:
		{
			TeamRow* row = dynamic_cast<TeamRow*>(
				fTeamsListView->CurrentSelection());
			if (row != NULL) {
				BMessage message(MSG_DEBUG_THIS_TEAM);
				message.AddInt32("team", row->TeamID());
				message.AddPointer("interface", fTargetHostInterface);
				be_app_messenger.SendMessage(&message);
			}
			break;
		}
 
		case MSG_TEAM_SELECTION_CHANGED:
		{
			TeamRow* row = dynamic_cast<TeamRow*>(
				fTeamsListView->CurrentSelection());
			bool enabled = false;
			if (row != NULL) {
				team_id id = row->TeamID();
				if (id != fCurrentTeam && id != B_SYSTEM_TEAM)
					enabled = true;
			}
 
			fAttachTeamButton->SetEnabled(enabled);
			break;
		}
 
		case MSG_SHOW_START_TEAM_WINDOW:
		{
			BMessage startMessage(*message);
			startMessage.AddPointer("interface", fTargetHostInterface);
			be_app_messenger.SendMessage(&startMessage);
			break;
		}
 
		case MSG_CHOSE_CORE_FILE:
		case B_CANCEL:
		{
			delete fCoreSelectionPanel;
			fCoreSelectionPanel = NULL;
			if (message->what == B_CANCEL)
				break;
 
			entry_ref ref;
			if (message->FindRef("refs", &ref) != B_OK)
				break;
 
			BMessage coreMessage(MSG_LOAD_CORE_TEAM);
			coreMessage.AddPointer("interface", fTargetHostInterface);
			coreMessage.AddRef("core", &ref);
			be_app_messenger.SendMessage(&coreMessage);
			break;
		}
 
		case MSG_LOAD_CORE_TEAM:
		{
			try {
				BMessenger messenger(this);
				fCoreSelectionPanel = new BFilePanel(B_OPEN_PANEL, &messenger,
					NULL, 0, false, new BMessage(MSG_CHOSE_CORE_FILE));
				fCoreSelectionPanel->Show();
			} catch (...) {
				delete fCoreSelectionPanel;
				fCoreSelectionPanel = NULL;
			}
			break;
		}
 
		case MSG_SWITCH_TARGET_CONNECTION:
		{
			TargetHostInterface* interface;
			if (message->FindPointer("interface", reinterpret_cast<void**>(
					&interface)) != B_OK) {
				break;
			}
 
			if (interface == fTargetHostInterface)
				break;
 
			fTargetHostInterface = interface;
			_NotifySelectedInterfaceChanged(interface);
			fLoadCoreButton->SetEnabled(fTargetHostInterface->IsLocal());
			break;
		}
 
		default:
			BWindow::MessageReceived(message);
			break;
	}
}
 
 
bool
TeamsWindow::QuitRequested()
{
	_SaveSettings();
 
	be_app_messenger.SendMessage(MSG_TEAMS_WINDOW_CLOSED);
	return true;
}
 
 
void
TeamsWindow::AddListener(Listener* listener)
{
	AutoLocker<TeamsWindow> locker(this);
	fListeners.Add(listener);
}
 
 
void
TeamsWindow::RemoveListener(Listener* listener)
{
	AutoLocker<TeamsWindow> locker(this);
	fListeners.Remove(listener);
}
 
 
// #pragma mark --
 
 
void
TeamsWindow::_Init()
{
	BMessage settings;
	_LoadSettings(settings);
 
	BRect frame;
	if (settings.FindRect("teams window frame", &frame) == B_OK) {
		MoveTo(frame.LeftTop());
		ResizeTo(frame.Width(), frame.Height());
	}
 
	BMenu* connectionMenu = new BMenu("Connection");
	ObjectDeleter<BMenu> menuDeleter(connectionMenu);
	connectionMenu->SetLabelFromMarked(true);
 
	TargetHostInterfaceRoster* roster = TargetHostInterfaceRoster::Default();
	for (int32 i = 0; i < roster->CountActiveInterfaces(); i++) {
		TargetHostInterface* interface = roster->ActiveInterfaceAt(i);
		BMenuItem* item = new BMenuItem(interface->GetTargetHost()->Name(),
			new BMessage(MSG_SWITCH_TARGET_CONNECTION));
		if (item->Message()->AddPointer("interface", interface) != B_OK) {
			delete item;
			throw std::bad_alloc();
		}
 
		if (interface->IsLocal()) {
			item->SetMarked(true);
			fTargetHostInterface = interface;
		}
 
		connectionMenu->AddItem(item);
	}
 
	BGroupLayout* connectionLayout = NULL;
 
	BLayoutBuilder::Group<>(this, B_VERTICAL)
		.AddGroup(B_HORIZONTAL)
			.SetInsets(B_USE_DEFAULT_SPACING)
			.GetLayout(&connectionLayout)
			.Add(fConnectionField = new BMenuField("Connected to:",
				connectionMenu))
			.AddGlue()
			.Add(fCreateConnectionButton = new BButton("Create new connection"
					B_UTF8_ELLIPSIS, new BMessage(
						MSG_SHOW_CONNECTION_CONFIG_WINDOW)))
		.End()
		.Add(fTeamsListView = new TeamsListView("TeamsList"))
		.SetInsets(1.0f, 1.0f, 1.0f, 5.0f)
		.AddGroup(B_HORIZONTAL)
			.SetInsets(B_USE_DEFAULT_SPACING)
			.Add(fAttachTeamButton = new BButton("Attach", new BMessage(
					MSG_DEBUG_THIS_TEAM)))
			.AddGlue()
			.Add(fCreateTeamButton = new BButton("Start new team"
					B_UTF8_ELLIPSIS, new BMessage(MSG_SHOW_START_TEAM_WINDOW)))
			.Add(fLoadCoreButton = new BButton("Load core" B_UTF8_ELLIPSIS,
					new BMessage(MSG_LOAD_CORE_TEAM)))
			.End()
		.End();
 
	connectionLayout->SetVisible(false);
 
	menuDeleter.Detach();
 
	AddListener(fTeamsListView);
 
	connectionMenu->SetTargetForItems(this);
 
	fTeamsListView->SetInvocationMessage(new BMessage(MSG_DEBUG_THIS_TEAM));
	fTeamsListView->SetSelectionMessage(new BMessage(
			MSG_TEAM_SELECTION_CHANGED));
 
	fAttachTeamButton->SetEnabled(false);
	fCreateTeamButton->SetTarget(this);
	fLoadCoreButton->SetTarget(this);
	fCreateConnectionButton->SetTarget(be_app);
 
	_NotifySelectedInterfaceChanged(fTargetHostInterface);
}
 
 
status_t
TeamsWindow::_OpenSettings(BFile& file, uint32 mode)
{
	BPath path;
	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
		return B_ERROR;
 
	path.Append("Debugger settings");
 
	return file.SetTo(path.Path(), mode);
}
 
 
status_t
TeamsWindow::_LoadSettings(BMessage& settings)
{
	BFile file;
	status_t status = _OpenSettings(file, B_READ_ONLY);
	if (status < B_OK)
		return status;
 
	return settings.Unflatten(&file);
}
 
 
status_t
TeamsWindow::_SaveSettings()
{
	BFile file;
	status_t status = _OpenSettings(file,
		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
 
	if (status < B_OK)
		return status;
 
	BMessage settings('hdbg');
	status = settings.AddRect("teams window frame", Frame());
	if (status != B_OK)
		return status;
 
	if (status == B_OK)
		status = settings.Flatten(&file);
 
	return status;
}
 
 
void
TeamsWindow::_NotifySelectedInterfaceChanged(TargetHostInterface* interface)
{
	for (ListenerList::Iterator it = fListeners.GetIterator();
			Listener* listener = it.Next();) {
		listener->SelectedInterfaceChanged(interface);
	}
}
 
 
// #pragma mark - TeamsWindow::Listener
 
 
TeamsWindow::Listener::~Listener()
{
}

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

V547 Expression 'status == ((int) 0)' is always true.