/** 
 * @file llviewermenu.cpp
 * @brief Builds menus out of items.
 *
 * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
 * $License$
 */

#include "llviewerprecompiledheaders.h"

#include "llviewermenu.h" 

// system library includes
#include <iostream>
#include <fstream>
#include <sstream>
#include <boost/tokenizer.hpp>

// linden library includes
#include "audioengine.h"
#include "indra_constants.h"
#include "llassetuploadresponders.h"
#include "llassetstorage.h"
#include "llchat.h"
#include "lleconomy.h"
#include "llfocusmgr.h"
#include "llfontgl.h"
#include "llinstantmessage.h"
#include "llpermissionsflags.h"
#include "llrect.h"
#include "llsecondlifeurls.h"
#include "lltransactiontypes.h"
#include "llui.h"
#include "llview.h"
#include "llxfermanager.h"
#include "message.h"
#include "raytrace.h"
#include "llsdserialize.h"
#include "lltimer.h"
#include "vorbisencode.h"
#include "llvfile.h"
#include "llvolumemgr.h"
#include "llwindow.h"	// for shell_open()

// newview includes
#include "llagent.h"
#include "llagentpilot.h"
#include "llbox.h"
#include "llcallingcard.h"
#include "llcameraview.h"
#include "llclipboard.h"
#include "llcompilequeue.h"
#include "llconsole.h"
#include "llviewercontrol.h"
#include "lldebugview.h"
#include "lldir.h"
#include "lldrawable.h"
#include "lldrawpoolalpha.h"
#include "lldrawpoolhud.h"
#include "lldrawpooltree.h"
#include "llface.h"
#include "llfirstuse.h"
#include "llfloater.h"
#include "llfloaterabout.h"
#include "llfloaterbuycurrency.h"
#include "llfloateranimpreview.h"
#include "llfloateravatarinfo.h"
#include "llfloateravatartextures.h"
#include "llfloaterbuildoptions.h"
#include "llfloaterbump.h"
#include "llfloaterbuy.h"
#include "llfloaterbuycontents.h"
#include "llfloaterbuycurrency.h"
#include "llfloaterbuyland.h"
#include "llfloaterchat.h"
#include "llfloatercustomize.h"
#include "llfloaterdirectory.h"
#include "llfloatereditui.h"
#include "llfloaterfriends.h"
#include "llfloatergesture.h"
#include "llfloatergodtools.h"
#include "llfloatergroupinfo.h"
#include "llfloatergroups.h"
#include "llfloaterhtmlhelp.h"
#include "llfloaterhtmlfind.h"
#include "llfloaterimport.h"
#include "llfloaterland.h"
#include "llfloaterlandholdings.h"
#include "llfloatermap.h"
#include "llfloateraccounthistory.h"
#include "llfloaterimagepreview.h"
#include "llfloatermute.h"
#include "llfloaternamedesc.h"
#include "llfloateropenobject.h"
#include "llfloaterpermissionsmgr.h"
#include "llfloaterpreference.h"
#include "llfloaterrate.h"
#include "llfloaterregioninfo.h"
#include "llfloaterreporter.h"
#include "llfloaterscriptdebug.h"
#include "llfloatersnapshot.h"
#include "llfloatertest.h"
#include "llfloatertools.h"
#include "llfloaterworldmap.h"
#include "llframestats.h"
#include "llframestatview.h"
#include "llfasttimerview.h"
#include "llmemoryview.h"
#include "llgivemoney.h"
#include "llgroupmgr.h"
#include "llhoverview.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llimage.h"
#include "llimagebmp.h"
#include "llimagej2c.h"
#include "llimagetga.h"
#include "llinventorymodel.h"
#include "llinventoryview.h"
#include "llkeyboard.h"
#include "llpanellogin.h"
#include "llmenucommands.h"
#include "llmenugl.h"
#include "llmorphview.h"
#include "llmoveview.h"
#include "llmutelist.h"
#include "llnotify.h"
#include "llpanelobject.h"
#include "llparcel.h"
#include "llpreviewscript.h"
#include "llpreviewtexture.h"
#include "llprimitive.h"
#include "llresmgr.h"
#include "llselectmgr.h"
#include "llsky.h"
#include "llstatusbar.h"
#include "llstatview.h"
#include "llstring.h"
#include "llsurfacepatch.h"
#include "llimview.h"
#include "lltextureview.h"
#include "lltool.h"
#include "lltoolbar.h"
#include "lltoolcomp.h"
#include "lltoolfocus.h"
#include "lltoolgrab.h"
#include "lltoolmgr.h"
#include "lltoolpie.h"
#include "lltoolplacer.h"
#include "lltoolselectland.h"
#include "llvieweruictrlfactory.h"
#include "lluploaddialog.h"
#include "lluserauth.h"
#include "lluuid.h"
#include "llvelocitybar.h"
#include "llviewercamera.h"
#include "llviewergesture.h"
#include "llviewerimagelist.h"
#include "llviewerinventory.h"
#include "llviewermessage.h"
#include "llviewernetwork.h"
#include "llviewerobjectlist.h"
#include "llviewerparcelmgr.h"
#include "llviewerparceloverlay.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewerwindow.h"
#include "llvoavatar.h"
#include "llvolume.h"
#include "llweb.h"
#include "llworld.h"
#include "llworldmap.h"
#include "object_flags.h"
#include "pipeline.h"
#include "viewer.h"
#include "roles_constants.h"

#include "lltexlayer.h"

void init_client_menu(LLMenuGL* menu);
void init_server_menu(LLMenuGL* menu);

void init_debug_world_menu(LLMenuGL* menu);
void init_debug_rendering_menu(LLMenuGL* menu);
void init_debug_ui_menu(LLMenuGL* menu);
void init_debug_xui_menu(LLMenuGL* menu);
void init_debug_avatar_menu(LLMenuGL* menu);
void init_debug_baked_texture_menu(LLMenuGL* menu);

BOOL enable_land_build(void*);
BOOL enable_object_build(void*);

LLVOAvatar* find_avatar_from_object( LLViewerObject* object );
LLVOAvatar* find_avatar_from_object( const LLUUID& object_id );

void handle_test_load_url(void*);

extern void disconnect_viewer(void *);

//
// Evil hackish imported globals
//
extern BOOL	gRenderLightGlows;
extern BOOL gRenderAvatar;
extern BOOL	gHideSelectedObjects;
extern BOOL gShowOverlayTitle;
extern BOOL gRandomizeFramerate;
extern BOOL gPeriodicSlowFrame;
extern BOOL gOcclusionCull;
extern BOOL gAllowSelectAvatar;

//
// Globals
//

LLMenuBarGL		*gMenuBarView = NULL;
LLViewerMenuHolderGL	*gMenuHolder = NULL;
LLMenuGL		*gPopupMenuView = NULL;

// Pie menus
LLPieMenu	*gPieSelf	= NULL;
LLPieMenu	*gPieAvatar = NULL;
LLPieMenu	*gPieObject = NULL;
LLPieMenu	*gPieAttachment = NULL;
LLPieMenu	*gPieLand	= NULL;

// local constants
const LLString CLIENT_MENU_NAME("Client");
const LLString SERVER_MENU_NAME("Server");

const LLString SAVE_INTO_INVENTORY("Save Object Back to My Inventory");
const LLString SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents");

#if LL_WINDOWS
static const char* SOUND_EXTENSIONS = ".wav";
static const char* IMAGE_EXTENSIONS = ".tga .bmp .jpg .jpeg";
static const char* ANIM_EXTENSIONS =  ".bvh";
#ifdef _CORY_TESTING
static const char* GEOMETRY_EXTENSIONS = ".slg";
#endif
static const char* XML_EXTENSIONS = ".xml";
static const char* SLOBJECT_EXTENSIONS = ".slobject";
#endif
static const char* ALL_FILE_EXTENSIONS = "*.*";

LLMenuGL* gAttachSubMenu = NULL;
LLMenuGL* gDetachSubMenu = NULL;
LLMenuGL* gTakeOffClothes = NULL;
LLPieMenu* gPieRate = NULL;
LLPieMenu* gAttachScreenPieMenu = NULL;
LLPieMenu* gAttachPieMenu = NULL;
LLPieMenu* gAttachBodyPartPieMenus[8];
LLPieMenu* gDetachPieMenu = NULL;
LLPieMenu* gDetachScreenPieMenu = NULL;
LLPieMenu* gDetachBodyPartPieMenus[8];

LLMenuItemCallGL* gAFKMenu = NULL;
LLMenuItemCallGL* gBusyMenu = NULL;

typedef LLMemberListener<LLView> view_listener_t;

//
// Local prototypes
//
BOOL enable_attach(void*);
void handle_leave_group(void *);

// File Menu
const char* upload_pick(void* data);
void handle_upload(void* data);
void handle_upload_object(void* data);
void handle_compress_image(void*);
BOOL enable_save_as(void *);

// Edit menu
void handle_dump_group_info(void *);
void handle_dump_focus(void*);

void handle_region_dump_settings(void*);
void handle_region_dump_temp_asset_data(void*);
void handle_region_clear_temp_asset_data(void*);

// Object pie menu
BOOL sitting_on_selection();

void near_sit_object();
void label_sit_or_stand(LLString& label, void*);
// buy and take alias into the same UI positions, so these
// declarations handle this mess.
BOOL is_selection_buy_not_take();
S32 selection_price();
BOOL enable_take();
void handle_take();
void confirm_take(S32 option, void* data);
BOOL enable_buy(void*); 
void handle_buy(void *);
void handle_buy_object(LLSaleInfo sale_info);
void handle_buy_contents(LLSaleInfo sale_info);
void label_touch(LLString& label, void*);

// Land pie menu
void near_sit_down_point(BOOL success, void *);

// Avatar pie menu
void handle_follow(void *userdata);
void handle_talk_to(void *userdata);

// Debug menu
void show_permissions_control(void*);
void load_url_local_file(const char* file_name);
void toggle_build_options(void* user_data);
#if 0 // Unused
void handle_audio_status_1(void*);
void handle_audio_status_2(void*);
void handle_audio_status_3(void*);
void handle_audio_status_4(void*);
#endif
void reload_ui(void*);
void handle_agent_stop_moving(void*);
void print_packets_lost(void*);
void drop_packet(void*);
void velocity_interpolate( void* data );
void update_fov(S32 increments);
void toggle_wind_audio(void);
void toggle_water_audio(void);
void handle_rebake_textures(void*);
BOOL check_admin_override(void*);
void handle_admin_override_toggle(void*);
#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
void handle_toggle_hacked_godmode(void*);
BOOL check_toggle_hacked_godmode(void*);
#endif

void toggle_glow(void *);
BOOL check_glow(void *);

void toggle_vbo(void *);
BOOL check_vbo(void *);

void toggle_vertex_shaders(void *);
BOOL check_vertex_shaders(void *);

void toggle_cull_small(void *);

void toggle_show_xui_names(void *);
BOOL check_show_xui_names(void *);

// Debug UI
void handle_save_to_xml(void*);
void handle_load_from_xml(void*);

void handle_god_mode(void*);

// God menu
void handle_leave_god_mode(void*);

BOOL is_inventory_visible( void* user_data );
void handle_reset_view();

void disabled_duplicate(void*);
void handle_duplicate_in_place(void*);
void handle_repeat_duplicate(void*);

void handle_export(void*);
void handle_deed_object_to_group(void*);
BOOL enable_deed_object_to_group(void*);
void handle_object_owner_self(void*);
void handle_object_owner_permissive(void*);
void handle_object_lock(void*);
void handle_object_asset_ids(void*);
void force_take_copy(void*);
#ifdef _CORY_TESTING
void force_export_copy(void*);
void force_import_geometry(void*);
#endif

void handle_force_parcel_owner_to_me(void*);
void handle_force_parcel_to_content(void*);
void handle_claim_public_land(void*);

void handle_god_expunge_user(void*);

void handle_god_request_havok(void *);
void handle_god_request_avatar_geometry(void *);	// Hack for easy testing of new avatar geometry
void reload_personal_settings_overrides(void *);
void force_breakpoint(void *);
void reload_vertex_shader(void *);
void flush_animations(void *);
void slow_mo_animations(void *);
void handle_disconnect_viewer(void *);

void handle_stopall(void*);
void handle_hinge(void*);
void handle_ptop(void*);
void handle_lptop(void*);
void handle_wheel(void*);
void handle_dehinge(void*);
BOOL enable_dehinge(void*);
void handle_force_delete(void*);
void print_object_info(void*);
void show_debug_menus();
void toggle_debug_menus(void*);
void toggle_map( void* user_data );
void export_info_callback(LLAssetInfo *info, void **user_data, S32 result);
void export_data_callback(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void **user_data, S32 result);
void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result);
BOOL menu_check_build_tool( void* user_data );
void handle_reload_settings(void*);
void focus_here(void*);
void dump_select_mgr(void*);
void dump_volume_mgr(void*);
void dump_inventory(void*);
void edit_ui(void*);
void toggle_visibility(void*);
BOOL get_visibility(void*);

// Avatar Pie menu
void request_friendship(const LLUUID& agent_id);

// Tools menu
void handle_first_tool(void*);
void handle_next_tool(void*);
void handle_previous_tool(void*);
void handle_force_unlock(void*);
void handle_selected_texture_info(void*);
void handle_dump_image_list(void*);

void handle_fullscreen_debug(void*);
void handle_crash(void*);
void handle_dump_followcam(void*);
void handle_viewer_enable_circuit_log(void*);
void handle_viewer_disable_circuit_log(void*);
void handle_viewer_enable_message_log(void*);
void handle_viewer_disable_message_log(void*);
void handle_send_postcard(void*);
void handle_gestures_old(void*);
void handle_focus(void *);
BOOL enable_buy_land(void*);
void handle_move(void*);
void handle_show_inventory(void*);
void handle_activate(void*);
BOOL enable_activate(void*);

// Help menu
void handle_buy_currency(void*);

void handle_test_male(void *);
void handle_test_female(void *);
void handle_toggle_pg(void*);
void handle_dump_attachments(void *);
void handle_show_overlay_title(void*);
void handle_dump_avatar_local_textures(void*);
void handle_debug_avatar_textures(void*);
void handle_grab_texture(void*);
BOOL enable_grab_texture(void*);

BOOL menu_ui_enabled(void *user_data);
void check_toggle_control( LLUICtrl *, void* user_data );
BOOL menu_check_control( void* user_data);
void menu_toggle_variable( void* user_data );
BOOL menu_check_variable( void* user_data);
BOOL enable_land_selected( void* );
BOOL enable_more_than_one_selected(void* );
BOOL enable_selection_you_own_all(void*);
BOOL enable_selection_you_own_one(void*);
BOOL enable_save_into_inventory(void*);
BOOL enable_save_into_task_inventory(void*);
BOOL enable_not_thirdperson(void*);
BOOL enable_export_selected(void *);
BOOL enable_have_card(void*);
BOOL enable_detach(void*);
BOOL enable_region_owner(void*);


class LLMenuParcelObserver : public LLParcelObserver
{
public:
	LLMenuParcelObserver();
	~LLMenuParcelObserver();
	virtual void changed();
};

static LLMenuParcelObserver* gMenuParcelObserver = NULL;

LLMenuParcelObserver::LLMenuParcelObserver()
{
	gParcelMgr->addObserver(this);
}

LLMenuParcelObserver::~LLMenuParcelObserver()
{
	gParcelMgr->removeObserver(this);
}

void LLMenuParcelObserver::changed()
{
	gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL));
	
	BOOL buyable = enable_buy_land(NULL);
	gMenuHolder->childSetEnabled("Land Buy", buyable);
	gMenuHolder->childSetEnabled("Buy Land...", buyable);
}


//-----------------------------------------------------------------------------
// Menu Construction
//-----------------------------------------------------------------------------

// code required to calculate anything about the menus
void pre_init_menus()
{
	// static information
	LLColor4 color;
	color = gColors.getColor( "MenuDefaultBgColor" );
	LLMenuGL::setDefaultBackgroundColor( color );
	color = gColors.getColor( "MenuItemEnabledColor" );
	LLMenuItemGL::setEnabledColor( color );
	color = gColors.getColor( "MenuItemDisabledColor" );
	LLMenuItemGL::setDisabledColor( color );
	color = gColors.getColor( "MenuItemHighlightBgColor" );
	LLMenuItemGL::setHighlightBGColor( color );
	color = gColors.getColor( "MenuItemHighlightFgColor" );
	LLMenuItemGL::setHighlightFGColor( color );
}

void initialize_menu_actions();

//-----------------------------------------------------------------------------
// Initialize main menus
//
// HOW TO NAME MENUS:
//
// First Letter Of Each Word Is Capitalized, Even At Or And
//
// Items that lead to dialog boxes end in "..."
//
// Break up groups of more than 6 items with separators
//-----------------------------------------------------------------------------
void init_menus()
{
	S32 top = gViewerWindow->getRootView()->getRect().getHeight();
	S32 width = gViewerWindow->getRootView()->getRect().getWidth();

	//
	// Main menu bar
	//
	gMenuHolder = new LLViewerMenuHolderGL();
	gMenuHolder->setRect(LLRect(0, top - MENU_BAR_HEIGHT, width, STATUS_BAR_HEIGHT));
	gMenuHolder->setFollowsAll();

	LLMenuGL::sDefaultMenuContainer = gMenuHolder;

	// Initialize actions
	initialize_menu_actions();

	gMenuBarView = (LLMenuBarGL*)gUICtrlFactory->buildMenu("menu_viewer.xml", gMenuHolder);
	gMenuBarView->setRect(LLRect(0, top, width, top - MENU_BAR_HEIGHT));
	gViewerWindow->getRootView()->addChild(gMenuBarView);
	
	// menu holder appears on top of menu bar so you can see the menu title
	// flash when an item is triggered (the flash occurs in the holder)
	gViewerWindow->getRootView()->addChild(gMenuHolder);

		gMenuHolder->childSetLabelArg("Upload Image", "[COST]", "10");
		gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", "10");
		gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", "10");
		gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", "10");

		gAFKMenu = (LLMenuItemCallGL*)gMenuBarView->getChildByName("Set Away", TRUE);
		gBusyMenu = (LLMenuItemCallGL*)gMenuBarView->getChildByName("Set Busy", TRUE);
		gAttachSubMenu = gMenuBarView->getChildMenuByName("Attach Object", TRUE);
		gDetachSubMenu = gMenuBarView->getChildMenuByName("Detach Object", TRUE);

		if (gAgent.mAccess < SIM_ACCESS_MATURE)
		{
			gMenuBarView->getChildByName("Menu Underpants", TRUE)->setVisible(FALSE);
			gMenuBarView->getChildByName("Menu Undershirt", TRUE)->setVisible(FALSE);
		}

	// TomY TODO convert these two
	LLMenuGL*menu;
	menu = new LLMenuGL(CLIENT_MENU_NAME);
	init_client_menu(menu);
	gMenuBarView->appendMenu( menu );
	menu->updateParent(gMenuHolder);

	menu = new LLMenuGL(SERVER_MENU_NAME);
	init_server_menu(menu);
	gMenuBarView->appendMenu( menu );
	menu->updateParent(gMenuHolder);

	gMenuBarView->createJumpKeys();

	///
	/// Popup menu
	///
	/// The popup menu is now populated by the show_context_menu()
	/// method.
	
	gPopupMenuView = new LLMenuGL( "Popup" );
	gPopupMenuView->setVisible( FALSE );
	gMenuHolder->addChild( gPopupMenuView );

	///
	/// Pie menus
	///
	gPieSelf = gUICtrlFactory->buildPieMenu("menu_pie_self.xml", gMenuHolder);

		// TomY TODO: what shall we do about these?
		gDetachScreenPieMenu = (LLPieMenu*)gMenuHolder->getChildByName("Object Detach HUD", true);
		gDetachPieMenu = (LLPieMenu*)gMenuHolder->getChildByName("Object Detach", true);

		if (gAgent.mAccess < SIM_ACCESS_MATURE)
		{
			gMenuHolder->getChildByName("Self Underpants", TRUE)->setVisible(FALSE);
			gMenuHolder->getChildByName("Self Undershirt", TRUE)->setVisible(FALSE);
		}

	gPieAvatar = gUICtrlFactory->buildPieMenu("menu_pie_avatar.xml", gMenuHolder);

	gPieObject = gUICtrlFactory->buildPieMenu("menu_pie_object.xml", gMenuHolder);

		gAttachScreenPieMenu = (LLPieMenu*)gMenuHolder->getChildByName("Object Attach HUD", true);
		gAttachPieMenu = (LLPieMenu*)gMenuHolder->getChildByName("Object Attach", true);
		gPieRate = (LLPieMenu*)gMenuHolder->getChildByName("Rate Menu", true);

	gPieAttachment = gUICtrlFactory->buildPieMenu("menu_pie_attachment.xml", gMenuHolder);

	gPieLand = gUICtrlFactory->buildPieMenu("menu_pie_land.xml", gMenuHolder);

	///
	/// set up the colors
	///
	LLColor4 color;

	// If we are not in production, use a different color to make it apparent.
	if (gInProductionGrid)
	{
		color = gColors.getColor( "MenuBarBgColor" );
	}
	else
	{
		color = gColors.getColor( "MenuNonProductionBgColor" );
	}

	gMenuBarView->setBackgroundColor( color );

	LLColor4 pie_color = gColors.getColor("PieMenuBgColor");
	gPieSelf->setBackgroundColor( pie_color );
	gPieAvatar->setBackgroundColor( pie_color );
	gPieObject->setBackgroundColor( pie_color );
	gPieAttachment->setBackgroundColor( pie_color );
	gPieLand->setBackgroundColor( pie_color );

	color = gColors.getColor( "MenuPopupBgColor" );
	gPopupMenuView->setBackgroundColor( color );

	// Let land based option enable when parcel changes
	gMenuParcelObserver = new LLMenuParcelObserver();

	//
	// Debug menu visiblity
	//
	show_debug_menus();
}

void init_client_menu(LLMenuGL* menu)
{
	LLMenuGL* sub_menu = NULL;

	//menu->append(new LLMenuItemCallGL("Permissions Control", &show_permissions_control));

// this is now in the view menu so we don't need it here!
	{
		LLMenuGL* sub = new LLMenuGL("Consoles");
		menu->appendMenu(sub);
		sub->append(new LLMenuItemCheckGL("Frame Console", 
										&toggle_visibility,
										NULL,
										&get_visibility,
										(void*)gDebugView->mFrameStatView,
										'2', MASK_CONTROL|MASK_SHIFT ) );
		sub->append(new LLMenuItemCheckGL("Texture Console", 
										&toggle_visibility,
										NULL,
										&get_visibility,
										(void*)gTextureView,
									   	'3', MASK_CONTROL|MASK_SHIFT ) );
		LLView* debugview = gDebugView->mDebugConsolep;
		sub->append(new LLMenuItemCheckGL("Debug Console", 
										&toggle_visibility,
										NULL,
										&get_visibility,
										debugview,
									   	'4', MASK_CONTROL|MASK_SHIFT ) );
#if 0 // Unused
	{
		LLMenuGL* sub = new LLMenuGL("Audio");
		menu->appendMenu(sub);

		sub->append(new LLMenuItemCallGL("Global Pos", 
					&handle_audio_status_1, NULL, NULL ,'5', MASK_CONTROL|MASK_SHIFT) );
		sub->append(new LLMenuItemCallGL("Cone", 
					&handle_audio_status_2, NULL, NULL ,'6', MASK_CONTROL|MASK_SHIFT) );
		sub->append(new LLMenuItemCallGL("Local Pos", 
					&handle_audio_status_3, NULL, NULL ,'7', MASK_CONTROL|MASK_SHIFT) );
		sub->append(new LLMenuItemCallGL("Duration", 
					&handle_audio_status_4, NULL, NULL ,'8', MASK_CONTROL|MASK_SHIFT) );
		sub->createJumpKeys();
	}
#endif
		sub->append(new LLMenuItemCheckGL("Fast Timers", 
										&toggle_visibility,
										NULL,
										&get_visibility,
										(void*)gDebugView->mFastTimerView,
										'9', MASK_CONTROL|MASK_SHIFT ) );
		sub->append(new LLMenuItemCheckGL("Memory", 
										&toggle_visibility,
										NULL,
										&get_visibility,
										(void*)gDebugView->mMemoryView,
										'0', MASK_CONTROL|MASK_SHIFT ) );
		sub->appendSeparator();
		sub->append(new LLMenuItemCallGL("Region Info to Debug Console", 
			&handle_region_dump_settings, NULL));
		sub->append(new LLMenuItemCallGL("Group Info to Debug Console",
			&handle_dump_group_info, NULL, NULL));
		sub->createJumpKeys();
	}
	
	// neither of these works particularly well at the moment
	/*menu->append(new LLMenuItemCallGL(  "Reload UI XML",	&reload_ui,	
	  				NULL, NULL, 'R', MASK_ALT | MASK_CONTROL ) );*/
	/*menu->append(new LLMenuItemCallGL("Reload settings/colors", 
					&handle_reload_settings, NULL, NULL));*/
	menu->append(new LLMenuItemCallGL("Reload personal setting overrides", 
		&reload_personal_settings_overrides, NULL, NULL, KEY_F2, MASK_CONTROL|MASK_SHIFT));

	sub_menu = new LLMenuGL("HUD Info");
	{
		sub_menu->append(new LLMenuItemCheckGL("Velocity", 
												&toggle_visibility,
												NULL,
												&get_visibility,
												(void*)gVelocityBar));

		sub_menu->append(new LLMenuItemToggleGL("Camera",	&gDisplayCameraPos ) );
		sub_menu->append(new LLMenuItemToggleGL("Wind", 	&gDisplayWindInfo) );
		sub_menu->append(new LLMenuItemToggleGL("FOV",  	&gDisplayFOV ) );
		sub_menu->createJumpKeys();
	}
	menu->appendMenu(sub_menu);

	menu->appendSeparator();

	menu->append(new LLMenuItemCheckGL( "High-res Snapshot",
										&menu_toggle_control,
										NULL,
										&menu_check_control,
										(void*)"HighResSnapshot"));

	menu->append(new LLMenuItemToggleGL("Quiet Snapshots to Disk",
										&gQuietSnapshot));

	menu->append(new LLMenuItemCheckGL("Show Mouselook Crosshairs",
									   &menu_toggle_control,
									   NULL,
									   &menu_check_control,
									   (void*)"ShowCrosshairs"));

	menu->append(new LLMenuItemCheckGL("Debug Permissions",
									   &menu_toggle_control,
									   NULL,
									   &menu_check_control,
									   (void*)"DebugPermissions"));
	


#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
	if (!gInProductionGrid)
	{
		menu->append(new LLMenuItemCheckGL("Hacked Godmode",
										   &handle_toggle_hacked_godmode,
										   NULL,
										   &check_toggle_hacked_godmode,
										   (void*)"HackedGodmode"));
	}
#endif

	menu->append(new LLMenuItemCallGL("Clear Group Cache", 
									  LLGroupMgr::debugClearAllGroups));
	menu->appendSeparator();

	sub_menu = new LLMenuGL("Rendering");
	init_debug_rendering_menu(sub_menu);
	menu->appendMenu(sub_menu);

	sub_menu = new LLMenuGL("World");
	init_debug_world_menu(sub_menu);
	menu->appendMenu(sub_menu);

	sub_menu = new LLMenuGL("UI");
	init_debug_ui_menu(sub_menu);
	menu->appendMenu(sub_menu);

	sub_menu = new LLMenuGL("XUI");
	init_debug_xui_menu(sub_menu);
	menu->appendMenu(sub_menu);

	sub_menu = new LLMenuGL("Character");
	init_debug_avatar_menu(sub_menu);
	menu->appendMenu(sub_menu);

{
		LLMenuGL* sub = NULL;
		sub = new LLMenuGL("Network");

		sub->append(new LLMenuItemCallGL("Enable Circuit Log",  
			&handle_viewer_enable_circuit_log,  NULL));
		sub->append(new LLMenuItemCallGL("Disable Circuit Log", 
			&handle_viewer_disable_circuit_log, NULL));
		sub->append(new LLMenuItemCallGL("Enable Message Log",  
			&handle_viewer_enable_message_log,  NULL));
		sub->append(new LLMenuItemCallGL("Disable Message Log", 
			&handle_viewer_disable_message_log, NULL));

		sub->appendSeparator();

		sub->append(new LLMenuItemCheckGL("Velocity Interpolate Objects", 
										  &velocity_interpolate,
										  NULL, 
										  &menu_check_control,
										  (void*)"VelocityInterpolate"));
		sub->append(new LLMenuItemCheckGL("Ping Interpolate Object Positions", 
										  &menu_toggle_control,
										  NULL, 
										  &menu_check_control,
										  (void*)"PingInterpolate"));

		sub->appendSeparator();

		sub->append(new LLMenuItemCallGL("Drop a Packet", 
			&drop_packet, NULL, NULL, 
			'L', MASK_ALT | MASK_CONTROL));

		menu->appendMenu( sub );
		sub->createJumpKeys();
	}
	{
		LLMenuGL* sub = NULL;
		sub = new LLMenuGL("Recorder");

		sub->append(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats"));

		sub->append(new LLMenuItemCallGL("Start Logging",	&LLFrameStats::startLogging, NULL));
		sub->append(new LLMenuItemCallGL("Stop Logging",	&LLFrameStats::stopLogging, NULL));
		sub->append(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL));
		sub->append(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL));
		sub->append(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL));
		sub->appendSeparator();
		sub->append(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL));
		sub->append(new LLMenuItemCallGL("Stop Playback",	&LLAgentPilot::stopPlayback, NULL));
		sub->append(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) );
		sub->append(new LLMenuItemCallGL("Start Record",	&LLAgentPilot::startRecord, NULL));
		sub->append(new LLMenuItemCallGL("Stop Record",	&LLAgentPilot::saveRecord, NULL));

		menu->appendMenu( sub );
		sub->createJumpKeys();
	}

	menu->appendSeparator();

	menu->append(new LLMenuItemToggleGL("Show Updates", 
		&gShowObjectUpdates,
		'U', MASK_ALT | MASK_SHIFT | MASK_CONTROL));
	
	menu->appendSeparator(); 
	
	menu->append(new LLMenuItemCallGL("Compress Image...", 
		&handle_compress_image, NULL, NULL));

	menu->append(new LLMenuItemCheckGL("Limit Select Distance", 
									   &menu_toggle_control,
									   NULL, 
									   &menu_check_control,
									   (void*)"LimitSelectDistance"));

	menu->append(new LLMenuItemToggleGL("Disable Camera Constraints", 
		&LLViewerCamera::sDisableCameraConstraints));

	menu->appendSeparator();

	menu->append(new LLMenuItemCheckGL( "Console Window", 
										&menu_toggle_control,
										NULL, 
										&menu_check_control,
										(void*)"ShowConsoleWindow"));

