/** 
 * @file llfloaterregioninfo.cpp
 * @author Aaron Brashears
 * @brief Implementation of the region info and controls floater and panels.
 *
 * Copyright (c) 2004-$CurrentYear$, Linden Research, Inc.
 * $License$
 */

#include "llviewerprecompiledheaders.h"
#include "llfloaterregioninfo.h"

#include <algorithm>
#include <functional>

#include "llcachename.h"
#include "lldir.h"
#include "lldispatcher.h"
#include "llglheaders.h"
#include "llregionflags.h"
#include "llstl.h"
#include "indra_constants.h"
#include "message.h"

#include "llagent.h"
#include "llalertdialog.h"
#include "llfloateravatarpicker.h"
#include "llbutton.h" 
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llfilepicker.h"
#include "llfloatergodtools.h"	// for send_sim_wide_deletes()
#include "llfloatergroups.h"
#include "llfloatertelehub.h"
#include "lllineeditor.h"
#include "llalertdialog.h"
#include "llnamelistctrl.h"
#include "llsliderctrl.h"
#include "llspinctrl.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
#include "llinventory.h"
#include "lltexturectrl.h"
#include "llviewercontrol.h"
#include "llvieweruictrlfactory.h"
#include "llviewerimage.h"
#include "llviewerimagelist.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewertexteditor.h"
#include "llviewerwindow.h"
#include "llvlcomposition.h"

const S32 TERRAIN_TEXTURE_COUNT = 4;
const S32 CORNER_COUNT = 4;

#define LL_ENABLE_MAINLAND_VISIBLE_CONTROL 0

///----------------------------------------------------------------------------
/// Local class declaration
///----------------------------------------------------------------------------

/*
class LLDispatchSetEstateOwner : public LLDispatchHandler
{
public:
	LLDispatchSetEstateOwner() {}
	virtual ~LLDispatchSetEstateOwner() {}
	virtual bool operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const sparam_t& strings,
		const iparam_t& integers);
};
*/

class LLDispatchEstateUpdateInfo : public LLDispatchHandler
{
public:
	LLDispatchEstateUpdateInfo() {}
	virtual ~LLDispatchEstateUpdateInfo() {}
	virtual bool operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const LLUUID& invoice,
		const sparam_t& strings);
};

class LLDispatchSetEstateAccess : public LLDispatchHandler
{
public:
	LLDispatchSetEstateAccess() {}
	virtual ~LLDispatchSetEstateAccess() {}
	virtual bool operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const LLUUID& invoice,
		const sparam_t& strings);
};


/*
void unpack_request_params(
	LLMessageSystem* msg,
	LLDispatcher::sparam_t& strings,
	LLDispatcher::iparam_t& integers)
{
	char str_buf[MAX_STRING];
	S32 str_count = msg->getNumberOfBlocksFast(_PREHASH_StringData);
	S32 i;
	for (i = 0; i < str_count; ++i)
	{
		// we treat the SParam as binary data (since it might be an 
		// LLUUID in compressed form which may have embedded \0's,)
		str_buf[0] = '\0';
		S32 data_size = msg->getSizeFast(_PREHASH_StringData, i, _PREHASH_SParam);
		msg->getBinaryDataFast(_PREHASH_StringData, _PREHASH_SParam,
							   str_buf, data_size, i, MAX_STRING - 1);
		strings.push_back(std::string(str_buf, data_size));
	}

	U32 int_buf;
	S32 int_count = msg->getNumberOfBlocksFast(_PREHASH_IntegerData);
	for (i = 0; i < int_count; ++i)
	{
		msg->getU32("IntegerData", "IParam", int_buf, i);
		integers.push_back(int_buf);
	}
}
*/



bool estate_dispatch_initialized = false;


///----------------------------------------------------------------------------
/// LLFloaterRegionInfo
///----------------------------------------------------------------------------

LLFloaterRegionInfo* LLFloaterRegionInfo::sInstance = NULL;
//S32 LLFloaterRegionInfo::sRequestSerial = 0;
LLUUID LLFloaterRegionInfo::sRequestInvoice;

LLFloaterRegionInfo::LLFloaterRegionInfo(const LLRect& rect) :
	LLFloater("regioninfo", rect, "Region/Estate")
{
	LLRect tr(0, rect.getHeight() - LLFLOATER_HEADER_SIZE, rect.getWidth(), 0);
	mTab = new LLTabContainer("tab", tr, LLTabContainer::TOP, NULL,NULL,"");
	mTab->setBorderVisible(FALSE);
	addChild(mTab);

	// contruct the panels
	LLPanel* panel;
	panel = new LLPanelRegionGeneralInfo;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_general.xml");
	mTab->addTabPanel(panel, panel->getLabel(), TRUE);

	panel = new LLPanelRegionDebugInfo;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_debug.xml");
	mTab->addTabPanel(panel, panel->getLabel(), FALSE);

	panel = new LLPanelRegionTextureInfo;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_texture.xml");
	mTab->addTabPanel(panel, panel->getLabel(), FALSE);

	panel = new LLPanelRegionTerrainInfo;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_terrain.xml");
	mTab->addTabPanel(panel, panel->getLabel(), FALSE);

	panel = new LLPanelEstateInfo;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_estate.xml");
	mTab->addTabPanel(panel, panel->getLabel(), FALSE);

	panel = new LLPanelEstateCovenant;
	mInfoPanels.push_back((LLPanelRegionInfo*)panel);
	gUICtrlFactory->buildPanel(panel, "panel_region_covenant.xml");
	mTab->addTabPanel(panel, panel->getLabel(), FALSE);
}

LLFloaterRegionInfo::~LLFloaterRegionInfo()
{
	sInstance = NULL;
}

// static
void LLFloaterRegionInfo::show(LLViewerRegion* region)
{
	if (!sInstance)
	{
		LLRect rect = gSavedSettings.getRect("FloaterRegionInfo");
		S32 left, top;
		gFloaterView->getNewFloaterPosition(&left, &top);
		rect.translate(left,top);
		sInstance = new LLFloaterRegionInfo(rect);
		gMessageSystem->setHandlerFunc(
			"EstateOwnerMessage", 
			&processEstateOwnerRequest);
	}
	sInstance->open();
	sInstance->refreshFromRegion(region);

	// Must allow anyone to request the RegionInfo data
	// so non-owners/non-gods can see the values. 
	// Therefore can't use an EstateOwnerMessage JC
	LLMessageSystem* msg = gMessageSystem;
	msg->newMessage("RequestRegionInfo");
	msg->nextBlock("AgentData");
	msg->addUUID("AgentID", gAgent.getID());
	msg->addUUID("SessionID", gAgent.getSessionID());
	gAgent.sendReliableMessage();
}

// static
void LLFloaterRegionInfo::show(void*)
{
	show(gAgent.getRegion());
}

// static
LLFloaterRegionInfo* LLFloaterRegionInfo::getInstance()
{
	return sInstance;
}

// static
void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**)
{
	static LLDispatcher dispatch;
	if(!sInstance) return;

	if (!estate_dispatch_initialized)
	{
		LLPanelEstateInfo::initDispatch(dispatch);
	}

	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "tab");
	if (!tab) return;

	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab, "Estate");
	if (!panel) return;

	// unpack the message
	std::string request;
	LLUUID invoice;
	LLDispatcher::sparam_t strings;
	LLDispatcher::unpackMessage(msg, request, invoice, strings);
	if(invoice != getLastInvoice())
	{
		llwarns << "Mismatched Estate message: " << request.c_str() << llendl;
		return;
	}

	//dispatch the message
	dispatch.dispatch(request, invoice, strings);
}


// static
void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
{
	LLPanel* panel;

	llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl;
	if(!sInstance) return;
	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(sInstance, "tab");
	if(!tab) return;

	// extract message
	char sim_name[MAX_STRING];
	U32 region_flags;
	U8 agent_limit;
	F32 object_bonus_factor;
	U8 sim_access;
	F32 water_height;
	F32 terrain_raise_limit;
	F32 terrain_lower_limit;
	BOOL use_estate_sun;
	F32 sun_hour;
	msg->getString("RegionInfo", "SimName", MAX_STRING, sim_name);
	msg->getU32("RegionInfo", "RegionFlags", region_flags);
	msg->getU8("RegionInfo", "MaxAgents", agent_limit);
	msg->getF32("RegionInfo", "ObjectBonusFactor", object_bonus_factor);
	msg->getU8("RegionInfo", "SimAccess", sim_access);
	msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_WaterHeight, water_height);
	msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainRaiseLimit, terrain_raise_limit);
	msg->getF32Fast(_PREHASH_RegionInfo, _PREHASH_TerrainLowerLimit, terrain_lower_limit);
	msg->getBOOL("RegionInfo", "UseEstateSun", use_estate_sun);
	// actually the "last set" sun hour, not the current sun hour. JC
	msg->getF32("RegionInfo", "SunHour", sun_hour);

	// GENERAL PANEL
	panel = LLUICtrlFactory::getPanelByName(tab, "General");
	if(!panel) return;
	panel->childSetValue("region_text", LLSD(sim_name));

	panel->childSetValue("block_terraform_check", (region_flags & REGION_FLAGS_BLOCK_TERRAFORM) ? TRUE : FALSE );
	panel->childSetValue("block_fly_check", (region_flags & REGION_FLAGS_BLOCK_FLY) ? TRUE : FALSE );
	panel->childSetValue("allow_damage_check", (region_flags & REGION_FLAGS_ALLOW_DAMAGE) ? TRUE : FALSE );
	panel->childSetValue("restrict_pushobject", (region_flags & REGION_FLAGS_RESTRICT_PUSHOBJECT) ? TRUE : FALSE );
	panel->childSetValue("allow_land_resell_check", (region_flags & REGION_FLAGS_BLOCK_LAND_RESELL) ? FALSE : TRUE );
	panel->childSetValue("allow_parcel_changes_check", (region_flags & REGION_FLAGS_ALLOW_PARCEL_CHANGES) ? TRUE : FALSE );

	panel->childSetValue("agent_limit_spin", LLSD((F32)agent_limit) );
	panel->childSetValue("object_bonus_spin", LLSD(object_bonus_factor) );

	panel->childSetValue("access_combo", LLSD(LLViewerRegion::accessToString(sim_access)) );

	// DEBUG PANEL
	panel = LLUICtrlFactory::getPanelByName(tab, "Debug");
	if(!panel) return;

	panel->childSetValue("region_text", LLSD(sim_name) );
	panel->childSetValue("disable_scripts_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_SCRIPTS)) );
	panel->childSetValue("disable_collisions_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_COLLISIONS)) );
	panel->childSetValue("disable_physics_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SKIP_PHYSICS)) );

	// TERRAIN PANEL
	panel = LLUICtrlFactory::getPanelByName(tab, "Terrain");
	if(!panel) return;

	panel->childSetValue("region_text", LLSD(sim_name));
	panel->childSetValue("water_height_spin", LLSD(water_height));
	panel->childSetValue("terrain_raise_spin", LLSD(terrain_raise_limit));
	panel->childSetValue("terrain_lower_spin", LLSD(terrain_lower_limit));
	panel->childSetValue("use_estate_sun_check", LLSD(use_estate_sun));

	LLViewerRegion* region = gAgent.getRegion();
	BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
	panel->childSetValue("fixed_sun_check", LLSD((BOOL)(region_flags & REGION_FLAGS_SUN_FIXED)));
	panel->childSetEnabled("fixed_sun_check", allow_modify && !use_estate_sun);
	panel->childSetValue("sun_hour_slider", LLSD(sun_hour));
	panel->childSetEnabled("sun_hour_slider", allow_modify && !use_estate_sun);
}

// static
LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate()
{
	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
	if (!floater) return NULL;
	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
	if (!tab) return NULL;
	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab,"Estate");
	return panel;
}

// static
LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant()
{
	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
	if (!floater) return NULL;
	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
	if (!tab) return NULL;
	LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)LLUICtrlFactory::getPanelByName(tab, "Covenant");
	return panel;
}

