// Copyright 2001-2005, Danger, Inc.  All Rights Reserved.
// This file is subject to the Danger, Inc. Sample Code License,
// which is provided in the file SAMPLE_CODE_LICENSE.
// Copies are also available from http://developer.danger.com/

package com.example.GUIDemo;

import danger.app.Application;
import danger.app.Event;
import danger.app.IPCMessage;
import danger.audio.RingToneObject;
import danger.ui.ActiveListView;
import danger.ui.AlertWindow;
import danger.ui.DialogWindow;
import danger.ui.LinkView;
import danger.ui.Menu;
import danger.ui.MenuItem;
import danger.ui.MultiModeButton;
import danger.ui.NumberEditor;
import danger.ui.PasswordTextField;
import danger.ui.ProgressBar;
import danger.ui.RingTonePicker;
import danger.ui.ScreenWindow;
import danger.ui.Scrollbar;
import danger.ui.TextInputAlertWindow;
import danger.ui.TypeAheadTextField;
import danger.ui.View;
import danger.util.DEBUG;
import danger.util.Folder;
import danger.util.StdActiveList;

/**
 * Implements a main window class. It is created from a Screen resource. The
 * layout starts with the DemoFolderView, and the StaticText header.
 */
public class ResourceWindow extends ScreenWindow implements Resources, Commands {

	/**
	 * Local reference for the application, to avoid the need for coercion.
	 */
	private static GUIDemo sApplication;

	/**
	 * The main scrolling view of all widgets to be displayed. It's the local
	 * subclass of the FolderView.
	 */
	private DemoFolderView mFolderView;

	// ------------------------------------------------------------------------
	/**
	 * This is called after the window has been created from resources.
	 * 
	 * At this point it will populate the DemoFolderView lists with all of the
	 * candidate Folders and Items in the folders. Those are defined in the
	 * resource file via the Menu for this ScreenWindow, so that this part of
	 * the program does not need to know how many there are, or how they are
	 * layed out.
	 */
	public void onDecoded() {
		// Get a coerced reference to the current App for later use.
		sApplication = (GUIDemo) Application.getCurrentApp();

		// Find the ScrollView descendant that the Table will be stuffed into.
		// It also must be the main focus, so that it will scroll when needed.
		View view = getDescendantWithID(ID_FOLDER_VIEW);

		mFolderView = new DemoFolderView(view.getFrame());
		mFolderView.setHasScrollbar(true);
		mFolderView.show();

		addChild(mFolderView);
		setFocusedChild(mFolderView);

		// The desired hierarchy for the FolderView is found in the Menu
		// resource for this WindowScreen. Drive the Menu structure, and plug
		// all the strings into Folders, and folderItems. The main menu is
		// the name of the Folder, the submenu has the item names and events.
		Folder folder;
		MenuItem item;
		Menu sub;
		Menu m = getActionMenu();

		for (int i = 0; i < m.itemCount(); i++) {
			item = m.getItem(i);
			if (item.hasSubmenu()) {
				folder = mFolderView.createFolder(item.getTitle());

				sub = item.getSubMenu();
				sub.collateMenuItems(); // sort the items.
				for (int j = 0; j < sub.itemCount(); j++) {
					folder.addItem(sub.getItem(j));
					if (sub.getItem(j).getEvent() == null) {
						sub.getItem(j).disable();
					}
				}
			}
		}

		super.onDecoded();
	}