#ifndef LL_RELEASE_FOR_DOWNLOAD
	{
		LLMenuGL* sub = NULL;
		sub = new LLMenuGL("Debugging");
		sub->append(new LLMenuItemCallGL("Force Breakpoint", &force_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT));
		sub->append(new LLMenuItemCallGL("LLError And Crash", &handle_crash));
		sub->createJumpKeys();
		menu->appendMenu(sub);
	}
#endif	

	// TomY Temporary menu item so we can test this floater
	menu->append(new LLMenuItemCheckGL("Clothing...", 
												&handle_clothing,
												NULL,
												NULL,
												NULL));

	menu->append(new LLMenuItemCallGL("Debug Settings", LLFloaterSettingsDebug::show, NULL, NULL));
	menu->append(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT));
	menu->createJumpKeys();
}

void handle_upload_data(void*)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if(!picker.getOpenFile())
	{
		llwarns << "No file" << llendl;
		return;
	}
 	const char* filename = picker.getFirstFile();
	S32 index = strlen(filename);
	char delim = gDirUtilp->getDirDelimiter()[0];
	while(index && filename[index--] != delim);
	index += 2;
	const char* basename = &filename[index];

	LLMessageSystem* msg = gMessageSystem;
	msg->newMessage("InitiateUpload");
	msg->nextBlock("AgentData");
	msg->addUUID("AgentID", gAgent.getID());
	msg->nextBlock("FileData");
	msg->addString("BaseFilename", basename);
	msg->addString("SourceFilename", filename);
	gAgent.sendReliableMessage();
}

void init_debug_world_menu(LLMenuGL* menu)
{
	menu->append(new LLMenuItemCheckGL("Mouse Moves Sun", 
									   &menu_toggle_control,
									   NULL, 
									   &menu_check_control,
									   (void*)"MouseSun", 
									   'M', MASK_CONTROL|MASK_ALT));
	menu->append(new LLMenuItemCheckGL("Sim Sun Override", 
									   &menu_toggle_control,
									   NULL, 
									   &menu_check_control,
									   (void*)"SkyOverrideSimSunPosition"));
	menu->append(new LLMenuItemCallGL("Dump Scripted Camera",
		&handle_dump_followcam, NULL, NULL));
	menu->append(new LLMenuItemCheckGL("Fixed Weather", 
									   &menu_toggle_control,
									   NULL, 
									   &menu_check_control,
									   (void*)"FixedWeather"));
	menu->createJumpKeys();
}


void handle_export_menus_to_xml(void*)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if(!picker.getSaveFile(LLFilePicker::FFSAVE_XML))
	{
		llwarns << "No file" << llendl;
		return;
	}
 	const char* filename = picker.getFirstFile();

	llofstream out(filename);
	LLXMLNodePtr node = gMenuBarView->getXML();
	node->writeToOstream(out);
	out.close();
}

extern BOOL gDebugClicks;
extern BOOL gDebugWindowProc;
extern BOOL gDebugTextEditorTips;
extern BOOL gDebugSelectMgr;

void init_debug_ui_menu(LLMenuGL* menu)
{
	menu->append(new LLMenuItemCallGL("Editable UI", &edit_ui));
	menu->append(new LLMenuItemToggleGL("Async Keystrokes", &gHandleKeysAsync));
	menu->append(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr));
	menu->append(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory));
	menu->append(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL));
	menu->append(new LLMenuItemCallGL( "Dump VolumeMgr",	&dump_volume_mgr, NULL, NULL));
	menu->append(new LLMenuItemCallGL( "Print Selected Object Info",	&print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT ));
	menu->append(new LLMenuItemCallGL( "Print Agent Info",			&print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT ));
	menu->append(new LLMenuItemCallGL( "Print Texture Memory Stats",  &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL));
	menu->append(new LLMenuItemCheckGL("Double-Click Auto-Pilot", 
		menu_toggle_control, NULL, menu_check_control, 
		(void*)"DoubleClickAutoPilot"));
	menu->appendSeparator();
//	menu->append(new LLMenuItemCallGL( "Print Packets Lost",			&print_packets_lost, NULL, NULL, 'L', MASK_SHIFT ));
	menu->append(new LLMenuItemToggleGL("Debug SelectMgr", &gDebugSelectMgr));
	menu->append(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks));
	menu->append(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects));
	menu->append(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling));
	menu->append(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys));
	menu->append(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc));
	menu->append(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips));
	menu->createJumpKeys();
}

void init_debug_xui_menu(LLMenuGL* menu)
{
	menu->append(new LLMenuItemCallGL("Floater Test...", LLFloaterTest::show));
	menu->append(new LLMenuItemCallGL("Export Menus to XML...", handle_export_menus_to_xml));
	menu->append(new LLMenuItemCallGL("Edit UI...", LLFloaterEditUI::show));	
	menu->append(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml));
	menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml));
	menu->append(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL));

	//menu->append(new LLMenuItemCallGL("Buy Currency...", handle_buy_currency));
	menu->createJumpKeys();
}

void init_debug_rendering_menu(LLMenuGL* menu)
{
	LLMenuGL* sub_menu = NULL;

	///////////////////////////
	//
	// Debug menu for types/pools
	//
	sub_menu = new LLMenuGL("Types");
	menu->appendMenu(sub_menu);

	sub_menu->append(new LLMenuItemCheckGL("Simple",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_SIMPLE,	'1', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Alpha",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Tree",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Character",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("SurfacePatch",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Sky",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Water",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Ground",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Volume",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Grass",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Clouds",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_CLOUDS, '-', MASK_CONTROL|MASK_ALT| MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Particles",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_PARTICLES, '=', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->append(new LLMenuItemCheckGL("Bump",
											&LLPipeline::toggleRenderType, NULL,
											&LLPipeline::toggleRenderTypeControl,
											(void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_CONTROL|MASK_ALT|MASK_SHIFT));
	sub_menu->createJumpKeys();
	sub_menu = new LLMenuGL("Features");
	menu->appendMenu(sub_menu);
	sub_menu->append(new LLMenuItemCheckGL("UI",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_UI, '1', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Selected",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_SELECTED, '2', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Highlighted",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED, '3', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Dynamic Textures",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, '4', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Fog",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_FOG, '6', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Palletized Textures",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_PALETTE, '7', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL("Test FRInfo",
											&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, '8', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL( "Flexible Objects", 
										&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, '9', MASK_ALT|MASK_CONTROL));
	sub_menu->append(new LLMenuItemCheckGL( "Chain Faces", 
										&LLPipeline::toggleRenderDebugFeature, NULL,
											&LLPipeline::toggleRenderDebugFeatureControl,
											(void*)LLPipeline::RENDER_DEBUG_FEATURE_CHAIN_FACES, '0', MASK_ALT|MASK_CONTROL));
	sub_menu->createJumpKeys();

	/////////////////////////////
	//
	// Debug menu for info displays
	//
	sub_menu = new LLMenuGL("Info Displays");
	menu->appendMenu(sub_menu);

	sub_menu->append(new LLMenuItemCheckGL("Verify",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_VERIFY));
	sub_menu->append(new LLMenuItemCheckGL("AGP Map",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_AGP_MEM));
	sub_menu->append(new LLMenuItemCheckGL("BBoxes",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_BBOXES));
	sub_menu->append(new LLMenuItemCheckGL("Points",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_POINTS));
	sub_menu->append(new LLMenuItemCheckGL("Octree",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_OCTREE));
	sub_menu->append(new LLMenuItemCheckGL("Occlusion",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_OCCLUSION));
	sub_menu->append(new LLMenuItemCheckGL("Face Chains",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_FACE_CHAINS));
	sub_menu->append(new LLMenuItemCheckGL("Texture Priority",	&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY));													
	sub_menu->append(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_COMPOSITION));
	sub_menu->append(new LLMenuItemCheckGL("ShadowMap", &LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_SHADOW_MAP));
	sub_menu->append(new LLMenuItemCheckGL("LightTrace",&LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_LIGHT_TRACE));
	sub_menu->append(new LLMenuItemCheckGL("Pools",     &LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_POOLS));
	sub_menu->append(new LLMenuItemCheckGL("Queues",    &LLPipeline::toggleRenderDebug, NULL,
													&LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_QUEUES));
	sub_menu->append(new LLMenuItemCheckGL("Map",       &LLPipeline::toggleRenderDebug, NULL,
													LLPipeline::toggleRenderDebugControl,
													(void*)LLPipeline::RENDER_DEBUG_MAP));

	sub_menu->append(new LLMenuItemCheckGL("Show Depth Buffer",
										   &menu_toggle_control,
										   NULL,
										   &menu_check_control,
										   (void*)"ShowDepthBuffer"));
	sub_menu->append(new LLMenuItemToggleGL("Show Select Buffer", &gDebugSelect));

	sub_menu = new LLMenuGL("Render Tests");

	sub_menu->append(new LLMenuItemCheckGL("Camera Offset", 
										  &menu_toggle_control,
										  NULL, 
										  &menu_check_control,
										  (void*)"CameraOffset"));

	sub_menu->append(new LLMenuItemToggleGL("Randomize Framerate", &gRandomizeFramerate));

	sub_menu->append(new LLMenuItemToggleGL("Periodic Slow Frame", &gPeriodicSlowFrame));
	sub_menu->createJumpKeys();

	menu->appendMenu( sub_menu );

	menu->appendSeparator();
	menu->append(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes"));
	menu->append(new LLMenuItemCheckGL("Use VBO", toggle_vbo, NULL, check_vbo, NULL));
	menu->append(new LLMenuItemCheckGL("Light Glows", toggle_glow, NULL, check_glow, NULL));
//	menu->append(new LLMenuItemCheckGL("Cull Small Objects", toggle_cull_small, NULL, menu_check_control, (void*)"RenderCullBySize"));

	menu->appendSeparator();
	menu->append(new LLMenuItemToggleGL("Hide Selected", &gHideSelectedObjects));
	menu->appendSeparator();
	menu->append(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis"));
	menu->append(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT));
	//menu->append(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT));
	
	menu->append(new LLMenuItemToggleGL("Wireframe", &gUseWireframe, 
			'R', MASK_CONTROL|MASK_SHIFT));

	LLMenuItemCheckGL* item;
	item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, NULL, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT);
	item->setEnabled(gGLManager.mHasOcclusionQuery);
	menu->append(item);
	
	
	item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures", 'A', MASK_CONTROL|MASK_ALT);
	menu->append(item);
	
	item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_variable, NULL, menu_check_variable, (void*)&LLViewerImage::sDontLoadVolumeTextures);
	menu->append(item);
	
	item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon");
	menu->append(item);
	
#if 0 // 1.9.2
	item = new LLMenuItemCheckGL("Vertex Shaders", toggle_vertex_shaders, NULL, check_vertex_shaders, (void*)"VertexShaderEnable", 'V', MASK_CONTROL|MASK_ALT);
	item->setEnabled(gGLManager.mHasVertexShader);
	menu->append(item);
#endif
	menu->createJumpKeys();
}

extern BOOL gDebugAvatarRotation;

void init_debug_avatar_menu(LLMenuGL* menu)
{
	LLMenuGL* sub_menu = new LLMenuGL("Grab Baked Texture");
	init_debug_baked_texture_menu(sub_menu);
	menu->appendMenu(sub_menu);

	sub_menu = new LLMenuGL("Character Tests");
	sub_menu->append(new LLMenuItemToggleGL("Go Away/AFK When Idle",
		&gAllowAFK));

	sub_menu->append(new LLMenuItemCallGL("Appearance To XML", 
		&LLVOAvatar::dumpArchetypeXML));

	// HACK for easy testing of avatar geometry
	sub_menu->append(new LLMenuItemCallGL( "Toggle Character Geometry", 
		&handle_god_request_avatar_geometry, &enable_god_customer_service, NULL));

	sub_menu->append(new LLMenuItemCallGL("Test Male", 
		handle_test_male));

	sub_menu->append(new LLMenuItemCallGL("Test Female", 
		handle_test_female));

	sub_menu->append(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg));

	sub_menu->append(new LLMenuItemToggleGL("Allow Select Avatar", &gAllowSelectAvatar));
	sub_menu->createJumpKeys();

	menu->appendMenu(sub_menu);

	menu->append(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL));
	menu->append(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL));
	menu->append(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug));
	menu->append(new LLMenuItemCallGL("Flush Animations", &flush_animations, NULL));
	menu->append(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL));
	menu->append(new LLMenuItemToggleGL("Show Look At", &LLHUDEffectLookAt::sDebugLookAt));
	menu->append(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt));
	menu->append(new LLMenuItemToggleGL("Debug Joint Updates", &LLVOAvatar::sJointDebug));
	menu->append(new LLMenuItemToggleGL("Disable LOD", &LLViewerJoint::sDisableLOD));
	menu->append(new LLMenuItemToggleGL("Debug Character Vis", &LLVOAvatar::sDebugInvisible));
	//menu->append(new LLMenuItemToggleGL("Show Attachment Points", &LLVOAvatar::sShowAttachmentPoints));
	menu->append(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane));
	menu->append(new LLMenuItemToggleGL("Show Collision Skeleton", &LLVOAvatar::sShowCollisionVolumes));
	menu->append(new LLMenuItemToggleGL("Software Blending SSE", &gGLManager.mSoftwareBlendSSE));
#if 0 // Removed since this feature doesn't actually work as of 1.9.1 --TomY
	menu->append(new LLMenuItemToggleGL("Character Load Test", &LLVOAvatar::sAvatarLoadTest));
#endif
	menu->append(new LLMenuItemToggleGL( "Display Agent Target", &LLAgent::sDebugDisplayTarget));
	menu->append(new LLMenuItemToggleGL( "Debug Rotation", &gDebugAvatarRotation));
	menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments));
	menu->append(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures));
#ifndef LL_RELEASE_FOR_DOWNLOAD
	menu->append(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT));
	menu->append(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT ));	
#endif
	menu->createJumpKeys();
}

void init_debug_baked_texture_menu(LLMenuGL* menu)
{
	menu->append(new LLMenuItemCallGL("Iris", handle_grab_texture, enable_grab_texture, (void*) LLVOAvatar::TEX_EYES_BAKED));
	menu->append(new LLMenuItemCallGL("Head", handle_grab_texture, enable_grab_texture, (void*) LLVOAvatar::TEX_HEAD_BAKED));
	menu->append(new LLMenuItemCallGL("Upper Body", handle_grab_texture, enable_grab_texture, (void*) LLVOAvatar::TEX_UPPER_BAKED));
	menu->append(new LLMenuItemCallGL("Lower Body", handle_grab_texture, enable_grab_texture, (void*) LLVOAvatar::TEX_LOWER_BAKED));
	menu->append(new LLMenuItemCallGL("Skirt", handle_grab_texture, enable_grab_texture, (void*) LLVOAvatar::TEX_SKIRT_BAKED));
	menu->createJumpKeys();
}

void init_server_menu(LLMenuGL* menu)
{
	/*
	{
		// These messages are now trusted. We can write scripts to do
		// this, and the message is unchecked for source.
		LLMenuGL* sub_menu = NULL;
		sub_menu = new LLMenuGL("Sim Logging");

		sub_menu->append(new LLMenuItemCallGL("Turn off llinfos Log", 
			&handle_reduce_llinfo_log, &enable_god_customer_service));

		sub_menu->append(new LLMenuItemCallGL("Normal Logging", 
			&handle_normal_llinfo_log, &enable_god_customer_service));

		sub_menu->appendSeparator();
		sub_menu->append(new LLMenuItemCallGL("Enable Circuit Log",  
			&handle_sim_enable_circuit_log,  &enable_god_customer_service));
		sub_menu->append(new LLMenuItemCallGL("Disable Circuit Log", 
			&handle_sim_disable_circuit_log, &enable_god_customer_service));
		sub_menu->appendSeparator();
		sub_menu->append(new LLMenuItemCallGL("Enable Message Log",  
			&handle_sim_enable_message_log,  &enable_god_customer_service));
		sub_menu->append(new LLMenuItemCallGL("Disable Message Log", 
			&handle_sim_disable_message_log, &enable_god_customer_service));

		sub_menu->appendSeparator();

		sub_menu->append(new LLMenuItemCallGL("Fetch Message Log",	
			&handle_sim_fetch_message_log,  &enable_god_customer_service));

		sub_menu->append(new LLMenuItemCallGL("Fetch Log",			
			&handle_sim_fetch_log, &enable_god_customer_service));

		menu->appendMenu( sub_menu );
	}
	*/

	{
		LLMenuGL* sub = new LLMenuGL("Object");
		menu->appendMenu(sub);

		sub->append(new LLMenuItemCallGL( "Take Copy",
										   &force_take_copy, &enable_god_customer_service, NULL));
#ifdef _CORY_TESTING
		sub->append(new LLMenuItemCallGL( "Export Copy",
										   &force_export_copy, NULL, NULL));
		sub->append(new LLMenuItemCallGL( "Import Geometry",
										   &force_import_geometry, NULL, NULL));
#endif
		//sub->append(new LLMenuItemCallGL( "Force Public", 
		//			&handle_object_owner_none, NULL, NULL));
		//sub->append(new LLMenuItemCallGL( "Force Ownership/Permissive", 
		//			&handle_object_owner_self_and_permissive, NULL, NULL, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL));
		sub->append(new LLMenuItemCallGL( "Force Owner To Me", 
					&handle_object_owner_self, &enable_god_customer_service));
		sub->append(new LLMenuItemCallGL( "Force Owner Permissive", 
					&handle_object_owner_permissive, &enable_god_customer_service));
		//sub->append(new LLMenuItemCallGL( "Force Totally Permissive", 
		//			&handle_object_permissive));
		sub->append(new LLMenuItemCallGL( "Delete", 
					&handle_force_delete, &enable_god_customer_service, NULL, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL));
		sub->append(new LLMenuItemCallGL( "Lock", 
					&handle_object_lock, &enable_god_customer_service, NULL, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL));
		sub->append(new LLMenuItemCallGL( "Get Asset IDs", 
					&handle_object_asset_ids, &enable_god_customer_service, NULL, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL));
		sub->createJumpKeys();
	}
	{
		LLMenuGL* sub = new LLMenuGL("Parcel");
		menu->appendMenu(sub);

		sub->append(new LLMenuItemCallGL("Owner To Me",
										 &handle_force_parcel_owner_to_me,
										 &enable_god_customer_service, NULL));
		sub->append(new LLMenuItemCallGL("Set to Linden Content",
										 &handle_force_parcel_to_content,
										 &enable_god_customer_service, NULL,
										 'C', MASK_SHIFT | MASK_ALT | MASK_CONTROL));
		//sub->append(new LLMenuItemCallGL("Toggle First Land bit",
		//								 &handle_toggle_parcel_newbie));
		sub->appendSeparator();
		sub->append(new LLMenuItemCallGL("Claim Public Land",
										 &handle_claim_public_land, &enable_god_customer_service));

		sub->createJumpKeys();
	}
	{
		LLMenuGL* sub = new LLMenuGL("Region");
		menu->appendMenu(sub);
		sub->append(new LLMenuItemCallGL("Dump Temp Asset Data",
			&handle_region_dump_temp_asset_data,
			&enable_god_customer_service, NULL));
		sub->createJumpKeys();
	}	
	menu->append(new LLMenuItemCallGL( "God Tools...", 
		&LLFloaterGodTools::show, &enable_god_basic, NULL));

	menu->appendSeparator();

	menu->append(new LLMenuItemCallGL("Upload Data File...", 
									  &handle_upload_data,
									  &enable_god_customer_service,
									  NULL));


	menu->appendSeparator();

	menu->append(new LLMenuItemCallGL("Save Region State", 
		&LLPanelRegionTools::onSaveState, &enable_god_customer_service, NULL));

//	menu->append(new LLMenuItemCallGL("Force Join Group", handle_force_join_group));



	menu->appendSeparator();
//
//	menu->append(new LLMenuItemCallGL( "OverlayTitle",
//		&handle_show_overlay_title, &enable_god_customer_service, NULL));

	menu->append(new LLMenuItemCallGL("Request Admin Status", 
		&handle_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_CONTROL));

	menu->append(new LLMenuItemCallGL("Leave Admin Status", 
		&handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL));
	menu->createJumpKeys();
}

//-----------------------------------------------------------------------------
// cleanup_menus()
//-----------------------------------------------------------------------------
void cleanup_menus()
{
	delete gMenuParcelObserver;
	gMenuParcelObserver = NULL;
}

//-----------------------------------------------------------------------------
// Object pie menu
//-----------------------------------------------------------------------------

class LLObjectRateCreator : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloaterRate::show(LLFloaterRate::RS_CREATOR);
		return true;
	}
};

class LLObjectRateOwner : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// Don't allow rating of group owned objects.
		LLSelectNode* node = gSelectMgr->getFirstRootNode();
		if (!node) return true;
		if (node->mPermissions->isGroupOwned())
		{
			gViewerWindow->alertXml("CantRateOwnedByGroup");
			return true;
		}

		LLFloaterRate::show(LLFloaterRate::RS_OWNER);
		return true;
	}
};

class LLObjectReportAbuse : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloaterReporter::showFromObject(gLastHitObjectID);
		return true;
	}
};

// Enable only when you didn't create it, and the creator
// is not the owner.
class LLObjectEnableRateCreator : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLUUID creator_id;
		LLUUID owner_id;
		LLString dummy;
		BOOL identical_creator = gSelectMgr->selectGetCreator(creator_id, dummy);

		BOOL new_value;
		if (!identical_creator)
		{
			new_value = FALSE;
		}
		else
		{
			new_value = (creator_id != gAgent.getID());
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// Enabled if object owner isn't the agent.
class LLObjectEnableRateOwner : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLUUID owner_id;
		LLString dummy;
		BOOL identical_owner = gSelectMgr->selectGetOwner(owner_id, dummy);

		BOOL new_value;
		if (!identical_owner)
		{
			new_value = FALSE;
		}
		else if (owner_id.isNull())
		{
			new_value = FALSE;
		}
		else
		{
			new_value = (owner_id != gAgent.getID());
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


// Enabled it you clicked an object
class LLObjectEnableReportAbuse : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = !gLastHitObjectID.isNull();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


BOOL enable_attach(void*)
{
	// All root objects must be owned by agent.
	BOOL rv = FALSE;
	LLViewerObject* obj = gSelectMgr->getFirstRootObject();
	if(obj)
	{
		rv = TRUE;
		for(obj = gSelectMgr->getFirstRootObject() ; obj != NULL; obj = gSelectMgr->getNextRootObject())
		{
			for (U32 child_num = 0; child_num < obj->mChildList.size(); child_num++ )
			{
				LLViewerObject *child = obj->mChildList[child_num];
				if (child->isAvatar())
				{
					return FALSE;
				}
			}
			if(!obj->permMove())
			{
				rv = FALSE;
				break;
			}
		}
	}
	return rv;
}


class LLObjectTouch : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerObject* object = gObjectList.findObject(gLastHitObjectID);
		if (!object) return true;

		LLMessageSystem	*msg = gMessageSystem;

		msg->newMessageFast(_PREHASH_ObjectGrab);
		msg->nextBlockFast( _PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->nextBlockFast( _PREHASH_ObjectData);
		msg->addU32Fast(    _PREHASH_LocalID, object->mLocalID);
		msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero );
		msg->sendMessage( object->getRegion()->getHost());

		// HACK: Hope the packets arrive safely and in order.
		msg->newMessageFast(_PREHASH_ObjectDeGrab);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->nextBlockFast(_PREHASH_ObjectData);
		msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
		msg->sendMessage(object->getRegion()->getHost());

		gSelectMgr->deselectTransient();
		return true;
	}
};


// One object must have touch sensor
class LLObjectEnableTouch : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerObject* obj = gObjectList.findObject(gLastHitObjectID);
		bool new_value = obj && obj->flagHandleTouch();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);

		// HACK Update label
		LLSelectNode* node = gSelectMgr->getFirstRootNode();
		if (node && node->mValid && !node->mTouchName.empty())
		{
			gMenuHolder->childSetText("Object Touch", node->mTouchName);
		}
		else
		{
			gMenuHolder->childSetText("Object Touch", userdata["data"].asString());
		}

		return true;
	}
};

void label_touch(LLString& label, void*)
{
	LLSelectNode* node = gSelectMgr->getFirstRootNode();
	if (node && node->mValid && !node->mTouchName.empty())
	{
		label.assign(node->mTouchName);
	}
	else
	{
		label.assign("Touch");
	}
}

bool handle_object_open()
{
	LLViewerObject* obj = gObjectList.findObject(gLastHitObjectID);
	if(!obj) return true;

	// transient selection must be made permanent
	gSelectMgr->convertTransient();
	LLFloaterOpenObject::show();
	return true;
}

class LLObjectOpen : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		return handle_object_open();
	}
};

class LLObjectEnableOpen : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// Look for contents in root object, which is all the LLFloaterOpenObject
		// understands.
		LLViewerObject* obj = gObjectList.findObject(gLastHitObjectID);
		bool new_value = (obj != NULL);
		if (new_value)
		{
			LLViewerObject* root = obj->getRootEdit();
			if (!root) new_value = false;
			else new_value = root->allowOpen();
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


class LLViewCheckBuildMode : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gToolMgr->inEdit();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

bool toggle_build_mode()
{
	if (gToolMgr->inEdit())
	{
		// just reset the view, will pull us out of edit mode
		handle_reset_view();
	}
	else
	{
		if (gAgent.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") )
		{
			// zoom in if we're looking at the avatar
			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
			gAgent.setFocusGlobal(gAgent.getPositionGlobal() + 2.0 * LLVector3d(gAgent.getAtAxis()));
			gAgent.cameraZoomIn(0.666f);
			gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
		}

		gCurrentToolset = gBasicToolset;
		gCurrentToolset->selectTool( gToolCreate );

		// Could be first use
		LLFirstUse::useBuild();
	}
	return true;
}

class LLViewBuildMode : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		return toggle_build_mode();
	}
};


class LLObjectBuild : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gAgent.getFocusOnAvatar() && !gToolMgr->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
		{
			// zoom in if we're looking at the avatar
			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
			gAgent.cameraZoomIn(0.666f);
			gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
			gViewerWindow->moveCursorToCenter();
		}
		else if ( gSavedSettings.getBOOL("EditCameraMovement") )
		{
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
			gViewerWindow->moveCursorToCenter();
		}

		gCurrentToolset = gBasicToolset;
		gCurrentToolset->selectTool( gToolCreate );

		// Could be first use
		LLFirstUse::useBuild();
		return true;
	}
};

class LLObjectEdit : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gParcelMgr->deselectLand();
		// convert transient selections to permanent
		gSelectMgr->convertTransient();

		if (gAgent.getFocusOnAvatar() && !gToolMgr->inEdit())
		{
			if (gSelectMgr->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
			{
				// always freeze camera in space, even if camera doesn't move
				// so, for example, follow cam scripts can't affect you when in build mode
				gAgent.setFocusGlobal(gAgent.calcFocusPositionTargetGlobal(), LLUUID::null);
				gAgent.setFocusOnAvatar(FALSE, ANIMATE);
			}
			else
			{
				gAgent.setFocusOnAvatar(FALSE, ANIMATE);
				// zoom in on object center instead of where we clicked, as we need to see the manipulator handles
				gAgent.setFocusGlobal(gLastHitPosGlobal /*+ gLastHitObjectOffset*/, gLastHitObjectID);
				gAgent.cameraZoomIn(0.666f);
				gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
				gViewerWindow->moveCursorToCenter();
			}
		}

		gFloaterTools->open();
	
		gCurrentToolset = gBasicToolset;
		gCurrentToolset->selectTool( gToolTranslate );

		// Could be first use
		LLFirstUse::useBuild();
		return true;
	}
};


//---------------------------------------------------------------------------
// Land pie menu
//---------------------------------------------------------------------------
class LLLandBuild : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gParcelMgr->deselectLand();

		if (gAgent.getFocusOnAvatar() && !gToolMgr->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
		{
			// zoom in if we're looking at the avatar
			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
			gAgent.cameraZoomIn(0.666f);
			gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD );
			gViewerWindow->moveCursorToCenter();
		}
		else if ( gSavedSettings.getBOOL("EditCameraMovement")  )
		{
			// otherwise just move focus
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
			gViewerWindow->moveCursorToCenter();
		}


		gCurrentToolset = gBasicToolset;
		gCurrentToolset->selectTool( gToolCreate );

		// Could be first use
		LLFirstUse::useBuild();
		return true;
	}
};