void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region)
{
	// call refresh from region on all panels
	std::for_each(
		mInfoPanels.begin(),
		mInfoPanels.end(),
		llbind2nd(
#if LL_WINDOWS
			std::mem_fun1(&LLPanelRegionInfo::refreshFromRegion),
#else
			std::mem_fun(&LLPanelRegionInfo::refreshFromRegion),
#endif
			region));
}



///----------------------------------------------------------------------------
/// Local class implementation
///----------------------------------------------------------------------------

//
// LLPanelRegionInfo
//

// static
void LLPanelRegionInfo::onBtnSet(void* user_data)
{
	LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data;
	if(!panel) return;
	if (panel->sendUpdate())
	{
		panel->disableButton("apply_btn");
	}
}

//static 
void LLPanelRegionInfo::onChangeChildCtrl(LLUICtrl* ctrl, void* user_data)
{
	if (ctrl)
	{
		LLPanelRegionInfo* panel = (LLPanelRegionInfo*) ctrl->getParent();
		panel->updateChild(ctrl);
	}
}

// static
// Enables the "set" button if it is not already enabled
void LLPanelRegionInfo::onChangeAnything(LLUICtrl* ctrl, void* user_data)
{
	LLPanelRegionInfo* panel = (LLPanelRegionInfo*)user_data;
	if(panel)
	{
		panel->enableButton("apply_btn");
	}
}

// virtual
BOOL LLPanelRegionInfo::postBuild()
{
	childSetAction("apply_btn", onBtnSet, this);
	childDisable("apply_btn");
	return TRUE;
}

// virtual 
void LLPanelRegionInfo::updateChild(LLUICtrl* child_ctr)
{
}

// virtual
bool LLPanelRegionInfo::refreshFromRegion(LLViewerRegion* region)
{
	if (region) mHost = region->getHost();
	return true;
}

void LLPanelRegionInfo::sendEstateOwnerMessage(
	LLMessageSystem* msg,
	const char* request,
	const LLUUID& invoice,
	const strings_t& strings)
{
	llinfos << "Sending estate request '" << request << "'" << llendl;
	msg->newMessage("EstateOwnerMessage");
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	msg->nextBlock("MethodData");
	msg->addString("Method", request);
	msg->addUUID("Invoice", invoice);
	if(strings.empty())
	{
		msg->nextBlock("ParamList");
		msg->addString("Parameter", NULL);
	}
	else
	{
		strings_t::const_iterator it = strings.begin();
		strings_t::const_iterator end = strings.end();
		for(; it != end; ++it)
		{
			msg->nextBlock("ParamList");
			msg->addString("Parameter", (*it).c_str());
		}
	}
	msg->sendReliable(mHost);
}

void LLPanelRegionInfo::enableButton(const char* btn_name, BOOL enable)
{
	childSetEnabled(btn_name, enable);
}

void LLPanelRegionInfo::disableButton(const char* btn_name)
{
	childDisable(btn_name);
}

void LLPanelRegionInfo::initCtrl(const char* name)
{
	childSetCommitCallback(name, onChangeAnything, this);
}

void LLPanelRegionInfo::initHelpBtn(const char* name, const char* xml_alert)
{
	childSetAction(name, onClickHelp, (void*)xml_alert);
}

// static
void LLPanelRegionInfo::onClickHelp(void* data)
{
	const char* xml_alert = (const char*)data;
	gViewerWindow->alertXml(xml_alert);
}

/////////////////////////////////////////////////////////////////////////////
// LLPanelRegionGeneralInfo
//
bool LLPanelRegionGeneralInfo::refreshFromRegion(LLViewerRegion* region)
{
	BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
	setCtrlsEnabled(allow_modify);
	childDisable("apply_btn");
	childSetEnabled("access_text", allow_modify);
	childSetEnabled("access_combo", allow_modify);
	childSetEnabled("kick_btn", allow_modify);
	childSetEnabled("kick_all_btn", allow_modify);
	childSetEnabled("im_btn", allow_modify);
	childSetEnabled("manage_telehub_btn", allow_modify);

	// Data gets filled in by processRegionInfo

	return LLPanelRegionInfo::refreshFromRegion(region);
}

BOOL LLPanelRegionGeneralInfo::postBuild()
{
	// Enable the "Apply" button if something is changed. JC
	initCtrl("block_terraform_check");
	initCtrl("block_fly_check");
	initCtrl("allow_damage_check");
    initCtrl("allow_land_resell_check");
	initCtrl("allow_parcel_changes_check");
	initCtrl("agent_limit_spin");
	initCtrl("object_bonus_spin");
	initCtrl("access_combo");
	initCtrl("restrict_pushobject");

	initHelpBtn("terraform_help",		"HelpRegionBlockTerraform");
	initHelpBtn("fly_help",				"HelpRegionBlockFly");
	initHelpBtn("damage_help",			"HelpRegionAllowDamage");
	initHelpBtn("agent_limit_help",		"HelpRegionAgentLimit");
	initHelpBtn("object_bonus_help",	"HelpRegionObjectBonus");
	initHelpBtn("access_help",			"HelpRegionMaturity");
	initHelpBtn("restrict_pushobject_help",		"HelpRegionRestrictPushObject");
	initHelpBtn("land_resell_help",	"HelpRegionLandResell");
	initHelpBtn("parcel_changes_help", "HelpParcelChanges");

	childSetAction("kick_btn", onClickKick, this);
	childSetAction("kick_all_btn", onClickKickAll, this);
	childSetAction("im_btn", onClickMessage, this);
	childSetAction("manage_telehub_btn", onClickManageTelehub, this);

	return LLPanelRegionInfo::postBuild();
}

// static
void LLPanelRegionGeneralInfo::onClickKick(void* userdata)
{
	llinfos << "LLPanelRegionGeneralInfo::onClickKick" << llendl;
	LLPanelRegionGeneralInfo* panelp = (LLPanelRegionGeneralInfo*)userdata;

	// this depends on the grandparent view being a floater
	// in order to set up floater dependency
	LLFloater* parent_floater = gFloaterView->getParentFloater(panelp);
	LLFloater* child_floater = LLFloaterAvatarPicker::show(onKickCommit, userdata, FALSE, TRUE);
	parent_floater->addDependentFloater(child_floater);
}

// static
void LLPanelRegionGeneralInfo::onKickCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata)
{
	if (names.empty() || ids.empty()) return;
	if(ids[0].notNull())
	{
		LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata;
		if(!self) return;
		strings_t strings;
		// [0] = our agent id
		// [1] = target agent id
		char buffer[MAX_STRING];
		gAgent.getID().toString(buffer);
		strings.push_back(buffer);

		ids[0].toString(buffer);
		strings.push_back(strings_t::value_type(buffer));

		LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
		self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", invoice, strings);
	}
}

// static
void LLPanelRegionGeneralInfo::onClickKickAll(void* userdata)
{
	llinfos << "LLPanelRegionGeneralInfo::onClickKickAll" << llendl;
	gViewerWindow->alertXml("KickUsersFromRegion", onKickAllCommit, userdata);
}

// static
void LLPanelRegionGeneralInfo::onKickAllCommit(S32 option, void* userdata)
{
	if (option == 0)
	{
		LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata;
		if(!self) return;
		strings_t strings;
		// [0] = our agent id
		char buffer[MAX_STRING];
		gAgent.getID().toString(buffer);
		strings.push_back(buffer);

		LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
		// historical message name
		self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeallusers", invoice, strings);
	}
}

// static
void LLPanelRegionGeneralInfo::onClickMessage(void* userdata)
{
	llinfos << "LLPanelRegionGeneralInfo::onClickMessage" << llendl;
	gViewerWindow->alertXmlEditText("MessageRegion", LLString::format_map_t(),
									NULL, NULL,
									onMessageCommit, userdata);
}

// static
void LLPanelRegionGeneralInfo::onMessageCommit(S32 option, const LLString& text, void* userdata)
{
	if(option != 0) return;
	if(text.empty()) return;
	LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata;
	if(!self) return;
	llinfos << "Message to everyone: " << text << llendl;
	strings_t strings;
	// [0] grid_x, unused here
	// [1] grid_y, unused here
	// [2] agent_id of sender
	// [3] sender name
	// [4] message
	strings.push_back("-1");
	strings.push_back("-1");
	char buffer[MAX_STRING];
	gAgent.getID().toString(buffer);
	strings.push_back(buffer);
	std::string name;
	gAgent.buildFullname(name);
	strings.push_back(strings_t::value_type(name));
	strings.push_back(strings_t::value_type(text));
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "simulatormessage", invoice, strings);
}

// static
void LLPanelRegionGeneralInfo::onClickManageTelehub(void* data)
{
	LLFloaterRegionInfo::getInstance()->close();

	LLFloaterTelehub::show();
}