	/**
	 * Handles device buttons, specifically the Jump, Cancel, and Done buttons.
	 */
	public boolean eventWidgetUp(int inWhichWidget, Event inEvent) {

		adjustActionMenuState(getActionMenu());

		switch (inWhichWidget) {
		// For both the Cancel or Back/Done button from the ResourceWindow, it
		// will jump back to the launcher screen to provide a better
		// experience.
		case Event.DEVICE_BUTTON_BACK:
			sApplication.returnToLauncher();
			return true;

		case Event.DEVICE_BUTTON_CANCEL:
			sApplication.returnToLauncher();
			return true;

		case Event.DEVICE_BUTTON_LEFT_SHOULDER:
			mFolderView.previousSelection();
			return true;

		case Event.DEVICE_BUTTON_RIGHT_SHOULDER:
			mFolderView.nextSelection();
			return true;

		case Event.DEVICE_ARROW_RIGHT:
			sApplication.showProgWindow();
			return true;
		}

		// Always make sure to call super.eventWidgetUp for other events so the
		// system can execute the correct behavior (e.g. returning to the Jump
		// screen with phone selected).
		return (super.eventWidgetUp(inWhichWidget, inEvent));
	}

	/**
	 * Handles events. Called automatically whenever this window receives an
	 * event. The only events handled are related to the menu. All other events
	 * are handled automatically by the window, by calling super.
	 * 
	 * Every demo item is shown here as a call to the resource file to create
	 * them.
	 */
	public boolean receiveEvent(Event e) {
		DialogWindow dialog;

		switch (e.type) {

		// Sent from a Done choice in a screen menu. Just hide the top
		// window to display this ResourceWindow. Hiding the top window
		// is preferable to just showing this window, as it can then
		// get garbage collected.
		case EVENT_HIDE:
			sApplication.getFrontWindow().hide();
			return true;

		case EVENT_SHOW_PROGRAMMATIC:
			sApplication.showProgWindow();
			return true;

		case EVENT_SHOW_RESOURCEBASED:
			show();
			return true;

		case EVENT_PREVIOUS:
			// Hide any prior screens that might be open.
			if (sApplication.getFrontWindow() != this) {
				sApplication.getFrontWindow().hide();
			}
			mFolderView.previousSelection();
			return true;

		case EVENT_NEXT:
			// Hide any prior screens that might be open.
			if (sApplication.getFrontWindow() != this) {
				sApplication.getFrontWindow().hide();
			}
			mFolderView.nextSelection();
			return true;

		/**
		 * When creating dialogs for all the examples below, the 'this'
		 * parameter is passed to the showDialog or getDialog, so that the
		 * events generated will be passed back here to be handled.
		 * 
		 * In particular, the HIDE_EVENT specified in the resource file would
		 * otherwise go to the dialog which doesn't know what to do.
		 */

		/** *************** Buttons & Boxes ********************** */
		case EVENT_BUTTON:
			dialog = sApplication.showDialog(ID_BUTTON, this);
			return true;

		case EVENT_CHECK_BOX:
			dialog = sApplication.showDialog(ID_CHECK_BOX, this);
			return true;

		case EVENT_CHECK_BOX_GROUP:
			dialog = sApplication.showDialog(ID_CHECK_BOX_GROUP, this);
			return true;

		case EVENT_MULTI_MODE_BUTTON:
			dialog = sApplication.showDialog(ID_MULTI_MODE_BUTTON, this);
			// Auto-advance is not set by default.
			View mmb = dialog.getControlWithID(ID_MULTI_VIEW);
			((MultiModeButton) mmb).setAutoAdvanceMode(true);
			return true;

		case EVENT_RADIO_BUTTON:
			dialog = sApplication.showDialog(ID_RADIO_BUTTON, this);
			return true;

		case EVENT_RADIO_BUTTON_GROUP:
			dialog = sApplication.showDialog(ID_RADIO_GROUP, this);
			return true;

		/** *************** Containers *************************** */
		case EVENT_CONTAINER:
			dialog = sApplication.showDialog(ID_CONTAINER, this);
			return true;

		case EVENT_GROUP_BOX:
			dialog = sApplication.showDialog(ID_GROUP_BOX, this);
			return true;

		case EVENT_ROUND_RECT_CONTAINER:
			dialog = sApplication.showDialog(ID_ROUND_RECT_CONTAINER, this);
			return true;

		case EVENT_SCROLL_VIEW:
			dialog = sApplication.showDialog(ID_SCROLL_VIEW, this);
			return true;

		/** *************** Menus ******************************** */
		// The ID_DEMO_MENU is attached to the screen, to allow Done.
		// Plus the textEditMenu. Note that the LRScreenWindow subclass (via
		// className in the resource file) of ScreenWindow is required to
		// implement adjustActionMenuState in order for textEditMenu to work
		// correctly.
		case EVENT_MENU:
			ScreenWindow screen = sApplication.getResources().getScreen(
					ID_MENU, this);
			screen.show();
			return true;

		/** *************** Misc Controls ************************ */
		// The ActiveListView has a complicated API, which this demo
		// can not do justice. This will thus just demonstrate a
		// simple list, and defer to a larger specific demo later.
		// Current Device examples of this class are the Terminal App
		// sessions list, and the Telephone App call log list.
		case EVENT_ACTIVE_LIST_VIEW:
			dialog = sApplication.getDialog(ID_ACTIVE_LIST_VIEW, this);
			ActiveListView listView = (ActiveListView) dialog
					.getDescendantWithID(ID_ACTIVE_VIEW);

			// Create a standard list, and fill it with the fruit strings.
			StdActiveList items = new StdActiveList();
			String[] fruits = sApplication.getStringArray(ID_FRUIT_STRINGS);
			for (int i = 0; i < fruits.length; i++) {
				items.addItem(fruits[i]);
			}
			listView.setList(items);

			dialog.show();
			return true;

		case EVENT_LINK_VIEW:
			String[] viewStrings = sApplication
					.getStringArray(ID_LINKVIEW_STRINGS);

			dialog = sApplication.getDialog(ID_LINK_VIEW, this);
			LinkView linkView = (LinkView) dialog
					.getDescendantWithID(ID_LINKIN_PARK);

			// Add two links to the dialog. Setting the events to be
			// generated to simply close the window, (this, EVENT_HIDE).
			linkView.addLink(LinkView.PHONE_ICON, viewStrings[0], new Event(
					this, EVENT_HIDE));
			linkView.addLink(LinkView.GLOBE_ICON, viewStrings[1], new Event(
					this, EVENT_HIDE));

			dialog.setSize(215, 120); // fixes 2.0 sizing bug
			dialog.show();
			return true;

		case EVENT_LIST_VIEW:
			dialog = sApplication.showDialog(ID_LIST_VIEW, this);
			return true;

		case EVENT_POPUP_MENU:
			dialog = sApplication.showDialog(ID_POPUP_MENU, this);
			return true;

		// A scroll bar by itself is not terribly useful. Normally this
		// will be next to another view, and updated by when that view
		// changes, using the setValue().
		case EVENT_SCROLL_BAR:
			dialog = sApplication.showDialog(ID_SCROLL_BAR, this);
			Scrollbar scrollBar = (Scrollbar) dialog
					.getDescendantWithID(ID_SCROLLY);
			scrollBar.setData(11, 20, 100);
			scrollBar.setValue(23);
			return true;

		case EVENT_SLIDER:
			dialog = sApplication.showDialog(ID_SLIDER, this);
			return true;

		/** *************** Misc Views *************************** */
		case EVENT_ANIMATED_BITMAP_VIEW:
			Version.showAnimatedBitmapView(this);
			return true;

		case EVENT_BATTERY_STATUS_VIEW:
			dialog = sApplication.showDialog(ID_BATTERY_STATUS_VIEW, this);
			return true;

		// Another example of this class can be found in the Email
		// program for the Accounts window.
		case EVENT_ICON_LABEL:
			dialog = sApplication.showDialog(ID_ICON_LABEL, this);
			return true;

		case EVENT_IMAGE:
			dialog = sApplication.showDialog(ID_IMAGE_VIEW, this);
			View image = dialog.getDescendantWithID(ID_IMAGINING);
			image.setHeight(45); // fix 2.0 sizing bug
			return true;

		case EVENT_RADIO_STATUS_VIEW:
			dialog = sApplication.showDialog(ID_RADIO_STATUS_VIEW, this);
			return true;

		// To animate the progress bar properly, it is necessary to call
		// advanceState() repeatedly. This just shows a static advanced state.
		case EVENT_PROGRESS_BAR:
			dialog = sApplication.showDialog(ID_PROGRESS_BAR, this);
			View throbber = dialog.getDescendantWithID(ID_THROBBER);
			for (int i = 0; i < 15; i++) {
				((ProgressBar) throbber).advanceState();
			}
			return true;

		case EVENT_SHAPE:
			dialog = sApplication.showDialog(ID_SHAPE, this);
			return true;

		case EVENT_VIEW:
			dialog = sApplication.showDialog(ID_VIEW, this);
			return true;

		/** *************** Pickers ****************************** */
		case EVENT_DATE_PICKER:
			dialog = sApplication.showDialog(ID_DATE_PICKER, this);
			return true;

		case EVENT_DATE_EDITOR:
			dialog = sApplication.showDialog(ID_DATE_EDITOR, this);
			return true;

		case EVENT_NUMBER_EDITOR:
			dialog = sApplication.getDialog(ID_NUMBER_EDITOR, this);

			// Set up the event to be sent upon completion of the dialog.
			// This will send the EVENT_NUMBER_EDITOR_RESULT, to allow access 
			// to the end result. The argument being set is to the dialog
			// being created, allowing for easy access to the end result.
			dialog.setEventArgForControlWithID(ID_NUMBER_EDITOR_DONE, dialog);
			dialog.show();
			return true;
			
		case EVENT_NUMBER_EDITOR_RESULT:
			// The argument was set above to be the NumberEditor 
			// dialog, so that this can easily get to the subview
			// to fetch the chosen NumberEditor.
			dialog = (DialogWindow) e.argument;
			NumberEditor numberView = (NumberEditor) dialog
					.getChildWithID(ID_NUMBER_VIEW);

			// Here is where the final result is found from the user choice.
			int finalNumber = numberView.getValue();
			DEBUG.p("EVENT_NUMBER_EDITOR_RESULT: " + finalNumber);
			return true;

		case EVENT_RING_TONE_PICKER:
			dialog = sApplication.getDialog(ID_RING_TONE_PICKER, this);
			
			// Set up the event to be sent upon completion of the dialog.
			// This will send the EVENT_RING_TONE_RESULT, to allow access 
			// to the end result. The argument being set is to the dialog
			// being created, allowing for easy access to the end result.
			dialog.setEventArgForControlWithID(ID_RING_TONE_DONE, dialog);
			dialog.show();
			return true;

		case EVENT_RING_TONE_RESULT:
			// The argument was set above to be the RingTonePicker 
			// dialog, so that this can easily get to the subview
			// to fetch the chosen RingToneObject.
			dialog = (DialogWindow) e.argument;
			RingTonePicker pickerView = (RingTonePicker) dialog
					.getChildWithID(ID_TONE_VIEW);

			// Here is where the final result is found from the user choice.
			RingToneObject chosen = pickerView.getRingTone();
			DEBUG.p("EVENT_RING_TONE_RESULT: " + chosen.getName());
			return true;

		// ToDo: probably make 2.3 specific version with photo picker icon.
		case EVENT_ICON_PICKER:
			dialog = sApplication.showDialog(ID_ICON_PICKER, this);
			return true;

		/** *************** Screens & Dialogs ******************** */
		case EVENT_ALERT_WINDOW:
			dialog = sApplication.showAlert(ID_ALERT_WINDOW, this);
			return true;

		// Since the program is full of standard dialogs, this variant for
		// the DialogWindow resource itself will show more complex uses of
		// the Dialog. The resource specifies a System dialog, and thus
		// requires the sleepScreenMessage here.
		case EVENT_DIALOG_WINDOW:
			dialog = sApplication.getDialog(ID_DIALOG_WINDOW, this);
			dialog.setSleepScreenMessage(sApplication
					.getString(ID_SLEEP_MESSAGE));
			dialog.show();
			return true;

		// The TextInputAlertWindow will send the EVENT_PASSWORD_TEXT after the
		// text is accepted, as specified in the resource file.
		case EVENT_TEXT_INPUT_ALERT:
			dialog = sApplication.getTextInputAlert(ID_TEXT_INPUT_ALERT, this);
			dialog.setShowCancel(false);
			dialog.show();
			return true;

		// The TextInputAlert above will send this event upon Done. This
		// demonstrates how to extract the text from the alert, for later use.
		case EVENT_PASSWORD_TEXT:
			String password = TextInputAlertWindow.getTextFieldValue(
					(IPCMessage) e.argument, ID_PASSWORD_FIELD);
			AlertWindow aw = sApplication.showAlert(ID_SHOW_PASSWORD_ALERT);
			aw.setMessage(password);
			return true;

		// The ID_SCREENS_MENU is attached to this screen, to allow Done.
		case EVENT_SCREEN_WINDOW:
			ScreenWindow sw = sApplication.getResources().getScreen(
					ID_SCREEN_WINDOW, this);
			sw.show();
			return true;

		/** *************** Text ************************************ */
		case EVENT_STATIC_TEXT:
			dialog = sApplication.showDialog(ID_STATIC_TEXT, this);
			return true;

		case EVENT_EDIT_TEXT:
			dialog = sApplication.showDialog(ID_EDIT_TEXT, this);
			return true;

		case EVENT_STATIC_TEXT_BOX:
			dialog = sApplication.showDialog(ID_STATIC_TEXT_BOX, this);
			return true;

		case EVENT_TEXT_FIELD:
			dialog = sApplication.showDialog(ID_TEXT_FIELD, this);
			return true;

		case EVENT_TYPE_AHEAD_TEXT_FIELD:
			dialog = sApplication.getDialog(ID_TYPE_AHEAD_TEXT_FIELD, this);
			TypeAheadTextField v = (TypeAheadTextField) dialog
					.getChildWithID(ID_TYPE_AHEAD_VIEW);
			v.setTextFinder(new FruitFinder());
			dialog.setShowCancel(false);

			// The listener defaults to the owning dialog, which is not set up
			// to handle the WidgetUp events, and will overflow the stack.
			// Setting it to null means the TypeAheadTextField handles them.
			v.setListener(null);
			dialog.show();

			// Under 2.0, the resource spec of initialFocus deselects the text,
			// specified by initiallySelectAll. This reselects the text, to
			// make the demo more sensible.
			v.selectAll();
			return true;

		case EVENT_PASSWORD_TEXT_FIELD:
			dialog = sApplication.getDialog(ID_PASSWORD_TEXT_FIELD, this);

			// Set up the event to be sent upon completion of the dialog.
			// This will send the EVENT_PASSWORD_TEXT_RESULT, to allow access 
			// to the end result. The argument being set is to the dialog
			// being created, allowing for easy access to the end result.
			dialog.setEventArgForControlWithID(ID_PASSWORD_TEXT_DONE, dialog);
			dialog.show();
			return true;

		case EVENT_PASSWORD_TEXT_RESULT:
			// The argument was set above to be the PasswordText 
			// dialog, so that this can easily get to the subview
			// to fetch the chosen text field.
			dialog = (DialogWindow) e.argument;
			PasswordTextField passwordView = (PasswordTextField) dialog
					.getChildWithID(ID_PASSWORD_VIEW);

			// Here is where the final result is found from the user choice.
			String passwordString = passwordView.toString();
			DEBUG.p("EVENT_NUMBER_EDITOR_RESULT: " + passwordString);
			return true;


		case EVENT_LABELED_GRID:
			dialog = sApplication.showDialog(ID_LABELED_GRID, this);
			return true;
		}

		return super.receiveEvent(e);
	}
}