class LLLandBuyPass : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLPanelLandGeneral::onClickBuyPass((void *)FALSE);
		return true;
	}
};

class LLLandEnableBuyPass : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = LLPanelLandGeneral::enableBuyPass(NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// BUG: Should really check if CLICK POINT is in a parcel where you can build.
BOOL enable_land_build(void*)
{
	if (gAgent.isGodlike()) return TRUE;
	if (gAgent.inPrelude()) return FALSE;

	BOOL can_build = FALSE;
	LLParcel* agent_parcel = gParcelMgr->getAgentParcel();
	if (agent_parcel)
	{
		can_build = agent_parcel->getAllowModify();
	}
	return can_build;
}

// BUG: Should really check if OBJECT is in a parcel where you can build.
BOOL enable_object_build(void*)
{
	if (gAgent.isGodlike()) return TRUE;
	if (gAgent.inPrelude()) return FALSE;

	BOOL can_build = FALSE;
	LLParcel* agent_parcel = gParcelMgr->getAgentParcel();
	if (agent_parcel)
	{
		can_build = agent_parcel->getAllowModify();
	}
	return can_build;
}

class LLEnableEdit : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.isGodlike() || !gAgent.inPrelude();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLSelfRemoveAllAttachments : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLAgent::userRemoveAllAttachments(NULL);
		return true;
	}
};

class LLSelfEnableRemoveAllAttachments : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = false;
		if (gAgent.getAvatarObject())
		{
			LLVOAvatar* avatarp = gAgent.getAvatarObject();
			for (LLViewerJointAttachment* attachmentp = avatarp->mAttachmentPoints.getFirstData();
				attachmentp;
				attachmentp = avatarp->mAttachmentPoints.getNextData())
			{
				if (attachmentp->getObject(0))
				{
					new_value = true;
					break;
				}
			}
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_has_attachments(void*)
{

	return FALSE;
}

//---------------------------------------------------------------------------
// Avatar pie menu
//---------------------------------------------------------------------------
void handle_follow(void *userdata)
{
	// follow a given avatar, ID in gLastHitObjectID
	gAgent.startFollowPilot(gLastHitObjectID);
}

class LLObjectEnableMute : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerObject* object = gViewerWindow->lastObjectHit();
		bool new_value = (object != NULL);
		if (new_value)
		{
			LLVOAvatar* avatar = find_avatar_from_object(object); 
			if (avatar)
			{
				// It's an avatar
				LLNameValue *lastname = avatar->getNVPair("LastName");
				BOOL is_linden = lastname && !LLString::compareStrings(lastname->getString(), "Linden");
				BOOL is_self = avatar->isSelf();
				new_value = !is_linden && !is_self;
			}
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLObjectMute : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerObject* object = gViewerWindow->lastObjectHit();
		if (!object) return true;
		
		LLUUID id;
		LLString name;
		LLMute::EType type;
		LLVOAvatar* avatar = find_avatar_from_object(object); 
		if (avatar)
		{
			id = avatar->getID();

			LLNameValue *firstname = avatar->getNVPair("FirstName");
			LLNameValue *lastname = avatar->getNVPair("LastName");
			if (firstname && lastname)
			{
				name = firstname->getString();
				name += " ";
				name += lastname->getString();
			}
			
			type = LLMute::AGENT;
		}
		else
		{
			// it's an object
			id = object->getID();

			LLSelectNode* node = gSelectMgr->getFirstRootNode();
			if (node)
			{
				name = node->mName;
			}
			
			type = LLMute::OBJECT;
		}
		
		LLMute mute(id, name, type);
		if (gMuteListp->isMuted(mute.mID, mute.mName))
		{
			gMuteListp->remove(mute);
		}
		else
		{
			gMuteListp->add(mute);
			gFloaterMute->show();
		}
		
		gSelectMgr->deselectAll();
		return true;
	}
};

bool handle_go_to()
{
	// JAMESDEBUG try simulator autopilot
	std::vector<std::string> strings;
	std::string val;
	val = llformat("%g", gLastHitPosGlobal.mdV[VX]);
	strings.push_back(val);
	val = llformat("%g", gLastHitPosGlobal.mdV[VY]);
	strings.push_back(val);
	val = llformat("%g", gLastHitPosGlobal.mdV[VZ]);
	strings.push_back(val);
	send_generic_message("autopilot", strings);

	// Don't select anything
	gSelectMgr->deselectTransient();

	gParcelMgr->deselectLand();

	if (gAgent.getAvatarObject() && !gSavedSettings.getBOOL("AutoPilotLocksCamera"))
	{
		gAgent.setFocusGlobal(gAgent.getFocusTargetGlobal(), gAgent.getAvatarObject()->getID());
	}
	else 
	{
		// Snap camera back to behind avatar
		gAgent.setFocusOnAvatar(TRUE, ANIMATE);
	}

	// Could be first use
	LLFirstUse::useGoTo();
	return true;
}

class LLGoToObject : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		return handle_go_to();
	}
};

//---------------------------------------------------------------------------
// Parcel freeze, eject, etc.
//---------------------------------------------------------------------------
void callback_freeze(S32 option, void* data)
{
	LLUUID* avatar_id = (LLUUID*) data;

	if (0 == option || 1 == option)
	{
		U32 flags = 0x0;
		if (1 == option)
		{
			// unfreeze
			flags |= 0x1;
		}

		LLMessageSystem* msg = gMessageSystem;
		LLViewerObject* avatar = gObjectList.findObject(*avatar_id);

		if (avatar)
		{
			msg->newMessage("FreezeUser");
			msg->nextBlock("AgentData");
			msg->addUUID("AgentID", gAgent.getID());
			msg->addUUID("SessionID", gAgent.getSessionID());
			msg->nextBlock("Data");
			msg->addUUID("TargetID", *avatar_id );
			msg->addU32("Flags", flags );
			msg->sendReliable( avatar->getRegion()->getHost() );
		}
	}

	delete avatar_id;
	avatar_id = NULL;
}

class LLAvatarFreeze : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if( avatar )
		{
			LLUUID* avatar_id = new LLUUID( avatar->getID() );

			gViewerWindow->alertXml("FreezeAvatar",
				callback_freeze, (void*)avatar_id);
			
		}
		return true;
	}
};

class LLAvatarVisibleDebug : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.isGodlike();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLAvatarEnableDebug : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.isGodlike();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLAvatarDebug : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if( avatar )
		{
			avatar->dumpLocalTextures();
		}
		llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl;
		std::vector<std::string> strings;
		strings.push_back( avatar->getID().getString() );
		LLUUID invoice;
		send_generic_message("dumptempassetdata", strings, invoice);
		LLFloaterAvatarTextures::show( avatar->getID() );
		return true;
	}
};

void callback_eject(S32 option, void* data)
{
	LLUUID* avatar_id = (LLUUID*) data;

	if (0 == option || 1 == option)
	{
		LLMessageSystem* msg = gMessageSystem;
		LLViewerObject* avatar = gObjectList.findObject(*avatar_id);

		if (avatar)
		{
			U32 flags = 0x0;
			if (1 == option)
			{
				// eject and add to ban list
				flags |= 0x1;
			}

			msg->newMessage("EjectUser");
			msg->nextBlock("AgentData");
			msg->addUUID("AgentID", gAgent.getID() );
			msg->addUUID("SessionID", gAgent.getSessionID() );
			msg->nextBlock("Data");
			msg->addUUID("TargetID", *avatar_id );
			msg->addU32("Flags", flags );
			msg->sendReliable( avatar->getRegion()->getHost() );
		}
	}

	delete avatar_id;
	avatar_id = NULL;
}

class LLAvatarEject : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if( avatar )
		{
			LLUUID* avatar_id = new LLUUID( avatar->getID() );
			gViewerWindow->alertXml("EjectAvatar",
					callback_eject, (void*)avatar_id);
			
		}
		return true;
	}
};

class LLAvatarEnableFreezeEject : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		bool new_value = (avatar != NULL);

		if (new_value)
		{
			const LLVector3& pos = avatar->getPositionRegion();
			LLViewerRegion* region = avatar->getRegion();
			new_value = (region != NULL);

			if (new_value)
			{
				new_value = (region->isOwnedSelf(pos) || region->isOwnedGroup(pos));
			}
		}

		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLAvatarGiveCard : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		llinfos << "handle_give_card()" << llendl;
		LLViewerObject* dest = gViewerWindow->lastObjectHit();
		if(dest && dest->isAvatar())
		{
			bool found_name = false;
			LLString::format_map_t args;
			LLNameValue* nvfirst = dest->getNVPair("FirstName");
			LLNameValue* nvlast = dest->getNVPair("LastName");
			if(nvfirst && nvlast)
			{
				args["[FIRST]"] = nvfirst->getString();
				args["[LAST]"] = nvlast->getString();
				found_name = true;
			}
			LLViewerRegion* region = dest->getRegion();
			LLHost dest_host;
			if(region)
			{
				dest_host = region->getHost();
			}
			if(found_name && dest_host.isOk())
			{
				LLMessageSystem* msg = gMessageSystem;
				msg->newMessage("OfferCallingCard");
				msg->nextBlockFast(_PREHASH_AgentData);
				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
				msg->nextBlockFast(_PREHASH_AgentBlock);
				msg->addUUIDFast(_PREHASH_DestID, dest->getID());
				LLUUID transaction_id;
				transaction_id.generate();
				msg->addUUIDFast(_PREHASH_TransactionID, transaction_id);
				msg->sendReliable(dest_host);
				LLNotifyBox::showXml("OfferedCard", args);
			}
			else
			{
				gViewerWindow->alertXml("CantOfferCallingCard", args);
			}
		}
		return true;
	}
};



void login_done(S32 which, void *user)
{
	llinfos << "Login done " << which << llendl;

	LLPanelLogin::close();
}



class LLAvatarRate : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if( avatar )
		{
			LLFloaterRate::show( avatar->getID() );
		}
		return true;
	}
};

void callback_leave_group(S32 option, void *userdata)
{
	if (option == 0)
	{
		LLMessageSystem *msg = gMessageSystem;

		msg->newMessageFast(_PREHASH_LeaveGroupRequest);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->nextBlockFast(_PREHASH_GroupData);
		msg->addUUIDFast(_PREHASH_GroupID, gAgent.mGroupID );
		//msg->sendReliable( gUserServer );
		gAgent.sendReliableMessage();
	}
}

void handle_leave_group(void *)
{
	if (gAgent.getGroupID() != LLUUID::null)
	{
		LLString::format_map_t args;
		args["[GROUP]"] = gAgent.mGroupName;
		gViewerWindow->alertXml("GroupLeaveConfirmMember", args, callback_leave_group);
	}
}

void append_aggregate(LLString& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt)
{
	LLAggregatePermissions::EValue val = ag_perm.getValue(bit);
	char buffer[MAX_STRING];
	buffer[0] = '\0';
	switch(val)
	{
	case LLAggregatePermissions::AP_NONE:
		sprintf(buffer, "* %s None\n", txt);
		break;
	case LLAggregatePermissions::AP_SOME:
		sprintf(buffer, "* %s Some\n", txt);
		break;
	case LLAggregatePermissions::AP_ALL:
		sprintf(buffer, "* %s All\n", txt);
		break;
	case LLAggregatePermissions::AP_EMPTY:
	default:
		break;
	}
	string.append(buffer);
}

const char* build_extensions_string(LLFilePicker::ELoadFilter filter)
{
	switch(filter)
	{
#if LL_WINDOWS
	case LLFilePicker::FFLOAD_IMAGE:
		return IMAGE_EXTENSIONS;
	case LLFilePicker::FFLOAD_WAV:
		return SOUND_EXTENSIONS;
	case LLFilePicker::FFLOAD_ANIM:
		return ANIM_EXTENSIONS;
	case LLFilePicker::FFLOAD_SLOBJECT:
		return SLOBJECT_EXTENSIONS;
#ifdef _CORY_TESTING
	case LLFilePicker::FFLOAD_GEOMETRY:
		return GEOMETRY_EXTENSIONS;
#endif
	case LLFilePicker::FFLOAD_XML:
	    return XML_EXTENSIONS;
	case LLFilePicker::FFLOAD_ALL:
		return ALL_FILE_EXTENSIONS;
#endif
    default:
	return ALL_FILE_EXTENSIONS;
	}
}


BOOL enable_buy(void*)
{
    // In order to buy, there must only be 1 purchaseable object in
    // the selection manger.
	if(gSelectMgr->getRootObjectCount() != 1) return FALSE;
    LLViewerObject* obj = NULL;
    LLSelectNode* node = gSelectMgr->getFirstRootNode();
	if(node)
    {
        obj = node->getObject();
        if(!obj) return FALSE;

		if(node->mSaleInfo.isForSale() && node->mPermissions->getMaskOwner() & PERM_TRANSFER &&
			(node->mPermissions->getMaskOwner() & PERM_COPY || node->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY))
		{
			if(obj->permAnyOwner()) return TRUE;
		}
    }
	return FALSE;
}

class LLObjectEnableBuy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = enable_buy(NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// Note: This will only work if the selected object's data has been
// received by the viewer and cached in the selection manager.
void handle_buy_object(LLSaleInfo sale_info)
{
	if(!gSelectMgr->selectGetAllRootsValid())
	{
		LLNotifyBox::showXml("UnableToBuyWhileDownloading");
		return;
	}

	LLUUID owner_id;
	LLString owner_name;
	BOOL owners_identical = gSelectMgr->selectGetOwner(owner_id, owner_name);
	if (!owners_identical)
	{
		LLNotifyBox::showXml("CannotBuyObjectsFromDifferentOwners");
		return;
	}

	LLPermissions perm;
	BOOL valid = gSelectMgr->selectGetPermissions(perm);
	LLAggregatePermissions ag_perm;
	valid &= gSelectMgr->selectGetAggregatePermissions(ag_perm);
	if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID()))
	{
		LLNotifyBox::showXml("ObjectNotForSale");
		return;
	}

	if(sale_info.getSalePrice() > gStatusBar->getBalance())
	{
		LLFloaterBuyCurrency::buyCurrency(
			"This object costs", sale_info.getSalePrice());
		return;
	}

	LLFloaterBuy::show(sale_info);
}


void handle_buy_contents(LLSaleInfo sale_info)
{
	LLFloaterBuyContents::show(sale_info);
}

class LLFileEnableSaveAs : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gFloaterView->getFrontmost() && gFloaterView->getFrontmost()->canSaveAs();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

void handle_region_dump_temp_asset_data(void*)
{
	llinfos << "Dumping temporary asset data to simulator logs" << llendl;
	std::vector<std::string> strings;
	LLUUID invoice;
	send_generic_message("dumptempassetdata", strings, invoice);
}

void handle_region_clear_temp_asset_data(void*)
{
	llinfos << "Clearing temporary asset data" << llendl;
	std::vector<std::string> strings;
	LLUUID invoice;
	send_generic_message("cleartempassetdata", strings, invoice);
}

void handle_region_dump_settings(void*)
{
	LLViewerRegion* regionp = gAgent.getRegion();
	if (regionp)
	{
		llinfos << "Damage:    " << (regionp->getAllowDamage() ? "on" : "off") << llendl;
		llinfos << "Landmark:  " << (regionp->getAllowLandmark() ? "on" : "off") << llendl;
		llinfos << "SetHome:   " << (regionp->getAllowSetHome() ? "on" : "off") << llendl;
		llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl;
		llinfos << "SunFixed:  " << (regionp->getSunFixed() ? "on" : "off") << llendl;
		llinfos << "BlockFly:  " << (regionp->getBlockFly() ? "on" : "off") << llendl;
		llinfos << "AllowP2P:  " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl;
		llinfos << "Water:     " << (regionp->getWaterHeight()) << llendl;
	}
}

void handle_dump_group_info(void *)
{
	llinfos << "group   " << gAgent.mGroupName << llendl;
	llinfos << "ID      " << gAgent.mGroupID << llendl;
	llinfos << "powers " << gAgent.mGroupPowers << llendl;
	llinfos << "title   " << gAgent.mGroupTitle << llendl;
	//llinfos << "insig   " << gAgent.mGroupInsigniaID << llendl;
}


void handle_dump_focus(void *)
{
	LLView *view = gFocusMgr.getKeyboardFocus();

	llinfos << "Keyboard focus " << (view ? view->getName() : "(none)") << llendl;
}

class LLSelfStandUp : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
		return true;
	}
};

class LLSelfEnableStandUp : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.getAvatarObject() && gAgent.getAvatarObject()->mIsSitting;
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL check_admin_override(void*)
{
	return gAgent.getAdminOverride();
}

void handle_admin_override_toggle(void*)
{
	if(!gAgent.getAdminOverride())
	{
		gAgent.setAdminOverride(TRUE);
		show_debug_menus();
	}
	else gAgent.setAdminOverride(FALSE);
}

void handle_god_mode(void*)
{
	gAgent.requestEnterGodMode();
}

void handle_leave_god_mode(void*)
{
	gAgent.requestLeaveGodMode();
}

void set_god_level(U8 god_level)
{
		U8 old_god_level = gAgent.getGodLevel();
		gAgent.setGodLevel( god_level );
		show_debug_menus();
		gIMView->refresh();
		gParcelMgr->notifyObservers();

		// Some classifieds change visibility on god mode
		LLFloaterDirectory::requestClassified();

		// God mode changes sim visibility
		gWorldMap->reset();
		gWorldMap->setCurrentLayer(0);

		// inventory in items may change in god mode
		gObjectList.dirtyAllObjectInventory();

		LLString::format_map_t args;
		if(god_level > GOD_NOT)
		{
			args["[LEVEL]"] = llformat("%d",(S32)god_level);
			if (gInProductionGrid)
			{
				gMenuBarView->setBackgroundColor( gColors.getColor( "MenuBarGodBgColor" ) );
			}
			else
			{
				gMenuBarView->setBackgroundColor( gColors.getColor( "MenuNonProductionGodBgColor" ) );
			}
			LLNotifyBox::showXml("EnteringGodMode", args);
		}
		else
		{
			args["[LEVEL]"] = llformat("%d",(S32)old_god_level);
			if (gInProductionGrid)
			{
				gMenuBarView->setBackgroundColor( gColors.getColor( "MenuBarBgColor" ) );
			}
			else
			{
				gMenuBarView->setBackgroundColor( gColors.getColor( "MenuNonProductionBgColor" ) );
			}
			LLNotifyBox::showXml("LeavingGodMode", args);
		}
}

#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
void handle_toggle_hacked_godmode(void*)
{
	gHackGodmode = !gHackGodmode;
	set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT);
}

BOOL check_toggle_hacked_godmode(void*)
{
	return gHackGodmode;
}
#endif

void process_grant_godlike_powers(LLMessageSystem* msg, void**)
{
	LLUUID agent_id;
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
	LLUUID session_id;
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
	if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID()))
	{
		U8 god_level;
		msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level);
		set_god_level(god_level);
	}
	else
	{
		llwarns << "Grant godlike for wrong agent " << agent_id << llendl;
	}
}

void load_url_local_file(const char* file_name)
{
	if( gAgent.cameraMouselook() )
	{
		gAgent.changeCameraToDefault();
	}

#if LL_DARWIN || LL_LINUX
	// MBW -- If the Mac client is in fullscreen mode, it needs to go windowed so the browser will be visible.
	if(gViewerWindow->mWindow->getFullscreen())
	{
		gViewerWindow->toggleFullscreen(TRUE);
	}
#endif

	// JC - system() blocks until IE has launched.
	// spawn() runs asynchronously, but opens a command prompt.
	// ShellExecute() just opens the damn file with the default
	// web browser.
	std::string full_path = "file:///";
	full_path.append(gDirUtilp->getAppRODataDir());
	full_path.append(gDirUtilp->getDirDelimiter());
	full_path.append(file_name);

	LLWeb::loadURL(full_path.c_str());
}

/*
class LLHaveCallingcard : public LLInventoryCollectFunctor
{
public:
	LLHaveCallingcard(const LLUUID& agent_id);
	virtual ~LLHaveCallingcard() {}
	virtual bool operator()(LLInventoryCategory* cat,
							LLInventoryItem* item);
	BOOL isThere() const { return mIsThere;}
protected:
	LLUUID mID;
	BOOL mIsThere;
};

LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) :
	mID(agent_id),
	mIsThere(FALSE)
{
}

bool LLHaveCallingcard::operator()(LLInventoryCategory* cat,
								   LLInventoryItem* item)
{
	if(item)
	{
		if((item->getType() == LLAssetType::AT_CALLINGCARD)
		   && (item->getCreatorUUID() == mID))
		{
			mIsThere = TRUE;
		}
	}
	return FALSE;
}
*/

BOOL is_agent_friend(const LLUUID& agent_id)
{
	return (LLAvatarTracker::instance().getBuddyInfo(agent_id) != NULL);
}

BOOL is_agent_mappable(const LLUUID& agent_id)
{
	return (is_agent_friend(agent_id) &&
		LLAvatarTracker::instance().getBuddyInfo(agent_id)->isOnline() &&
		LLAvatarTracker::instance().getBuddyInfo(agent_id)->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)
		);
}

// Enable a menu item when you have someone's card.
/*
BOOL enable_have_card(void *userdata)
{
	LLUUID* avatar_id = (LLUUID *)userdata;
	if (gAgent.isGodlike())
	{
		return TRUE;
	}
	else if(avatar_id)
	{
		return is_agent_friend(*avatar_id);
	}
	else
	{
		return FALSE;
	}
}
*/

// Enable a menu item when you don't have someone's card.
class LLAvatarEnableAddFriend : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object(gViewerWindow->lastObjectHit());
		bool new_value = avatar && !is_agent_friend(avatar->getID());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

void request_friendship(const LLUUID& dest_id)
{
	LLViewerObject* dest = gObjectList.findObject(dest_id);
	if(dest && dest->isAvatar())
	{
		LLString fullname;
		LLString::format_map_t args;
		LLNameValue* nvfirst = dest->getNVPair("FirstName");
		LLNameValue* nvlast = dest->getNVPair("LastName");
		if(nvfirst && nvlast)
		{
			args["[FIRST]"] = nvfirst->getString();
			args["[LAST]"] = nvlast->getString();
			fullname = nvfirst->getString();
			fullname += " ";
			fullname += nvlast->getString();
		}
		if (!fullname.empty())
		{
			LLFloaterFriends::requestFriendship(dest_id, fullname);
			LLNotifyBox::showXml("OfferedFriendship", args);
		}
		else
		{
			gViewerWindow->alertXml("CantOfferFriendship");
		}
	}
}


class LLEditEnableCustomizeAvatar : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.getWearablesLoaded();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

bool handle_sit_or_stand()
{
	LLViewerObject *object = gObjectList.findObject(gLastHitNonFloraObjectID);	
	if (!object)
	{
		return true;
	}

	if (sitting_on_selection())
	{
		gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
		gSelectMgr->deselectTransient();
		return true;
	}

	// get object selection offset 

	if (object && object->getPCode() == LL_PCODE_VOLUME)
	{
		LLVector3d offset_double = gViewerWindow->lastNonFloraObjectHitOffset();
		LLVector3 offset_single;
		offset_single.setVec(offset_double);
		
		gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
		gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
		gMessageSystem->addVector3Fast(_PREHASH_Offset, offset_single);

		object->getRegion()->sendReliableMessage();

		gSelectMgr->deselectTransient();
	}
	return true;
}

class LLObjectSitOrStand : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		return handle_sit_or_stand();
	}
};

void near_sit_down_point(BOOL success, void *)
{
	gAgent.setFlying(FALSE);
	gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);

	// Might be first sit
	LLFirstUse::useSit();
}

class LLLandSit : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gAgent.setControlFlags(AGENT_CONTROL_STAND_UP);
		gParcelMgr->deselectLand();

		LLVector3d posGlobal = gLastHitPosGlobal;
		
		LLQuaternion target_rot;
		if (gAgent.getAvatarObject())
		{
			target_rot = gAgent.getAvatarObject()->getRotation();
		}
		else
		{
			target_rot = gAgent.getFrameAgent().getQuaternion();
		}
		gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f);
		return true;
	}
};

void show_permissions_control(void*)
{
	LLFloaterPermissionsMgr* floaterp = LLFloaterPermissionsMgr::show();
	floaterp->mPermissions->addPermissionsData("foo1", LLUUID::null, 0);
	floaterp->mPermissions->addPermissionsData("foo2", LLUUID::null, 0);
	floaterp->mPermissions->addPermissionsData("foo3", LLUUID::null, 0);
}

#if 0 // Unused (these just modify AudioInfoPage which is not used anywhere in the code
void handle_audio_status_1(void*)
{
	S32 page = gSavedSettings.getS32("AudioInfoPage");
	if (1 == page)
	{
		page = 0;
	}
	else
	{
		page = 1;
	}
	gSavedSettings.setS32("AudioInfoPage", page);	
}

void handle_audio_status_2(void*)
{
	S32 page = gSavedSettings.getS32("AudioInfoPage");
	if (2 == page)
	{
		page = 0;
	}
	else
	{
		page = 2;
	}
	gSavedSettings.setS32("AudioInfoPage", page);	
}

void handle_audio_status_3(void*)
{
	S32 page = gSavedSettings.getS32("AudioInfoPage");
	if (3 == page)
	{
		page = 0;
	}
	else
	{
		page = 3;
	}
	gSavedSettings.setS32("AudioInfoPage", page);	
}

void handle_audio_status_4(void*)
{
	S32 page = gSavedSettings.getS32("AudioInfoPage");
	if (4 == page)
	{
		page = 0;
	}
	else
	{
		page = 4;
	}
	gSavedSettings.setS32("AudioInfoPage", page);	
}
#endif

void reload_ui(void *)
{
	gUICtrlFactory->rebuild();
}

class LLWorldFly : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gAgent.toggleFlying();
		return true;
	}
};

void handle_agent_stop_moving(void*)
{
	// stop agent
	gAgent.setControlFlags(AGENT_CONTROL_STOP);

	// cancel autopilot
	gAgent.stopAutoPilot();
}

void print_packets_lost(void*)
{
	gWorldPointer->printPacketsLost();
}


void drop_packet(void*)
{
	gMessageSystem->mPacketRing.dropPackets(1);
}


void velocity_interpolate( void* data )
{
	BOOL toggle = gSavedSettings.getBOOL("VelocityInterpolate");
	LLMessageSystem* msg = gMessageSystem;
	if ( !toggle )
	{
		msg->newMessageFast(_PREHASH_VelocityInterpolateOn);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		gAgent.sendReliableMessage();
		llinfos << "Velocity Interpolation On" << llendl;
	}
	else
	{
		msg->newMessageFast(_PREHASH_VelocityInterpolateOff);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		gAgent.sendReliableMessage();
		llinfos << "Velocity Interpolation Off" << llendl;
	}
	// BUG this is a hack because of the change in menu behavior.  The
	// old menu system would automatically change a control's value,
	// but the new LLMenuGL system doesn't know what a control
	// is. However, it's easy to distinguish between the two callers
	// because LLMenuGL passes in the name of the user data (the
	// control name) to the callback function, and the user data goes
	// unused in the old menu code. Thus, if data is not null, then we
	// need to swap the value of the control.
	if( data )
	{
		gSavedSettings.setBOOL( static_cast<char*>(data), !toggle );
	}
}


void update_fov(S32 increments)
{
	F32 old_fov = gCamera->getDefaultFOV();
	// for each increment, FoV is 20% bigger
	F32 new_fov = old_fov * pow(1.2f, increments);

	// cap the FoV
	new_fov = llclamp(new_fov, MIN_FIELD_OF_VIEW, MAX_FIELD_OF_VIEW);

	if (new_fov != old_fov)
	{
		LLMessageSystem* msg = gMessageSystem;
		msg->newMessageFast(_PREHASH_AgentFOV);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);

		msg->nextBlockFast(_PREHASH_FOVBlock);
		msg->addU32Fast(_PREHASH_GenCounter, 0);
		msg->addF32Fast(_PREHASH_VerticalAngle, new_fov);

		gAgent.sendReliableMessage();

		// force agent to update dirty patches
		gCamera->setDefaultFOV(new_fov);
		gCamera->setView(new_fov);
	}
}

class LLViewZoomOut : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		update_fov(1);
		return true;
	}
};

class LLViewZoomIn : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		update_fov(-1);
		return true;
	}
};

class LLViewZoomDefault : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		F32 old_fov = gCamera->getView();
		// for each increment, FoV is 20% bigger
		F32 new_fov = DEFAULT_FIELD_OF_VIEW;

		if (new_fov != old_fov)
		{
			LLMessageSystem* msg = gMessageSystem;
			msg->newMessageFast(_PREHASH_AgentFOV);
			msg->nextBlockFast(_PREHASH_AgentData);
			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
			msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
			msg->nextBlockFast(_PREHASH_FOVBlock);
			msg->addU32Fast(_PREHASH_GenCounter, 0);
			msg->addF32Fast(_PREHASH_VerticalAngle, new_fov);

			gAgent.sendReliableMessage();

			// force agent to update dirty patches
			gCamera->setDefaultFOV(new_fov);
			gCamera->setView(new_fov);
		}
		return true;
	}
};



void toggle_wind_audio(void)
{
	if (gAudiop)
	{
		gAudiop->enableWind(!(gAudiop->isWindEnabled()));
	}
}


// Callback for enablement
BOOL is_inventory_visible( void* user_data )
{
	LLInventoryView* iv = reinterpret_cast<LLInventoryView*>(user_data);
	if( iv )
	{
		return iv->getVisible();
	}
	return FALSE;
}

void handle_show_newest_map(void*)
{
	LLFloaterWorldMap::show(NULL, FALSE);
}