// setregioninfo
// strings[0] = 'Y' - block terraform, 'N' - not
// strings[1] = 'Y' - block fly, 'N' - not
// strings[2] = 'Y' - allow damage, 'N' - not
// strings[3] = 'Y' - allow land sale, 'N' - not
// strings[4] = agent limit
// strings[5] = object bonus
// strings[6] = sim access (0 = unknown, 13 = PG, 21 = Mature)
// strings[7] = restrict pushobject
// strings[8] = 'Y' - allow parcel subdivide, 'N' - not
BOOL LLPanelRegionGeneralInfo::sendUpdate()
{
	llinfos << "LLPanelRegionGeneralInfo::sendUpdate()" << llendl;
	strings_t strings;
	//integers_t integers;
	char buffer[MAX_STRING];
	sprintf(buffer, "%s", (childGetValue("block_terraform_check").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));
	
	sprintf(buffer, "%s", (childGetValue("block_fly_check").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));

	sprintf(buffer, "%s", (childGetValue("allow_damage_check").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));

	sprintf(buffer, "%s", (childGetValue("allow_land_resell_check").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));

	F32 value = (F32)childGetValue("agent_limit_spin").asReal();
	sprintf(buffer, "%f", value);
	strings.push_back(strings_t::value_type(buffer));

	value = (F32)childGetValue("object_bonus_spin").asReal();
	sprintf(buffer, "%f", value);
	strings.push_back(strings_t::value_type(buffer));

	U8 access = LLViewerRegion::stringToAccess(childGetValue("access_combo").asString().c_str());
	sprintf(buffer, "%d", (S32)access);
	strings.push_back(strings_t::value_type(buffer));

	sprintf(buffer, "%s", (childGetValue("restrict_pushobject").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));

	sprintf(buffer, "%s", (childGetValue("allow_parcel_changes_check").asBoolean() ? "Y" : "N"));
	strings.push_back(strings_t::value_type(buffer));

	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	sendEstateOwnerMessage(gMessageSystem, "setregioninfo", invoice, strings);

	LLViewerRegion* region = gAgent.getRegion();
	if (region
		&& access != region->getSimAccess() )
	{
		gViewerWindow->alertXml("RegionMaturityChange");
	}

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// LLPanelRegionDebugInfo
/////////////////////////////////////////////////////////////////////////////
BOOL LLPanelRegionDebugInfo::postBuild()
{
	LLPanelRegionInfo::postBuild();
	initCtrl("disable_scripts_check");
	initCtrl("disable_collisions_check");
	initCtrl("disable_physics_check");

	initHelpBtn("disable_scripts_help",		"HelpRegionDisableScripts");
	initHelpBtn("disable_collisions_help",	"HelpRegionDisableCollisions");
	initHelpBtn("disable_physics_help",		"HelpRegionDisablePhysics");
	initHelpBtn("top_colliders_help",		"HelpRegionTopColliders");
	initHelpBtn("top_scripts_help",			"HelpRegionTopScripts");
	initHelpBtn("restart_help",				"HelpRegionRestart");

	childSetAction("choose_avatar_btn", onClickChooseAvatar, this);
	childSetAction("return_scripted_other_land_btn", onClickReturnScriptedOtherLand, this);
	childSetAction("return_scripted_all_btn", onClickReturnScriptedAll, this);
	childSetAction("top_colliders_btn", onClickTopColliders, this);
	childSetAction("top_scripts_btn", onClickTopScripts, this);
	childSetAction("restart_btn", onClickRestart, this);
	childSetAction("cancel_restart_btn", onClickCancelRestart, this);

	return TRUE;
}

// virtual
bool LLPanelRegionDebugInfo::refreshFromRegion(LLViewerRegion* region)
{
	BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
	setCtrlsEnabled(allow_modify);
	childDisable("apply_btn");

	childSetEnabled("choose_avatar_btn", allow_modify);
	childSetEnabled("return_scripted_other_land_btn", allow_modify && !mTargetAvatar.isNull());
	childSetEnabled("return_scripted_all_btn", allow_modify && !mTargetAvatar.isNull());
	childSetEnabled("top_colliders_btn", allow_modify);
	childSetEnabled("top_scripts_btn", allow_modify);
	childSetEnabled("restart_btn", allow_modify);
	childSetEnabled("cancel_restart_btn", allow_modify);

	return LLPanelRegionInfo::refreshFromRegion(region);
}

// virtual
BOOL LLPanelRegionDebugInfo::sendUpdate()
{
	llinfos << "LLPanelRegionDebugInfo::sendUpdate" << llendl;
	strings_t strings;
	char buffer[MAX_STRING];

	sprintf(buffer, "%s", (childGetValue("disable_scripts_check").asBoolean() ? "Y" : "N"));
	strings.push_back(buffer);

	sprintf(buffer, "%s", (childGetValue("disable_collisions_check").asBoolean() ? "Y" : "N"));
	strings.push_back(buffer);

	sprintf(buffer, "%s", (childGetValue("disable_physics_check").asBoolean() ? "Y" : "N"));
	strings.push_back(buffer);

	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	sendEstateOwnerMessage(gMessageSystem, "setregiondebug", invoice, strings);
	return TRUE;
}

void LLPanelRegionDebugInfo::onClickChooseAvatar(void* data)
{
	LLFloaterAvatarPicker::show(callbackAvatarID, data, FALSE, TRUE);
}

// static
void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data)
{
	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) data;
	if (ids.empty() || names.empty()) return;
	self->mTargetAvatar = ids[0];
	self->childSetValue("target_avatar_name", LLSD(names[0]));
	self->refreshFromRegion( gAgent.getRegion() );
}

// static
void LLPanelRegionDebugInfo::onClickReturnScriptedOtherLand(void* data)
{
	LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data;
	if (panelp->mTargetAvatar.isNull()) return;

	LLString::format_map_t args;
	args["[USER_NAME]"] = panelp->childGetValue("target_avatar_name").asString();
	gViewerWindow->alertXml("ReturnScriptedOnOthersLand", args, callbackReturnScriptedOtherLand, data);
}

// static
void LLPanelRegionDebugInfo::callbackReturnScriptedOtherLand( S32 option, void* userdata )
{
	if (option != 0) return;

	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) userdata;
	if (!self->mTargetAvatar.isNull())
	{
		U32 flags = 0;
		flags = flags | SWD_OTHERS_LAND_ONLY;
		flags = flags | SWD_ALWAYS_RETURN_OBJECTS;
		flags |= SWD_SCRIPTED_ONLY;

		send_sim_wide_deletes(self->mTargetAvatar, flags);
	}
}

// static
void LLPanelRegionDebugInfo::onClickReturnScriptedAll(void* data)
{
	LLPanelRegionDebugInfo* panelp = (LLPanelRegionDebugInfo*) data;
	if (panelp->mTargetAvatar.isNull()) return;
	
	
	LLString::format_map_t args;
	args["[USER_NAME]"] = panelp->childGetValue("target_avatar_name").asString();
	gViewerWindow->alertXml("ReturnScriptedOnAllLand", args, callbackReturnScriptedAll, data);
}

// static
void LLPanelRegionDebugInfo::callbackReturnScriptedAll( S32 option, void* userdata )
{
	if (option != 0) return;

	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) userdata;
	if (!self->mTargetAvatar.isNull())
	{
		U32 flags = 0;
		flags |= SWD_ALWAYS_RETURN_OBJECTS;
		flags |= SWD_SCRIPTED_ONLY;

		send_sim_wide_deletes(self->mTargetAvatar, flags);
	}
}

// static
void LLPanelRegionDebugInfo::onClickTopColliders(void* data)
{
	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data;
	strings_t strings;
	strings.push_back("1");	// one physics step
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "colliders", invoice, strings);
}

// static
void LLPanelRegionDebugInfo::onClickTopScripts(void* data)
{
	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data;
	strings_t strings;
	strings.push_back("6");	// top 5 scripts
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "scripts", invoice, strings);
}

// static
void LLPanelRegionDebugInfo::onClickRestart(void* data)
{
	gViewerWindow->alertXml("ConfirmRestart", callbackRestart, data);
}

// static
void LLPanelRegionDebugInfo::callbackRestart(S32 option, void* data)
{
	if (option != 0) return;

	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data;
	strings_t strings;
	strings.push_back("120");
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings);
}

// static
void LLPanelRegionDebugInfo::onClickCancelRestart(void* data)
{
	LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*)data;
	strings_t strings;
	strings.push_back("-1");
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "restart", invoice, strings);
}


/////////////////////////////////////////////////////////////////////////////
// LLPanelRegionTextureInfo
//
LLPanelRegionTextureInfo::LLPanelRegionTextureInfo() : LLPanelRegionInfo()
{
	// nothing.
}

bool LLPanelRegionTextureInfo::refreshFromRegion(LLViewerRegion* region)
{
	BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate());
	setCtrlsEnabled(allow_modify);
	childDisable("apply_btn");

	if (region)
	{
		childSetValue("region_text", LLSD(region->getName()));
	}
	else
	{
		childSetValue("region_text", LLSD(""));
	}

	if (!region) return LLPanelRegionInfo::refreshFromRegion(region);

	LLVLComposition* compp = region->getComposition();
	LLTextureCtrl* texture_ctrl;
	char buffer[MAX_STRING];
	for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
	{
		sprintf(buffer, "texture_detail_%d", i);
		texture_ctrl = LLViewerUICtrlFactory::getTexturePickerByName(this, buffer);
		if(texture_ctrl)
		{
			lldebugs << "Detail Texture " << i << ": "
					 << compp->getDetailTextureID(i) << llendl;
			LLUUID tmp_id(compp->getDetailTextureID(i));
			texture_ctrl->setImageAssetID(tmp_id);
		}
	}

	for(S32 i = 0; i < CORNER_COUNT; ++i)
    {
		sprintf(buffer, "height_start_spin_%d", i);
		childSetValue(buffer, LLSD(compp->getStartHeight(i)));
		sprintf(buffer, "height_range_spin_%d", i);
		childSetValue(buffer, LLSD(compp->getHeightRange(i)));
	}

	// Call the parent for common book-keeping
	return LLPanelRegionInfo::refreshFromRegion(region);
}


BOOL LLPanelRegionTextureInfo::postBuild()
{
	LLPanelRegionInfo::postBuild();
	char buffer[MAX_STRING];
	for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
	{
		sprintf(buffer, "texture_detail_%d", i);
		initCtrl(buffer);
	}

	for(S32 i = 0; i < CORNER_COUNT; ++i)
	{
		sprintf(buffer, "height_start_spin_%d", i);
		initCtrl(buffer);
		sprintf(buffer, "height_range_spin_%d", i);
		initCtrl(buffer);
	}

//	LLButton* btn = new LLButton("dump", LLRect(0, 20, 100, 0), "", onClickDump, this);
//	btn->setFollows(FOLLOWS_TOP|FOLLOWS_LEFT);
//	addChild(btn);

	return LLPanelRegionInfo::postBuild();
}

void LLPanelRegionTextureInfo::draw()
{
	if(getVisible())
	{
		LLPanel::draw();
	}
}

BOOL LLPanelRegionTextureInfo::sendUpdate()
{
	llinfos << "LLPanelRegionTextureInfo::sendUpdate()" << llendl;

	// Make sure user hasn't chosen wacky textures.
	if (!validateTextureSizes())
	{
		return FALSE;
	}

	LLTextureCtrl* texture_ctrl;
	char buffer[MAX_STRING];
	char buffer2[MAX_STRING];
	char id_str[UUID_STR_LENGTH];
	LLMessageSystem* msg = gMessageSystem;
	strings_t strings;

	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	
	for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
	{
		sprintf(buffer, "texture_detail_%d", i);
		texture_ctrl = LLViewerUICtrlFactory::getTexturePickerByName(this, buffer);
		if(texture_ctrl)
		{
			LLUUID tmp_id(texture_ctrl->getImageAssetID());
			tmp_id.toString(id_str);
			sprintf(buffer, "%d %s", i, id_str);
			strings.push_back(strings_t::value_type(buffer));
		}
	}
	sendEstateOwnerMessage(msg, "texturedetail", invoice, strings);
	strings.clear();
	for(S32 i = 0; i < CORNER_COUNT; ++i)
	{
		sprintf(buffer, "height_start_spin_%d", i);
		sprintf(buffer2, "height_range_spin_%d", i);
		sprintf(buffer, "%d %f %f", i, (F32)childGetValue(buffer).asReal(), (F32)childGetValue(buffer2).asReal());
		strings.push_back(strings_t::value_type(buffer));
	}
	sendEstateOwnerMessage(msg, "textureheights", invoice, strings);
	strings.clear();
	sendEstateOwnerMessage(msg, "texturecommit", invoice, strings);
	return TRUE;
}

BOOL LLPanelRegionTextureInfo::validateTextureSizes()
{
	for(S32 i = 0; i < TERRAIN_TEXTURE_COUNT; ++i)
	{
		char buffer[MAX_STRING];
		sprintf(buffer, "texture_detail_%d", i);
		LLTextureCtrl* texture_ctrl = LLViewerUICtrlFactory::getTexturePickerByName(this, buffer);
		if (!texture_ctrl) continue;

		LLUUID image_asset_id = texture_ctrl->getImageAssetID();
		LLViewerImage* img = gImageList.getImage(image_asset_id);
		S32 components = img->getComponents();
		// Must ask for highest resolution version's width. JC
		S32 width = img->getWidth(0);
		S32 height = img->getHeight(0);

		//llinfos << "texture detail " << i << " is " << width << "x" << height << "x" << components << llendl;

		if (components != 3)
		{
			LLString::format_map_t args;
			args["[TEXTURE_NUM]"] = llformat("%d",i+1);
			args["[TEXTURE_BIT_DEPTH]"] = llformat("%d",components * 8);
			gViewerWindow->alertXml("InvalidTerrainBitDepth", args);
			return FALSE;
		}

		if (width > 512 || height > 512)
		{

			LLString::format_map_t args;
			args["[TEXTURE_NUM]"] = i+1;
			args["[TEXTURE_SIZE_X]"] = llformat("%d",width);
			args["[TEXTURE_SIZE_Y]"] = llformat("%d",height);
			gViewerWindow->alertXml("InvalidTerrainSize", args);
			return FALSE;
			
		}
	}

	return TRUE;
}


// static
void LLPanelRegionTextureInfo::onClickDump(void* data)
{
	llinfos << "LLPanelRegionTextureInfo::onClickDump()" << llendl;
}


