/*
 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Jonas Sundström, jonas@kirilla.com
 */
 
 
#include "ZipOMatic.h"
 
#include <Alert.h>
#include <Roster.h>
#include <StringFormat.h>
#include <TrackerAddOnAppLaunch.h>
 
#include "ZipOMaticMisc.h"
#include "ZipOMaticWindow.h"
 
 
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "file:ZipOMatic.cpp"
 
 
int
main()
{
	ZipOMatic app;
	app.Run();
 
	return 0;
}
 
 
ZipOMatic::ZipOMatic()
	:
	BApplication(ZIPOMATIC_APP_SIG),
	fGotRefs(false),
	fInvoker(new BInvoker(new BMessage(ZIPPO_QUIT_OR_CONTINUE), NULL, this))
{
}
 
 
ZipOMatic::~ZipOMatic()
{
}
 
 
void
ZipOMatic::RefsReceived(BMessage* message)
{
	entry_ref ref;
	if (message->FindRef("refs", &ref) == B_OK) {
		_UseExistingOrCreateNewWindow(message);
		fGotRefs = true;
	} else if (!IsLaunching()) {
		PostMessage(B_SILENT_RELAUNCH);
	}
}
 
 
void
ZipOMatic::ReadyToRun()
{
	if (!fGotRefs)
		_UseExistingOrCreateNewWindow();
}
 
 
void
ZipOMatic::MessageReceived(BMessage* message)
{
	switch (message->what) {
		case ZIPPO_WINDOW_QUIT:
		{
			snooze(200000);
			if (CountWindows() == 0)
				Quit();
			break;
		}
		case B_SILENT_RELAUNCH:
			_SilentRelaunch();
			break;
 
		case ZIPPO_QUIT_OR_CONTINUE:
		{
			int32 button;
			if (message->FindInt32("which", &button) == B_OK) {
				if (button == 0) {
					_StopZipping();
				} else {
					if (CountWindows() == 0)
						Quit();
				}
			}
			break;
		}
 
		default:
			BApplication::MessageReceived(message);
			break;
	}
}
 
 
bool
ZipOMatic::QuitRequested(void)
{
	if (CountWindows() <= 0)
		return true;
 
	BWindow* window;
	ZippoWindow* zippo;
	ZippoWindow* lastFoundZippo = NULL;
	int32 zippoCount = 0;
 
	for (int32 i = 0;; i++) {
		window = WindowAt(i);
		if (window == NULL)
			break;
 
		zippo = dynamic_cast<ZippoWindow*>(window);
		if (zippo == NULL)
			continue;
 
		lastFoundZippo = zippo;
 
		if (zippo->Lock()) {
			if (zippo->IsZipping())
				zippoCount++;
			else
				zippo->PostMessage(B_QUIT_REQUESTED);
 
			zippo->Unlock();
		}
	}
 
	if (zippoCount == 1) {
		// This is likely the most frequent case - a single zipper.
		// We post a message to the window so it can put up its own
		// BAlert instead of the app-wide BAlert. This avoids making
		// a difference between having pressed Commmand-W or Command-Q.
		// Closing or quitting, it doesn't matter for a single window.
 
		if (lastFoundZippo->Lock()) {
			lastFoundZippo->Activate();
			lastFoundZippo->PostMessage(B_QUIT_REQUESTED);
			lastFoundZippo->Unlock();
		}
		return false;
	}
 
	if (zippoCount > 0) {
		// The multi-zipper case differs from the single-zipper case
		// in that zippers are not paused while the BAlert is up.
 
		static BStringFormat format(
			B_TRANSLATE("You have {0, plural, one{# Zip-O-Matic} "
				"other{# Zip-O-Matics}} running.\n\n"));
 
		BString question;
 
		format.Format(question, zippoCount);
 
		question << B_TRANSLATE("Do you want to stop them?");
 
		BAlert* alert = new BAlert(NULL, question.String(),
			B_TRANSLATE("Stop them"), B_TRANSLATE("Let them continue"), NULL,
			B_WIDTH_AS_USUAL, B_WARNING_ALERT);
		alert->Go(fInvoker);
		alert->Activate();
			// BAlert, being modal, does not show on the current workspace
			// if the application has no window there. Activate() triggers
			// a switch to a workspace where it does have a window.
 
			// TODO: See if AS_ACTIVATE_WINDOW should be handled differently
			// in src/servers/app/Desktop.cpp Desktop::ActivateWindow()
			// or if maybe BAlert should (and does not?) activate itself.
 
		return false;
	}
 
	if (CountWindows() <= 0)
		return true;
 
	return false;
}
 
 
void
ZipOMatic::_SilentRelaunch()
{
	_UseExistingOrCreateNewWindow();
}
 
 
void
ZipOMatic::_UseExistingOrCreateNewWindow(BMessage* message)
{
	int32 windowCount = 0;
	BWindow* bWindow;
	ZippoWindow* zWindow;
	BList list;
 
	while (1) {
		bWindow = WindowAt(windowCount++);
		if (bWindow == NULL)
			break;
 
		zWindow = dynamic_cast<ZippoWindow*>(bWindow);
		if (zWindow == NULL)
			continue;
 
		list.AddItem(zWindow);
 
		if (zWindow->Lock()) {
			if (!zWindow->IsZipping()) {
				if (message != NULL)
					zWindow->PostMessage(message);
				zWindow->SetWorkspaces(B_CURRENT_WORKSPACE);
				zWindow->Activate();
				zWindow->Unlock();
				return;
			}
			zWindow->Unlock();
		}
	}
 
	if (message) {
		zWindow = new ZippoWindow(list);
		zWindow->PostMessage(message);
	} else {
		zWindow = new ZippoWindow(list, true);
	}
 
	zWindow->Show();
}
 
 
void
ZipOMatic::_StopZipping()
{
	BWindow* window;
	ZippoWindow* zippo;
	BList list;
 
	for (int32 i = 0;; i++) {
		window = WindowAt(i);
		if (window == NULL)
			break;
 
		zippo = dynamic_cast<ZippoWindow*>(window);
		if (zippo == NULL)
			continue;
 
		list.AddItem(zippo);
	}
 
	for (int32 i = 0;; i++) {
		zippo = static_cast<ZippoWindow*>(list.ItemAt(i));
		if (zippo == NULL)
			break;
 
		if (zippo->Lock()) {
			if (zippo->IsZipping())
				zippo->StopZipping();
 
			zippo->PostMessage(B_QUIT_REQUESTED);
			zippo->Unlock();
		}
	}
}
 

V773 The function was exited without releasing the 'alert' pointer. A memory leak is possible.