//-------------------------------------------------------------------
// Help menu functions
//-------------------------------------------------------------------

class LLHelpMOTD : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString::format_map_t args;
		args["[MOTD]"] = gAgent.mMOTD;
		gViewerWindow->alertXml("MOTD", args, NULL, NULL);
		return true;
	}
};

class LLHelpLiveHelp : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// the session_id of a 911 session will always be this agent's session id
		static LLUUID session_id(LLUUID::null);
		if (session_id.isNull())
		{
			session_id.generate();
		}
		gIMView->setFloaterOpen(TRUE);
		LLDynamicArray<LLUUID> members;
		members.put(gAgent.getID());
		gIMView->addSession("Help Request", IM_SESSION_911_START, session_id, members); //xui: translate
		return true;
	}
};

//
// Major mode switching
//
void reset_view_final( BOOL proceed, void* );

void handle_reset_view()
{
	if( (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgent.getCameraMode()) && gFloaterCustomize )
	{
		// Show dialog box if needed.
		gFloaterCustomize->askToSaveAllIfDirty( reset_view_final, NULL );
	}
	else
	{
		reset_view_final( TRUE, NULL );
	}
}

class LLViewResetView : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		handle_reset_view();
		return true;
	}
};

// Note: extra parameters allow this function to be called from dialog.
void reset_view_final( BOOL proceed, void* ) 
{
	if( !proceed )
	{
		return;
	}

	gAgent.changeCameraToDefault();
	
	gAgent.resetView(!gFloaterTools->getVisible());
	
	gViewerWindow->showCursor();

	// Switch back to basic toolset
	gCurrentToolset = gBasicToolset;
	gBasicToolset->selectFirstTool();
	gToolMgr->useSelectedTool( gBasicToolset );
}

class LLViewLookAtLastChatter : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gAgent.lookAtLastChat();
		return true;
	}
};

class LLViewMouselook : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (!gAgent.cameraMouselook())
		{
			gAgent.changeCameraToMouselook();
		}
		else
		{
			gAgent.changeCameraToDefault();
		}
		return true;
	}
};

class LLViewFullscreen : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gViewerWindow->toggleFullscreen(TRUE);
		return true;
	}
};

class LLViewDefaultUISize : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gSavedSettings.setF32("UIScaleFactor", 1.0f);
		gSavedSettings.setBOOL("UIAutoScale", FALSE);	
		gViewerWindow->reshape(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
		return true;
	}
};

class LLEditDuplicate : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if(gEditMenuHandler)
		{
			gEditMenuHandler->duplicate();
		}
		return true;
	}
};

class LLEditEnableDuplicate : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canDuplicate();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


void disabled_duplicate(void*)
{
	if (gSelectMgr->getFirstObject())
	{
		LLNotifyBox::showXml("CopyFailed");
	}
}

void handle_duplicate_in_place(void*)
{
	llinfos << "handle_duplicate_in_place" << llendl;

	LLVector3 offset(0.f, 0.f, 0.f);
	gSelectMgr->selectDuplicate(offset, TRUE);
}

void handle_repeat_duplicate(void*)
{
	gSelectMgr->repeatDuplicate();
}

void handle_deed_object_to_group(void*)
{
	LLUUID group_id;
	
	gSelectMgr->selectGetGroup(group_id);
	gSelectMgr->sendOwner(LLUUID::null, group_id, FALSE);
	gViewerStats->incStat(LLViewerStats::ST_RELEASE_COUNT);
}

BOOL enable_deed_object_to_group(void*)
{
	if(gSelectMgr->isEmpty()) return FALSE;
	LLPermissions perm;
	LLUUID group_id;

	if (gSelectMgr->selectGetGroup(group_id) &&
		gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) &&
		gSelectMgr->selectGetPermissions(perm) &&
		perm.deedToGroup(gAgent.getID(), group_id))
	{
		return TRUE;
	}
	return FALSE;
}


/*
 * No longer able to support viewer side manipulations in this way
 *
void god_force_inv_owner_permissive(LLViewerObject* object,
									InventoryObjectList* inventory,
									S32 serial_num,
									void*)
{
	typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t;
	item_array_t items;

	InventoryObjectList::const_iterator inv_it = inventory->begin();
	InventoryObjectList::const_iterator inv_end = inventory->end();
	for ( ; inv_it != inv_end; ++inv_it)
	{
		if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY)
		   && ((*inv_it)->getType() != LLAssetType::AT_ROOT_CATEGORY))
		{
			LLInventoryObject* obj = *inv_it;
			LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj);
			LLPermissions perm(new_item->getPermissions());
			perm.setMaskBase(PERM_ALL);
			perm.setMaskOwner(PERM_ALL);
			new_item->setPermissions(perm);
			items.push_back(new_item);
		}
	}
	item_array_t::iterator end = items.end();
	item_array_t::iterator it;
	for(it = items.begin(); it != end; ++it)
	{
		// since we have the inventory item in the callback, it should not
		// invalidate iteration through the selection manager.
		object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false);
	}
}
*/

void handle_object_owner_permissive(void*)
{
	// only send this if they're a god.
	if(gAgent.isGodlike())
	{
		// do the objects.
		gSelectMgr->setObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE);
		gSelectMgr->setObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE);
	}
}

void handle_object_owner_self(void*)
{
	// only send this if they're a god.
	if(gAgent.isGodlike())
	{
		gSelectMgr->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE);
	}
}

// Shortcut to set owner permissions to not editable.
void handle_object_lock(void*)
{
	gSelectMgr->setObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY);
}

void handle_object_asset_ids(void*)
{
	// only send this if they're a god.
	if (gAgent.isGodlike())
	{
		gSelectMgr->sendGodlikeRequest("objectinfo", "assetids");
	}
}

void handle_force_parcel_owner_to_me(void*)
{
	gParcelMgr->sendParcelGodForceOwner( gAgent.getID() );
}

void handle_force_parcel_to_content(void*)
{
	gParcelMgr->sendParcelGodForceToContent();
}

void handle_claim_public_land(void*)
{
	if (gParcelMgr->getSelectionRegion() != gAgent.getRegion())
	{
		LLNotifyBox::showXml("ClaimPublicLand");
		return;
	}

	LLVector3d west_south_global;
	LLVector3d east_north_global;
	gParcelMgr->getSelection(west_south_global, east_north_global);
	LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global);
	LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global);

	LLMessageSystem* msg = gMessageSystem;
	msg->newMessage("GodlikeMessage");
	msg->nextBlock("AgentData");
	msg->addUUID("AgentID", gAgent.getID());
	msg->addUUID("SessionID", gAgent.getSessionID());
	msg->nextBlock("MethodData");
	msg->addString("Method", "claimpublicland");
	msg->addUUID("Invoice", LLUUID::null);
	char buffer[32];
	sprintf(buffer, "%f", west_south.mV[VX]);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buffer);
	sprintf(buffer, "%f", west_south.mV[VY]);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buffer);
	sprintf(buffer, "%f", east_north.mV[VX]);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buffer);
	sprintf(buffer, "%f", east_north.mV[VY]);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buffer);
	gAgent.sendReliableMessage();
}

//void handle_toggle_parcel_newbie(void*)
//{
//	gParcelMgr->toggleParcelGodReserveForNewbie();
//}

void on_expunge_user(S32 option, const LLString& text, void*)
{
	if(option == -1) return;
	llinfos << "on_expunge_user(" << option << "," << text << ")" << llendl;
	LLMessageSystem* msg = gMessageSystem;
	LLUUID user_id;
	if(user_id.set(text))
	{
		msg->newMessage("GodExpungeUser");
		msg->nextBlock("AgentData");
		msg->addUUID("AgentID", gAgent.getID());
		msg->addUUID("SessionID", gAgent.getSessionID());
		msg->nextBlock("ExpungeData");
		msg->addUUID("AgentID", user_id);
		msg->sendReliable(gUserServer);
	}
	else
	{
		gViewerWindow->alertXml("InvalidUUID");
	}
}

void handle_god_expunge_user(void*)
{
	gViewerWindow->alertXmlEditText("ExpungeUser", LLString::format_map_t(),
									NULL, NULL,
									on_expunge_user, NULL);
}

void handle_god_request_havok(void *)
{
	if (gAgent.isGodlike())
	{
		gSelectMgr->sendGodlikeRequest("havok", "infoverbose");
	}
}

//void handle_god_request_foo(void *)
//{
//	if (gAgent.isGodlike())
//	{
//		gSelectMgr->sendGodlikeRequest(GOD_WANTS_FOO);
//	}
//}

//void handle_god_request_terrain_save(void *)
//{
//	if (gAgent.isGodlike())
//	{
//		gSelectMgr->sendGodlikeRequest("terrain", "save");
//	}
//}

//void handle_god_request_terrain_load(void *)
//{
//	if (gAgent.isGodlike())
//	{
//		gSelectMgr->sendGodlikeRequest("terrain", "load");
//	}
//}


// HACK for easily testing new avatar geometry
void handle_god_request_avatar_geometry(void *)
{
	if (gAgent.isGodlike())
	{
		gSelectMgr->sendGodlikeRequest("avatar toggle", NULL);
	}
}


void handle_show_overlay_title(void*)
{
	gShowOverlayTitle = !gShowOverlayTitle;
	gSavedSettings.setBOOL("ShowOverlayTitle", gShowOverlayTitle);
}

void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
{
	if(gAgent.cameraMouselook())
	{
		gAgent.changeCameraToDefault();
	}
	//gInventoryView->setPanelOpen(TRUE);

	LLViewerObject* object = NULL;
	LLSelectNode* node = gSelectMgr->getFirstRootNode();
	if(!node) return;
	object = node->getObject();
	if(!object) return;
	LLViewerRegion* region = object->getRegion();
	char* error = NULL;

	// Check conditions that we can't deal with, building a list of
	// everything that we'll actually be derezzing.
	LLDynamicArray<LLViewerObject*> derez_objects;
	BOOL can_derez_current;
	for( ; node != NULL; node = gSelectMgr->getNextRootNode())
	{
		object = node->getObject();
		if(!object || !node->mValid) continue;
		if(object->getRegion() != region)
		{
			// *FIX: This doesn't work at all if the some of the
			// objects are in regions besides the first object
			// selected. We should really support this.

			// ...crosses region boundaries
			error = "AcquireErrorObjectSpan";
			break;
		}
		if (object->isAvatar())
		{
			// ...don't acquire avatars
			continue;
		}

		// If AssetContainers are being sent back, they will appear as 
		// boxes in the owner's inventory.
		if (object->getNVPair("AssetContainer")
			&& dest != DRD_RETURN_TO_OWNER)
		{
			// this object is an asset container, derez its contents, not it
			llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl;
			/*
			object->requestInventory(container_inventory_arrived, 
				(void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest));
			*/
			continue;
		}
		can_derez_current = FALSE;
		switch(dest)
		{
		case DRD_TAKE_INTO_AGENT_INVENTORY:
		case DRD_TRASH:
			if( (node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify())
				|| (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)) )
			{
				can_derez_current = TRUE;
			}
			break;

		case DRD_RETURN_TO_OWNER:
			can_derez_current = TRUE;
			break;

		default:
			if((node->mPermissions->allowTransferTo(gAgent.getID())
				&& object->permCopy())
			   || gAgent.isGodlike())
			{
				can_derez_current = TRUE;
			}
			break;
		}
		if(can_derez_current)
		{
			derez_objects.put(object);
		}
	}

	// This constant is based on (1200 - HEADER_SIZE) / 4 bytes per
	// root.  I lopped off a few (33) to provide a bit
	// pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs.
	// This gives us a maximum of 63500 root objects - which should
	// satisfy anybody.
	const S32 MAX_ROOTS_PER_PACKET = 250;
	const S32 MAX_PACKET_COUNT = 254;
	F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET);
	if(packets > (F32)MAX_PACKET_COUNT)
	{
		error = "AcquireErrorTooManyObjects";
	}

	if(!error && derez_objects.count() > 0)
	{
		U8 d = (U8)dest;
		LLUUID tid;
		tid.generate();
		U8 packet_count = (U8)packets;
		S32 object_index = 0;
		S32 objects_in_packet = 0;
		LLMessageSystem* msg = gMessageSystem;
		for(U8 packet_number = 0;
			packet_number < packet_count;
			++packet_number)
		{
			msg->newMessageFast(_PREHASH_DeRezObject);
			msg->nextBlockFast(_PREHASH_AgentData);
			msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
			msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
			msg->nextBlockFast(_PREHASH_AgentBlock);
			msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
			msg->addU8Fast(_PREHASH_Destination, d);	
			msg->addUUIDFast(_PREHASH_DestinationID, dest_id);
			msg->addUUIDFast(_PREHASH_TransactionID, tid);
			msg->addU8Fast(_PREHASH_PacketCount, packet_count);
			msg->addU8Fast(_PREHASH_PacketNumber, packet_number);
			objects_in_packet = 0;
			while((object_index < derez_objects.count())
				  && (objects_in_packet++ < MAX_ROOTS_PER_PACKET))

			{
				object = derez_objects.get(object_index++);
				msg->nextBlockFast(_PREHASH_ObjectData);
				msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
				// VEFFECT: DerezObject
				LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
				effectp->setPositionGlobal(object->getPositionGlobal());
				effectp->setColor(LLColor4U(gAgent.getEffectColor()));
			}
			msg->sendReliable(region->getHost());
		}
		make_ui_sound("UISndObjectRezOut");

		// Busy count decremented by inventory update, so only increment
		// if will be causing an update.
		if (dest != DRD_RETURN_TO_OWNER)
		{
			gViewerWindow->getWindow()->incBusyCount();
		}
	}
	else if(error)
	{
		gViewerWindow->alertXml(error);
	}
}

class LLToolsTakeCopy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gSelectMgr->isEmpty()) return true;

		const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT);
		derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);

		// Only deselect if we're not building
		if (!gToolMgr->inEdit())
		{
			gSelectMgr->deselectTransient();
		}
		return true;
	}
};


void callback_return_to_owner(S32 option, void* data)
{
	if (0 == option)
	{
		// Ignore category ID for this derez destination.
		derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null);
	}
}

// You can return an object to its owner if it is on your land.
class LLObjectReturn : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gSelectMgr->isEmpty()) return true;

		gViewerWindow->alertXml("ReturnToOwner",
			callback_return_to_owner,
			NULL);
		return true;
	}
};


// Allow return to owner if one or more of the selected items is
// over land you own.
class LLObjectEnableReturn : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
#ifdef HACKED_GODLIKE_VIEWER
		bool new_value = true;
#else
		bool new_value = false;
		if (gAgent.isGodlike())
		{
			new_value = true;
		}
		else
		{
			LLViewerRegion* region = gAgent.getRegion();
			if (region)
			{
				// Estate owners and managers can always return objects.
				if (region->canManageEstate())
				{
					new_value = true;
				}
				else
				{
					LLViewerObject* obj = NULL;
					for(obj = gSelectMgr->getFirstRootObject();
						obj;
						obj = gSelectMgr->getNextRootObject())
					{
						if (obj->isOverAgentOwnedLand()
							|| obj->isOverGroupOwnedLand()
							|| obj->permModify())
						{
							new_value = true;
							break;
						}
					}
				}
			}
		}
#endif
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

void force_take_copy(void*)
{
	if (gSelectMgr->isEmpty()) return;
	const LLUUID& category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT);
	derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id);

	// Only deselect if we're not building
	if (!gToolMgr->inEdit())
	{
		gSelectMgr->deselectTransient();
	}
}
#ifdef _CORY_TESTING

void force_export_copy(void*)
{
	LLViewerObject* object = NULL;
	LLSelectNode* node = gSelectMgr->getFirstNode();
	if(!node) return;
	object = node->getObject();
	if(!object) return;


	LLString proposed_name;
	proposed_name.append(node->mName);
	proposed_name.append( ".slg" );

	LLViewerRegion* region = object->getRegion();

	// Check conditions that we can't deal with, building a list of
	// everything that we'll actually be derezzing.
	
	std::vector<LLViewerObject*>		export_objects;
	std::vector<std::string>			export_names;
	std::vector<std::string>			export_descriptions;

	S32 object_index = 0;

	for( ; node != NULL; node = gSelectMgr->getNextNode())
	{
		object = node->getObject();
		if(!object || !node->mValid)
		{
			// Clicked cancel
			return;
		}
		if(object->getRegion() != region)
		{
			// Clicked cancel
			return;
		}
		if (object->isAvatar())
		{
			continue;
		}

		if (object->getNVPair("AssetContainer"))
		{
			continue;
		}
		export_objects.push_back(node->getObject());
		export_names.push_back(node->mName);
		export_descriptions.push_back(node->mDescription);
	}

	if (export_objects.empty())
	{
		return;
	}

	// pick a save file
	LLFilePicker& picker = LLFilePicker::instance();
	if (!picker.getSaveFile(LLFilePicker::FFSAVE_GEOMETRY, proposed_name))
	{
		// Clicked cancel
		return;
	}

	// Copy the directory + file name
	char filepath[LL_MAX_PATH];
	strcpy(filepath, picker.getFirstFile());

	apr_file_t* fp = ll_apr_file_open(filepath, LL_APR_W);

	if (!fp)
	{
		return;
	}

	object = export_objects[object_index];
	LLVector3 baseoffset = object->getPositionRegion();

	apr_file_printf(fp, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n");
	apr_file_printf(fp, "<LindenGeometry>\n");

	while(object_index < export_objects.size())
	{
		apr_file_printf(fp, "<Object\n");
		apr_file_printf(fp, "\tShape='%s'\n", export_names[object_index].c_str());
		apr_file_printf(fp, "\tDescription='%s'\n", export_descriptions[object_index].c_str());

		apr_file_printf(fp, "\tPCode='%d'\n", (U32)object->getPCode());
		apr_file_printf(fp, "\tMaterial='%d'\n", object->getMaterial());
		apr_file_printf(fp, "\tScale='%5f %5f %5f'\n", object->getScale().mV[VX], object->getScale().mV[VY], object->getScale().mV[VZ]);
		LLVector3 delta = object->getPositionRegion() - baseoffset;
		LLQuaternion rot = object->getRotationRegion();
		apr_file_printf(fp, "\tOffset='%5f %5f %5f'\n", delta.mV[VX], delta.mV[VY], delta.mV[VZ]);
		apr_file_printf(fp, "\tOrientation='%5f %5f %5f %5f'\n", rot.mQ[VX], rot.mQ[VY], rot.mQ[VZ], rot.mQ[VS]);
		const LLProfileParams pparams = object->getVolume()->getProfile().mParams;
		apr_file_printf(fp, "\tShapeProfile='%d %f %f %f'\n", pparams.getCurveType(), pparams.getBegin(), pparams.getEnd(), pparams.getHollow());
		const LLPathParams paparams = object->getVolume()->getPath().mParams;
		apr_file_printf(fp, "\tShapePath='%d %f %f %f %f %f %f %f %f %f %f %f %f %f'\n",
								 paparams.getCurveType(), paparams.getBegin(), paparams.getEnd(), paparams.getTwist(), paparams.getTwistBegin(), paparams.getScaleX(), paparams.getScaleY(),
								 paparams.getShearX(), paparams.getShearY(), paparams.getRadiusOffset(), paparams.getTaperX(), paparams.getTaperY(),
								 paparams.getRevolutions(), paparams.getSkew());
		S32 face, numfaces;
		numfaces = object->getNumTEs();
		apr_file_printf(fp, "\tNumberOfFaces='%d'>\n", numfaces);
		for (face = 0; face < numfaces; face++)
		{
			const LLTextureEntry *te = object->getTE(face);
			LLColor4 color = te->getColor();
			apr_file_printf(fp, "\t<Face\n\t\tFaceColor='%d %5f %5f %5f %5f'\n", face, color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW]);
			
			char texture[UUID_STR_LENGTH];
			LLUUID texid = te->getID();
			texid.toString(texture);
			F32 sx, sy, ox, oy;
			te->getScale(&sx, &sy);
			te->getOffset(&ox, &oy);
			
			apr_file_printf(fp, "\t\tFace='%d %5f %5f %5f %5f %5f %d %s'\n\t/>\n", face, sx, sy, ox, oy, te->getRotation(), te->getBumpShinyFullbright(), texture);
		}
		apr_file_printf(fp, "</Object>\n");
		object = export_objects[++object_index];
	}

	apr_file_printf(fp, "</LindenGeometry>\n");

	fclose(fp);
}

void undo_find_local_contact_point(LLVector3 &contact,
								   const LLVector3& surface_norm, 
								   const LLQuaternion& rot, 
								   const LLVector3& scale  )
{
	LLVector3 local_norm = surface_norm;
	local_norm.rotVec( ~rot );

	LLVector3 v[6]; 
	v[0].mV[VX] = -1.f;
	v[1].mV[VX] = 1.f;
	
	v[2].mV[VY] = -1.f;
	v[3].mV[VY] = 1.f;

	v[4].mV[VZ] = -1.f;
	v[5].mV[VZ] = 1.f;

	contact = v[0];
	F32 cur_val = 0;

	for( S32 i = 0; i < 6; i++ )
	{
		F32 val = v[i] * local_norm;
		if( val < cur_val )
		{
			contact = v[i];
			cur_val = val;
		}
	}

	contact.mV[VX] *= 0.5f * scale.mV[VX];
	contact.mV[VY] *= 0.5f * scale.mV[VY];
	contact.mV[VZ] *= 0.5f * scale.mV[VZ];
	contact.rotVec( rot );
}



void force_import_geometry(void*)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if (!picker.getOpenFile(LLFilePicker::FFLOAD_GEOMETRY))
	{
		llinfos << "Couldn't import objects from file" << llendl;
		return;
	}

	char directory[LL_MAX_PATH];
	strcpy(directory, picker.getFirstFile());

	llinfos << "Loading LSG file " << directory << llendl;
	LLXmlTree *xmlparser = new LLXmlTree();
	xmlparser->parseFile(directory, TRUE);
	LLXmlTreeNode	*root = xmlparser->getRoot();
	if( !root )
	{
		return;
	}
	// header
	if( !root->hasName( "LindenGeometry" ) )
	{
		llwarns << "Invalid LindenGeometry file header: " << directory << llendl;
		return;
	}
	// objects
	for (LLXmlTreeNode *child = root->getChildByName( "Object" );
		 child;
		 child = root->getNextNamedChild())
	{
		// get object data
		char name[255];			// Shape
		char description[255];	// Description
		U32	 material;			// Material
		F32  sx, sy, sz;		// Scale
		LLVector3 scale;
		F32  ox, oy, oz;		// Offset
		LLVector3 offset;
		F32  rx, ry, rz, rs;	// Orientation
		LLQuaternion rot;
		U32	 curve;
		F32  begin;
		F32  end;
		F32	 hollow;
		F32	 twist;
		F32	 scx, scy;
		F32  shx, shy;
		F32  twist_begin;
		F32	 radius_offset;
		F32  tx, ty;
		F32	 revolutions;
		F32	 skew;
		S32  faces;
		U32 pcode;
		U32 flags = FLAGS_CREATE_SELECTED;

		LLString attribute;

		S32 count = 0;

		child->getAttributeString("PCode", &attribute);
		pcode = atoi(attribute.c_str());
		child->getAttributeString("Shape", &attribute);
		sscanf(attribute.c_str(), "%s", name);
		child->getAttributeString("Description", &attribute);
		sscanf(attribute.c_str(), "%s", description);
		child->getAttributeString("Material", &attribute);
		material = atoi(attribute.c_str());
		child->getAttributeString("Scale", &attribute);
		sscanf(attribute.c_str(), "%f %f %f", &sx, &sy, &sz);
		scale.setVec(sx, sy, sz);
		child->getAttributeString("Offset", &attribute);
		sscanf(attribute.c_str(), "%f %f %f", &ox, &oy, &oz);
		offset.setVec(ox, oy, oz);
		child->getAttributeString("Orientation", &attribute);
		sscanf(attribute.c_str(), "%f %f %f %f", &rx, &ry, &rz, &rs);
		rot.mQ[VX] = rx;
		rot.mQ[VY] = ry;
		rot.mQ[VZ] = rz;
		rot.mQ[VS] = rs;

		child->getAttributeString("ShapeProfile", &attribute);
		sscanf(attribute.c_str(), "%d %f %f %f", &curve, &begin, &end, &hollow);
		LLProfileParams pparams(curve, begin, end, hollow);
		child->getAttributeString("ShapePath", &attribute);
		sscanf(attribute.c_str(), "%d %f %f %f %f %f %f %f %f %f %f %f %f %f", 
			&curve, &begin, &end, &twist, &twist_begin, &scx, &scy, &shx, &shy, &radius_offset, &tx, &ty, &revolutions, &skew);
		LLPathParams paparams(curve, begin, end, scx, scy, shx, shy, twist, twist_begin, radius_offset, tx, ty, revolutions, skew);
		child->getAttributeString("NumberOfFaces", &attribute);
		faces = atoi(attribute.c_str());



		gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());

		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
		gMessageSystem->addU8Fast(_PREHASH_PCode,		pcode);
		gMessageSystem->addU8Fast(_PREHASH_Material,	material);
		gMessageSystem->addU32Fast(_PREHASH_AddFlags,	flags );
		pparams.packMessage(gMessageSystem);
		paparams.packMessage(gMessageSystem);

		LLVector3 forward;
		forward.setVec(3.f, 0.f, 1.f);
		forward = forward * gAgent.getQuat();

		LLVector3 start = gAgent.getPositionAgent() + forward;

		start += offset;

		// offset position to make up for error introduced by placement code
		LLVector3 normal(0.f, 0.f, 1.f);
		LLVector3 delta;

		undo_find_local_contact_point(delta, normal, rot, scale);

		start += delta;

		gMessageSystem->addVector3Fast(_PREHASH_Scale,			scale );
		gMessageSystem->addQuatFast(_PREHASH_Rotation,			rot );
		gMessageSystem->addVector3Fast(_PREHASH_RayStart,		start );
		gMessageSystem->addVector3Fast(_PREHASH_RayEnd,			start );
		gMessageSystem->addBOOLFast(_PREHASH_BypassRaycast,		TRUE );
		gMessageSystem->addBOOLFast(_PREHASH_RayEndIsIntersection,	FALSE );

		U8 state = 0;
		gMessageSystem->addU8Fast(_PREHASH_State, state);
	
		LLUUID ray_target_id;
		gMessageSystem->addUUIDFast(_PREHASH_RayTargetID,			ray_target_id );
	
		/* Setting TE info through ObjectAdd is no longer supported.
		LLPrimitive     temp_primitive;
		temp_primitive.setNumTEs(faces);
		for (LLXmlTreeNode *face = child->getChildByName( "Face" );
			 face;
			 face = child->getNextNamedChild())
		{
			// read the faces
			U32 facenumber;
			LLColor4 color;
			char texture[UUID_STR_LENGTH];
			LLUUID texid;
			texid.toString(texture);
			F32 sx, sy, ox, oy, rot;
			U8 bump;
			LLTextureEntry te;

			face->getAttributeString("FaceColor", &attribute);
			sscanf(attribute, "%d %f %f %f %f", &facenumber, &color.mV[VX], &color.mV[VY], &color.mV[VZ], &color.mV[VW]);
			face->getAttributeString("Face", &attribute);
			sscanf(attribute, "%d %f %f %f %f %f %d %s", &facenumber, &sx, &sy, &ox, &oy, &rot, &bump, texture);
			texid.set(texture);
			te.setColor(color);
			te.setBumpShinyFullbright(bump);
			te.setID(texid);
			te.setRotation(rot);
			te.setOffset(ox, oy);
			te.setScale(sx, sy);

			temp_primitive.setTE(facenumber, te);
		}

		temp_primitive.packTEMessage(gMessageSystem);
		*/
		gMessageSystem->sendReliable(gAgent.getRegionHost());
	}

}
#endif

void handle_take()
{
	// we want to use the folder this was derezzed from if it's
	// available. Otherwise, derez to the normal place.
	if(gSelectMgr->isEmpty()) return;
	LLSelectNode* node = NULL;
	LLViewerObject* object = NULL;
	BOOL you_own_everything = TRUE;

	BOOL locked_but_takeable_object = FALSE;
	LLUUID category_id;
	for(node = gSelectMgr->getFirstRootNode();
		node != NULL;
		node = gSelectMgr->getNextRootNode())
	{
		object = node->getObject();
		if(object)
		{
			if(!object->permYouOwner())
			{
				you_own_everything = FALSE;
			}

			if(!object->permMove())

			{

				locked_but_takeable_object = TRUE;

			}
		}
		if(node->mFolderID.notNull())
		{
			if(category_id.isNull())
			{
				category_id = node->mFolderID;
			}
			else if(category_id != node->mFolderID)
			{
				// we have found two potential destinations. break out
				// now and send to the default location.
				category_id.setNull();
				break;
			}
		}
	}
	if(category_id.notNull())
	{
		// there is an unambiguous destination. See if this agent has
		// such a location and it is not in the trash.
		if(!gInventory.getCategory(category_id))
		{
			// nope, set to NULL.
			category_id.setNull();
		}
		if(category_id.notNull())
		{
			LLUUID trash;
			trash = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH);
			if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash))
			{
				category_id.setNull();
			}
		}
	}
	if(category_id.isNull())
	{
		category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT);
	}
	LLUUID* cat_id = new LLUUID(category_id);
	if(locked_but_takeable_object ||

	   !you_own_everything)
	{

		if(locked_but_takeable_object && you_own_everything)
		{
			
			gViewerWindow->alertXml("ConfirmObjectTakeLock",
			confirm_take,
			(void*)cat_id);

		}
		else if(!locked_but_takeable_object && !you_own_everything)
		{
			
			gViewerWindow->alertXml("ConfirmObjectTakeNoOwn",
			confirm_take,
			(void*)cat_id);
		}
		else
		{
			gViewerWindow->alertXml("ConfirmObjectTakeLockNoOwn",
			confirm_take,
			(void*)cat_id);
		}


	}

	else
	{
		confirm_take(0, (void*)cat_id);
	}
}