/////////////////////////////////////////////////////////////////////////////
// LLPanelRegionTerrainInfo
/////////////////////////////////////////////////////////////////////////////
BOOL LLPanelRegionTerrainInfo::postBuild()
{
	LLPanelRegionInfo::postBuild();

	initHelpBtn("water_height_help",	"HelpRegionWaterHeight");
	initHelpBtn("terrain_raise_help",	"HelpRegionTerrainRaise");
	initHelpBtn("terrain_lower_help",	"HelpRegionTerrainLower");
	initHelpBtn("upload_raw_help",		"HelpRegionUploadRaw");
	initHelpBtn("download_raw_help",	"HelpRegionDownloadRaw");
	initHelpBtn("use_estate_sun_help",	"HelpRegionUseEstateSun");
	initHelpBtn("fixed_sun_help",		"HelpRegionFixedSun");
	initHelpBtn("bake_terrain_help",	"HelpRegionBakeTerrain");

	initCtrl("water_height_spin");
	initCtrl("terrain_raise_spin");
	initCtrl("terrain_lower_spin");

	initCtrl("fixed_sun_check");
	childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this);
	childSetCommitCallback("use_estate_sun_check", onChangeUseEstateTime, this);
	childSetCommitCallback("sun_hour_slider", onChangeSunHour, this);

	childSetAction("download_raw_btn", onClickDownloadRaw, this);
	childSetAction("upload_raw_btn", onClickUploadRaw, this);
	childSetAction("bake_terrain_btn", onClickBakeTerrain, this);

	return TRUE;
}

// virtual
bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
{
	llinfos << "LLPanelRegionTerrainInfo::refreshFromRegion" << llendl;

	BOOL owner_or_god = gAgent.isGodlike() 
						|| (region && (region->getOwner() == gAgent.getID()));
	BOOL owner_or_god_or_manager = owner_or_god
						|| (region && region->isEstateManager());
	setCtrlsEnabled(owner_or_god_or_manager);
	childDisable("apply_btn");

	childSetEnabled("download_raw_btn", owner_or_god);
	childSetEnabled("upload_raw_btn", owner_or_god);
	childSetEnabled("bake_terrain_btn", owner_or_god);

	return LLPanelRegionInfo::refreshFromRegion(region);
}

// virtual
BOOL LLPanelRegionTerrainInfo::sendUpdate()
{
	llinfos << "LLPanelRegionTerrainInfo::sendUpdate" << llendl;
	char buffer[MAX_STRING];
	strings_t strings;
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());

	sprintf(buffer, "%f", (F32)childGetValue("water_height_spin").asReal());
	strings.push_back(buffer);
	sprintf(buffer, "%f", (F32)childGetValue("terrain_raise_spin").asReal());
	strings.push_back(buffer);
	sprintf(buffer, "%f", (F32)childGetValue("terrain_lower_spin").asReal());
	strings.push_back(buffer);
	sprintf(buffer, "%s", (childGetValue("use_estate_sun_check").asBoolean() ? "Y" : "N"));
	strings.push_back(buffer);
	sprintf(buffer, "%s", (childGetValue("fixed_sun_check").asBoolean() ? "Y" : "N"));
	strings.push_back(buffer);
	sprintf(buffer, "%f", (F32)childGetValue("sun_hour_slider").asReal() );
	strings.push_back(buffer);

	// Grab estate information in case the user decided to set the
	// region back to estate time. JC
	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
	if (!floater) return true;

	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(floater, "tab");
	if (!tab) return true;

	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)LLUICtrlFactory::getPanelByName(tab, "Estate");
	if (!panel) return true;

	BOOL estate_global_time = panel->getGlobalTime();
	BOOL estate_fixed_sun = panel->getFixedSun();
	F32 estate_sun_hour;
	if (estate_global_time)
	{
		estate_sun_hour = 0.f;
	}
	else
	{
		estate_sun_hour = panel->getSunHour();
	}

	sprintf(buffer, "%s", (estate_global_time ? "Y" : "N") );
	strings.push_back(buffer);
	sprintf(buffer, "%s", (estate_fixed_sun ? "Y" : "N") );
	strings.push_back(buffer);
	sprintf(buffer, "%f", estate_sun_hour);
	strings.push_back(buffer);

	sendEstateOwnerMessage(gMessageSystem, "setregionterrain", invoice, strings);
	return TRUE;
}

// static 
void LLPanelRegionTerrainInfo::onChangeUseEstateTime(LLUICtrl* ctrl, void* user_data)
{
	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data;
	if (!panel) return;
	BOOL use_estate_sun = panel->childGetValue("use_estate_sun_check").asBoolean();
	panel->childSetEnabled("fixed_sun_check", !use_estate_sun);
	panel->childSetEnabled("sun_hour_slider", !use_estate_sun);
	if (use_estate_sun)
	{
		panel->childSetValue("fixed_sun_check", LLSD(FALSE));
		panel->childSetValue("sun_hour_slider", LLSD(0.f));
	}
	panel->childEnable("apply_btn");
}

// static 
void LLPanelRegionTerrainInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data)
{
	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) user_data;
	if (!panel) return;
	// Just enable the apply button.  We let the sun-hour slider be enabled
	// for both fixed-sun and non-fixed-sun. JC
	panel->childEnable("apply_btn");
}

// static 
void LLPanelRegionTerrainInfo::onChangeSunHour(LLUICtrl* ctrl, void*)
{
	// can't use userdata to get panel, slider uses it internally
	LLPanelRegionTerrainInfo* panel = (LLPanelRegionTerrainInfo*) ctrl->getParent();
	if (!panel) return;
	panel->childEnable("apply_btn");
}

// static
void LLPanelRegionTerrainInfo::onClickDownloadRaw(void* data)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if (!picker.getSaveFile(LLFilePicker::FFSAVE_RAW, "terrain.raw"))
	{
		llwarns << "No file" << llendl;
		return;
	}
	LLString filepath = picker.getFirstFile();

	LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data;
	strings_t strings;
	strings.push_back("download filename");
	strings.push_back(filepath);
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings);
}

// static
void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data)
{
	LLFilePicker& picker = LLFilePicker::instance();
	if (!picker.getOpenFile(LLFilePicker::FFLOAD_RAW))
	{
		llwarns << "No file" << llendl;
		return;
	}
	LLString filepath = picker.getFirstFile();

	LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data;
	strings_t strings;
	strings.push_back("upload filename");
	strings.push_back(filepath);
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings);

	gViewerWindow->alertXml("RawUploadStarted");
}

// static
void LLPanelRegionTerrainInfo::onClickBakeTerrain(void* data)
{
	gViewerWindow->alertXml("ConfirmBakeTerrain", 
							 callbackBakeTerrain, data);
}

// static
void LLPanelRegionTerrainInfo::callbackBakeTerrain(S32 option, void* data)
{
	if (option != 0) return;

	LLPanelRegionTerrainInfo* self = (LLPanelRegionTerrainInfo*)data;
	strings_t strings;
	strings.push_back("bake");
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "terrain", invoice, strings);
}

/////////////////////////////////////////////////////////////////////////////
// LLPanelEstateInfo
//

LLPanelEstateInfo::LLPanelEstateInfo() 
:	LLPanelRegionInfo(),
	mEstateID(0)	// invalid
{
}

// static
void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch)
{
	std::string name;

//	name.assign("setowner");
//	static LLDispatchSetEstateOwner set_owner;
//	dispatch.addHandler(name, &set_owner);

	name.assign("estateupdateinfo");
	static LLDispatchEstateUpdateInfo estate_update_info;
	dispatch.addHandler(name, &estate_update_info);

	name.assign("setaccess");
	static LLDispatchSetEstateAccess set_access;
	dispatch.addHandler(name, &set_access);

	estate_dispatch_initialized = true;
}

// static
// Disables the sun-hour slider and the use fixed time check if the use global time is check
void LLPanelEstateInfo::onChangeUseGlobalTime(LLUICtrl* ctrl, void* user_data)
{
	LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data;
	if (panel)
	{
		bool enabled = !panel->childGetValue("use_global_time_check").asBoolean();
		panel->childSetEnabled("sun_hour_slider", enabled);
		panel->childSetEnabled("fixed_sun_check", enabled);
		panel->childSetValue("fixed_sun_check", LLSD(FALSE));
		panel->enableButton("apply_btn");
	}
}

// Enables the sun-hour slider if the fixed-sun checkbox is set
void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data)
{
	LLPanelEstateInfo* panel = (LLPanelEstateInfo*) user_data;
	if (panel)
	{
		bool enabled = !panel->childGetValue("fixed_sun_check").asBoolean();
		panel->childSetEnabled("use_global_time_check", enabled);
		panel->childSetValue("use_global_time_check", LLSD(FALSE));
		panel->enableButton("apply_btn");
	}
}

//---------------------------------------------------------------------------
// Add/Remove estate access button callbacks
//---------------------------------------------------------------------------

// static
void LLPanelEstateInfo::onClickAddAllowedAgent(void* user_data)
{
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data;
	LLCtrlListInterface *list = self->childGetListInterface("allowed_avatar_name_list");
	if (!list) return;
	if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS)
	{
		//args

		LLString::format_map_t args;
		args["[MAX_AGENTS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
		gViewerWindow->alertXml("MaxAllowedAgentOnRegion", args);
		return;
	}
	accessAddCore(ESTATE_ACCESS_ALLOWED_AGENT_ADD, "EstateAllowedAgentAdd");
}

// static
void LLPanelEstateInfo::onClickRemoveAllowedAgent(void* user_data)
{
	accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list");
}

// static
void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data)
{
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data;
	LLCtrlListInterface *list = self->childGetListInterface("allowed_group_name_list");
	if (!list) return;
	if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS)
	{
		LLString::format_map_t args;
		args["[MAX_GROUPS]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
		gViewerWindow->alertXml("MaxAllowedGroupsOnRegion", args);
		return;
	}
	if (isLindenEstate())
	{
		gViewerWindow->alertXml("ChangeLindenAccess", addAllowedGroup, user_data);
	}
	else
	{
		addAllowedGroup(0, user_data);
	}
}

// static
void LLPanelEstateInfo::addAllowedGroup(S32 option, void* user_data)
{
	if (option != 0) return;

	LLFloaterGroups* widget;
	widget = LLFloaterGroups::show(gAgent.getID(), LLFloaterGroups::CHOOSE_ONE);
	if (widget)
	{
		widget->setOkCallback(addAllowedGroup2, user_data);
	}
}

// static
void LLPanelEstateInfo::onClickRemoveAllowedGroup(void* user_data)
{
	accessRemoveCore(ESTATE_ACCESS_ALLOWED_GROUP_REMOVE, "EstateAllowedGroupRemove", "allowed_group_name_list");
}

// static
void LLPanelEstateInfo::onClickAddBannedAgent(void* user_data)
{
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data;
	LLCtrlListInterface *list = self->childGetListInterface("banned_avatar_name_list");
	if (!list) return;
	if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS)
	{
		LLString::format_map_t args;
		args["[MAX_BANNED]"] = llformat("%d",ESTATE_MAX_ACCESS_IDS);
		gViewerWindow->alertXml("MaxBannedAgentsOnRegion", args);
		return;
	}
	accessAddCore(ESTATE_ACCESS_BANNED_AGENT_ADD, "EstateBannedAgentAdd");
}

// static
void LLPanelEstateInfo::onClickRemoveBannedAgent(void* user_data)
{
	accessRemoveCore(ESTATE_ACCESS_BANNED_AGENT_REMOVE, "EstateBannedAgentRemove", "banned_avatar_name_list");
}