void confirm_take(S32 option, void* data)
{
	LLUUID* cat_id = (LLUUID*)data;
	if(!cat_id) return;
	if(enable_take() && (option == 0))
	{
		derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, *cat_id);
	}
	delete cat_id;
}

// You can take an item when it is public and transferrable, or when
// you own it. We err on the side of enabling the item when at least
// one item selected can be copied to inventory.
BOOL enable_take()
{
	if (sitting_on_selection())
	{
		return FALSE;
	}

	LLViewerObject* object = NULL;
	for(LLSelectNode* node = gSelectMgr->getFirstRootNode();
		node != NULL;
		node = gSelectMgr->getNextRootNode())
	{
		object = node->getObject();
		if(!object || !node->mValid) continue;
		if (object->isAvatar())
		{
			// ...don't acquire avatars
			continue;
		}

#ifdef HACKED_GODLIKE_VIEWER
		return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
		if (!gInProductionGrid && gAgent.isGodlike())
		{
			return TRUE;
		}
# endif
		if((node->mPermissions->allowTransferTo(gAgent.getID())
			&& object->permModify())
		   || (node->mPermissions->getOwner() == gAgent.getID()))
		{
			return TRUE;
		}
#endif
	}
	return FALSE;
}

class LLToolsBuyOrTake : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gSelectMgr->isEmpty())
		{
			return true;
		}

		if (is_selection_buy_not_take())
		{
			S32 total_price = selection_price();

			if (total_price <= gStatusBar->getBalance())
			{
				handle_buy(NULL);
			}
			else
			{
				LLFloaterBuyCurrency::buyCurrency(
					"Buying this costs", total_price);
			}
		}
		else
		{
			handle_take();
		}
		return true;
	}
};

class LLToolsEnableBuyOrTake : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool is_buy = is_selection_buy_not_take();
		bool new_value = is_buy ? enable_buy(NULL) : enable_take();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);

		// HACK: Update label
		LLString label;
		LLString buy_text;
		LLString take_text;
		LLString param = userdata["data"].asString();
		LLString::size_type offset = param.find(",");
		if (offset != param.npos)
		{
			buy_text = param.substr(0, offset);
			take_text = param.substr(offset+1);
		}
		if (is_buy)
		{
			label = buy_text;
		}
		else
		{
			label = take_text;
		}
		gMenuHolder->childSetText("Pie Object Take", label);
		gMenuHolder->childSetText("Menu Object Take", label);

		return true;
	}
};

// This is a small helper function to determine if we have a buy or a
// take in the selection. This method is to help with the aliasing
// problems of putting buy and take in the same pie menu space. After
// a fair amont of discussion, it was determined to prefer buy over
// take. The reasoning follows from the fact that when users walk up
// to buy something, they will click on one or more items. Thus, if
// anything is for sale, it becomes a buy operation, and the server
// will group all of the buy items, and copyable/modifiable items into
// one package and give the end user as much as the permissions will
// allow. If the user wanted to take something, they will select fewer
// and fewer items until only 'takeable' items are left. The one
// exception is if you own everything in the selection that is for
// sale, in this case, you can't buy stuff from yourself, so you can
// take it.
// return value = TRUE if selection is a 'buy'.
//                FALSE if selection is a 'take'
BOOL is_selection_buy_not_take()
{
	LLViewerObject* obj = NULL;
	for(LLSelectNode* node = gSelectMgr->getFirstRootNode();
		node != NULL;
		node = gSelectMgr->getNextRootNode())
	{
		obj = node->getObject();
		if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
		{
			// you do not own the object and it is for sale, thus,
			// it's a buy
			return TRUE;
		}
	}
	return FALSE;
}

S32 selection_price()
{
	LLViewerObject* obj = NULL;
	S32 total_price = 0;
	for(LLSelectNode* node = gSelectMgr->getFirstRootNode();
		node != NULL;
		node = gSelectMgr->getNextRootNode())
	{
		obj = node->getObject();
		if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
		{
			// you do not own the object and it is for sale.
			// Add its price.
			total_price += node->mSaleInfo.getSalePrice();
		}
	}

	return total_price;
}

void callback_show_buy_currency(S32 option, void*)
{
	if (0 == option)
	{
		llinfos << "Loading page " << BUY_CURRENCY_URL << llendl;
		LLWeb::loadURL(BUY_CURRENCY_URL);
	}
}


void show_buy_currency(const char* extra)
{
	// Don't show currency web page for branded clients.

	std::ostringstream mesg;
	if (extra != NULL)
	{	
		mesg << extra << "\n \n";
	}
	mesg << "Go to " << BUY_CURRENCY_URL << "\nfor information on purchasing currency?";

	LLString::format_map_t args;
	args["[EXTRA]"] = extra;
	args["[URL]"] = BUY_CURRENCY_URL;
	gViewerWindow->alertXml("PromptGoToCurrencyPage", args, 
		callback_show_buy_currency);
}

void handle_buy_currency(void*)
{
//	LLFloaterBuyCurrency::buyCurrency();
}

void handle_buy(void*)
{
	if (gSelectMgr->isEmpty()) return;

	LLSaleInfo sale_info;
	BOOL valid = gSelectMgr->selectGetSaleInfo(sale_info);
	if (!valid) return;

	if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS)
	{
		handle_buy_contents(sale_info);
	}
	else
	{
		handle_buy_object(sale_info);
	}
}

class LLObjectBuy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		handle_buy(NULL);
		return true;
	}
};

BOOL sitting_on_selection()
{
	LLSelectNode* node = gSelectMgr->getFirstRootNode();
	if (!node)
	{
		return FALSE;
	}

	if (!node->mValid)
	{
		return FALSE;
	}

	LLViewerObject* root_object = node->getObject();
	if (!root_object)
	{
		return FALSE;
	}

	// Need to determine if avatar is sitting on this object
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if (!avatar)
	{
		return FALSE;
	}

	return (avatar->mIsSitting && avatar->getRoot() == root_object);
}

class LLToolsSaveToInventory : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if(enable_save_into_inventory(NULL))
		{
			derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
		}
		return true;
	}
};

class LLToolsSaveToObjectInventory : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if(gSelectMgr)
		{
			LLSelectNode* node = gSelectMgr->getFirstRootNode();
			if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
			{
				// *FIX: check to see if the fromtaskid object exists.
				derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID);
			}
		}
		return true;
	}
};

// Round the position of all root objects to the grid
class LLToolsSnapObjectXY : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		F64 snap_size = (F64)gSavedSettings.getF32("GridResolution");

		LLViewerObject* obj;
		for (obj = gSelectMgr->getFirstRootObject();
			obj != NULL;
			obj = gSelectMgr->getNextRootObject())
		{
			if (obj->permModify())
			{
				LLVector3d pos_global = obj->getPositionGlobal();
				F64 round_x = fmod(pos_global.mdV[VX], snap_size);
				if (round_x < snap_size * 0.5)
				{
					// closer to round down
					pos_global.mdV[VX] -= round_x;
				}
				else
				{
					// closer to round up
					pos_global.mdV[VX] -= round_x;
					pos_global.mdV[VX] += snap_size;
				}

				F64 round_y = fmod(pos_global.mdV[VY], snap_size);
				if (round_y < snap_size * 0.5)
				{
					pos_global.mdV[VY] -= round_y;
				}
				else
				{
					pos_global.mdV[VY] -= round_y;
					pos_global.mdV[VY] += snap_size;
				}

				obj->setPositionGlobal(pos_global, FALSE);
			}
		}
		gSelectMgr->sendMultipleUpdate(UPD_POSITION);
		return true;
	}
};

// in order to link, all objects must have the same owner, and the
// agent must have the ability to modify all of the objects. However,
// we're not answering that question with this method. The question
// we're answering is: does the user have a reasonable expectation
// that a link operation should work? If so, return true, false
// otherwise. this allows the handle_link method to more finely check
// the selection and give an error message when the uer has a
// reasonable expectation for the link to work, but it will fail.
class LLToolsEnableLink : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = false;
		// check if there are at least 2 objects selected, and that the
		// user can modify at least one of the selected objects.

		// in component mode, can't link
		if (gSavedSettings.getBOOL("SelectLinkedSet"))
		{
			if(gSelectMgr->selectGetAllRootsValid() && gSelectMgr->getRootObjectCount() >= 2)
			{
				for(LLViewerObject* object = gSelectMgr->getFirstRootObject();
					object != NULL;
					object = gSelectMgr->getNextRootObject())
				{
					if(object->permModify())
					{
						new_value = true;
						break;
					}
				}
			}
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLToolsLink : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if(!gSelectMgr->selectGetAllRootsValid())
		{
			LLNotifyBox::showXml("UnableToLinkWhileDownloading");
			return true;
		}

		S32 object_count = gSelectMgr->getObjectCount();
		if (object_count > MAX_CHILDREN_PER_TASK + 1)
		{
			LLStringBase<char>::format_map_t args;
			args["[COUNT]"] = llformat("%d", object_count);
			int max = MAX_CHILDREN_PER_TASK+1;
			args["[MAX]"] = llformat("%d", max);
			gViewerWindow->alertXml("UnableToLinkObjects", args);
			return true;
		}

		if(gSelectMgr->getRootObjectCount() < 2)
		{
			gViewerWindow->alertXml("CannotLinkIncompleteSet");
			return true;
		}
		if(!gSelectMgr->selectGetRootsModify())
		{
			gViewerWindow->alertXml("CannotLinkModify");
			return true;
		}
		LLUUID owner_id;
		LLString owner_name;
		if(!gSelectMgr->selectGetOwner(owner_id, owner_name))
		{
			// we don't actually care if you're the owner, but novices are
			// the most likely to be stumped by this one, so offer the
			// easiest and most likely solution.
			gViewerWindow->alertXml("CannotLinkDifferentOwners");
			return true;
		}
		gSelectMgr->sendLink();
		return true;
	}
};

class LLToolsEnableUnlink : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gSelectMgr->selectGetAllRootsValid() &&
			gSelectMgr->getFirstEditableObject() &&
			!gSelectMgr->getFirstEditableObject()->isAttachment();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLToolsUnlink : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gSelectMgr->sendDelink();
		return true;
	}
};


class LLToolsStopAllAnimations : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatarp = gAgent.getAvatarObject();
		
		if (!avatarp) return true;
		
		LLVOAvatar::AnimSourceIterator anim_it = avatarp->mAnimationSources.begin();
		for (;anim_it != avatarp->mAnimationSources.end(); ++anim_it)
		{
			avatarp->stopMotion( anim_it->second, TRUE );
		}
	
		avatarp->processAnimationStateChanges();
		return true;
	}
};

void handle_hinge(void*)
{
	gSelectMgr->sendHinge(1);
}

void handle_ptop(void*)
{
	gSelectMgr->sendHinge(2);
}

void handle_lptop(void*)
{
	gSelectMgr->sendHinge(3);
}

void handle_wheel(void*)
{
	gSelectMgr->sendHinge(4);
}

void handle_dehinge(void*)
{
	gSelectMgr->sendDehinge();
}

BOOL enable_dehinge(void*)
{
	LLViewerObject* obj = gSelectMgr->getFirstEditableObject();
	return obj && !obj->isAttachment();
}


class LLEditEnableCut : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canCut();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditCut : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler )
		{
			gEditMenuHandler->cut();
		}
		return true;
	}
};

class LLEditEnableCopy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canCopy();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditCopy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler )
		{
			gEditMenuHandler->copy();
		}
		return true;
	}
};

class LLEditEnablePaste : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canPaste();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditPaste : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler )
		{
			gEditMenuHandler->paste();
		}
		return true;
	}
};

class LLEditEnableDelete : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canDoDelete();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditDelete : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// If a text field can do a deletion, it gets precedence over deleting
		// an object in the world.
		if( gEditMenuHandler && gEditMenuHandler->canDoDelete())
		{
			gEditMenuHandler->doDelete();
		}

		// and close any pie/context menus when done
		gMenuHolder->hideMenus();

		// When deleting an object we may not actually be done
		// Keep selection so we know what to delete when confirmation is needed about the delete
		gPieObject->hide(TRUE);
		return true;
	}
};

class LLObjectEnableDelete : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = 
#ifdef HACKED_GODLIKE_VIEWER
			TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
			(!gInProductionGrid && gAgent.isGodlike()) ||
# endif
			(gSelectMgr && gSelectMgr->canDoDelete());
#endif
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditSearch : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloaterDirectory::toggleFind(NULL);
		return true;
	}
};

class LLObjectDelete : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gSelectMgr)
		{
			gSelectMgr->doDelete();
		}

		// and close any pie/context menus when done
		gMenuHolder->hideMenus();

		// When deleting an object we may not actually be done
		// Keep selection so we know what to delete when confirmation is needed about the delete
		gPieObject->hide(TRUE);
		return true;
	}
};

void handle_force_delete(void*)
{
	gSelectMgr->selectForceDelete();
}

class LLViewEnableLastChatter : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		//FIXME: add check that last chatter is in range
		bool new_value = (gAgent.cameraThirdPerson() && gAgent.getLastChatter().notNull());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditEnableDeselect : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canDeselect();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditDeselect : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler )
		{
			gEditMenuHandler->deselect();
		}
		return true;
	}
};

class LLEditEnableSelectAll : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canSelectAll();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


class LLEditSelectAll : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler )
		{
			gEditMenuHandler->selectAll();
		}
		return true;
	}
};


class LLEditEnableUndo : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canUndo();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditUndo : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler && gEditMenuHandler->canUndo() )
		{
			gEditMenuHandler->undo();
		}
		return true;
	}
};

class LLEditEnableRedo : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gEditMenuHandler && gEditMenuHandler->canRedo();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditRedo : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gEditMenuHandler && gEditMenuHandler->canRedo() )
		{
			gEditMenuHandler->redo();
		}
		return true;
	}
};



void print_object_info(void*)
{
	gSelectMgr->selectionDump();
}


void show_debug_menus()
{
	// this can get called at login screen where there is no menu so only toggle it if one exists
	if ( gMenuBarView )
	{
		BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
		gMenuBarView->setItemVisible(CLIENT_MENU_NAME, debug);
		gMenuBarView->setItemEnabled(CLIENT_MENU_NAME, debug);
		gMenuBarView->setItemVisible(SERVER_MENU_NAME, debug);
		gMenuBarView->setItemEnabled(SERVER_MENU_NAME, debug);
		//gMenuBarView->setItemVisible(LLString("DebugOptions"),	visible);
		//gMenuBarView->setItemVisible(LLString(AVI_TOOLS),	visible);
	};
}

void toggle_debug_menus(void*)
{
	BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus");
	gSavedSettings.setBOOL("UseDebugMenus", visible);
	show_debug_menus();
}


void toggle_map( void* user_data )
{
	// Toggle the item
	BOOL checked = gSavedSettings.getBOOL( static_cast<char*>(user_data) );
	gSavedSettings.setBOOL( static_cast<char*>(user_data), !checked );
	if (checked)
	{
		gFloaterMap->close();
	}
	else
	{
		gFloaterMap->open();
	}
}

/**
   char* upload_pick(void* data)

   If applicable, brings up a file chooser in which the user selects a file
   to upload for a particular task.  If the file is valid for the given action,
   returns the string to the full path filename, else returns NULL.
   Data is the load filter for the type of file as defined in LLFilePicker.
**/
const char* upload_pick(void* data)
{
 	if( gAgent.cameraMouselook() )
	{
		gAgent.changeCameraToDefault();
		// This doesn't seem necessary. JC
		// display();
	}

	LLFilePicker::ELoadFilter type;
	if(data)
	{
		type = (LLFilePicker::ELoadFilter)((S32)data);
	}
	else
	{
		type = LLFilePicker::FFLOAD_ALL;
	}

	LLFilePicker& picker = LLFilePicker::instance();
	if (!picker.getOpenFile(type))
	{
		llinfos << "Couldn't import objects from file" << llendl;
		return NULL;
	}

 	const char* filename = picker.getFirstFile();
	const char* ext = strrchr(filename, '.');

	//strincmp doesn't like NULL pointers
	if (ext == NULL)
	{
		const char* short_name = strrchr(filename,
										 *gDirUtilp->getDirDelimiter().c_str());
		
		// No extension
		LLStringBase<char>::format_map_t args;
		args["[FILE]"] = LLString(short_name + 1);
		gViewerWindow->alertXml("NoFileExtension", args);
		return NULL;
	}
	else
	{
		//so there is an extension
		//loop over the valid extensions and compare to see
		//if the extension is valid

		//now grab the set of valid file extensions
		const char* valids = build_extensions_string(type);
		std::string valid_extensions = std::string(valids);

		BOOL ext_valid = FALSE;
		
		typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
		boost::char_separator<char> sep(" ");
		tokenizer tokens(valid_extensions, sep);
		tokenizer::iterator token_iter;

		//now loop over all valid file extensions
		//and compare them to the extension of the file
		//to be uploaded
		for( token_iter = tokens.begin();
			 token_iter != tokens.end() && ext_valid != TRUE;
			 ++token_iter)
		{
			const char* cur_token = token_iter->c_str();

			if (0 == strnicmp(cur_token, ext, strlen(cur_token)) ||
				0 == strnicmp(cur_token, "*.*", strlen(cur_token))) 
			{
				//valid extension
				//or the acceptable extension is any
				ext_valid = TRUE;
			}
		}//end for (loop over all tokens)

		if (ext_valid == FALSE)
		{
			//should only get here if the extension exists
			//but is invalid
			LLStringBase<char>::format_map_t args;
			args["[EXTENSION]"] = ext;
			args["[VALIDS]"] = valids;
			gViewerWindow->alertXml("InvalidFileExtension", args);
			return NULL;
		}
	}//end else (non-null extension)

	//valid file extension
	
	//now we check to see
	//if the file is actually a valid image/sound/etc.
	if (type == LLFilePicker::FFLOAD_WAV)
	{
		// pre-qualify wavs to make sure the format is acceptable
		char error_msg[MAX_STRING];
		if (check_for_invalid_wav_formats(filename,error_msg))
		{
			llinfos << error_msg << ": " << filename << llendl;
			LLStringBase<char>::format_map_t args;
			args["[FILE]"] = filename;
			gViewerWindow->alertXml( error_msg, args );
			return NULL;
		}
	}//end if a wave/sound file

	
	return filename;
}

void handle_upload_object(void* data)
{
	const char* filename = upload_pick(data);
	if (filename)
	{
		// start the import
		LLFloaterImport* floaterp = new LLFloaterImport(filename);
		gUICtrlFactory->buildFloater(floaterp, "floater_import.xml");
	}
}

class LLFileUploadImage : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		const char* filename = upload_pick((void *)(S32)LLFilePicker::FFLOAD_IMAGE);
		if (filename)
		{
			LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename);
			gUICtrlFactory->buildFloater(floaterp, "floater_image_preview.xml");
		}
		return TRUE;
	}
};

class LLFileUploadSound : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		const char* filename = upload_pick((void*)((S32)LLFilePicker::FFLOAD_WAV));
		if (filename)
		{
			LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename);
			gUICtrlFactory->buildFloater(floaterp, "floater_sound_preview.xml");
		}
		return true;
	}
};

class LLFileUploadAnim : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		const char* filename = upload_pick((void*)((S32)LLFilePicker::FFLOAD_ANIM));
		if (filename)
		{
			LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename);
			gUICtrlFactory->buildFloater(floaterp, "floater_animation_preview.xml");
		}
		return true;
	}
};

class LLFileUploadBulk : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if( gAgent.cameraMouselook() )
		{
			gAgent.changeCameraToDefault();
		}

		// TODO:
		// Iterate over all files
		// Check extensions for uploadability, cost
		// Check user balance for entire cost
		// Charge user entire cost
		// Loop, uploading
		// If an upload fails, refund the user for that one
		//
		// Also fix single upload to charge first, then refund

		LLFilePicker& picker = LLFilePicker::instance();
		if (picker.getMultipleOpenFiles())
		{
			const char* filename = picker.getFirstFile();
			const char* name = picker.getDirname();

			LLString asset_name = name;
			LLString::replaceNonstandardASCII( asset_name, '?' );
			LLString::replaceChar(asset_name, '|', '?');
			LLString::stripNonprintable(asset_name);
			LLString::trim(asset_name);

			char* asset_name_str = (char*)asset_name.c_str();
			char* end_p = strrchr(asset_name_str, '.');		 // strip extension if exists
			if( !end_p )
			{
				end_p = asset_name_str + strlen( asset_name_str );
			}
				
			S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );

			asset_name = asset_name.substr( 0, len );

			upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE); // file
		}
		else
		{
			llinfos << "Couldn't import objects from file" << llendl;
		}
		return true;
	}
};

void upload_error(const char* error_message, const char* label, const std::string filename, const LLStringBase<char>::format_map_t args) 
{
	llwarns << error_message << llendl;
	gViewerWindow->alertXml(label, args);
	if(remove(filename.c_str()) == -1)
	{
		lldebugs << "unable to remove temp file" << llendl;
	}
	LLFilePicker::instance().reset();						
}

class LLFileCloseWindow : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloater *top = gFloaterView->getFrontmost();
		if (top && top->hasFocus())
		{
			LLFloater::closeByMenu( top );
		}
		return true;
	}
};

class LLFileSaveTexture : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloater* top = gFloaterView->getFrontmost();
		if (top)
		{
			top->saveAs();
		}
		return true;
	}
};

class LLFileTakeSnapshot : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLFloaterSnapshot::show(NULL);
		return true;
	}
};

class LLFileTakeSnapshotToDisk : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLPointer<LLImageRaw> raw = new LLImageRaw;

		S32 width = gViewerWindow->getWindowDisplayWidth();
		S32 height = gViewerWindow->getWindowDisplayHeight();

		if (gSavedSettings.getBOOL("HighResSnapshot"))
		{
			width *= 2;
			height *= 2;
		}

		if (gViewerWindow->rawSnapshot(raw,
									   width,
									   height,
									   TRUE,
									   gSavedSettings.getBOOL("RenderUIInSnapshot"),
									   FALSE))
		{
			if (!gQuietSnapshot)
			{
				gViewerWindow->playSnapshotAnimAndSound();
			}
			LLImageBase::setSizeOverride(TRUE);
			gViewerWindow->saveImageNumbered(raw);
			LLImageBase::setSizeOverride(FALSE);
		}
		return true;
	}
};

class LLFileSaveMovie : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerWindow::saveMovieNumbered(NULL);
		return true;
	}
};

class LLFileSetWindowSize : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString size = userdata.asString();
		S32 width, height;
		sscanf(size.c_str(), "%d,%d", &width, &height);
		LLViewerWindow::movieSize(width, height);
		return true;
	}
};

class LLFileQuit : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		app_request_quit();
		return true;
	}
};

void handle_upload(void* data)
{
	const char* filename = upload_pick(data);
	if (filename)
	{
		LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename);
		gUICtrlFactory->buildFloater(floaterp, "floater_name_description.xml");
	}
}

void handle_compress_image(void*)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if (picker.getOpenFile(LLFilePicker::FFLOAD_IMAGE))
	{
		std::string infile(picker.getFirstFile());
		std::string outfile = infile + ".j2c";

		llinfos << "Input:  " << infile << llendl;
		llinfos << "Output: " << outfile << llendl;

		BOOL success;

		success = LLViewerImageList::createUploadFile(infile, outfile, IMG_CODEC_TGA);

		if (success)
		{
			llinfos << "Compression complete" << llendl;
		}
		else
		{
			llinfos << "Compression failed: " << LLImageBase::getLastError() << llendl;
		}
	}
}

void upload_new_resource(const LLString& src_filename, std::string name,
						 std::string desc, S32 compression_info,
						 LLAssetType::EType destination_folder_type,
						 LLInventoryType::EType inv_type,
						 U32 next_owner_perm,
						 const LLString& display_name,
						 LLAssetStorage::LLStoreAssetCallback callback,
						 void *userdata)
{	
	// Generate the temporary UUID.
	LLString filename = gDirUtilp->getTempFilename();
	LLTransactionID tid;
	LLAssetID uuid;
	
	LLStringBase<char>::format_map_t args;

	LLString ext = src_filename.substr(src_filename.find_last_of('.'));
	LLAssetType::EType asset_type = LLAssetType::AT_NONE;
	char error_message[MAX_STRING];
	error_message[0] = '\0';
	LLString temp_str;

	BOOL error = FALSE;
	
	if (ext.empty())
	{
		LLString::size_type offset = filename.find_last_of(gDirUtilp->getDirDelimiter());
		if (offset != LLString::npos)
			offset++;
		LLString short_name = filename.substr(offset);
		
		// No extension
		sprintf(error_message,
				"No file extension for the file: '%s'\nPlease make sure the file has a correct file extension",
				short_name.c_str());
		args["[FILE]"] = short_name;
 		upload_error(error_message, "NofileExtension", filename, args);
		return;
	}
	else if( LLString::compareInsensitive(ext.c_str(),".bmp") == 0 )
	{
		asset_type = LLAssetType::AT_TEXTURE;
		if (!LLViewerImageList::createUploadFile(src_filename,
												 filename,
												 IMG_CODEC_BMP ))
		{
			sprintf(error_message, "Problem with file %s:\n\n%s\n",
					src_filename.c_str(), LLImageBase::getLastError().c_str());
			args["[FILE]"] = src_filename;
			args["[ERROR]"] = LLImageBase::getLastError();
			upload_error(error_message, "ProblemWithFile", filename, args);
			return;
		}
	}
	else if( LLString::compareInsensitive(ext.c_str(),".tga") == 0 )
	{
		asset_type = LLAssetType::AT_TEXTURE;
		if (!LLViewerImageList::createUploadFile(src_filename,
												 filename,
												 IMG_CODEC_TGA ))
		{
			sprintf(error_message, "Problem with file %s:\n\n%s\n",
					src_filename.c_str(), LLImageBase::getLastError().c_str());
			args["[FILE]"] = src_filename;
			args["[ERROR]"] = LLImageBase::getLastError();
			upload_error(error_message, "ProblemWithFile", filename, args);
			return;
		}
	}
	else if( LLString::compareInsensitive(ext.c_str(),".jpg") == 0 || LLString::compareInsensitive(ext.c_str(),".jpeg") == 0)
	{
		asset_type = LLAssetType::AT_TEXTURE;
		if (!LLViewerImageList::createUploadFile(src_filename,
												 filename,
												 IMG_CODEC_JPEG ))
		{
			sprintf(error_message, "Problem with file %s:\n\n%s\n",
					src_filename.c_str(), LLImageBase::getLastError().c_str());
			args["[FILE]"] = src_filename;
			args["[ERROR]"] = LLImageBase::getLastError();
			upload_error(error_message, "ProblemWithFile", filename, args);
			return;
		}
	}
	else if(LLString::compareInsensitive(ext.c_str(),".wav") == 0)
	{
		asset_type = LLAssetType::AT_SOUND;  // tag it as audio
		S32 encode_result = 0;

		S32 bitrate = 128;

		if (compression_info)
		{
			bitrate = compression_info;
		}
		llinfos << "Attempting to encode wav as an ogg file at " << bitrate << "kbps" << llendl;

		encode_result = encode_vorbis_file_at(src_filename.c_str(), filename.c_str(), bitrate*1000);
		
		if (LLVORBISENC_NOERR != encode_result)
		{
			switch(encode_result)
			{
				case LLVORBISENC_DEST_OPEN_ERR:
                    sprintf(error_message, "Couldn't open temporary compressed sound file for writing: %s\n", filename.c_str());
					args["[FILE]"] = filename;
					upload_error(error_message, "CannotOpenTemporarySoundFile", filename, args);
					break;

				default:	
				  sprintf(error_message, "Unknown vorbis encode failure on: %s\n", src_filename.c_str());
					args["[FILE]"] = src_filename;
					upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
					break;	
			}	
			return;
		}
	}
	else if(LLString::compareInsensitive(ext.c_str(),".tmp") == 0)	 	
	{	 	
		// This is a generic .lin resource file	 	
         asset_type = LLAssetType::AT_OBJECT;	 	
         FILE *in = LLFile::fopen(src_filename.c_str(), "rb");	 	
         if (in)	 	
         {	 	
                 // read in the file header	 	
                 char buf[16384];	 	
                 S32 read;	 	
                 S32  version;	 	
                 if (fscanf(in, "LindenResource\nversion %d\n", &version))	 	
                 {	 	
                         if (2 == version)	 	
                         {	 	
                                 char label[MAX_STRING];	 	
                                 char value[MAX_STRING];	 	
                                 S32  tokens_read;	 	
                                 while (fgets(buf, 1024, in))	 	
                                 {	 	
                                         label[0] = '\0';	 	
                                         value[0] = '\0';	 	
                                         tokens_read = sscanf(buf, "%s %s\n", label, value);	 	

                                         llinfos << "got: " << label << " = " << value	 	
                                                         << llendl;	 	

                                         if (EOF == tokens_read)	 	
                                         {	 	
                                                 fclose(in);	 	
                                                 sprintf(error_message, "corrupt resource file: %s", src_filename.c_str());
												 args["[FILE]"] = src_filename;
												 upload_error(error_message, "CorruptResourceFile", filename, args);
                                                 return;
                                         }	 	

                                         if (2 == tokens_read)	 	
                                         {	 	
                                                 if (! strcmp("type", label))	 	
                                                 {	 	
                                                         asset_type = (LLAssetType::EType)(atoi(value));	 	
                                                 }	 	
                                         }	 	
                                         else	 	
                                         {	 	
                                                 if (! strcmp("_DATA_", label))	 	
                                                 {	 	
                                                         // below is the data section	 	
                                                         break;	 	
                                                 }	 	
                                         }	 	
                                         // other values are currently discarded	 	
                                 }	 	

                         }	 	
                         else	 	
                         {	 	
                                 fclose(in);	 	
                                 sprintf(error_message, "unknown linden resource file version in file: %s", src_filename.c_str());	 	
								 args["[FILE]"] = src_filename;
								 upload_error(error_message, "UnknownResourceFileVersion", filename, args);
                                 return;
                         }	 	
                 }	 	
                 else	 	
                 {	 	
                         // this is an original binary formatted .lin file	 	
                         // start over at the beginning of the file	 	
                         fseek(in, 0, SEEK_SET);	 	

                         const S32 MAX_ASSET_DESCRIPTION_LENGTH = 256;	 	
                         const S32 MAX_ASSET_NAME_LENGTH = 64;	 	
                         S32 header_size = 34 + MAX_ASSET_DESCRIPTION_LENGTH + MAX_ASSET_NAME_LENGTH;	 	
                         S16     type_num;	 	

                         // read in and throw out most of the header except for the type	 	
                         fread(buf, header_size, 1, in);	 	
                         memcpy(&type_num, buf + 16, sizeof(S16));	 	
                         asset_type = (LLAssetType::EType)type_num;	 	
                 }	 	

                 // copy the file's data segment into another file for uploading	 	
                 FILE *out = LLFile::fopen(filename.c_str(), "wb");	 	
                 if (out)	 	
                 {	 	
                         while((read = fread(buf, 1, 16384, in)))	 	
                         {	 	
                                 fwrite(buf, 1, read, out);	 	
                         }	 	
                         fclose(out);	 	
                 }	 	
                 else	 	
                 {	 	
                         fclose(in);	 	
                         sprintf(error_message, "Unable to create output file: %s", filename.c_str());	 	
						 args["[FILE]"] = filename;
						 upload_error(error_message, "UnableToCreateOutputFile", filename, args);
                         return;
                 }	 	

                 fclose(in);	 	
         }	 	
         else	 	
         {	 	
                 llinfos << "Couldn't open .lin file " << src_filename << llendl;	 	
         }	 	
	}
	else if (LLString::compareInsensitive(ext.c_str(),".bvh") == 0)
	{
		sprintf(error_message, "We do not currently support bulk upload of animation files\n");
		upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
		return;
	}
	else
	{
		// Unknown extension
		sprintf(error_message, "Unknown file extension %s\nExpected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh", ext.c_str());
		error = TRUE;;
	}

	// gen a new transaction ID for this asset
	tid.generate();

	if (!error)
	{
		uuid = tid.makeAssetID(gAgent.getSecureSessionID());
		// copy this file into the vfs for upload
		S32 file_size;
		apr_file_t* fp = ll_apr_file_open(filename, LL_APR_RB, &file_size);
		if (fp)
		{
			LLVFile file(gVFS, uuid, asset_type, LLVFile::WRITE);

			file.setMaxSize(file_size);

			const S32 buf_size = 65536;
			U8 copy_buf[buf_size];
			while ((file_size = ll_apr_file_read(fp, copy_buf, buf_size)))
			{
				file.write(copy_buf, file_size);
			}
			apr_file_close(fp);
		}
		else
		{
			sprintf(error_message, "Unable to access output file: %s", filename.c_str());
			error = TRUE;
		}
	}

	if (!error)
	{
		LLString t_disp_name = display_name;
		if (t_disp_name.empty())
		{
			t_disp_name = src_filename;
		}
		upload_new_resource(tid, asset_type, name, desc, compression_info, // tid
							destination_folder_type, inv_type, next_owner_perm,
							display_name, callback, userdata);
	}
	else
	{
		llwarns << error_message << llendl;
		LLStringBase<char>::format_map_t args;
		args["[ERROR_MESSAGE]"] = error_message;
		gViewerWindow->alertXml("ErrorMessage", args);
		if(LLFile::remove(filename.c_str()) == -1)
		{
			lldebugs << "unable to remove temp file" << llendl;
		}
		LLFilePicker::instance().reset();
	}
}