// static
void LLPanelEstateInfo::onClickAddEstateManager(void* user_data)
{
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data;
	LLCtrlListInterface *list = self->childGetListInterface("estate_manager_name_list");
	if (!list) return;
	if (list->getItemCount() >= ESTATE_MAX_MANAGERS)
	{
		LLString::format_map_t args;
		args["[MAX_MANAGER]"] = llformat("%d",ESTATE_MAX_MANAGERS);
		gViewerWindow->alertXml("MaxManagersOnRegion", args);
		return;
	}
	accessAddCore(ESTATE_ACCESS_MANAGER_ADD, "EstateManagerAdd");
}

// static
void LLPanelEstateInfo::onClickRemoveEstateManager(void* user_data)
{
	accessRemoveCore(ESTATE_ACCESS_MANAGER_REMOVE, "EstateManagerRemove", "estate_manager_name_list");
}

//---------------------------------------------------------------------------
// Kick from estate methods
//---------------------------------------------------------------------------
struct LLKickFromEstateInfo
{
	LLPanelEstateInfo *mEstatePanelp;
	LLString    mDialogName;
	LLUUID      mAgentID;
};

void LLPanelEstateInfo::onClickKickUser(void *user_data)
{
	LLPanelEstateInfo* panelp = (LLPanelEstateInfo*)user_data;

	// this depends on the grandparent view being a floater
	// in order to set up floater dependency
	LLFloater* parent_floater = gFloaterView->getParentFloater(panelp);
	LLFloater* child_floater = LLFloaterAvatarPicker::show(LLPanelEstateInfo::onKickUserCommit, user_data, FALSE, TRUE);
	parent_floater->addDependentFloater(child_floater);
}

void LLPanelEstateInfo::onKickUserCommit(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata)
{
	if (names.empty() || ids.empty()) return;
	
	//check to make sure there is one valid user and id
	if( (ids[0].isNull()) ||
		(names[0].length() == 0) )
	{
		return;
	}

	LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata;
	if(!self) return;

	//keep track of what user they want to kick and other misc info
	LLKickFromEstateInfo *kick_info = new LLKickFromEstateInfo();
	kick_info->mEstatePanelp = self;
	kick_info->mDialogName  = "EstateKickUser";
	kick_info->mAgentID     = ids[0];

	//Bring up a confirmation dialog
	LLString::format_map_t args;
	args["[EVIL_USER]"] = names[0];
	gViewerWindow->alertXml(kick_info->mDialogName, args, LLPanelEstateInfo::kickUserConfirm, (void*)kick_info);

}

void LLPanelEstateInfo::kickUserConfirm(S32 option, void* userdata)
{
	//extract the callback parameter
	LLKickFromEstateInfo *kick_info = (LLKickFromEstateInfo*) userdata;
	if (!kick_info) return;

	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	strings_t strings;
	char buffer[MAX_STRING];

	switch(option)
	{
	case 0:
		//Kick User
		kick_info->mAgentID.toString(buffer);
		strings.push_back(strings_t::value_type(buffer));

		kick_info->mEstatePanelp->sendEstateOwnerMessage(gMessageSystem, "kickestate", invoice, strings);
		break;
	default:
		break;
	}

	delete kick_info;
	kick_info = NULL;
}

//---------------------------------------------------------------------------
// Core Add/Remove estate access methods
//---------------------------------------------------------------------------
std::string all_estates_text()
{
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return "(error)";

	std::string owner = panel->getOwnerName();

	LLViewerRegion* region = gAgent.getRegion();
	if (gAgent.isGodlike())
	{
		return llformat("all estates\nowned by %s", owner.c_str());
	}
	else if (region && region->getOwner() == gAgent.getID())
	{
		return "all estates you own";
	}
	else if (region && region->isEstateManager())
	{
		return llformat("all estates that\nyou manage for %s", owner.c_str());
	}
	else
	{
		return "(error)";
	}
}

// static
bool LLPanelEstateInfo::isLindenEstate()
{
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return false;

	U32 estate_id = panel->getEstateID();
	return (estate_id <= ESTATE_LAST_LINDEN);
}

struct LLEstateAccessChangeInfo
{
	U32 mOperationFlag;	// ESTATE_ACCESS_BANNED_AGENT_ADD, _REMOVE, etc.
	LLString mDialogName;
	LLUUID mAgentOrGroupID;
};

// Special case callback for groups, since it has different callback format than names
// static
void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data)
{
	LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo;
	change_info->mOperationFlag = ESTATE_ACCESS_ALLOWED_GROUP_ADD;
	change_info->mDialogName = "EstateAllowedGroupAdd";
	change_info->mAgentOrGroupID = id;

	if (isLindenEstate())
	{
		accessCoreConfirm(0, (void*)change_info);
	}
	else
	{
		LLString::format_map_t args;
		args["[ALL_ESTATES]"] = all_estates_text();
		gViewerWindow->alertXml(change_info->mDialogName, args, accessCoreConfirm, (void*)change_info);
	}
}

// static
void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const char* dialog_name)
{
	LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo;
	change_info->mOperationFlag = operation_flag;
	change_info->mDialogName = dialog_name;
	// agent id filled in after avatar picker

	if (isLindenEstate())
	{
		gViewerWindow->alertXml("ChangeLindenAccess", accessAddCore2, change_info);
	}
	else
	{
		// same as clicking "OK"
		accessAddCore2(0, change_info);
	}
}

// static
void LLPanelEstateInfo::accessAddCore2(S32 option, void* data)
{
	LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;
	if (option != 0)
	{
		// abort change
		delete change_info;
		change_info = NULL;
		return;
	}

	// avatar picker no multi-select, yes close-on-select
	LLFloaterAvatarPicker::show(accessAddCore3, (void*)change_info, FALSE, TRUE);
}

// static
void LLPanelEstateInfo::accessAddCore3(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* data)
{
	LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;
	if (!change_info) return;
	if (ids.empty()) 
	{
		// User didn't select a name.
		delete change_info;
		change_info = NULL;
		return;
	}
	// User did select a name.
	change_info->mAgentOrGroupID = ids[0];

	// Can't put estate owner on ban list
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return;
	LLViewerRegion* region = gAgent.getRegion();
	if (!region) return;

	if ((change_info->mOperationFlag & ESTATE_ACCESS_BANNED_AGENT_ADD)
		&& (region->getOwner() == change_info->mAgentOrGroupID))
	{
		gViewerWindow->alertXml("OwnerCanNotBeDenied");
		delete change_info;
		change_info = NULL;
		return;
	}

	if (isLindenEstate())
	{
		// just apply to this estate
		accessCoreConfirm(0, (void*)change_info);
	}
	else
	{
		// ask if this estate or all estates with this owner
		LLString::format_map_t args;
		args["[ALL_ESTATES]"] = all_estates_text();
		gViewerWindow->alertXml(change_info->mDialogName, args, accessCoreConfirm, (void*)change_info);
	}
}

// static
void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const char* dialog_name, const char* list_ctrl_name)
{
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return;
	LLNameListCtrl* name_list = LLViewerUICtrlFactory::getNameListByName(panel, list_ctrl_name);
	if (!name_list) return;
	LLScrollListItem* item = name_list->getFirstSelected();
	if (!item) return;
	LLUUID agent_id = item->getUUID();

	LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo;
	change_info->mAgentOrGroupID = agent_id;
	change_info->mOperationFlag = operation_flag;
	change_info->mDialogName = dialog_name;

	if (isLindenEstate())
	{
		// warn on change linden estate
		gViewerWindow->alertXml("ChangeLindenAccess", 
							   accessRemoveCore2,
							   (void*)change_info);
	}
	else
	{
		// just proceed, as if clicking OK
		accessRemoveCore2(0, (void*)change_info);
	}
}

// static
void LLPanelEstateInfo::accessRemoveCore2(S32 option, void* data)
{
	LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;
	if (option != 0)
	{
		// abort
		delete change_info;
		change_info = NULL;
		return;
	}

	// If Linden estate, can only apply to "this" estate, not all estates
	// owned by NULL.
	if (isLindenEstate())
	{
		accessCoreConfirm(0, (void*)change_info);
	}
	else
	{
		LLString::format_map_t args;
		args["[ALL_ESTATES]"] = all_estates_text();
		gViewerWindow->alertXml(change_info->mDialogName, 
							   args, 
							   accessCoreConfirm, 
							   (void*)change_info);
	}
}

// Used for both access add and remove operations, depending on the mOperationFlag
// passed in (ESTATE_ACCESS_BANNED_AGENT_ADD, ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, etc.)
// static
void LLPanelEstateInfo::accessCoreConfirm(S32 option, void* data)
{
	LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data;
	U32 flags = change_info->mOperationFlag;
	switch(option)
	{
	case 0:
		// This estate
		sendEstateAccessDelta(flags, change_info->mAgentOrGroupID);
		break;
	case 1:
		{
			// All estates, either than I own or manage for this owner.  
			// This will be verified on simulator. JC
			LLViewerRegion* region = gAgent.getRegion();
			if (!region) break;
			if (region->getOwner() == gAgent.getID()
				|| gAgent.isGodlike())
			{
				flags |= ESTATE_ACCESS_APPLY_TO_ALL_ESTATES;
				sendEstateAccessDelta(flags, change_info->mAgentOrGroupID);
			}
			else if (region->isEstateManager())
			{
				flags |= ESTATE_ACCESS_APPLY_TO_MANAGED_ESTATES;
				sendEstateAccessDelta(flags, change_info->mAgentOrGroupID);
			}
			break;
		}
	case 2:
	default:
		break;
	}
	delete change_info;
	change_info = NULL;
}

// key = "estateaccessdelta"
// str(estate_id) will be added to front of list by forward_EstateOwnerRequest_to_dataserver
// str[0] = str(agent_id) requesting the change
// str[1] = str(flags) (ESTATE_ACCESS_DELTA_*)
// str[2] = str(agent_id) to add or remove
// static
void LLPanelEstateInfo::sendEstateAccessDelta(U32 flags, const LLUUID& agent_or_group_id)
{
	LLMessageSystem* msg = gMessageSystem;
	msg->newMessage("EstateOwnerMessage");
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());

	msg->nextBlock("MethodData");
	msg->addString("Method", "estateaccessdelta");
	msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice());

	char buf[MAX_STRING];
	gAgent.getID().toString(buf);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buf);

	sprintf(buf, "%u", flags);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buf);

	agent_or_group_id.toString(buf);
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buf);


	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();

	if (flags & (ESTATE_ACCESS_ALLOWED_AGENT_ADD | ESTATE_ACCESS_ALLOWED_AGENT_REMOVE |
		         ESTATE_ACCESS_BANNED_AGENT_ADD | ESTATE_ACCESS_BANNED_AGENT_REMOVE))
	{
		
		panel->clearAccessLists();
	}

	gAgent.sendReliableMessage();
}


bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region)
{
	BOOL god = gAgent.isGodlike();
	BOOL owner = (region && (region->getOwner() == gAgent.getID()));
	BOOL manager = (region && region->isEstateManager());
	setCtrlsEnabled(god || owner || manager);
	childDisable("apply_btn");
	childSetEnabled("add_allowed_avatar_btn",		god || owner || manager);
	childSetEnabled("remove_allowed_avatar_btn",	god || owner || manager);
	childSetEnabled("add_allowed_group_btn",		god || owner || manager);
	childSetEnabled("remove_allowed_group_btn",		god || owner || manager);
	childSetEnabled("add_banned_avatar_btn",		god || owner || manager);
	childSetEnabled("remove_banned_avatar_btn",		god || owner || manager);
	childSetEnabled("message_estate_btn",			god || owner || manager);
	childSetEnabled("kick_user_from_estate_btn",	god || owner || manager);

	// estate managers can't add estate managers
	childSetEnabled("add_estate_manager_btn",		god || owner);
	childSetEnabled("remove_estate_manager_btn",	god || owner);
	childSetEnabled("estate_manager_name_list",		god || owner);

	// let the parent class handle the general data collection. 
	bool rv = LLPanelRegionInfo::refreshFromRegion(region);

	// We want estate info. To make sure it works across region
	// boundaries and multiple packets, we add a serial number to the
	// integers and track against that on update.
	strings_t strings;
	//integers_t integers;
	//LLFloaterRegionInfo::incrementSerial();
	LLFloaterRegionInfo::nextInvoice();
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	//integers.push_back(LLFloaterRegionInfo::());::getPanelEstate();

	
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	panel->clearAccessLists();
	

	sendEstateOwnerMessage(gMessageSystem, "getinfo", invoice, strings);

	


	return rv;
}

void LLPanelEstateInfo::updateChild(LLUICtrl* child_ctrl)
{
	if (checkRemovalButton(child_ctrl->getName()))
	{
		// do nothing
	}
	else if (checkSunHourSlider(child_ctrl))
	{
		// do nothing
	}
}

bool LLPanelEstateInfo::estateUpdate(LLMessageSystem* msg)
{
	llinfos << "LLPanelEstateInfo::estateUpdate()" << llendl;
	return false;
}


BOOL LLPanelEstateInfo::postBuild()
{
	// set up the callbacks for the generic controls
	initCtrl("externally_visible_check");
#if LL_ENABLE_MAINLAND_VISIBLE_CONTROL
	initCtrl("mainland_visible_check");
#endif
	initCtrl("use_global_time_check");
	initCtrl("fixed_sun_check");
	initCtrl("allow_direct_teleport");
	initCtrl("deny_anonymous");
	initCtrl("deny_identified");
	initCtrl("deny_transacted");

	initHelpBtn("estate_manager_help",			"HelpEstateEstateManager");
	initHelpBtn("use_global_time_help",			"HelpEstateUseGlobalTime");
	initHelpBtn("fixed_sun_help",				"HelpEstateFixedSun");
	initHelpBtn("externally_visible_help",		"HelpEstateExternallyVisible");
#if LL_ENABLE_MAINLAND_VISIBLE_CONTROL
	initHelpBtn("mainland_visible_help",		"HelpEstateMainlandVisible");
#endif
	initHelpBtn("allow_direct_teleport_help",	"HelpEstateAllowDirectTeleport");
	initHelpBtn("allow_resident_help",			"HelpEstateAllowResident");
	initHelpBtn("allow_group_help",				"HelpEstateAllowGroup");
	initHelpBtn("ban_resident_help",			"HelpEstateBanResident");

	// set up the use global time checkbox
	childSetCommitCallback("use_global_time_check", onChangeUseGlobalTime, this);
	childSetCommitCallback("fixed_sun_check", onChangeFixedSun, this);
	childSetCommitCallback("sun_hour_slider", onChangeChildCtrl, this);

	childSetCommitCallback("allowed_avatar_name_list", onChangeChildCtrl, this);
	LLNameListCtrl *avatar_name_list = LLViewerUICtrlFactory::getNameListByName(this, "allowed_avatar_name_list");
	if (avatar_name_list)
	{
		avatar_name_list->setCommitOnSelectionChange(TRUE);
		avatar_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS);
	}

	childSetAction("add_allowed_avatar_btn", onClickAddAllowedAgent, this);
	childSetAction("remove_allowed_avatar_btn", onClickRemoveAllowedAgent, this);

	childSetCommitCallback("allowed_group_name_list", onChangeChildCtrl, this);
	LLNameListCtrl* group_name_list = LLViewerUICtrlFactory::getNameListByName(this, "allowed_group_name_list");
	if (group_name_list)
	{
		group_name_list->setCommitOnSelectionChange(TRUE);
		group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS);
	}

	childSetAction("add_allowed_group_btn", onClickAddAllowedGroup, this);
	childSetAction("remove_allowed_group_btn", onClickRemoveAllowedGroup, this);

	childSetCommitCallback("banned_avatar_name_list", onChangeChildCtrl, this);
	LLNameListCtrl* banned_name_list = LLViewerUICtrlFactory::getNameListByName(this, "banned_avatar_name_list");
	if (banned_name_list)
	{
		banned_name_list->setCommitOnSelectionChange(TRUE);
		banned_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS);
	}

	childSetAction("add_banned_avatar_btn", onClickAddBannedAgent, this);
	childSetAction("remove_banned_avatar_btn", onClickRemoveBannedAgent, this);

	childSetCommitCallback("estate_manager_name_list", onChangeChildCtrl, this);
	LLNameListCtrl* manager_name_list = LLViewerUICtrlFactory::getNameListByName(this, "estate_manager_name_list");
	if (manager_name_list)
	{
		manager_name_list->setCommitOnSelectionChange(TRUE);
		manager_name_list->setMaxItemCount(ESTATE_MAX_MANAGERS);
	}

	childSetAction("add_estate_manager_btn", onClickAddEstateManager, this);
	childSetAction("remove_estate_manager_btn", onClickRemoveEstateManager, this);
	childSetAction("message_estate_btn", onClickMessageEstate, this);
	childSetAction("kick_user_from_estate_btn", onClickKickUser, this);

	return LLPanelRegionInfo::postBuild();
}


BOOL LLPanelEstateInfo::sendUpdate()
{
	llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl;

	if (getEstateID() <= ESTATE_LAST_LINDEN)
	{
		// trying to change reserved estate, warn
		gViewerWindow->alertXml("ChangeLindenEstate",
							   callbackChangeLindenEstate,
							   this);
	}
	else
	{
		// for normal estates, just make the change
		callbackChangeLindenEstate(0, this);
	}
	return TRUE;
}

// static
void LLPanelEstateInfo::callbackChangeLindenEstate(S32 option, void* data)
{
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)data;
	switch(option)
	{
	case 0:
		// send the update
		LLFloaterRegionInfo::nextInvoice();
		self->commitEstateInfo();
		break;
	case 1:
	default:
		// do nothing
		break;
	}
}


/*
// Request = "getowner"
// SParam[0] = "" (empty string)
// IParam[0] = serial
void LLPanelEstateInfo::getEstateOwner()
{
	// TODO -- disable the panel
	// and call this function whenever we cross a region boundary
	// re-enable when owner matches, and get new estate info
	LLMessageSystem* msg = gMessageSystem;
	msg->newMessageFast(_PREHASH_EstateOwnerRequest);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());

	msg->nextBlockFast(_PREHASH_RequestData);
	msg->addStringFast(_PREHASH_Request, "getowner");

	// we send an empty string so that the variable block is not empty
	msg->nextBlockFast(_PREHASH_StringData);
	msg->addStringFast(_PREHASH_SParam, "");

	msg->nextBlockFast(_PREHASH_IntegerData);
	msg->addS32Fast(_PREHASH_IParam, LLFloaterRegionInfo::getSerial());

	gAgent.sendMessage();
}
*/

// key = "estatechangeinfo"
// strings[0] = str(estate_id) (added by simulator before relay - not here)
// strings[1] = estate_name
// strings[2] = str(estate_flags)
// strings[3] = str((S32)(sun_hour * 1024.f))
void LLPanelEstateInfo::commitEstateInfo()
{
	LLMessageSystem* msg = gMessageSystem;
	msg->newMessage("EstateOwnerMessage");
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());

	msg->nextBlock("MethodData");
	msg->addString("Method", "estatechangeinfo");
	msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice());

	msg->nextBlock("ParamList");
	msg->addString("Parameter", getEstateName());

	char buf[MAX_STRING];
	sprintf(buf, "%u", computeEstateFlags());
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buf);

	F32 sun_hour = getSunHour();
	if (childGetValue("use_global_time_check").asBoolean())
	{
		sun_hour = 0.f;	// 0 = global time
	}

	sprintf(buf, "%d", (S32)(sun_hour*1024.0f));
	msg->nextBlock("ParamList");
	msg->addString("Parameter", buf);

	gAgent.sendMessage();
}

void LLPanelEstateInfo::setEstateFlags(U32 flags)
{
	childSetValue("externally_visible_check", LLSD(flags & REGION_FLAGS_EXTERNALLY_VISIBLE ? TRUE : FALSE) );
#if LL_ENABLE_MAINLAND_VISIBLE_CONTROL
	childSetValue("mainland_visible_check", LLSD(flags & REGION_FLAGS_MAINLAND_VISIBLE ? TRUE : FALSE) );
#endif
	childSetValue("fixed_sun_check", LLSD(flags & REGION_FLAGS_SUN_FIXED ? TRUE : FALSE) );
	childSetValue("allow_direct_teleport", LLSD(flags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT ? TRUE : FALSE) );
	childSetValue("deny_anonymous", LLSD(flags & REGION_FLAGS_DENY_ANONYMOUS ? TRUE : FALSE) );
	childSetValue("deny_identified", LLSD(flags & REGION_FLAGS_DENY_IDENTIFIED ? TRUE : FALSE) );
	childSetValue("deny_transacted", LLSD(flags & REGION_FLAGS_DENY_TRANSACTED ? TRUE : FALSE) );

}

U32 LLPanelEstateInfo::computeEstateFlags()
{
	U32 flags = 0;

	if (childGetValue("externally_visible_check").asBoolean())
	{
		flags |= REGION_FLAGS_EXTERNALLY_VISIBLE;
	}
#if LL_ENABLE_MAINLAND_VISIBLE_CONTROL
	// This flag is ignored by everything. 2006-11-17 Phoenix.
	if (childGetValue("mainland_visible_check").asBoolean())
	{
		flags |= REGION_FLAGS_MAINLAND_VISIBLE;
	}
#else
	flags |= REGION_FLAGS_MAINLAND_VISIBLE;
#endif
	
	if (childGetValue("allow_direct_teleport").asBoolean())
	{
		flags |= REGION_FLAGS_ALLOW_DIRECT_TELEPORT;
	}

	if (childGetValue("fixed_sun_check").asBoolean())
	{
		flags |= REGION_FLAGS_SUN_FIXED;
	}
	
	if (childGetValue("deny_anonymous").asBoolean())
	{
		flags |= REGION_FLAGS_DENY_ANONYMOUS;
	}
	
	if (childGetValue("deny_identified").asBoolean())
	{
		flags |= REGION_FLAGS_DENY_IDENTIFIED;
	}

	if (childGetValue("deny_transacted").asBoolean())
	{
		flags |= REGION_FLAGS_DENY_TRANSACTED;
	}
	
	return flags;
}

BOOL LLPanelEstateInfo::getGlobalTime()
{
	return childGetValue("use_global_time_check").asBoolean();
}

void LLPanelEstateInfo::setGlobalTime(bool b)
{
	childSetValue("use_global_time_check", LLSD(b));
	childSetEnabled("fixed_sun_check", LLSD(!b));
	childSetEnabled("sun_hour_slider", LLSD(!b));
	if (b)
	{
		childSetValue("sun_hour_slider", LLSD(0.f));
	}
}


BOOL LLPanelEstateInfo::getFixedSun()
{
	return childGetValue("fixed_sun_check").asBoolean();
}

void LLPanelEstateInfo::setSunHour(F32 sun_hour)
{
	if(sun_hour < 6.0f)
	{
		sun_hour = 24.0f + sun_hour;
	}
	childSetValue("sun_hour_slider", LLSD(sun_hour));
}

F32 LLPanelEstateInfo::getSunHour()
{
	if (childIsEnabled("sun_hour_slider"))
	{
		return (F32)childGetValue("sun_hour_slider").asReal();
	}
	return 0.f;
}

const std::string LLPanelEstateInfo::getEstateName() const
{
	return childGetValue("estate_name").asString();
}

void LLPanelEstateInfo::setEstateName(const std::string& name)
{
	childSetValue("estate_name", LLSD(name));
}