void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_type,
						 std::string name,
						 std::string desc, S32 compression_info,
						 LLAssetType::EType destination_folder_type,
						 LLInventoryType::EType inv_type,
						 U32 next_owner_perm,
						 const LLString& display_name,
						 LLAssetStorage::LLStoreAssetCallback callback,
						 void *userdata)
{
	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
	
	if( LLAssetType::AT_SOUND == asset_type )
	{
		gViewerStats->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
	}
	else
	if( LLAssetType::AT_TEXTURE == asset_type )
	{
		gViewerStats->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
	}
	else
	if( LLAssetType::AT_ANIMATION == asset_type)
	{
		gViewerStats->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
	}

	if(LLInventoryType::IT_NONE == inv_type)
	{
		inv_type = LLInventoryType::defaultForAssetType(asset_type);
	}
	LLString::stripNonprintable(name);
	LLString::stripNonprintable(desc);
	if(name.empty())
	{
		name = "(No Name)";
	}
	if(desc.empty())
	{
		desc = "(No Description)";
	}
	
	// At this point, we're ready for the upload.
	LLString upload_message = "Uploading...\n\n";
	upload_message.append(display_name);
	LLUploadDialog::modalUploadDialog(upload_message);

	llinfos << "*** Uploading: " << llendl;
	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
	llinfos << "UUID: " << uuid << llendl;
	llinfos << "Name: " << name << llendl;
	llinfos << "Desc: " << desc << llendl;
	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType(destination_folder_type) << llendl;
	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
	std::string url = gAgent.getRegion()->getCapability("NewAgentInventory");
	if (!url.empty())
	{
		llinfos << "New Agent Inventory via capability" << llendl;
		LLSD body;
		body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type);
		body["asset_type"] = LLAssetType::lookup(asset_type);
		body["inventory_type"] = LLInventoryType::lookup(inv_type);
		body["name"] = name;
		body["description"] = desc;
		
		std::ostringstream llsdxml;
		LLSDSerialize::toXML(body, llsdxml);
		lldebugs << "posting body to capability: " << llsdxml.str() << llendl;
		LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(uuid, body));
	}
	else
	{
		llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
		// check for adequate funds
		// TODO: do this check on the sim
		if (LLAssetType::AT_SOUND == asset_type ||
			LLAssetType::AT_TEXTURE == asset_type ||
			LLAssetType::AT_ANIMATION == asset_type)
		{
			S32 upload_cost = gGlobalEconomy->getPriceUpload();
			S32 balance = gStatusBar->getBalance();
			if (balance < upload_cost)
			{
				// insufficient funds, bail on this upload
				LLFloaterBuyCurrency::buyCurrency("Uploading costs", upload_cost);
				return;
			}
		}

		LLResourceData* data = new LLResourceData;
		data->mAssetInfo.mTransactionID = tid;
		data->mAssetInfo.mUuid = uuid;
		data->mAssetInfo.mType = asset_type;
		data->mAssetInfo.mCreatorID = gAgentID;
		data->mInventoryType = inv_type;
		data->mNextOwnerPerm = next_owner_perm;
		data->mUserData = userdata;
		data->mAssetInfo.setName(name);
		data->mAssetInfo.setDescription(desc);
		data->mPreferredLocation = destination_folder_type;

		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
		if (callback)
		{
			asset_callback = callback;
		}
		gAssetStorage->storeAssetData(data->mAssetInfo.mTransactionID, data->mAssetInfo.mType,
										asset_callback,
										(void*)data,
										FALSE);
	}
}

void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result) // StoreAssetData callback (fixed)
{
	LLResourceData* data = (LLResourceData*)user_data;
	//LLAssetType::EType pref_loc = data->mPreferredLocation;
	BOOL is_balance_sufficient = TRUE;
	if(result >= 0)
	{
		LLAssetType::EType dest_loc = (data->mPreferredLocation == LLAssetType::AT_NONE) ? data->mAssetInfo.mType : data->mPreferredLocation;

		if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
			LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
			LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
		{
			// Charge the user for the upload.
			LLViewerRegion* region = gAgent.getRegion();
			S32 upload_cost = gGlobalEconomy->getPriceUpload();

			if(!(can_afford_transaction(upload_cost)))
			{
				LLFloaterBuyCurrency::buyCurrency(
					llformat("Uploading %s costs",
						data->mAssetInfo.getName().c_str()),
					upload_cost);
				is_balance_sufficient = FALSE;
			}
			else if(region)
			{
				// Charge user for upload
				gStatusBar->debitBalance(upload_cost);
				
				LLMessageSystem* msg = gMessageSystem;
				msg->newMessageFast(_PREHASH_MoneyTransferRequest);
				msg->nextBlockFast(_PREHASH_AgentData);
				msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
				msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
				msg->nextBlockFast(_PREHASH_MoneyData);
				msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
				msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
				msg->addU8("Flags", 0);
				msg->addS32Fast(_PREHASH_Amount, upload_cost);
				msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
				msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
				msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
				msg->addStringFast(_PREHASH_Description, NULL);
				msg->sendReliable(region->getHost());
			}
		}

		if(is_balance_sufficient)
		{
			// Actually add the upload to inventory
			llinfos << "Adding " << uuid << " to inventory." << llendl;
			LLUUID folder_id(gInventory.findCategoryUUIDForType(dest_loc));
			if(folder_id.notNull())
			{
				U32 next_owner_perm = data->mNextOwnerPerm;
				if(PERM_NONE == next_owner_perm)
				{
					next_owner_perm = PERM_MOVE | PERM_TRANSFER;
				}
				create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
					folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
					data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
					data->mInventoryType, NOT_WEARABLE, next_owner_perm,
					LLPointer<LLInventoryCallback>(NULL));
			}
			else
			{
				llwarns << "Can't find a folder to put it in" << llendl;
			}
		}
	}
	else // 	if(result >= 0)
	{
		LLStringBase<char>::format_map_t args;
		args["[FILE]"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
		args["[REASON]"] = LLString(LLAssetStorage::getErrorString(result));
		gViewerWindow->alertXml("CannotUploadReason", args);
	}

	LLUploadDialog::modalUploadFinished();
	delete data;

	// *FIX: This is a pretty big hack. What this does is check the
	// file picker if there are any more pending uploads. If so,
	// upload that file.
	const char* next_file = LLFilePicker::instance().getNextFile();
	if(is_balance_sufficient && next_file)
	{
		const char* name = LLFilePicker::instance().getDirname();

		LLString asset_name = name;
		LLString::replaceNonstandardASCII( asset_name, '?' );
		LLString::replaceChar(asset_name, '|', '?');
		LLString::stripNonprintable(asset_name);
		LLString::trim(asset_name);

		char* asset_name_str = (char*)asset_name.c_str();
		char* end_p = strrchr(asset_name_str, '.');		 // strip extension if exists
		if( !end_p )
		{
			end_p = asset_name_str + strlen( asset_name_str );
		}
			
		S32 len = llmin( (S32) (DB_INV_ITEM_NAME_STR_LEN), (S32) (end_p - asset_name_str) );

		asset_name = asset_name.substr( 0, len );

		upload_new_resource(next_file, asset_name, asset_name,	// file
							0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE);
	}
}

LLUUID gExporterRequestID;
LLString gExportDirectory;

LLUploadDialog *gExportDialog = NULL;

void handle_export_selected( void * )
{
	if (gSelectMgr->isEmpty())
	{
		return;
	}
	llinfos << "Exporting selected objects:" << llendl;
	LLViewerObject *object = gSelectMgr->getFirstRootObject();

	gExporterRequestID.generate();
	gExportDirectory = "";

	LLMessageSystem* msg = gMessageSystem;
	msg->newMessageFast(_PREHASH_ObjectExportSelected);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID);
	msg->addS16Fast(_PREHASH_VolumeDetail, 4);

	for (; object != NULL; object = gSelectMgr->getNextRootObject())
	{
		msg->nextBlockFast(_PREHASH_ObjectData);
		msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
		llinfos << "Object: " << object->getID() << llendl;
	}
	msg->sendReliable(gAgent.getRegion()->getHost());

	gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");
}

BOOL menu_check_build_tool( void* user_data )
{
	S32 index = (S32) user_data;
	return gCurrentToolset->isToolSelected( index );
}

void handle_reload_settings(void*)
{
	gSavedSettings.resetToDefaults();
	gSavedSettings.loadFromFile(gSettingsFileName, TRUE);

	llinfos << "Loading colors from colors.xml" << llendl;
	std::string color_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"colors.xml");
	gColors.resetToDefaults();
	gColors.loadFromFile(color_file, FALSE, TYPE_COL4U);
}

class LLWorldSetHomeLocation : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// we just send the message and let the server check for failure cases
		// server will echo back a "Home position set." alert if it succeeds
		// and the home location screencapture happens when that alert is recieved
		gAgent.setStartPosition(START_LOCATION_ID_HOME);
		return true;
	}
};

class LLWorldTeleportHome : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gAgent.teleportHome();
		return true;
	}
};

class LLWorldAlwaysRun : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gAgent.getAlwaysRun())
		{
			gAgent.clearAlwaysRun();
		}
		else
		{
			gAgent.setAlwaysRun();
		}
		LLMessageSystem *msg = gMessageSystem;


		msg->newMessageFast(_PREHASH_SetAlwaysRun);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->addBOOLFast(_PREHASH_AlwaysRun, gAgent.getAlwaysRun() );
		gAgent.sendReliableMessage();
		return true;
	}
};

class LLWorldCheckAlwaysRun : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.getAlwaysRun();
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLWorldSetAway : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gAgent.getAFK())
		{
			gAgent.clearAFK();
		}
		else
		{
			gAgent.setAFK();
		}
		return true;
	}
};

class LLWorldSetBusy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gAgent.getBusy())
		{
			gAgent.clearBusy();
		}
		else
		{
			gAgent.setBusy();
			gViewerWindow->alertXml("BusyModeSet");
		}
		return true;
	}
};


class LLWorldCreateLandmark : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerRegion* agent_region = gAgent.getRegion();
		if(!agent_region)
		{
			llwarns << "No agent region" << llendl;
			return true;
		}
		LLParcel* agent_parcel = gParcelMgr->getAgentParcel();
		if (!agent_parcel)
		{
			llwarns << "No agent parcel" << llendl;
			return true;
		}
		if (!agent_parcel->getAllowLandmark()
			&& !LLViewerParcelMgr::isParcelOwnedByAgent(agent_parcel, GP_LAND_ALLOW_LANDMARK))
		{
			gViewerWindow->alertXml("CannotCreateLandmarkNotOwner");
			return true;
		}

		LLUUID folder_id;
		folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK);
		std::string pos_string;
		gAgent.buildLocationString(pos_string);
		
		create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
							  folder_id, LLTransactionID::tnull,
							  pos_string, pos_string, // name, desc
							  LLAssetType::AT_LANDMARK,
							  LLInventoryType::IT_LANDMARK,
							  NOT_WEARABLE, PERM_ALL, 
							  NULL);
		return true;
	}
};

class LLToolsLookAtSelection : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		const F32 PADDING_FACTOR = 2.f;
		BOOL zoom = (userdata.asString() == "zoom");
		if (!gSelectMgr->isEmpty())
		{
			gAgent.setFocusOnAvatar(FALSE, ANIMATE);

			LLBBox selection_bbox = gSelectMgr->getBBoxOfSelection();
			F32 angle_of_view = llmax(0.1f, gCamera->getAspect() > 1.f ? gCamera->getView() * gCamera->getAspect() : gCamera->getView());
			F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);

			LLVector3 obj_to_cam = gCamera->getOrigin() - selection_bbox.getCenterAgent();
			obj_to_cam.normVec();

			if (zoom)
			{
				gAgent.setCameraPosAndFocusGlobal(gSelectMgr->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance), gSelectMgr->getSelectionCenterGlobal(), gSelectMgr->getFirstObject()->mID );
			}
			else
			{
				gAgent.setFocusGlobal( gSelectMgr->getSelectionCenterGlobal(), gSelectMgr->getFirstObject()->mID );
			}
		}
		return true;
	}
};

/*
void handle_reset_rotation(void*)
{
	gSelectMgr->selectionResetRotation();

	dialog_refresh_all();
}
*/

class LLAvatarAddFriend : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if(avatar && !is_agent_friend(avatar->getID()))
		{
			request_friendship(avatar->getID());
		}
		gSelectMgr->deselectTransient();
		return true;
	}
};

void complete_give_money(S32 option, void* user_data)
{
	if (option == 0)
	{
		gAgent.clearBusy();
	}

	LLUUID* object_id = (LLUUID*)user_data;

	LLViewerObject* object = gObjectList.findObject(*object_id);
	if (object)
	{
		if (object->isAvatar())
		{
			const BOOL is_group = FALSE;
			LLFloaterPay::payDirectly(&give_money,
									  *object_id,
									  is_group);
		}
		else
		{
			LLFloaterPay::payViaObject(&give_money, *object_id);
		}
	}
	
	delete object_id;
}

bool handle_give_money_dialog()
{
	LLViewerObject *objectp = gViewerWindow->lastObjectHit();
	LLUUID* object_id = new LLUUID();

	// Show avatar's name if paying attachment
	if (objectp && objectp->isAttachment())
	{
		while (objectp && !objectp->isAvatar())
		{
			objectp = (LLViewerObject*)objectp->getParent();
		}
	}

	if (objectp)
	{
		*object_id = objectp->getID();
	}
	
	if (gAgent.getBusy())
	{
		// warn users of being in busy mode during a transaction
		gViewerWindow->alertXml("BusyModePay", complete_give_money, object_id);
	}
	else
	{
		complete_give_money(1, object_id);
	}
	return true;
}

class LLPayObject : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		return handle_give_money_dialog();
	}
};

class LLEnablePayObject : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object(gViewerWindow->lastObjectHit());
		bool new_value = (avatar != NULL);
		if (!new_value)
		{
			LLViewerObject* object = gViewerWindow->lastObjectHit();
			if( object )
			{
				LLViewerObject *parent = (LLViewerObject *)object->getParent();
				if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
				{
					new_value = true;
				}
			}
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLObjectEnableSitOrStand : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = false;
		LLViewerObject* dest_object = NULL;
		if(dest_object = gObjectList.findObject(gLastHitObjectID))
		{
			if(dest_object->getPCode() == LL_PCODE_VOLUME)
			{
				new_value = true;
			}
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);

		// HACK: Update label
		LLString label;
		LLString sit_text;
		LLString stand_text;
		LLString param = userdata["data"].asString();
		LLString::size_type offset = param.find(",");
		if (offset != param.npos)
		{
			sit_text = param.substr(0, offset);
			stand_text = param.substr(offset+1);
		}
		if (sitting_on_selection())
		{
			label = stand_text;
		}
		else
		{
			LLSelectNode* node = gSelectMgr->getFirstRootNode();
			if (node && node->mValid && !node->mSitName.empty())
			{
				label.assign(node->mSitName);
			}
			else
			{
				label = sit_text;
			}
		}
		gMenuHolder->childSetText("Object Sit", label);

		return true;
	}
};

void edit_ui(void*)
{
	LLFloater::setEditModeEnabled(!LLFloater::getEditModeEnabled());
}

void dump_select_mgr(void*)
{
	gSelectMgr->dump();
}

void dump_volume_mgr(void*)
{
	gVolumeMgr->dump();
}

void dump_inventory(void*)
{
	gInventory.dumpInventory();
}


void handle_first_tool(void*)
{
	gCurrentToolset->selectFirstTool();
}


void handle_next_tool(void*)
{
	gCurrentToolset->selectNextTool();
}


void handle_previous_tool(void*)
{
	gCurrentToolset->selectPrevTool();
}


// forcibly unlock an object
void handle_force_unlock(void*)
{
	// First, make it public.
	gSelectMgr->sendOwner(LLUUID::null, LLUUID::null, TRUE);

	// Second, lie to the viewer and mark it editable and unowned
	LLViewerObject* object;
	for (object = gSelectMgr->getFirstObject(); object; object = gSelectMgr->getNextObject() )
	{
		object->mFlags |= FLAGS_OBJECT_MOVE;
		object->mFlags |= FLAGS_OBJECT_MODIFY;
		object->mFlags |= FLAGS_OBJECT_COPY;

		object->mFlags &= ~FLAGS_OBJECT_ANY_OWNER;
		object->mFlags &= ~FLAGS_OBJECT_YOU_OWNER;
	}
}

// Fullscreen debug stuff
void handle_fullscreen_debug(void*)
{
	llinfos << "Width " << gViewerWindow->getWindowWidth() << " Height " << gViewerWindow->getWindowHeight() << llendl;
	llinfos << "mouse_x_from_center(100) " << mouse_x_from_center(100) << " y " << mouse_y_from_center(100) << llendl;
}

void handle_crash(void*)
{
	llerrs << "This is an llerror" << llendl;
}

class LLWorldForceSun : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString tod = userdata.asString();
		LLVector3 sun_direction;
		if (tod == "sunrise")
		{
			sun_direction.setVec(1.0f, 0.f, 0.2f);
		}
		else if (tod == "noon")
		{
			sun_direction.setVec(0.0f, 0.3f, 1.0f);
		}
		else if (tod == "sunset")
		{
			sun_direction.setVec(-1.0f, 0.f, 0.2f);
		}
		else if (tod == "midnight")
		{
			sun_direction.setVec(0.0f, 0.3f, -1.0f);
		}
		else
		{
			gSky.setOverrideSun(FALSE);
			return true;
		}
		sun_direction.normVec();
		gSky.setOverrideSun(TRUE);
		gSky.setSunDirection( sun_direction, LLVector3(0.f, 0.f, 0.f));
		return true;
	}
};

void handle_dump_followcam(void*)
{
	LLFollowCamMgr::dump();
}

void handle_viewer_enable_circuit_log(void*)
{
	llinfos << "Showing circuit information every " << gMessageSystem->mCircuitPrintFreq << " seconds" << llendl;
	gErrorStream.setLevel( LLErrorStream::DEBUG );
	gErrorStream.setDebugFlag( LLERR_CIRCUIT_INFO );
	// and dump stuff out immediately
	gMessageSystem->dumpCircuitInfo();
}

void handle_viewer_disable_circuit_log(void*)
{
	llinfos << "Hiding circuit information" << llendl;
#if !LL_DEBUG
	gErrorStream.setLevel( LLErrorStream::INFO );
#endif
	gErrorStream.clearDebugFlag( LLERR_CIRCUIT_INFO );
}

void handle_viewer_enable_message_log(void*)
{
	gMessageSystem->startLogging();
}

void handle_viewer_disable_message_log(void*)
{
	gMessageSystem->stopLogging();
}

// TomY TODO: Move!
class LLShowFloater : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString floater_name = userdata.asString();
		if (floater_name == "gestures")
		{
			LLFloaterGesture::toggleVisibility();
		}
		else if (floater_name == "appearance")
		{
			if (gAgent.getWearablesLoaded())
			{
				gAgent.changeCameraToCustomizeAvatar();
			}
		}
		else if (floater_name == "friends")
		{
			LLFloaterFriends::toggle(NULL);
		}
		else if (floater_name == "preferences")
		{
			LLFloaterPreference::show(NULL);
		}
		else if (floater_name == "toolbar")
		{
			LLToolBar::toggle(NULL);
		}
		else if (floater_name == "chat history")
		{
			LLFloaterChat::toggle(NULL);
		}
		else if (floater_name == "im")
		{
			LLToolBar::onClickIM(NULL);
		}
		else if (floater_name == "inventory")
		{
			LLInventoryView::toggleVisibility(NULL);
		}
		else if (floater_name == "mute list")
		{
			LLFloaterMute::toggle(NULL);
		}
		else if (floater_name == "camera controls")
		{
			LLFloaterCamera::toggle(NULL);
		}
		else if (floater_name == "movement controls")
		{
			LLFloaterMove::show(NULL);
		}
		else if (floater_name == "world map")
		{
			LLFloaterWorldMap::toggle(NULL);
		}
		else if (floater_name == "mini map")
		{
			LLFloaterMap::toggle(NULL);
		}
		else if (floater_name == "stat bar")
		{
			gDebugView->mStatViewp->setVisible(!gDebugView->mStatViewp->getVisible());
		}
		else if (floater_name == "account history")
		{
			LLFloaterAccountHistory::show(NULL);
		}
		else if (floater_name == "my land")
		{
			LLFloaterLandHoldings::show(NULL);
		}
		else if (floater_name == "about land")
		{
			if (gParcelMgr->selectionEmpty())
			{
				gParcelMgr->selectParcelAt(gAgent.getPositionGlobal());
			}

			LLFloaterLand::show();
		}
		else if (floater_name == "buy land")
		{
			if (gParcelMgr->selectionEmpty())
			{
				gParcelMgr->selectParcelAt(gAgent.getPositionGlobal());
			}
			
			gParcelMgr->startBuyLand();
		}
		else if (floater_name == "about region")
		{
			LLFloaterRegionInfo::show((void *)NULL);
		}
		else if (floater_name == "grid options")
		{
			LLFloaterBuildOptions::show(NULL);
		}
		else if (floater_name == "script errors")
		{
			LLFloaterScriptDebug::show(LLUUID::null);
		}
		else if (floater_name == "help")
		{
#if LL_LIBXUL_ENABLED
			LLHtmlHelp::show(NULL);
#endif
		}
		else if (floater_name == "complaint reporter")
		{
			// Prevent menu from appearing in screen shot.
			gMenuHolder->hideMenus();
			LLFloaterReporter::showFromMenu(COMPLAINT_REPORT);
		}
		else if (floater_name == "mean events")
		{
			if (!gNoRender)
			{
				LLFloaterBump::show(NULL);
			}
		}
		else if (floater_name == "bug reporter")
		{
			// Prevent menu from appearing in screen shot.
			gMenuHolder->hideMenus();
			LLFloaterReporter::showFromMenu(BUG_REPORT);
		}
		else if (floater_name == "buy currency")
		{
			LLFloaterBuyCurrency::buyCurrency();
		}
		else if (floater_name == "about")
		{
			LLFloaterAbout::show(NULL);
		}
		return true;
	}
};

class LLFloaterVisible : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString control_name = userdata["control"].asString();
		LLString floater_name = userdata["data"].asString();
		bool new_value = false;
		if (floater_name == "friends")
		{
			new_value = LLFloaterFriends::visible(NULL);
		}
		else if (floater_name == "toolbar")
		{
			new_value = LLToolBar::visible(NULL);
		}
		else if (floater_name == "chat history")
		{
			new_value = LLFloaterChat::visible(NULL);
		}
		else if (floater_name == "im")
		{
			new_value = gIMView && gIMView->mTalkFloater && gIMView->mTalkFloater->getVisible();
		}
		else if (floater_name == "mute list")
		{
			new_value = LLFloaterMute::visible(NULL);
		}
		else if (floater_name == "camera controls")
		{
			new_value = LLFloaterCamera::visible(NULL);
		}
		else if (floater_name == "movement controls")
		{
			new_value = LLFloaterMove::visible(NULL);
		}
		else if (floater_name == "stat bar")
		{
			new_value = gDebugView->mStatViewp->getVisible();
		}
		gMenuHolder->findControl(control_name)->setValue(new_value);
		return true;
	}
};

void callback_show_url(S32 option, void* url)
{
	const char* urlp = (const char*)url;
	if (0 == option)
	{
		LLWeb::loadURL(urlp);
	}
	delete urlp;
}

class LLPromptShowURL : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString param = userdata.asString();
		LLString::size_type offset = param.find(",");
		if (offset != param.npos)
		{
			LLString alert = param.substr(0, offset);
			LLString url = param.substr(offset+1);
			char *url_copy = new char[url.size()+1];
			strcpy(url_copy, url.c_str());
			gViewerWindow->alertXml(alert, callback_show_url, url_copy);
		}
		else
		{
			llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl;
		}
		return true;
	}
};

void callback_show_file(S32 option, void* filename)
{
	const char* filenamep = (const char*)filename;
	if (0 == option)
	{
		load_url_local_file(filenamep);
	}
	delete filenamep;
}

class LLPromptShowFile : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString param = userdata.asString();
		LLString::size_type offset = param.find(",");
		if (offset != param.npos)
		{
			LLString alert = param.substr(0, offset);
			LLString file = param.substr(offset+1);
			char *file_copy = new char[file.size()+1];
			strcpy(file_copy, file.c_str());
			gViewerWindow->alertXml(alert, callback_show_file, file_copy);
		}
		else
		{
			llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl;
		}
		return true;
	}
};

class LLShowAgentProfile : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLUUID agent_id;
		if (userdata.asString() == "agent")
		{
			agent_id = gAgent.getID();
		}
		else if (userdata.asString() == "hit object")
		{
			agent_id = gLastHitObjectID;
		}
		else
		{
			agent_id = userdata.asUUID();
		}

		LLVOAvatar* avatar = find_avatar_from_object(agent_id);
		if (avatar)
		{
			LLFloaterAvatarInfo::showFromAvatar(avatar);
		}
		return true;
	}
};

class LLShowAgentGroups : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLUUID agent_id;
		if (userdata.asString() == "agent")
		{
			agent_id = gAgent.getID();
		}
		else
		{
			agent_id = userdata.asUUID();
		}
		if(agent_id.notNull())
		{
			LLFloaterGroups::show(agent_id, LLFloaterGroups::AGENT_GROUPS);
		}
		return true;
	}
};