const std::string LLPanelEstateInfo::getOwnerName() const
{
	return childGetValue("estate_owner").asString();
}

void LLPanelEstateInfo::setOwnerName(const std::string& name)
{
	childSetValue("estate_owner", LLSD(name));
}

void LLPanelEstateInfo::setAccessAllowedEnabled(bool enable_agent,
												bool enable_group,
												bool enable_ban)
{
	childSetEnabled("allow_resident_label", enable_agent);
	childSetEnabled("allowed_avatar_name_list", enable_agent);
	childSetVisible("allowed_avatar_name_list", enable_agent);
	childSetEnabled("add_allowed_avatar_btn", enable_agent);
	childSetEnabled("remove_allowed_avatar_btn", enable_agent);

	// Groups
	childSetEnabled("allow_group_label", enable_group);
	childSetEnabled("allowed_group_name_list", enable_group);
	childSetVisible("allowed_group_name_list", enable_group);
	childSetEnabled("add_allowed_group_btn", enable_group);
	childSetEnabled("remove_allowed_group_btn", enable_group);

	// Ban
	childSetEnabled("ban_resident_label", enable_ban);
	childSetEnabled("banned_avatar_name_list", enable_ban);
	childSetVisible("banned_avatar_name_list", enable_ban);
	childSetEnabled("add_banned_avatar_btn", enable_ban);
	childSetEnabled("remove_banned_avatar_btn", enable_ban);

	// Update removal buttons if needed
	if (enable_agent)
	{
		checkRemovalButton("allowed_avatar_name_list");
	}

	if (enable_group)
	{
		checkRemovalButton("allowed_group_name_list");
	}

	if (enable_ban)
	{
		checkRemovalButton("banned_avatar_name_list");
	}
}

// static
void LLPanelEstateInfo::callbackCacheName(
	const LLUUID& id,
	const char* first,
	const char* last,
	BOOL is_group,
	void*)
{
	LLPanelEstateInfo* self = LLFloaterRegionInfo::getPanelEstate();
	if (!self) return;

	std::string name;
	
	if (id.isNull())
	{
		name = "(none)";
	}
	else
	{
		name = first;
		name += " ";
		name += last;
	}

	self->setOwnerName(name);
}

void LLPanelEstateInfo::clearAccessLists() 
{
	LLNameListCtrl* name_list = LLViewerUICtrlFactory::getNameListByName(this, "allowed_avatar_name_list");
	if (name_list)
	{
		name_list->deleteAllItems();
	}

	name_list = LLViewerUICtrlFactory::getNameListByName(this, "banned_avatar_name_list");
	if (name_list)
	{
		name_list->deleteAllItems();
	}
}

// enables/disables the "remove" button for the various allow/ban lists
BOOL LLPanelEstateInfo::checkRemovalButton(std::string name)
{
	std::string btn_name = "";
	if (name == "allowed_avatar_name_list")
	{
		btn_name = "remove_allowed_avatar_btn";
	}
	else if (name == "allowed_group_name_list")
	{
		btn_name = "remove_allowed_group_btn";
	}
	else if (name == "banned_avatar_name_list")
	{
		btn_name = "remove_banned_avatar_btn";
	}
	else if (name == "estate_manager_name_list")
	{
		btn_name = "remove_estate_manager_btn";
	}

	// enable the remove button if something is selected
	LLNameListCtrl* name_list = LLViewerUICtrlFactory::getNameListByName(this, name);
	childSetEnabled(btn_name.c_str(), name_list && name_list->getFirstSelected() ? TRUE : FALSE);

	return (btn_name != "");
}

BOOL LLPanelEstateInfo::checkSunHourSlider(LLUICtrl* child_ctrl)
{
	BOOL found_child_ctrl = FALSE;
	if (child_ctrl->getName() == "sun_hour_slider")
	{
		enableButton("apply_btn");
		found_child_ctrl = TRUE;
	}
	return found_child_ctrl;
}

// static
void LLPanelEstateInfo::onClickMessageEstate(void* userdata)
{
	llinfos << "LLPanelEstateInfo::onClickMessageEstate" << llendl;
	gViewerWindow->alertXmlEditText("MessageEstate", LLString::format_map_t(),
									NULL, NULL,
									onMessageCommit, userdata);
}

// static
void LLPanelEstateInfo::onMessageCommit(S32 option, const LLString& text, void* userdata)
{
	if(option != 0) return;
	if(text.empty()) return;
	LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata;
	if(!self) return;
	llinfos << "Message to everyone: " << text << llendl;
	strings_t strings;
	//integers_t integers;
	std::string name;
	gAgent.buildFullname(name);
	strings.push_back(strings_t::value_type(name));
	strings.push_back(strings_t::value_type(text));
	LLUUID invoice(LLFloaterRegionInfo::getLastInvoice());
	self->sendEstateOwnerMessage(gMessageSystem, "instantmessage", invoice, strings);
}

LLPanelEstateCovenant::LLPanelEstateCovenant()
: mCovenantID(LLUUID::null)
{
}

// virtual 
bool LLPanelEstateCovenant::refreshFromRegion(LLViewerRegion* region)
{
	LLTextBox* region_name = (LLTextBox*)getChildByName("region_name_text");
	if (region_name)
	{
		region_name->setText(region->getName());
	}

	LLTextBox* resellable_clause = (LLTextBox*)getChildByName("resellable_clause");
	if (resellable_clause)
	{
		if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
		{
			resellable_clause->setText(childGetText("can_not_resell"));
		}
		else
		{
			resellable_clause->setText(childGetText("can_resell"));
		}
	}
	
	LLTextBox* changeable_clause = (LLTextBox*)getChildByName("changeable_clause");
	if (changeable_clause)
	{
		if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES)
		{
			changeable_clause->setText(childGetText("can_change"));
		}
		else
		{
			changeable_clause->setText(childGetText("can_not_change"));
		}
	}

	// let the parent class handle the general data collection. 
	bool rv = LLPanelRegionInfo::refreshFromRegion(region);
	LLMessageSystem *msg = gMessageSystem;
	msg->newMessage("EstateCovenantRequest");
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
	msg->sendReliable(region->getHost());
	return rv;
}

// virtual 
bool LLPanelEstateCovenant::estateUpdate(LLMessageSystem* msg)
{
	llinfos << "LLPanelEstateCovenant::estateUpdate()" << llendl;
	return true;
}
	
// virtual 
BOOL LLPanelEstateCovenant::postBuild()
{
	initHelpBtn("covenant_help",		"HelpEstateCovenant");
	mEstateNameText = (LLTextBox*)getChildByName("estate_name_text");
	mEstateOwnerText = (LLTextBox*)getChildByName("estate_owner_text");
	mLastModifiedText = (LLTextBox*)getChildByName("covenant_timestamp_text");
	mEditor = (LLViewerTextEditor*)getChildByName("covenant_editor");
	if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE);
	LLButton* reset_button = (LLButton*)getChildByName("reset_covenant");
	reset_button->setEnabled(gAgent.canManageEstate());
	reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL);

	return LLPanelRegionInfo::postBuild();
}

// virtual 
void LLPanelEstateCovenant::updateChild(LLUICtrl* child_ctrl)
{
}

// virtual
BOOL LLPanelEstateCovenant::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
								  EDragAndDropType cargo_type,
								  void* cargo_data,
								  EAcceptance* accept,
								  LLString& tooltip_msg)
{
	LLInventoryItem* item = (LLInventoryItem*)cargo_data;

	if (!gAgent.canManageEstate())
	{
		*accept = ACCEPT_NO;
		return TRUE;
	}

	switch(cargo_type)
	{
	case DAD_NOTECARD:
		*accept = ACCEPT_YES_COPY_SINGLE;
		if (item && drop)
		{
			gViewerWindow->alertXml("EstateChangeCovenant",
									LLPanelEstateCovenant::confirmChangeCovenantCallback,
									item);
		}
		break;
	default:
		*accept = ACCEPT_NO;
		break;
	}

	return TRUE;
} 

// static 
void LLPanelEstateCovenant::confirmChangeCovenantCallback(S32 option, void* userdata)
{
	LLInventoryItem* item = (LLInventoryItem*)userdata;
	LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant();

	if (!item || !self) return;

	switch(option)
	{
	case 0:
		self->loadInvItem(item);
		break;
	default:
		break;
	}
}

// static
void LLPanelEstateCovenant::resetCovenantID(void* userdata)
{
	gViewerWindow->alertXml("EstateChangeCovenant",
							LLPanelEstateCovenant::confirmResetCovenantCallback,
							NULL);
}

// static
void LLPanelEstateCovenant::confirmResetCovenantCallback(S32 option, void* userdata)
{
	LLPanelEstateCovenant* self = LLFloaterRegionInfo::getPanelCovenant();
	if (!self) return;

	switch(option)
	{
	case 0:		
		self->loadInvItem(NULL);
		break;
	default:
		break;
	}
}

void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp)
{
	const BOOL high_priority = TRUE;	
	if (itemp)
	{
		gAssetStorage->getInvItemAsset(gAgent.getRegionHost(),
									gAgent.getID(),
									gAgent.getSessionID(),
									itemp->getPermissions().getOwner(),
									LLUUID::null,
									itemp->getUUID(),
									itemp->getAssetUUID(),
									itemp->getType(),
                                    onLoadComplete,
									(void*)this,
									high_priority);
		mAssetStatus = ASSET_LOADING;
	}
	else
	{
		mAssetStatus = ASSET_LOADED;
		setCovenantTextEditor("There is no Covenant provided for this Estate.");
		sendChangeCovenantID(LLUUID::null);
	}
}

// static
void LLPanelEstateCovenant::onLoadComplete(LLVFS *vfs,
									   const LLUUID& asset_uuid,
									   LLAssetType::EType type,
									   void* user_data, S32 status)
{
	llinfos << "LLPanelEstateCovenant::onLoadComplete()" << llendl;
	LLPanelEstateCovenant* panelp = (LLPanelEstateCovenant*)user_data;
	if( panelp )
	{
		if(0 == status)
		{
			LLVFile file(vfs, asset_uuid, type, LLVFile::READ);

			S32 file_length = file.getSize();

			char* buffer = new char[file_length+1];
			file.read((U8*)buffer, file_length);

			// put a EOS at the end
			buffer[file_length] = 0;

			if( (file_length > 19) && !strncmp( buffer, "Linden text version", 19 ) )
			{
				if( !panelp->mEditor->importBuffer( buffer ) )
				{
					llwarns << "Problem importing estate covenant." << llendl;
					gViewerWindow->alertXml("ProblemImportingEstateCovenant");
				}
				else
				{
					panelp->sendChangeCovenantID(asset_uuid);	
				}
			}
			else
			{
				// Version 0 (just text, doesn't include version number)
				panelp->sendChangeCovenantID(asset_uuid);
			}
			delete[] buffer;
		}
		else
		{
			if( gViewerStats )
			{
				gViewerStats->incStat( LLViewerStats::ST_DOWNLOAD_FAILED );
			}

			if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ||
				LL_ERR_FILE_EMPTY == status)
			{
				gViewerWindow->alertXml("MissingNotecardAssetID");
			}
			else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status)
			{
				gViewerWindow->alertXml("NotAllowedToViewNotecard");
			}
			else
			{
				gViewerWindow->alertXml("UnableToLoadNotecard");
			}

			llwarns << "Problem loading notecard: " << status << llendl;
		}
		panelp->mAssetStatus = ASSET_LOADED;
		panelp->setCovenantID(asset_uuid);
	}
}