void handle_focus(void *)
{
	if (gDisconnected)
	{
		return;
	}

	if (gAgent.getFocusOnAvatar())
	{
		// zoom in if we're looking at the avatar
		gAgent.setFocusOnAvatar(FALSE, ANIMATE);
		gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
		gAgent.cameraZoomIn(0.666f);
	}
	else
	{
		gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
	}

	gViewerWindow->moveCursorToCenter();

	// Switch to camera toolset
//	gCurrentToolset = gCameraToolset;
	gCurrentToolset->selectTool( gToolCamera );
}

class LLLandEdit : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		if (gAgent.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") )
		{
			// zoom in if we're looking at the avatar
			gAgent.setFocusOnAvatar(FALSE, ANIMATE);
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);

			gAgent.cameraOrbitOver( F_PI * 0.25f );
			gViewerWindow->moveCursorToCenter();
		}
		else if ( gSavedSettings.getBOOL("EditCameraMovement") )
		{
			gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
			gViewerWindow->moveCursorToCenter();
		}


		gParcelMgr->selectParcelAt( gLastHitPosGlobal );

		gFloaterTools->showMore(TRUE);
	gFloaterView->bringToFront( gFloaterTools );

		// Switch to land edit toolset
		gCurrentToolset->selectTool( gToolParcel );
		return true;
	}
};

class LLWorldEnableBuyLand : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gParcelMgr->canAgentBuyParcel(
								gParcelMgr->selectionEmpty()
									? gParcelMgr->getAgentParcel()
									: gParcelMgr->getSelectedParcel(),
								false);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_buy_land(void*)
{
	return gParcelMgr->canAgentBuyParcel(
				gParcelMgr->getSelectedParcel(), false);
}


void handle_move(void*)
{
	if (gAgent.getFocusOnAvatar())
	{
		// zoom in if we're looking at the avatar
		gAgent.setFocusOnAvatar(FALSE, ANIMATE);
		gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);

		gAgent.cameraZoomIn(0.666f);
	}
	else
	{
		gAgent.setFocusGlobal(gLastHitPosGlobal + gLastHitObjectOffset, gLastHitObjectID);
	}

	gViewerWindow->moveCursorToCenter();

	gCurrentToolset = gBasicToolset;
	gCurrentToolset->selectTool( gToolGrab );
}


void near_attach_object(BOOL success, void *user_data)
{
	LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;
	
	U8 attachment_id;
	if (attachment)
	{
		attachment_id = gAgent.getAvatarObject()->mAttachmentPoints.reverseLookup(attachment);
	}
	else
	{
		// interpret 0 as "default location"
		attachment_id = 0;
	}
	
	gSelectMgr->sendAttach(attachment_id);
	gSelectMgr->deselectTransient();
}

class LLObjectAttachToAvatar : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLViewerObject* selectedObject = gSelectMgr->getFirstRootObject();
		if (selectedObject)
		{
			confirm_replace_attachment(0, NULL);
		}
		return true;
	}
};

// move this somewhere global
void handle_attach_to_avatar(void* user_data)
{
    LLViewerObject* selectedObject = gSelectMgr->getFirstRootObject();
    if (selectedObject)
    {
        LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;

        if (attachment && attachment->getObject(0))
        {
            gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment, user_data);
        }
        else
        {
            confirm_replace_attachment(0, user_data);
        }
    }
}
void confirm_replace_attachment(S32 option, void* user_data)
{
	if (option == 0/*YES*/)
	{
		LLViewerObject* selectedObject = gSelectMgr->getFirstRootObject();
		if (selectedObject)
		{
			const F32 MIN_STOP_DISTANCE = 1.f;	// meters
			const F32 ARM_LENGTH = 0.5f;		// meters
			const F32 SCALE_FUDGE = 1.5f;

			F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH;
			if (stop_distance < MIN_STOP_DISTANCE)
			{
				stop_distance = MIN_STOP_DISTANCE;
			}

			LLVector3 walkToSpot = selectedObject->getPositionAgent();
			
			// make sure we stop in front of the object
			LLVector3 delta = walkToSpot - gAgent.getPositionAgent();
			delta.normVec();
			delta = delta * 0.5f;
			walkToSpot -= delta;

			gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, near_attach_object, user_data, stop_distance);
			gAgent.clearFocusObject();
		}
	}
}

class LLAttachmentDrop : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// Called when the user clicked on an object attached to them
		// and selected "Drop".
		LLViewerObject *object = gViewerWindow->lastObjectHit();
		if (!object)
		{
			llwarns << "handle_drop_attachment() - no object to drop" << llendl;
			return true;
		}

		LLViewerObject *parent = (LLViewerObject*)object->getParent();
		while (parent)
		{
			if(parent->isAvatar())
			{
				break;
			}
			object = parent;
			parent = (LLViewerObject*)parent->getParent();
		}

		if (!object)
		{
			llwarns << "handle_detach() - no object to detach" << llendl;
			return true;
		}

		if (object->isAvatar())
		{
			llwarns << "Trying to detach avatar from avatar." << llendl;
			return true;
		}

		// The sendDropAttachment() method works on the list of selected
		// objects.  Thus we need to clear the list, make sure it only
		// contains the object the user clicked, send the message,
		// then clear the list.
		// We use deselectAll to update the simulator's notion of what's
		// selected, and removeAll just to change things locally.
		//gSelectMgr->deselectAll();
		//gSelectMgr->selectObjectAndFamily(object);
		gSelectMgr->sendDropAttachment();
		gSelectMgr->deselectTransient();
		return true;
	}
};

// called from avatar pie menu
void handle_detach_from_avatar(void* user_data)
{
	LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;
	
	LLViewerObject* attached_object = attachment->getObject(0);

	if (attached_object)
	{
		gMessageSystem->newMessage("ObjectDetach");
		gMessageSystem->nextBlockFast(_PREHASH_AgentData);
		gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
		gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());

		gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
		gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
		gMessageSystem->sendReliable( gAgent.getRegionHost() );
	}
}

void attach_label(LLString& label, void* user_data)
{
	LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data;
	if (attachmentp)
	{
		label = attachmentp->getName();
		if (attachmentp->getObject(0))
		{
			LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID());
			if (itemp)
			{
				label += LLString(" (") + itemp->getName() + LLString(")");
			}
		}
	}
}

void detach_label(LLString& label, void* user_data)
{
	LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data;
	if (attachmentp)
	{
		label = attachmentp->getName();
		if (attachmentp->getObject(0))
		{
			LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID());
			if (itemp)
			{
				label += LLString(" (") + itemp->getName() + LLString(")");
			}
		}
	}
}


class LLAttachmentDetach : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// Called when the user clicked on an object attached to them
		// and selected "Detach".
		LLViewerObject *object = gViewerWindow->lastObjectHit();
		if (!object)
		{
			llwarns << "handle_detach() - no object to detach" << llendl;
			return true;
		}

		LLViewerObject *parent = (LLViewerObject*)object->getParent();
		while (parent)
		{
			if(parent->isAvatar())
			{
				break;
			}
			object = parent;
			parent = (LLViewerObject*)parent->getParent();
		}

		if (!object)
		{
			llwarns << "handle_detach() - no object to detach" << llendl;
			return true;
		}

		if (object->isAvatar())
		{
			llwarns << "Trying to detach avatar from avatar." << llendl;
			return true;
		}

		// The sendDetach() method works on the list of selected
		// objects.  Thus we need to clear the list, make sure it only
		// contains the object the user clicked, send the message,
		// then clear the list.
		// We use deselectAll to update the simulator's notion of what's
		// selected, and removeAll just to change things locally.
		//RN: I thought it was more useful to detach everything that was selected
		if (gSelectMgr->selectionIsAttachment())
		{
			gSelectMgr->sendDetach();
			gSelectMgr->deselectAll();
		}
		return true;
	}
};

//Adding an observer for a Jira 2422 and needs to be a fetch observer
//for Jira 3119
class LLWornItemFetchedObserver : public LLInventoryFetchObserver
{
public:
	LLWornItemFetchedObserver() {}
	virtual ~LLWornItemFetchedObserver() {}

protected:
	virtual void done()
	{
		gPieAttachment->buildDrawLabels();
		gInventory.removeObserver(this);
		delete this;
	}
};

// You can only drop items on parcels where you can build.
class LLAttachmentEnableDrop : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLParcel* parcel = gParcelMgr->getAgentParcel();
		BOOL can_build   = gAgent.isGodlike() || (parcel && parcel->getAllowModify());

		//Add an inventory observer to only allow dropping the newly attached item
		//once it exists in your inventory.  Look at Jira 2422.
		//-jwolk

		// A bug occurs when you wear/drop an item before it actively is added to your inventory
		// if this is the case (you're on a slow sim, etc.) a copy of the object,
		// well, a newly created object with the same properties, is placed
		// in your inventory.  Therefore, we disable the drop option until the
		// item is in your inventory

		LLViewerObject*              object         = gViewerWindow->lastObjectHit();
		LLViewerJointAttachment*     attachment_pt  = NULL;
		LLInventoryItem*             item           = NULL;

		if ( object )
		{
    		S32 attachmentID  = ATTACHMENT_ID_FROM_STATE(object->getState());
  				attachment_pt = gAgent.getAvatarObject()->mAttachmentPoints.getIfThere(attachmentID);

			if ( attachment_pt )
			{
				// make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
				// so check to see if the item is in the inventory already
				item = gInventory.getItem(attachment_pt->getItemID());
				
				if ( !item )
				{
					// Item does not exist, make an observer to enable the pie menu 
					// when the item finishes fetching worst case scenario 
					// if a fetch is already out there (being sent from a slow sim)
					// we refetch and there are 2 fetches
					LLWornItemFetchedObserver* wornItemFetched = new LLWornItemFetchedObserver();
					LLInventoryFetchObserver::item_ref_t items; //add item to the inventory item to be fetched

					items.push_back(attachment_pt->getItemID());
				
					wornItemFetched->fetchItems(items);
					gInventory.addObserver(wornItemFetched);
				}
			}
		}
		
		//now check to make sure that the item is actually in the inventory before we enable dropping it
		bool new_value = enable_detach(NULL) && can_build && item;

		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_detach(void*)
{
	LLViewerObject* object = gViewerWindow->lastObjectHit();
	if (!object) return FALSE;
	if (!object->isAttachment()) return FALSE;

	// Find the avatar who owns this attachment
	LLViewerObject* avatar = object;
	while (avatar)
	{
		// ...if it's you, good to detach
		if (avatar->getID() == gAgent.getID())
		{
			return TRUE;
		}

		avatar = (LLViewerObject*)avatar->getParent();
	}

	return FALSE;
}

class LLAttachmentEnableDetach : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = enable_detach(NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// Used to tell if the selected object can be attached to your avatar.
BOOL object_selected_and_point_valid(void *user_data)
{
	//LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;

	for (LLViewerObject *object = gSelectMgr->getFirstRootObject(); object; object = gSelectMgr->getNextRootObject())
	{
		for (U32 child_num = 0; child_num < object->mChildList.size(); child_num++ )
		{
			if (object->mChildList[child_num]->isAvatar())
			{
				return FALSE;
			}
		}
	}

	return ((gSelectMgr != NULL) && 
		(gSelectMgr->getRootObjectCount() == 1) && 
		(gSelectMgr->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) && 
		gSelectMgr->getFirstRootObject()->permYouOwner() &&
		!((LLViewerObject*)gSelectMgr->getFirstRootObject()->getRoot())->isAvatar() && 
		(gSelectMgr->getFirstRootObject()->getNVPair("AssetContainer") == NULL));
}

// Also for seeing if object can be attached.  See above.
class LLObjectEnableWear : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = false;
		if (gSelectMgr)
		{
			LLViewerObject* first_root = gSelectMgr->getFirstRootObject();
			if (first_root)
			{
				new_value = gSelectMgr->getRootObjectCount() == 1
								&& first_root->getPCode() == LL_PCODE_VOLUME
								&& first_root->permYouOwner()
								&& !((LLViewerObject*)gSelectMgr->getFirstRootObject()->getRoot())->isAvatar()
								&& (first_root->getNVPair("AssetContainer") == NULL);
			}
		}

		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};


BOOL object_attached(void *user_data)
{
	LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data;

	return attachment->getObject(0) != NULL;
}

class LLAvatarSendIM : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLVOAvatar* avatar = find_avatar_from_object( gViewerWindow->lastObjectHit() );
		if(avatar)
		{
			LLString name("IM");
			LLNameValue *first = avatar->getNVPair("FirstName");
			LLNameValue *last = avatar->getNVPair("LastName");
			if (first && last)
			{
				name.assign( first->getString() );
				name.append(" ");
				name.append( last->getString() );
			}

			gIMView->setFloaterOpen(TRUE);
			//EInstantMessage type = have_agent_callingcard(gLastHitObjectID)
			//	? IM_SESSION_ADD : IM_SESSION_CARDLESS_START;
			gIMView->addSession(name,
								IM_NOTHING_SPECIAL,
								avatar->getID());
		}
		return true;
	}
};


void handle_activate(void*)
{
}

BOOL enable_activate(void*)
{
	return FALSE;
}

class LLToolsSelectedScriptAction : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString action = userdata.asString();
		LLFloaterScriptQueue *queue = NULL;
		if (action == "compile")
		{
			queue = LLFloaterCompileQueue::create();
		}
		else if (action == "reset")
		{
			queue = LLFloaterResetQueue::create();
		}
		else if (action == "start")
		{
			queue = LLFloaterRunQueue::create();
		}
		else if (action == "stop")
		{
			queue = LLFloaterNotRunQueue::create();
		}
		if (!queue) return true;

		BOOL scripted = FALSE;
		BOOL modifiable = FALSE;

		for(LLViewerObject* obj = gSelectMgr->getFirstObject();
			obj;
			obj = gSelectMgr->getNextObject())
		{
			scripted = obj->flagScripted();
			modifiable = obj->permModify();

			if( scripted &&  modifiable )
				queue->addObject(obj->getID());
			else
				break;
		}

		if(!queue->start())
		{
			if ( ! scripted )
			{
				gViewerWindow->alertXml("CannotRecompileSelectObjectsNoScripts");
			}
			else if ( ! modifiable )
			{
				gViewerWindow->alertXml("CannotRecompileSelectObjectsNoPermission");
			}
		}
		return true;
	}
};

void handle_reset_selection(void*)
{
	LLFloaterResetQueue* queue = LLFloaterResetQueue::create();

	BOOL scripted = FALSE;
	BOOL modifiable = FALSE;

	for(LLViewerObject* obj = gSelectMgr->getFirstObject();
		obj;
		obj = gSelectMgr->getNextObject())
	{
		scripted = obj->flagScripted();
		modifiable = obj->permModify();

		if( scripted &&  modifiable )
			queue->addObject(obj->getID());
		else
			break;
	}

	if(!queue->start())
	{
		if ( ! scripted )
		{
			gViewerWindow->alertXml("CannotResetSelectObjectsNoScripts");
		}
		else if ( ! modifiable )
		{
			gViewerWindow->alertXml("CannotResetSelectObjectsNoPermission");
		}
	}
}

void handle_set_run_selection(void*)
{
	LLFloaterRunQueue* queue = LLFloaterRunQueue::create();

	BOOL scripted = FALSE;
	BOOL modifiable = FALSE;

	for(LLViewerObject* obj = gSelectMgr->getFirstObject();
		obj;
		obj = gSelectMgr->getNextObject())
	{
		scripted = obj->flagScripted();
		modifiable = obj->permModify();

		if( scripted &&  modifiable )
			queue->addObject(obj->getID());
		else
			break;
	}

	if(!queue->start())
	{
		if ( ! scripted )
		{
			gViewerWindow->alertXml("CannotSetRunningSelectObjectsNoScripts");
		}
		else if ( ! modifiable )
		{
			gViewerWindow->alertXml("CannotSerRunningSelectObjectsNoPermission");
		}
	}
}

void handle_set_not_run_selection(void*)
{
	LLFloaterNotRunQueue* queue = LLFloaterNotRunQueue::create();

	BOOL scripted = FALSE;
	BOOL modifiable = FALSE;

	for(LLViewerObject* obj = gSelectMgr->getFirstObject();
		obj;
		obj = gSelectMgr->getNextObject())
	{
		scripted = obj->flagScripted();
		modifiable = obj->permModify();

		if( scripted &&  modifiable )
			queue->addObject(obj->getID());
		else
			break;
	}

	if(!queue->start())
	{
		if ( ! scripted )
		{
			gViewerWindow->alertXml("CannotSetRunningNotSelectObjectsNoScripts");
		}
		else if ( ! modifiable )
		{
			gViewerWindow->alertXml("CannotSerRunningNotSelectObjectsNoPermission");
		}
	}
}

void handle_selected_texture_info(void*)
{
	LLSelectNode* node = NULL;
	for (node = gSelectMgr->getFirstNode(); node != NULL; node = gSelectMgr->getNextNode())
	{
		if (!node->mValid) continue;

		std::string msg;
		msg.assign("Texture info for: ");
		msg.append(node->mName);
		LLChat chat(msg);
		LLFloaterChat::addChat(chat);

		U8 te_count = node->getObject()->getNumTEs();
		// map from texture ID to list of faces using it
		typedef std::map< LLUUID, std::vector<U8> > map_t;
		map_t faces_per_texture;
		for (U8 i = 0; i < te_count; i++)
		{
			if (!node->isTESelected(i)) continue;

			LLViewerImage* img = node->getObject()->getTEImage(i);
			LLUUID image_id = img->getID();
			faces_per_texture[image_id].push_back(i);
		}
		// Per-texture, dump which faces are using it.
		map_t::iterator it;
		for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)
		{
			LLUUID image_id = it->first;
			U8 te = it->second[0];
			LLViewerImage* img = node->getObject()->getTEImage(te);
			S32 height = img->getHeight();
			S32 width = img->getWidth();
			S32 components = img->getComponents();
			std::string image_id_string;
			if (gAgent.isGodlike())
			{
				image_id_string = image_id.getString() + " ";
			}
			msg = llformat("%s%dx%d %s on face ",
								image_id_string.c_str(),
								width,
								height,
								(components == 4 ? "alpha" : "opaque"));
			for (U8 i = 0; i < it->second.size(); ++i)
			{
				msg.append( llformat("%d ", (S32)(it->second[i])));
			}
			LLChat chat(msg);
			LLFloaterChat::addChat(chat);
		}
	}
}

void handle_dump_image_list(void*)
{
	gImageList.dump();
}

void handle_test_male(void*)
{
	wear_outfit_by_name("Male Shape & Outfit");
	//gGestureList.requestResetFromServer( TRUE );
}

void handle_test_female(void*)
{
	wear_outfit_by_name("Female Shape & Outfit");
	//gGestureList.requestResetFromServer( FALSE );
}

void handle_toggle_pg(void*)
{
	if (gAgent.mAccess < SIM_ACCESS_MATURE)
	{
		gAgent.mAccess = SIM_ACCESS_MATURE;
	}
	else
	{
		gAgent.mAccess = SIM_ACCESS_PG;
	}

	LLFloaterWorldMap::reloadIcons(NULL);

	llinfos << "Access set to " << (S32)gAgent.mAccess << llendl;
}

void handle_dump_attachments(void*)
{
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if( !avatar )
	{
		llinfos << "NO AVATAR" << llendl;
		return;
	}

	for( LLViewerJointAttachment* attachment = avatar->mAttachmentPoints.getFirstData();
		attachment;
		attachment = avatar->mAttachmentPoints.getNextData() )
	{
		S32 key = avatar->mAttachmentPoints.getCurrentKeyWithoutIncrement();
		BOOL visible = (attachment->getObject(0) != NULL &&
						attachment->getObject(0)->mDrawable.notNull() && 
						!attachment->getObject(0)->mDrawable->isRenderType(0));
		LLVector3 pos;
		if (visible) pos = attachment->getObject(0)->mDrawable->getPosition();
		llinfos << "ATTACHMENT " << key << ": item_id=" << attachment->getItemID()
				<< (attachment->getObject(0) ? " present " : " absent ")
				<< (visible ? "visible " : "invisible ")
				<<  " at " << pos
				<< " and " << (visible ? attachment->getObject(0)->getPosition() : LLVector3::zero)
				<< llendl;
	}
}

//---------------------------------------------------------------------
// Callbacks for enabling/disabling items
//---------------------------------------------------------------------

BOOL menu_ui_enabled(void *user_data)
{
	BOOL high_res = gSavedSettings.getBOOL( "HighResSnapshot" );
	return !high_res;
}

// TomY TODO DEPRECATE & REMOVE
void menu_toggle_control( void* user_data )
{
        BOOL checked = gSavedSettings.getBOOL( static_cast<char*>(user_data) );
        if (LLString(static_cast<char*>(user_data)) == "HighResSnapshot" && !checked)
        {
                // High Res Snapshot active, must uncheck RenderUIInSnapshot
                gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE );
        }
        gSavedSettings.setBOOL( static_cast<char*>(user_data), !checked );
}


// these are used in the gl menus to set control values.
class LLToggleControl : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString control_name = userdata.asString();
		BOOL checked = gSavedSettings.getBOOL( control_name );
		if (control_name == "HighResSnapshot" && !checked)
		{
			// High Res Snapshot active, must uncheck RenderUIInSnapshot
			gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE );
		}
		gSavedSettings.setBOOL( control_name, !checked );
		return true;
	}
};

// As above, but can be a callback from a LLCheckboxCtrl
void check_toggle_control( LLUICtrl *, void* user_data )
{
	BOOL checked = gSavedSettings.getBOOL( static_cast<char*>(user_data) );
	gSavedSettings.setBOOL( static_cast<char*>(user_data), !checked );
}

BOOL menu_check_control( void* user_data)
{
	return gSavedSettings.getBOOL((char*)user_data);
}

// 
void menu_toggle_variable( void* user_data )
{
	BOOL checked = *(BOOL*)user_data;
	*(BOOL*)user_data = !checked;
}

BOOL menu_check_variable( void* user_data)
{
	return *(BOOL*)user_data;
}


BOOL enable_land_selected( void* )
{
	return gParcelMgr && !(gParcelMgr->selectionEmpty());
}

class LLSomethingSelected : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = !(gSelectMgr->isEmpty());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLSomethingSelectedNoHUD : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = !(gSelectMgr->isEmpty()) && !(gSelectMgr->getSelectType() == SELECT_TYPE_HUD);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_more_than_one_selected(void* )
{
	return (gSelectMgr->getObjectCount() > 1);
}

class LLEditableSelected : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = (gSelectMgr->getFirstEditableObject() != NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLToolsEnableTakeCopy : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = false;
		if (gSelectMgr)
		{
			new_value = true;
#ifndef HACKED_GODLIKE_VIEWER
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
			if (gInProductionGrid || !gAgent.isGodlike())
# endif
			{
				LLViewerObject* obj = gSelectMgr->getFirstRootObject();
				if(obj)
				{
					for( ; obj; obj = gSelectMgr->getNextRootObject())
					{
						if(!(obj->permCopy()) || obj->isAttachment())
						{
							new_value = false;
						}
					}
				}
			}
#endif // HACKED_GODLIKE_VIEWER
		}

		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_selection_you_own_all(void*)
{
	LLViewerObject *obj;
	for (obj = gSelectMgr->getFirstRootObject(); obj; obj = gSelectMgr->getNextRootObject())
	{
		if (!obj->permYouOwner())
		{
			return FALSE;
		}
	}

	return TRUE;
}

BOOL enable_selection_you_own_one(void*)
{
	LLViewerObject *obj;
	for (obj = gSelectMgr->getFirstRootObject(); obj; obj = gSelectMgr->getNextRootObject())
	{
		if (obj->permYouOwner())
		{
			return TRUE;
		}
	}

	return FALSE;
}

class LLHasAsset : public LLInventoryCollectFunctor
{
public:
	LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {}
	virtual ~LLHasAsset() {}
	virtual bool operator()(LLInventoryCategory* cat,
							LLInventoryItem* item);
	BOOL hasAsset() const { return mHasAsset; }

protected:
	LLUUID mAssetID;
	BOOL mHasAsset;
};

bool LLHasAsset::operator()(LLInventoryCategory* cat,
							LLInventoryItem* item)
{
	if(item && item->getAssetUUID() == mAssetID)
	{
		mHasAsset = TRUE;
	}
	return FALSE;
}

BOOL enable_save_into_inventory(void*)
{
	if(gSelectMgr)
	{
		// find the last root
		LLSelectNode* last_node = NULL;
		for(LLSelectNode* node = gSelectMgr->getFirstRootNode();
			node != NULL;
			node = gSelectMgr->getNextRootNode())
		{
			last_node = node;
		}

#ifdef HACKED_GODLIKE_VIEWER
		return TRUE;
#else
# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
		if (!gInProductionGrid && gAgent.isGodlike())
		{
			return TRUE;
		}
# endif
		// check all pre-req's for save into inventory.
		if(last_node && last_node->mValid && !last_node->mItemID.isNull()
		   && (last_node->mPermissions->getOwner() == gAgent.getID())
		   && (gInventory.getItem(last_node->mItemID) != NULL))
		{
			LLViewerObject* obj = last_node->getObject();
			if( obj && !obj->isAttachment() )
			{
				return TRUE;
			}
		}
#endif
	}
	return FALSE;
}

class LLToolsEnableSaveToInventory : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = enable_save_into_inventory(NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_save_into_task_inventory(void*)
{
	if(gSelectMgr)
	{
		LLSelectNode* node = gSelectMgr->getFirstRootNode();
		if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
		{
			// *FIX: check to see if the fromtaskid object exists.

			LLViewerObject* obj = node->getObject();
			if( obj && !obj->isAttachment() )
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}

class LLToolsEnableSaveToObjectInventory : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = enable_save_into_task_inventory(NULL);
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_not_thirdperson(void*)
{
	return !gAgent.cameraThirdPerson();
}

class LLFileEnableUpload : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gStatusBar && gGlobalEconomy && (gStatusBar->getBalance() >= gGlobalEconomy->getPriceUpload());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_export_selected(void *)
{
	if (gSelectMgr->isEmpty())
	{
		return FALSE;
	}
	if (!gExporterRequestID.isNull())
	{
		return FALSE;
	}
	if (!LLUploadDialog::modalUploadIsFinished())
	{
		return FALSE;
	}
	return TRUE;
}

class LLViewEnableMouselook : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// You can't go directly from customize avatar to mouselook.
		// TODO: write code with appropriate dialogs to handle this transition.
		bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime"));
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLToolsEnableToolNotPie : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = ( gToolMgr->getCurrentTool(MASK_NONE) != gToolPie );
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLWorldEnableCreateLandmark : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.isGodlike() || 
			(gAgent.getRegion() && gAgent.getRegion()->getAllowLandmark());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLWorldEnableSetHomeLocation : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = gAgent.isGodlike() || 
			(gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome());
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

BOOL enable_region_owner(void*)
{
	if(gAgent.getRegion() && gAgent.getRegion()->getOwner() == gAgent.getID())
		return TRUE;
	return enable_god_customer_service(NULL);
}

BOOL enable_god_full(void*)
{
	return gAgent.getGodLevel() >= GOD_FULL;
}

BOOL enable_god_liaison(void*)
{
	return gAgent.getGodLevel() >= GOD_LIAISON;
}

BOOL enable_god_customer_service(void*)
{
	return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE;
}

BOOL enable_god_basic(void*)
{
	return gAgent.getGodLevel() > GOD_NOT;
}

void toggle_vbo(void *)
{
	gPipeline.mUseVBO = !gPipeline.mUseVBO;

	if (!gPipeline.usingAGP())
	{
		return;
	}

	gPipeline.setUseAGP(FALSE);
	gPipeline.setUseAGP(TRUE);

	gSavedSettings.setBOOL("RenderUseVBO", gPipeline.mUseVBO);
}

BOOL check_vbo(void *)
{
	return gPipeline.mUseVBO;
}

#if 0 // 1.9.2
void toggle_vertex_shaders(void *)
{
	BOOL use_shaders = gPipeline.getUseVertexShaders();
	gPipeline.setUseVertexShaders(use_shaders);
}

BOOL check_vertex_shaders(void *)
{
	return gPipeline.getUseVertexShaders();
}
#endif

void toggle_glow(void *)
{
	gRenderLightGlows = !gRenderLightGlows;

	gSavedSettings.setBOOL("RenderLightGlows", gRenderLightGlows);
}

BOOL check_glow(void *)
{
	return gRenderLightGlows;
}


void toggle_show_xui_names(void *)
{
	BOOL showXUINames = gSavedSettings.getBOOL("ShowXUINames");
	
	showXUINames = !showXUINames;
	gSavedSettings.setBOOL("ShowXUINames", showXUINames);
}

BOOL check_show_xui_names(void *)
{
	return gSavedSettings.getBOOL("ShowXUINames");
}



void toggle_cull_small(void *)
{
//	gPipeline.mCullBySize = !gPipeline.mCullBySize;
//
//	gSavedSettings.setBOOL("RenderCullBySize", gPipeline.mCullBySize);
}

class LLToolsSelectOnlyMyObjects : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly");

		gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val );

		return true;
	}
};

class LLToolsSelectOnlyMovableObjects : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly");

		gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val );

		return true;
	}
};

class LLToolsSelectBySurrounding : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive;

		gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive);
		return true;
	}
};

class LLToolsShowHiddenSelection : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// TomY TODO Merge these
		LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections;

		gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections);
		return true;
	}
};

class LLToolsShowSelectionLightRadius : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		// TomY TODO merge these
		LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius;

		gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius);
		return true;
	}
};

void reload_personal_settings_overrides(void *)
{
	llinfos << "Loading overrides from " << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml") << llendl;
	
	gSavedSettings.loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml"));
}

void force_breakpoint(void *)
{
#if LL_WINDOWS // Forcing a breakpoint
	DebugBreak();
#endif
}

void reload_vertex_shader(void *)
{
	//THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought	- DaveP
}

void flush_animations(void *)
{
	if (gAgent.getAvatarObject())
	{
		gAgent.getAvatarObject()->resetAnimations();
	}
}

void slow_mo_animations(void*)
{
	static BOOL slow_mo = FALSE;
	if (slow_mo)
	{
		gAgent.getAvatarObject()->setAnimTimeFactor(1.f);
		slow_mo = FALSE;
	}
	else
	{
		gAgent.getAvatarObject()->setAnimTimeFactor(0.2f);
		slow_mo = TRUE;
	}
}

void handle_dump_avatar_local_textures(void*)
{
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if( avatar )
	{
		avatar->dumpLocalTextures();
	}
}

void handle_debug_avatar_textures(void*)
{
	LLFloaterAvatarTextures::show(gLastHitObjectID);
}

void handle_grab_texture(void* data)
{
	LLVOAvatar::ETextureIndex index = (LLVOAvatar::ETextureIndex) ((U32) data);
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if ( avatar )
	{
		const LLUUID& asset_id = avatar->grabLocalTexture(index);
		llinfos << "Adding baked texture " << asset_id << " to inventory." << llendl;
		LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
		LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
		LLUUID folder_id(gInventory.findCategoryUUIDForType(asset_type));
		if(folder_id.notNull())
		{
			LLString name = "Baked ";
			switch (index)
			{
			case LLVOAvatar::TEX_EYES_BAKED:
				name.append("Iris");
				break;
			case LLVOAvatar::TEX_HEAD_BAKED:
				name.append("Head");
				break;
			case LLVOAvatar::TEX_UPPER_BAKED:
				name.append("Upper Body");
				break;
			case LLVOAvatar::TEX_LOWER_BAKED:
				name.append("Lower Body");
				break;
			case LLVOAvatar::TEX_SKIRT_BAKED:
				name.append("Skirt");
				break;
			default:
				name.append("Unknown");
				break;
			}
			name.append(" Texture");

			LLUUID item_id;
			item_id.generate();
			LLPermissions perm;
			perm.init(gAgentID,
					  gAgentID,
					  LLUUID::null,
					  LLUUID::null);
			U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER;
			perm.initMasks(PERM_ALL,
						   PERM_ALL,
						   PERM_NONE,
						   PERM_NONE,
						   next_owner_perm);
			S32 creation_date_now = time_corrected();
			LLPointer<LLViewerInventoryItem> item
				= new LLViewerInventoryItem(item_id,
											folder_id,
											perm,
											asset_id,
											asset_type,
											inv_type,
											name,
											"",
											LLSaleInfo::DEFAULT,
											LLInventoryItem::II_FLAGS_NONE,
											creation_date_now);

			item->updateServer(TRUE);
			gInventory.updateItem(item);
			gInventory.notifyObservers();

			LLInventoryView* view = LLInventoryView::getActiveInventory();

			// Show the preview panel for textures to let
			// user know that the image is now in inventory.
			if(view)
			{
				LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus();
				LLFocusMgr::FocusLostCallback callback = gFocusMgr.getFocusCallback();

				view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO);
				view->getPanel()->openSelected();
				//LLInventoryView::dumpSelectionInformation((void*)view);
				// restore keyboard focus
				gFocusMgr.setKeyboardFocus(focus_ctrl, callback);
			}
		}
		else
		{
			llwarns << "Can't find a folder to put it in" << llendl;
		}
	}
}

BOOL enable_grab_texture(void* data)
{
	LLVOAvatar::ETextureIndex index = (LLVOAvatar::ETextureIndex) ((U32) data);
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if ( avatar )
	{
		return avatar->canGrabLocalTexture(index);
	}
	return FALSE;
}

// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
// Returns NULL on failure.
LLVOAvatar* find_avatar_from_object( LLViewerObject* object )
{
	if (object)
	{
		if( object->isAttachment() )
		{
			do
			{
				object = (LLViewerObject*) object->getParent();
			}
			while( object && !object->isAvatar() );
		}
		else
		if( !object->isAvatar() )
		{
			object = NULL;
		}
	}

	return (LLVOAvatar*) object;
}


// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
// Returns NULL on failure.
LLVOAvatar* find_avatar_from_object( const LLUUID& object_id )
{
	return find_avatar_from_object( gObjectList.findObject(object_id) );
}


void handle_disconnect_viewer(void *)
{
	char message[2048];
	message[0] = '\0';

	sprintf(message, "Testing viewer disconnect");

	do_disconnect(message);
}


class LLToolsUseSelectionForGrid : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		gSelectMgr->clearGridObjects();

		for (LLViewerObject* objectp = gSelectMgr->getFirstRootObject();
			objectp;
			objectp = gSelectMgr->getNextRootObject())
			{
				gSelectMgr->addGridObject(objectp);
			}
		gSelectMgr->setGridMode(GRID_MODE_REF_OBJECT);
		if (gFloaterTools)
		{
			gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT);
		}
		return true;
	}
};

void handle_test_load_url(void*)
{
	LLWeb::loadURL("");
	LLWeb::loadURL("hacker://www.google.com/");
	LLWeb::loadURL("http");
	LLWeb::loadURL("http://www.google.com/");
}

//
// LLViewerMenuHolderGL
//

BOOL LLViewerMenuHolderGL::hideMenus()
{
	BOOL handled = LLMenuHolderGL::hideMenus();
	if (handled)
	{
		gSelectMgr->deselectTransient();
		if (!gFloaterTools->getVisible() && !LLFloaterLand::floaterVisible())
		{
			gParcelMgr->deselectLand();	
		}
	}
	return handled;
}

void handle_save_to_xml(void*)
{
	LLFloater* frontmost = gFloaterView->getFrontmost();
	if (!frontmost)
	{
        gViewerWindow->alertXml("NoFrontmostFloater");
		return;
	}

	LLString default_name = "floater_";
	default_name += frontmost->getTitle();
	default_name += ".xml";

	LLString::toLower(default_name);
	LLString::replaceChar(default_name, ' ', '_');
	LLString::replaceChar(default_name, '/', '_');
	LLString::replaceChar(default_name, ':', '_');
	LLString::replaceChar(default_name, '"', '_');

	LLFilePicker& picker = LLFilePicker::instance();
	if (picker.getSaveFile(LLFilePicker::FFSAVE_XML, default_name.c_str()))
	{
		LLString filename = picker.getFirstFile();
		gUICtrlFactory->saveToXML(frontmost, filename);
	}
}

void handle_load_from_xml(void*)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if (picker.getOpenFile(LLFilePicker::FFLOAD_XML))
	{
		LLString filename = picker.getFirstFile();
		LLFloater* floater = new LLFloater("sample_floater");
		gUICtrlFactory->buildFloater(floater, filename);
	}
}

void handle_rebake_textures(void*)
{
	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if (!avatar) return;

	// Slam pending upload count to "unstick" things
	bool slam_for_debug = true;
	avatar->forceBakeAllTextures(slam_for_debug);
}

void toggle_visibility(void* user_data)
{
	LLView* viewp = (LLView*)user_data;
	viewp->setVisible(!viewp->getVisible());
}

BOOL get_visibility(void* user_data)
{
	LLView* viewp = (LLView*)user_data;
	return viewp->getVisible();
}

// TomY TODO: Get rid of these?
class LLViewShowHoverTips : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLHoverView::sShowHoverTips = !LLHoverView::sShowHoverTips;
		return true;
	}
};

class LLViewCheckShowHoverTips : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = LLHoverView::sShowHoverTips;
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// TomY TODO: Get rid of these?
class LLViewHighlightTransparent : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
		return true;
	}
};

class LLViewCheckHighlightTransparent : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = LLDrawPoolAlpha::sShowDebugAlpha;
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLViewToggleBeacon : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString beacon = userdata.asString();
		if (beacon == "scripts")
		{
			LLPipeline::toggleRenderScriptedBeacons(NULL);
		}
		else if (beacon == "physical")
		{
			LLPipeline::toggleRenderPhysicalBeacons(NULL);
		}
		else if (beacon == "sounds")
		{
			LLPipeline::toggleRenderSoundBeacons(NULL);
		}
		else if (beacon == "particles")
		{
			LLPipeline::toggleRenderParticleBeacons(NULL);
		}
		return true;
	}
};

class LLViewCheckBeaconEnabled : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString beacon = userdata["data"].asString();
		bool new_value = false;
		if (beacon == "scripts")
		{
			new_value = LLPipeline::getRenderScriptedBeacons(NULL);
		}
		else if (beacon == "physical")
		{
			new_value = LLPipeline::getRenderPhysicalBeacons(NULL);
		}
		else if (beacon == "sounds")
		{
			new_value = LLPipeline::getRenderSoundBeacons(NULL);
		}
		else if (beacon == "particles")
		{
			new_value = LLPipeline::getRenderParticleBeacons(NULL);
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLViewToggleRenderType : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString type = userdata.asString();
		if (type == "particles")
		{
			LLPipeline::toggleRenderType((void *)(S32)LLPipeline::RENDER_TYPE_PARTICLES);
		}
		return true;
	}
};

class LLViewCheckRenderType : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString type = userdata["data"].asString();
		bool new_value = false;
		if (type == "particles")
		{
			new_value = LLPipeline::toggleRenderTypeControlNegated((void *)(S32)LLPipeline::RENDER_TYPE_PARTICLES);
		}
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

// TomY TODO: Get rid of these?
class LLViewShowHUDAttachments : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLDrawPoolHUD::sShowHUDAttachments = !LLDrawPoolHUD::sShowHUDAttachments;
		return true;
	}
};

class LLViewCheckHUDAttachments : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		bool new_value = LLDrawPoolHUD::sShowHUDAttachments;
		gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value);
		return true;
	}
};

class LLEditEnableTakeOff : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString control_name = userdata["control"].asString();
		LLString clothing = userdata["data"].asString();
		bool new_value = false;
		if (clothing == "shirt")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_SHIRT);
		}
		if (clothing == "pants")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_PANTS);
		}
		if (clothing == "shoes")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_SHOES);
		}
		if (clothing == "socks")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_SOCKS);
		}
		if (clothing == "jacket")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_JACKET);
		}
		if (clothing == "gloves")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_GLOVES);
		}
		if (clothing == "undershirt")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_UNDERSHIRT);
		}
		if (clothing == "underpants")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_UNDERPANTS);
		}
		if (clothing == "skirt")
		{
			new_value = LLAgent::selfHasWearable((void *)WT_SKIRT);
		}
		gMenuHolder->findControl(control_name)->setValue(new_value);
		return true;
	}
};

class LLEditTakeOff : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString clothing = userdata.asString();
		if (clothing == "shirt")
		{
			LLAgent::userRemoveWearable((void*)WT_SHIRT);
		}
		else if (clothing == "pants")
		{
			LLAgent::userRemoveWearable((void*)WT_PANTS);
		}
		else if (clothing == "shoes")
		{
			LLAgent::userRemoveWearable((void*)WT_SHOES);
		}
		else if (clothing == "socks")
		{
			LLAgent::userRemoveWearable((void*)WT_SOCKS);
		}
		else if (clothing == "jacket")
		{
			LLAgent::userRemoveWearable((void*)WT_JACKET);
		}
		else if (clothing == "gloves")
		{
			LLAgent::userRemoveWearable((void*)WT_GLOVES);
		}
		else if (clothing == "undershirt")
		{
			LLAgent::userRemoveWearable((void*)WT_UNDERSHIRT);
		}
		else if (clothing == "underpants")
		{
			LLAgent::userRemoveWearable((void*)WT_UNDERPANTS);
		}
		else if (clothing == "skirt")
		{
			LLAgent::userRemoveWearable((void*)WT_SKIRT);
		}
		else if (clothing == "all")
		{
			LLAgent::userRemoveAllClothes(NULL);
		}
		return true;
	}
};

class LLWorldChat : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		handle_chat(NULL);
		return true;
	}
};

class LLWorldStartGesture : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		handle_slash_key(NULL);
		return true;
	}
};

class LLToolsSelectTool : public view_listener_t
{
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLString tool_name = userdata.asString();
		if (tool_name == "focus")
		{
			gCurrentToolset->selectToolByIndex(1);
		}
		else if (tool_name == "move")
		{
			gCurrentToolset->selectToolByIndex(2);
		}
		else if (tool_name == "edit")
		{
			gCurrentToolset->selectToolByIndex(3);
		}
		else if (tool_name == "create")
		{
			gCurrentToolset->selectToolByIndex(4);
		}
		else if (tool_name == "land")
		{
			gCurrentToolset->selectToolByIndex(5);
		}
		return true;
	}
};

void initialize_menu_actions()
{
	// File menu
	(new LLFileUploadImage())->registerListener(gMenuHolder, "File.UploadImage");
	(new LLFileUploadSound())->registerListener(gMenuHolder, "File.UploadSound");
	(new LLFileUploadAnim())->registerListener(gMenuHolder, "File.UploadAnim");
	(new LLFileUploadBulk())->registerListener(gMenuHolder, "File.UploadBulk");
	(new LLFileCloseWindow())->registerListener(gMenuHolder, "File.CloseWindow");
	(new LLFileSaveTexture())->registerListener(gMenuHolder, "File.SaveTexture");
	(new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot");
	(new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk");
	(new LLFileSaveMovie())->registerListener(gMenuHolder, "File.SaveMovie");
	(new LLFileSetWindowSize())->registerListener(gMenuHolder, "File.SetWindowSize");
	(new LLFileQuit())->registerListener(gMenuHolder, "File.Quit");

	(new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload");
	(new LLFileEnableSaveAs())->registerListener(gMenuHolder, "File.EnableSaveAs");

	// Edit menu
	(new LLEditUndo())->registerListener(gMenuHolder, "Edit.Undo");
	(new LLEditRedo())->registerListener(gMenuHolder, "Edit.Redo");
	(new LLEditCut())->registerListener(gMenuHolder, "Edit.Cut");
	(new LLEditCopy())->registerListener(gMenuHolder, "Edit.Copy");
	(new LLEditPaste())->registerListener(gMenuHolder, "Edit.Paste");
	(new LLEditDelete())->registerListener(gMenuHolder, "Edit.Delete");
	(new LLEditSearch())->registerListener(gMenuHolder, "Edit.Search");
	(new LLEditSelectAll())->registerListener(gMenuHolder, "Edit.SelectAll");
	(new LLEditDeselect())->registerListener(gMenuHolder, "Edit.Deselect");
	(new LLEditDuplicate())->registerListener(gMenuHolder, "Edit.Duplicate");
	(new LLEditTakeOff())->registerListener(gMenuHolder, "Edit.TakeOff");

	(new LLEditEnableUndo())->registerListener(gMenuHolder, "Edit.EnableUndo");
	(new LLEditEnableRedo())->registerListener(gMenuHolder, "Edit.EnableRedo");
	(new LLEditEnableCut())->registerListener(gMenuHolder, "Edit.EnableCut");
	(new LLEditEnableCopy())->registerListener(gMenuHolder, "Edit.EnableCopy");
	(new LLEditEnablePaste())->registerListener(gMenuHolder, "Edit.EnablePaste");
	(new LLEditEnableDelete())->registerListener(gMenuHolder, "Edit.EnableDelete");
	(new LLEditEnableSelectAll())->registerListener(gMenuHolder, "Edit.EnableSelectAll");
	(new LLEditEnableDeselect())->registerListener(gMenuHolder, "Edit.EnableDeselect");
	(new LLEditEnableDuplicate())->registerListener(gMenuHolder, "Edit.EnableDuplicate");
	(new LLEditEnableTakeOff())->registerListener(gMenuHolder, "Edit.EnableTakeOff");
	(new LLEditEnableCustomizeAvatar())->registerListener(gMenuHolder, "Edit.EnableCustomizeAvatar");

	// View menu
	(new LLViewMouselook())->registerListener(gMenuHolder, "View.Mouselook");
	(new LLViewBuildMode())->registerListener(gMenuHolder, "View.BuildMode");
	(new LLViewResetView())->registerListener(gMenuHolder, "View.ResetView");
	(new LLViewLookAtLastChatter())->registerListener(gMenuHolder, "View.LookAtLastChatter");
	(new LLViewShowHoverTips())->registerListener(gMenuHolder, "View.ShowHoverTips");
	(new LLViewHighlightTransparent())->registerListener(gMenuHolder, "View.HighlightTransparent");
	(new LLViewToggleBeacon())->registerListener(gMenuHolder, "View.ToggleBeacon");
	(new LLViewToggleRenderType())->registerListener(gMenuHolder, "View.ToggleRenderType");
	(new LLViewShowHUDAttachments())->registerListener(gMenuHolder, "View.ShowHUDAttachments");
	(new LLViewZoomOut())->registerListener(gMenuHolder, "View.ZoomOut");
	(new LLViewZoomIn())->registerListener(gMenuHolder, "View.ZoomIn");
	(new LLViewZoomDefault())->registerListener(gMenuHolder, "View.ZoomDefault");
	(new LLViewFullscreen())->registerListener(gMenuHolder, "View.Fullscreen");
	(new LLViewDefaultUISize())->registerListener(gMenuHolder, "View.DefaultUISize");

	(new LLViewEnableMouselook())->registerListener(gMenuHolder, "View.EnableMouselook");
	(new LLViewEnableLastChatter())->registerListener(gMenuHolder, "View.EnableLastChatter");

	(new LLViewCheckBuildMode())->registerListener(gMenuHolder, "View.CheckBuildMode");
	(new LLViewCheckShowHoverTips())->registerListener(gMenuHolder, "View.CheckShowHoverTips");
	(new LLViewCheckHighlightTransparent())->registerListener(gMenuHolder, "View.CheckHighlightTransparent");
	(new LLViewCheckBeaconEnabled())->registerListener(gMenuHolder, "View.CheckBeaconEnabled");
	(new LLViewCheckRenderType())->registerListener(gMenuHolder, "View.CheckRenderType");
	(new LLViewCheckHUDAttachments())->registerListener(gMenuHolder, "View.CheckHUDAttachments");

	// World menu
	(new LLWorldChat())->registerListener(gMenuHolder, "World.Chat");
	(new LLWorldStartGesture())->registerListener(gMenuHolder, "World.StartGesture");
	(new LLWorldAlwaysRun())->registerListener(gMenuHolder, "World.AlwaysRun");
	(new LLWorldFly())->registerListener(gMenuHolder, "World.Fly");
	(new LLWorldCreateLandmark())->registerListener(gMenuHolder, "World.CreateLandmark");
	(new LLWorldSetHomeLocation())->registerListener(gMenuHolder, "World.SetHomeLocation");
	(new LLWorldTeleportHome())->registerListener(gMenuHolder, "World.TeleportHome");
	(new LLWorldSetAway())->registerListener(gMenuHolder, "World.SetAway");
	(new LLWorldSetBusy())->registerListener(gMenuHolder, "World.SetBusy");

	(new LLWorldEnableCreateLandmark())->registerListener(gMenuHolder, "World.EnableCreateLandmark");
	(new LLWorldEnableSetHomeLocation())->registerListener(gMenuHolder, "World.EnableSetHomeLocation");
	(new LLWorldEnableBuyLand())->registerListener(gMenuHolder, "World.EnableBuyLand");

	(new LLWorldCheckAlwaysRun())->registerListener(gMenuHolder, "World.CheckAlwaysRun");

	(new LLWorldForceSun())->registerListener(gMenuHolder, "World.ForceSun");

	// Tools menu
	(new LLToolsSelectTool())->registerListener(gMenuHolder, "Tools.SelectTool");
	(new LLToolsSelectOnlyMyObjects())->registerListener(gMenuHolder, "Tools.SelectOnlyMyObjects");
	(new LLToolsSelectOnlyMovableObjects())->registerListener(gMenuHolder, "Tools.SelectOnlyMovableObjects");
	(new LLToolsSelectBySurrounding())->registerListener(gMenuHolder, "Tools.SelectBySurrounding");
	(new LLToolsShowHiddenSelection())->registerListener(gMenuHolder, "Tools.ShowHiddenSelection");
	(new LLToolsShowSelectionLightRadius())->registerListener(gMenuHolder, "Tools.ShowSelectionLightRadius");
	(new LLToolsSnapObjectXY())->registerListener(gMenuHolder, "Tools.SnapObjectXY");
	(new LLToolsUseSelectionForGrid())->registerListener(gMenuHolder, "Tools.UseSelectionForGrid");
	(new LLToolsLink())->registerListener(gMenuHolder, "Tools.Link");
	(new LLToolsUnlink())->registerListener(gMenuHolder, "Tools.Unlink");
	(new LLToolsStopAllAnimations())->registerListener(gMenuHolder, "Tools.StopAllAnimations");
	(new LLToolsLookAtSelection())->registerListener(gMenuHolder, "Tools.LookAtSelection");
	(new LLToolsBuyOrTake())->registerListener(gMenuHolder, "Tools.BuyOrTake");
	(new LLToolsTakeCopy())->registerListener(gMenuHolder, "Tools.TakeCopy");
	(new LLToolsSaveToInventory())->registerListener(gMenuHolder, "Tools.SaveToInventory");
	(new LLToolsSaveToObjectInventory())->registerListener(gMenuHolder, "Tools.SaveToObjectInventory");
	(new LLToolsSelectedScriptAction())->registerListener(gMenuHolder, "Tools.SelectedScriptAction");

	(new LLToolsEnableToolNotPie())->registerListener(gMenuHolder, "Tools.EnableToolNotPie");
	(new LLToolsEnableLink())->registerListener(gMenuHolder, "Tools.EnableLink");
	(new LLToolsEnableUnlink())->registerListener(gMenuHolder, "Tools.EnableUnlink");
	(new LLToolsEnableBuyOrTake())->registerListener(gMenuHolder, "Tools.EnableBuyOrTake");
	(new LLToolsEnableTakeCopy())->registerListener(gMenuHolder, "Tools.EnableTakeCopy");
	(new LLToolsEnableSaveToInventory())->registerListener(gMenuHolder, "Tools.SaveToInventory");
	(new LLToolsEnableSaveToObjectInventory())->registerListener(gMenuHolder, "Tools.SaveToObjectInventory");

	/*(new LLToolsVisibleBuyObject())->registerListener(gMenuHolder, "Tools.VisibleBuyObject");
	(new LLToolsVisibleTakeObject())->registerListener(gMenuHolder, "Tools.VisibleTakeObject");*/

	// Help menu
	(new LLHelpLiveHelp())->registerListener(gMenuHolder, "Help.LiveHelp");
	(new LLHelpMOTD())->registerListener(gMenuHolder, "Help.MOTD");

	// Self pie menu
	(new LLSelfStandUp())->registerListener(gMenuHolder, "Self.StandUp");
	(new LLSelfRemoveAllAttachments())->registerListener(gMenuHolder, "Self.RemoveAllAttachments");

	(new LLSelfEnableStandUp())->registerListener(gMenuHolder, "Self.EnableStandUp");
	(new LLSelfEnableRemoveAllAttachments())->registerListener(gMenuHolder, "Self.EnableRemoveAllAttachments");

	 // Avatar pie menu
	(new LLObjectMute())->registerListener(gMenuHolder, "Avatar.Mute");
	(new LLAvatarRate())->registerListener(gMenuHolder, "Avatar.Rate");
	(new LLAvatarAddFriend())->registerListener(gMenuHolder, "Avatar.AddFriend");
	(new LLAvatarFreeze())->registerListener(gMenuHolder, "Avatar.Freeze");
	(new LLAvatarDebug())->registerListener(gMenuHolder, "Avatar.Debug");
	(new LLAvatarVisibleDebug())->registerListener(gMenuHolder, "Avatar.VisibleDebug");
	(new LLAvatarEnableDebug())->registerListener(gMenuHolder, "Avatar.EnableDebug");
	(new LLAvatarGiveCard())->registerListener(gMenuHolder, "Avatar.GiveCard");
	(new LLAvatarEject())->registerListener(gMenuHolder, "Avatar.Eject");
	(new LLAvatarSendIM())->registerListener(gMenuHolder, "Avatar.SendIM");
	
	(new LLObjectEnableMute())->registerListener(gMenuHolder, "Avatar.EnableMute");
	(new LLAvatarEnableAddFriend())->registerListener(gMenuHolder, "Avatar.EnableAddFriend");
	(new LLAvatarEnableFreezeEject())->registerListener(gMenuHolder, "Avatar.EnableFreezeEject");

	// Object pie menu
	(new LLObjectOpen())->registerListener(gMenuHolder, "Object.Open");
	(new LLObjectBuild())->registerListener(gMenuHolder, "Object.Build");
	(new LLObjectTouch())->registerListener(gMenuHolder, "Object.Touch");
	(new LLObjectSitOrStand())->registerListener(gMenuHolder, "Object.SitOrStand");
	(new LLObjectDelete())->registerListener(gMenuHolder, "Object.Delete");
	(new LLObjectAttachToAvatar())->registerListener(gMenuHolder, "Object.AttachToAvatar");
	(new LLObjectReturn())->registerListener(gMenuHolder, "Object.Return");
	(new LLObjectRateOwner())->registerListener(gMenuHolder, "Object.RateOwner");
	(new LLObjectReportAbuse())->registerListener(gMenuHolder, "Object.ReportAbuse");
	(new LLObjectRateCreator())->registerListener(gMenuHolder, "Object.RateCreator");
	(new LLObjectMute())->registerListener(gMenuHolder, "Object.Mute");
	(new LLObjectBuy())->registerListener(gMenuHolder, "Object.Buy");
	(new LLObjectEdit())->registerListener(gMenuHolder, "Object.Edit");

	(new LLObjectEnableOpen())->registerListener(gMenuHolder, "Object.EnableOpen");
	(new LLObjectEnableTouch())->registerListener(gMenuHolder, "Object.EnableTouch");
	(new LLObjectEnableSitOrStand())->registerListener(gMenuHolder, "Object.EnableSitOrStand");
	(new LLObjectEnableDelete())->registerListener(gMenuHolder, "Object.EnableDelete");
	(new LLObjectEnableWear())->registerListener(gMenuHolder, "Object.EnableWear");
	(new LLObjectEnableReturn())->registerListener(gMenuHolder, "Object.EnableReturn");
	(new LLObjectEnableRateOwner())->registerListener(gMenuHolder, "Object.EnableRateOwner");
	(new LLObjectEnableReportAbuse())->registerListener(gMenuHolder, "Object.EnableReportAbuse");
	(new LLObjectEnableRateCreator())->registerListener(gMenuHolder, "Object.EnableRateCreator");
	(new LLObjectEnableMute())->registerListener(gMenuHolder, "Object.EnableMute");
	(new LLObjectEnableBuy())->registerListener(gMenuHolder, "Object.EnableBuy");

	/*(new LLObjectVisibleTouch())->registerListener(gMenuHolder, "Object.VisibleTouch");
	(new LLObjectVisibleCustomTouch())->registerListener(gMenuHolder, "Object.VisibleCustomTouch");
	(new LLObjectVisibleStandUp())->registerListener(gMenuHolder, "Object.VisibleStandUp");
	(new LLObjectVisibleSitHere())->registerListener(gMenuHolder, "Object.VisibleSitHere");
	(new LLObjectVisibleCustomSit())->registerListener(gMenuHolder, "Object.VisibleCustomSit");*/

	// Attachment pie menu
	(new LLAttachmentDrop())->registerListener(gMenuHolder, "Attachment.Drop");
	(new LLAttachmentDetach())->registerListener(gMenuHolder, "Attachment.Detach");

	(new LLAttachmentEnableDrop())->registerListener(gMenuHolder, "Attachment.EnableDrop");
	(new LLAttachmentEnableDetach())->registerListener(gMenuHolder, "Attachment.EnableDetach");

	// Land pie menu
	(new LLLandBuild())->registerListener(gMenuHolder, "Land.Build");
	(new LLLandSit())->registerListener(gMenuHolder, "Land.Sit");
	(new LLLandBuyPass())->registerListener(gMenuHolder, "Land.BuyPass");
	(new LLLandEdit())->registerListener(gMenuHolder, "Land.Edit");

	(new LLLandEnableBuyPass())->registerListener(gMenuHolder, "Land.EnableBuyPass");

	// Generic actions
	(new LLShowFloater())->registerListener(gMenuHolder, "ShowFloater");
	(new LLPromptShowURL())->registerListener(gMenuHolder, "PromptShowURL");
	(new LLPromptShowFile())->registerListener(gMenuHolder, "PromptShowFile");
	(new LLShowAgentProfile())->registerListener(gMenuHolder, "ShowAgentProfile");
	(new LLShowAgentGroups())->registerListener(gMenuHolder, "ShowAgentGroups");
	(new LLToggleControl())->registerListener(gMenuHolder, "ToggleControl");

	(new LLGoToObject())->registerListener(gMenuHolder, "GoToObject");
	(new LLPayObject())->registerListener(gMenuHolder, "PayObject");

	(new LLEnablePayObject())->registerListener(gMenuHolder, "EnablePayObject");
	(new LLEnableEdit())->registerListener(gMenuHolder, "EnableEdit");

	(new LLFloaterVisible())->registerListener(gMenuHolder, "FloaterVisible");
	(new LLSomethingSelected())->registerListener(gMenuHolder, "SomethingSelected");
	(new LLSomethingSelectedNoHUD())->registerListener(gMenuHolder, "SomethingSelectedNoHUD");
	(new LLEditableSelected())->registerListener(gMenuHolder, "EditableSelected");
}