// key = "estatechangecovenantid"
// strings[0] = str(estate_id) (added by simulator before relay - not here)
// strings[1] = str(covenant_id)
void LLPanelEstateCovenant::sendChangeCovenantID(const LLUUID &asset_id)
{
	if (asset_id != getCovenantID())
	{
        setCovenantID(asset_id);

		LLMessageSystem* msg = gMessageSystem;
		msg->newMessage("EstateOwnerMessage");
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());

		msg->nextBlock("MethodData");
		msg->addString("Method", "estatechangecovenantid");
		msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice());

		msg->nextBlock("ParamList");
		msg->addString("Parameter", getCovenantID().getString().c_str());
		gAgent.sendReliableMessage();
	}
}

// virtual 
BOOL LLPanelEstateCovenant::sendUpdate()
{
	return TRUE;
}

const std::string& LLPanelEstateCovenant::getEstateName() const
{
	return mEstateNameText->getText();
}

void LLPanelEstateCovenant::setEstateName(const std::string& name)
{
	mEstateNameText->setText(name);
}

// static
void LLPanelEstateCovenant::updateCovenantText(const std::string& string, const LLUUID& asset_id)
{
	LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant();
	if( panelp )
	{
		panelp->mEditor->setText(string);
		panelp->setCovenantID(asset_id);
	}
}

// static
void LLPanelEstateCovenant::updateEstateName(const std::string& name)
{
	LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant();
	if( panelp )
	{
		panelp->mEstateNameText->setText(name);
	}
}

// static
void LLPanelEstateCovenant::updateLastModified(const std::string& text)
{
	LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant();
	if( panelp )
	{
		panelp->mLastModifiedText->setText(text);
	}
}

// static
void LLPanelEstateCovenant::updateEstateOwnerName(const std::string& name)
{
	LLPanelEstateCovenant* panelp = LLFloaterRegionInfo::getPanelCovenant();
	if( panelp )
	{
		panelp->mEstateOwnerText->setText(name);
	}
}

const std::string& LLPanelEstateCovenant::getOwnerName() const
{
	return mEstateOwnerText->getText();
}

void LLPanelEstateCovenant::setOwnerName(const std::string& name)
{
	mEstateOwnerText->setText(name);
}

void LLPanelEstateCovenant::setCovenantTextEditor(const std::string& text)
{
	mEditor->setText(text);
}

/*
// AgentData = agent_id
// RequestData = "setowner"
// StringData[0] = compressed owner id
// IntegerData[0] = serial
bool LLDispatchSetEstateOwner::operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const sparam_t& strings,
		const iparam_t& integers)
{
	LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance();
	if (!floater) return true;

	LLTabContainer* tab = (LLTabContainer*)(floater->getChildByName("tab"));
	if (!tab) return true;

	LLPanelEstateInfo* panel = (LLPanelEstateInfo*)(tab->getChildByName("Estate"));
	if (!panel) return true;

	// TODO -- check owner, and disable floater if owner
	// does not match

	return true;
}
*/

// key = "estateupdateinfo"
// strings[0] = estate name
// strings[1] = str(owner_id)
// strings[2] = str(estate_id)
// strings[3] = str(estate_flags)
// strings[4] = str((S32)(sun_hour * 1024))
// strings[5] = str(parent_estate_id)
// strings[6] = str(covenant_id)
// strings[7] = str(covenant_timestamp)
// strings[8] = str(send_to_agent_only)
bool LLDispatchEstateUpdateInfo::operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const LLUUID& invoice,
		const sparam_t& strings)
{
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return true;

	// NOTE: LLDispatcher extracts strings with an extra \0 at the
	// end.  If we pass the std::string direct to the UI/renderer
	// it draws with a weird character at the end of the string.
	std::string estate_name = strings[0].c_str();
	panel->setEstateName(estate_name);


	LLViewerRegion* regionp = gAgent.getRegion();

	LLUUID owner_id(strings[1].c_str());
	regionp->setOwner(owner_id);
	// Update estate owner name in UI
	const BOOL is_group = FALSE;
	gCacheName->get(owner_id, is_group, LLPanelEstateInfo::callbackCacheName);

	U32 estate_id = strtoul(strings[2].c_str(), NULL, 10);
	panel->setEstateID(estate_id);

	U32 flags = strtoul(strings[3].c_str(), NULL, 10);
	panel->setEstateFlags(flags);

	F32 sun_hour = ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f;
	if(sun_hour == 0 && (flags & REGION_FLAGS_SUN_FIXED ? FALSE : TRUE))
	{
		panel->setGlobalTime(TRUE);
	} 
	else
	{
		panel->setGlobalTime(FALSE);
		panel->setSunHour(sun_hour);
	}

	bool visible_from_mainland = (bool)(flags & REGION_FLAGS_EXTERNALLY_VISIBLE);
	bool god = gAgent.isGodlike();
	bool linden_estate = (estate_id <= ESTATE_LAST_LINDEN);

	// If visible from mainland, disable the access allowed
	// UI, as anyone can teleport there.
	// However, gods need to be able to edit the access list for
	// linden estates, regardless of visibility, to allow object
	// and money transfers.
	bool enable_agent = (!visible_from_mainland || (god && linden_estate));
	bool enable_group = enable_agent;
	bool enable_ban = !linden_estate;
	panel->setAccessAllowedEnabled(enable_agent, enable_group, enable_ban);

	return true;
}


// key = "setaccess"
// strings[0] = str(estate_id)
// strings[1] = str(packed_access_lists)
// strings[2] = str(num allowed agent ids)
// strings[3] = str(num allowed group ids)
// strings[4] = str(num banned agent ids)
// strings[5] = str(num estate manager agent ids)
// strings[6] = bin(uuid)
// strings[7] = bin(uuid)
// strings[8] = bin(uuid)
// ...
bool LLDispatchSetEstateAccess::operator()(
		const LLDispatcher* dispatcher,
		const std::string& key,
		const LLUUID& invoice,
		const sparam_t& strings)
{
	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
	if (!panel) return true;

	S32 index = 1;	// skip estate_id
	U32 access_flags = strtoul(strings[index++].c_str(), NULL,10);
	S32 num_allowed_agents = strtol(strings[index++].c_str(), NULL, 10);
	S32 num_allowed_groups = strtol(strings[index++].c_str(), NULL, 10);
	S32 num_banned_agents = strtol(strings[index++].c_str(), NULL, 10);
	S32 num_estate_managers = strtol(strings[index++].c_str(), NULL, 10);

	// sanity ckecks
	if (num_allowed_agents > 0
		&& !(access_flags & ESTATE_ACCESS_ALLOWED_AGENTS))
	{
		llwarns << "non-zero count for allowed agents, but no corresponding flag" << llendl;
	}
	if (num_allowed_groups > 0
		&& !(access_flags & ESTATE_ACCESS_ALLOWED_GROUPS))
	{
		llwarns << "non-zero count for allowed groups, but no corresponding flag" << llendl;
	}
	if (num_banned_agents > 0
		&& !(access_flags & ESTATE_ACCESS_BANNED_AGENTS))
	{
		llwarns << "non-zero count for banned agents, but no corresponding flag" << llendl;
	}
	if (num_estate_managers > 0
		&& !(access_flags & ESTATE_ACCESS_MANAGERS))
	{
		llwarns << "non-zero count for managers, but no corresponding flag" << llendl;
	}

	// grab the UUID's out of the string fields
	if (access_flags & ESTATE_ACCESS_ALLOWED_AGENTS)
	{
		LLNameListCtrl* allowed_agent_name_list;
		allowed_agent_name_list = LLViewerUICtrlFactory::getNameListByName(panel, "allowed_avatar_name_list");

		int totalAllowedAgents = num_allowed_agents;
		
		if (allowed_agent_name_list) 
		{
			totalAllowedAgents += allowed_agent_name_list->getItemCount();
		}

		std::string msg = llformat("Allowed residents: (%d, max %d)",
									totalAllowedAgents,
									ESTATE_MAX_ACCESS_IDS);
		panel->childSetValue("allow_resident_label", LLSD(msg));

		if (allowed_agent_name_list)
		{
			//allowed_agent_name_list->deleteAllItems();
			for (S32 i = 0; i < num_allowed_agents && i < ESTATE_MAX_ACCESS_IDS; i++)
			{
				LLUUID id;
				memcpy(id.mData, strings[index++].data(), UUID_BYTES);
				allowed_agent_name_list->addNameItem(id);
			}
			panel->childSetEnabled("remove_allowed_avatar_btn", allowed_agent_name_list->getFirstSelected() ? TRUE : FALSE);
			allowed_agent_name_list->sortByColumn(0, TRUE);
		}
	}

	if (access_flags & ESTATE_ACCESS_ALLOWED_GROUPS)
	{
		LLNameListCtrl* allowed_group_name_list;
		allowed_group_name_list = LLViewerUICtrlFactory::getNameListByName(panel, "allowed_group_name_list");

		std::string msg = llformat("Allowed groups: (%d, max %d)",
									num_allowed_groups,
									(S32) ESTATE_MAX_GROUP_IDS);
		panel->childSetValue("allow_group_label", LLSD(msg));

		if (allowed_group_name_list)
		{
			allowed_group_name_list->deleteAllItems();
			for (S32 i = 0; i < num_allowed_groups && i < ESTATE_MAX_GROUP_IDS; i++)
			{
				LLUUID id;
				memcpy(id.mData, strings[index++].data(), UUID_BYTES);
				allowed_group_name_list->addGroupNameItem(id);
			}
			panel->childSetEnabled("remove_allowed_group_btn", allowed_group_name_list->getFirstSelected() ? TRUE : FALSE);
			allowed_group_name_list->sortByColumn(0, TRUE);
		}
	}

	if (access_flags & ESTATE_ACCESS_BANNED_AGENTS)
	{
		LLNameListCtrl* banned_agent_name_list;
		banned_agent_name_list = LLViewerUICtrlFactory::getNameListByName(panel, "banned_avatar_name_list");

		int totalBannedAgents = num_banned_agents;
		
		if (banned_agent_name_list) 
		{
			totalBannedAgents += banned_agent_name_list->getItemCount();
		}


		std::string msg = llformat("Banned residents: (%d, max %d)",
									totalBannedAgents,
									ESTATE_MAX_ACCESS_IDS);
		panel->childSetValue("ban_resident_label", LLSD(msg));

		if (banned_agent_name_list)
		{
			//banned_agent_name_list->deleteAllItems();
			for (S32 i = 0; i < num_banned_agents && i < ESTATE_MAX_ACCESS_IDS; i++)
			{
				LLUUID id;
				memcpy(id.mData, strings[index++].data(), UUID_BYTES);
				banned_agent_name_list->addNameItem(id);
			}
			panel->childSetEnabled("remove_banned_avatar_btn", banned_agent_name_list->getFirstSelected() ? TRUE : FALSE);
			banned_agent_name_list->sortByColumn(0, TRUE);
		}
	}

	if (access_flags & ESTATE_ACCESS_MANAGERS)
	{
		std::string msg = llformat("Estate Managers: (%d, max %d)",
									num_estate_managers,
									ESTATE_MAX_MANAGERS);
		panel->childSetValue("estate_manager_label", LLSD(msg));

		LLNameListCtrl* estate_manager_name_list =
			LLViewerUICtrlFactory::getNameListByName(panel, "estate_manager_name_list");
		if (estate_manager_name_list)
		{
			estate_manager_name_list->deleteAllItems();
			for (S32 i = 0; i < num_estate_managers && i < ESTATE_MAX_MANAGERS; i++)
			{
				LLUUID id;
				memcpy(id.mData, strings[index++].data(), UUID_BYTES);
				estate_manager_name_list->addNameItem(id);
			}
			panel->childSetEnabled("remove_estate_manager_btn", estate_manager_name_list->getFirstSelected() ? TRUE : FALSE);
			estate_manager_name_list->sortByColumn(0, TRUE);
		}
	}

	return true;
}
