/** 
 * @file llfloaterland.cpp
 * @brief "About Land" floater, allowing display and editing of land parcel properties.
 *
 * Copyright (c) 2002-$CurrentYear$, Linden Research, Inc.
 * $License$
 */

#include "llviewerprecompiledheaders.h"

#include <sstream>
#include <time.h>

#include "llfloaterland.h"

#include "llcachename.h"
#include "llfocusmgr.h"
#include "llparcel.h"
#include "message.h"

#include "llagent.h"
#include "llfloateravatarpicker.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "llfloaterauction.h"
#include "llfloateravatarinfo.h"
#include "llfloatergroups.h"
#include "llfloatergroupinfo.h"
#include "lllineeditor.h"
#include "llnamelistctrl.h"
#include "llnotify.h"
#include "llradiogroup.h"
#include "llscrolllistctrl.h"
#include "llselectmgr.h"
#include "llspinctrl.h"
#include "lltabcontainer.h"
#include "lltextbox.h"
#include "lltexturectrl.h"
#include "lluiconstants.h"
#include "llvieweruictrlfactory.h"
#include "llviewermessage.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
#include "llviewerstats.h"
#include "llviewertexteditor.h"
#include "llviewerwindow.h"
#include "llmediaengine.h"
#include "llviewercontrol.h"
#include "roles_constants.h"

static const S32 EDIT_HEIGHT = 16;
static const S32 LEFT = HPAD;
static const S32 BOTTOM = VPAD;
static const S32 RULER0  = LEFT;
static const S32 RULER05 = RULER0 + 24;
static const S32 RULER1  = RULER05 + 16;
static const S32 RULER15 = RULER1 + 20;
static const S32 RULER2  = RULER1 + 32;
static const S32 RULER205= RULER2 + 32;
static const S32 RULER20 = RULER2 + 64;
static const S32 RULER21 = RULER20 + 16;
static const S32 RULER22 = RULER21 + 32;
static const S32 RULER225 = RULER20 + 64;
static const S32 RULER23 = RULER22 + 64;
static const S32 RULER24 = RULER23 + 26;
static const S32 RULER3  = RULER2 + 102;
static const S32 RULER4  = RULER3 + 8;
static const S32 RULER5  = RULER4 + 50;
static const S32 RULER6  = RULER5 + 52;
static const S32 RULER7  = RULER6 + 24;
static const S32 RIGHT  = LEFT + 278;
static const S32 FAR_RIGHT  = LEFT + 324 + 40;

static const char PRICE[] = "Price:";
static const char NO_PRICE[] = "";
static const char AREA[] = "Area:";

static const char OWNER_ONLINE[] 	= "0";
static const char OWNER_OFFLINE[]	= "1";
static const char OWNER_GROUP[] 	= "2";

static const char NEED_TIER_TO_MODIFY_STRING[] = "You must approve your purchase to modify this land.";

static const char WEB_PAGE[] = "Web page";
static const char QUICKTIME_MOVIE[] = "QuickTime movie";
static const char RAW_HTML[] = "Raw HTML";

// constants used in callbacks below - syntactic sugar.
static const BOOL BUY_GROUP_LAND = TRUE;
static const BOOL BUY_PERSONAL_LAND = FALSE;

// Statics
LLFloaterLand* LLFloaterLand::sInstance = NULL;
LLParcelSelectionObserver* LLFloaterLand::sObserver = NULL;
S32 LLFloaterLand::sLastTab = 0;
BOOL LLFloaterLand::sRequestReplyOnUpdate = TRUE;

// Local classes
class LLParcelSelectionObserver : public LLParcelObserver
{
public:
	virtual void changed() { LLFloaterLand::refreshAll(); }
};

//---------------------------------------------------------------------------
// LLFloaterLand
//---------------------------------------------------------------------------

void send_parcel_select_objects(S32 parcel_local_id, S32 return_type,
								uuid_list_t* return_ids = NULL)
{
	LLMessageSystem *msg = gMessageSystem;

	LLViewerRegion* region = gParcelMgr->getSelectionRegion();
	if (!region) return;

	// Since new highlight will be coming in, drop any highlights
	// that exist right now.
	gSelectMgr->unhighlightAll();

	msg->newMessageFast(_PREHASH_ParcelSelectObjects);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
	msg->nextBlockFast(_PREHASH_ParcelData);
	msg->addS32Fast(_PREHASH_LocalID, parcel_local_id);
	msg->addS32Fast(_PREHASH_ReturnType, return_type);

	// Throw all return ids into the packet.
	// TODO: Check for too many ids.
	if (return_ids)
	{
		uuid_list_t::iterator end = return_ids->end();
		for (uuid_list_t::iterator it = return_ids->begin();
			 it != end;
			 ++it)
		{
			msg->nextBlockFast(_PREHASH_ReturnIDs);
			msg->addUUIDFast(_PREHASH_ReturnID, (*it));
		}
	}
	else
	{
		// Put in a null key so that the message is complete.
		msg->nextBlockFast(_PREHASH_ReturnIDs);
		msg->addUUIDFast(_PREHASH_ReturnID, LLUUID::null);
	}

	msg->sendReliable(region->getHost());
}


// static
void LLFloaterLand::show()
{
	if (!sInstance)
	{
		sInstance = new LLFloaterLand();

		// Select tab from last view
		sInstance->mTabLand->selectTab(sLastTab);

		sObserver = new LLParcelSelectionObserver();
		gParcelMgr->addObserver( sObserver );
	}

	sInstance->open();

	// Done automatically when the selected parcel's properties arrive
	// (and hence we have the local id).
	// gParcelMgr->sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_RENTER);

	// If we've already got the parcel data, fill the
	// floater with it.
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (parcel)
	{
		sInstance->refresh();
	}

	sRequestReplyOnUpdate = TRUE;
}

//static
LLPanelLandObjects* LLFloaterLand::getCurrentPanelLandObjects()
{
	if (!sInstance)
	{
		return NULL;
	}

	return sInstance->mPanelObjects;
}

//static
LLPanelLandCovenant* LLFloaterLand::getCurrentPanelLandCovenant()
{
	if (!sInstance)
	{
		return NULL;
	}

	return sInstance->mPanelCovenant;
}

// static
void LLFloaterLand::refreshAll()
{
	if (sInstance)
	{
		sInstance->refresh();
	}
}


// virtual
BOOL LLFloaterLand::canClose()
{
	// canClose is checked as the first step of attempting to close
	// the window, before focus is released from controls.  Since we're
	// closing the window and deselecting the land, we
	// don't want replies to the upstream messages that get sent
	// (because the reply will cause the land to be selected again).
	sRequestReplyOnUpdate = FALSE;
	return TRUE;
}

// virtual
void LLFloaterLand::onClose(bool app_quitting)
{
	gParcelMgr->removeObserver( sObserver );
	delete sObserver;
	sObserver = NULL;

	// Must do this after removing observer, otherwise
	// infinite loops notifying and closing.
	gParcelMgr->deselectLand();

	// Might have been showing owned objects
	gSelectMgr->unhighlightAll();

	// Save which panel we had open
	sLastTab = mTabLand->getCurrentPanelIndex();

	destroy();
}


LLFloaterLand::LLFloaterLand()
:	LLFloater("floaterland", "FloaterLandRect5", "About Land")
{


	std::map<LLString, LLCallbackMap> factory_map;
	factory_map["land_general_panel"] = LLCallbackMap(createPanelLandGeneral, this);

	
	factory_map["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this);
	factory_map["land_objects_panel"] = LLCallbackMap(createPanelLandObjects, this);
	factory_map["land_options_panel"] = LLCallbackMap(createPanelLandOptions, this);
	factory_map["land_media_panel"] =	LLCallbackMap(createPanelLandMedia, this);
	factory_map["land_access_panel"] =	LLCallbackMap(createPanelLandAccess, this);
	factory_map["land_ban_panel"] =		LLCallbackMap(createPanelLandBan, this);

	gUICtrlFactory->buildFloater(this, "floater_about_land.xml", &factory_map);


	LLTabContainerCommon* tab = LLUICtrlFactory::getTabContainerByName(this, "landtab");

	mTabLand = (LLTabContainer*) tab;


	if (tab)
	{
		tab->selectTab(sLastTab);
	}
}


// virtual
LLFloaterLand::~LLFloaterLand()
{
	sInstance = NULL;
}


// public
void LLFloaterLand::refresh()
{
	mPanelGeneral->refresh();
	mPanelObjects->refresh();
	mPanelOptions->refresh();
	mPanelMedia->refresh();
	mPanelAccess->refresh();
	mPanelBan->refresh();
}



void* LLFloaterLand::createPanelLandGeneral(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelGeneral = new LLPanelLandGeneral();
	return self->mPanelGeneral;
}

// static


void* LLFloaterLand::createPanelLandCovenant(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelCovenant = new LLPanelLandCovenant();
	return self->mPanelCovenant;
}


// static
void* LLFloaterLand::createPanelLandObjects(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelObjects = new LLPanelLandObjects();
	return self->mPanelObjects;
}

// static
void* LLFloaterLand::createPanelLandOptions(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelOptions = new LLPanelLandOptions();
	return self->mPanelOptions;
}

// static
void* LLFloaterLand::createPanelLandMedia(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelMedia = new LLPanelLandMedia();
	return self->mPanelMedia;
}

// static
void* LLFloaterLand::createPanelLandAccess(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelAccess = new LLPanelLandAccess();
	return self->mPanelAccess;
}

// static
void* LLFloaterLand::createPanelLandBan(void* data)
{
	LLFloaterLand* self = (LLFloaterLand*)data;
	self->mPanelBan = new LLPanelLandBan();
	return self->mPanelBan;
}


//---------------------------------------------------------------------------
// LLPanelLandGeneral
//---------------------------------------------------------------------------


LLPanelLandGeneral::LLPanelLandGeneral()
:	LLPanel("land_general_panel"),
	mUncheckedSell(FALSE)
{
}

BOOL LLPanelLandGeneral::postBuild()
{

	mEditName = LLUICtrlFactory::getLineEditorByName(this, "Name");
	mEditName->setCommitCallback(onCommitAny);	
	childSetPrevalidate("Name", LLLineEditor::prevalidatePrintableNotPipe);
	childSetUserData("Name", this);


	mEditDesc = LLUICtrlFactory::getLineEditorByName(this, "Description");
	mEditDesc->setCommitCallback(onCommitAny);	
	childSetPrevalidate("Description", LLLineEditor::prevalidatePrintableNotPipe);
	childSetUserData("Description", this);

	
	mTextSalePending = LLUICtrlFactory::getTextBoxByName(this, "SalePending");
	mTextOwnerLabel = LLUICtrlFactory::getTextBoxByName(this, "Owner:");
	mTextOwner = LLUICtrlFactory::getTextBoxByName(this, "OwnerText");

	
	mBtnProfile = LLUICtrlFactory::getButtonByName(this, "Profile...");
	mBtnProfile->setClickedCallback(onClickProfile, this);

	
	mTextGroupLabel = LLUICtrlFactory::getTextBoxByName(this, "Group:");
	mTextGroup = LLUICtrlFactory::getTextBoxByName(this, "GroupText");

	
	mBtnSetGroup = LLUICtrlFactory::getButtonByName(this, "Set...");
	mBtnSetGroup->setClickedCallback(onClickSetGroup, this);

	

	mCheckDeedToGroup = LLUICtrlFactory::getCheckBoxByName(this, "check deed");
	childSetCommitCallback("check deed", onCommitAny, this);

	
	mBtnDeedToGroup = LLUICtrlFactory::getButtonByName(this, "Deed...");
	mBtnDeedToGroup->setClickedCallback(onClickDeed, this);

	
	mCheckContributeWithDeed = LLUICtrlFactory::getCheckBoxByName(this, "check contib");
	childSetCommitCallback("check contib", onCommitAny, this);

	
	
	mSaleInfoNotForSale = LLUICtrlFactory::getTextBoxByName(this, "Not for sale.");
	
	mSaleInfoForSale1 = LLUICtrlFactory::getTextBoxByName(this, "For Sale: Price L$[PRICE].");

	
	mBtnSellLand = LLUICtrlFactory::getButtonByName(this, "Sell Land...");
	mBtnSellLand->setClickedCallback(onClickSellLand, this);
	
	mSaleInfoForSale2 = LLUICtrlFactory::getTextBoxByName(this, "For sale to");
	
	mSaleInfoForSaleObjects = LLUICtrlFactory::getTextBoxByName(this, "Sell with landowners objects in parcel.");
	
	mSaleInfoForSaleNoObjects = LLUICtrlFactory::getTextBoxByName(this, "Selling with no objects in parcel.");

	
	mBtnStopSellLand = LLUICtrlFactory::getButtonByName(this, "Cancel Land Sale");
	mBtnStopSellLand->setClickedCallback(onClickStopSellLand, this);

	
	mTextClaimDateLabel = LLUICtrlFactory::getTextBoxByName(this, "Claimed:");
	mTextClaimDate = LLUICtrlFactory::getTextBoxByName(this, "DateClaimText");

	
	mTextPriceLabel = LLUICtrlFactory::getTextBoxByName(this, "PriceLabel");
	mTextPrice = LLUICtrlFactory::getTextBoxByName(this, "PriceText");

	
	mTextDwell = LLUICtrlFactory::getTextBoxByName(this, "DwellText");

	
	mBtnBuyLand = LLUICtrlFactory::getButtonByName(this, "Buy Land...");
	mBtnBuyLand->setClickedCallback(onClickBuyLand, (void*)&BUY_PERSONAL_LAND);
	
	mBtnBuyGroupLand = LLUICtrlFactory::getButtonByName(this, "Buy For Group...");
	mBtnBuyGroupLand->setClickedCallback(onClickBuyLand, (void*)&BUY_GROUP_LAND);
	
	
	static BOOL deselect_when_done = FALSE;
	mBtnBuyPass = LLUICtrlFactory::getButtonByName(this, "Buy Pass...");
	mBtnBuyPass->setClickedCallback(onClickBuyPass, &deselect_when_done);

	mBtnReleaseLand = LLUICtrlFactory::getButtonByName(this, "Abandon Land...");
	mBtnReleaseLand->setClickedCallback(onClickRelease, NULL);

	mBtnReclaimLand = LLUICtrlFactory::getButtonByName(this, "Reclaim Land...");
	mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL);
	
	mBtnStartAuction = LLUICtrlFactory::getButtonByName(this, "Linden Sale...");
	mBtnStartAuction->setClickedCallback(onClickStartAuction, NULL);

	return TRUE;
}


// virtual
LLPanelLandGeneral::~LLPanelLandGeneral()
{ }


// public
void LLPanelLandGeneral::refresh()
{
	mBtnStartAuction->setVisible(gAgent.isGodlike());

	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	bool region_owner = false;
	LLViewerRegion* regionp = gParcelMgr->getSelectionRegion();
	if(regionp && (regionp->getOwner() == gAgent.getID()))
	{
		region_owner = true;
		mBtnReleaseLand->setVisible(FALSE);
		mBtnReclaimLand->setVisible(TRUE);
	}
	else
	{
		mBtnReleaseLand->setVisible(TRUE);
		mBtnReclaimLand->setVisible(FALSE);
	}
	if (!parcel)
	{
		// nothing selected, disable panel
		mEditName->setEnabled(FALSE);
		mEditName->setText("");

		mEditDesc->setEnabled(FALSE);
		mEditDesc->setText("");

		mTextSalePending->setText("");
		mTextSalePending->setEnabled(FALSE);

		mBtnDeedToGroup->setEnabled(FALSE);
		mBtnSetGroup->setEnabled(FALSE);
		mBtnStartAuction->setEnabled(FALSE);

		mCheckDeedToGroup	->set(FALSE);
		mCheckDeedToGroup	->setEnabled(FALSE);
		mCheckContributeWithDeed->set(FALSE);
		mCheckContributeWithDeed->setEnabled(FALSE);

		mTextOwner->setText("");
		mBtnProfile->setLabelSelected("Profile...");
		mBtnProfile->setLabelUnselected("Profile...");
		mBtnProfile->setEnabled(FALSE);

		mTextClaimDate->setText("");
		mTextGroup->setText("");
		mTextPrice->setText("");

		mSaleInfoForSale1->setVisible(FALSE);
		mSaleInfoForSale2->setVisible(FALSE);
		mSaleInfoForSaleObjects->setVisible(FALSE);
		mSaleInfoForSaleNoObjects->setVisible(FALSE);
		mSaleInfoNotForSale->setVisible(FALSE);
		mBtnSellLand->setVisible(FALSE);
		mBtnStopSellLand->setVisible(FALSE);

		mTextPriceLabel->setText(NO_PRICE);
		mTextDwell->setText("");

		mBtnBuyLand->setEnabled(FALSE);
		mBtnBuyGroupLand->setEnabled(FALSE);
		mBtnReleaseLand->setEnabled(FALSE);
		mBtnReclaimLand->setEnabled(FALSE);
		mBtnBuyPass->setEnabled(FALSE);
	}
	else
	{
		// something selected, hooray!
		BOOL is_leased = (LLParcel::OS_LEASED == parcel->getOwnershipStatus());
		BOOL region_xfer = FALSE;
		if(regionp
		   && !(regionp->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL))
		{
			region_xfer = TRUE;
		}

		// estate owner/manager cannot edit other parts of the parcel
		BOOL estate_manager_sellable = !parcel->getAuctionID()
										&& gAgent.canManageEstate()
										// estate manager/owner can only sell parcels owned by estate owner
										&& regionp
										&& (parcel->getOwnerID() == regionp->getOwner());
		BOOL owner_sellable = region_xfer && !parcel->getAuctionID()
							&& LLViewerParcelMgr::isParcelModifiableByAgent(
										parcel, GP_LAND_SET_SALE_INFO);
		BOOL can_be_sold = owner_sellable || estate_manager_sellable;

		const LLUUID &owner_id = parcel->getOwnerID();
		BOOL is_public = parcel->isPublic();

		// Is it owned?
		if (is_public)
		{
			mTextSalePending->setText("");
			mTextSalePending->setEnabled(FALSE);
			mTextOwner->setText("(public)");
			mTextOwner->setEnabled(FALSE);
			mBtnProfile->setEnabled(FALSE);
			mTextClaimDate->setText("");
			mTextClaimDate->setEnabled(FALSE);
			mTextGroup->setText("(none)");
			mTextGroup->setEnabled(FALSE);
			mBtnStartAuction->setEnabled(FALSE);
		}
		else
		{
			if(!is_leased && (owner_id == gAgent.getID()))
			{
				mTextSalePending->setText(NEED_TIER_TO_MODIFY_STRING);
				mTextSalePending->setEnabled(TRUE);
			}
			else if(parcel->getAuctionID())
			{
				char auction_str[MAX_STRING];
				sprintf(auction_str, "Auction ID: %u", parcel->getAuctionID());
				mTextSalePending->setText(auction_str);
				mTextSalePending->setEnabled(TRUE);
			}
			else
			{
				// not the owner, or it is leased
				mTextSalePending->setText("");
				mTextSalePending->setEnabled(FALSE);
			}
			//refreshNames();
			mTextOwner->setEnabled(TRUE);

			// We support both group and personal profiles
			mBtnProfile->setEnabled(TRUE);

			if (parcel->getGroupID().isNull())
			{
				// Not group owned, so "Profile"
				mBtnProfile->setLabelSelected("Profile...");
				mBtnProfile->setLabelUnselected("Profile...");

				mTextGroup->setText("(none)");
				mTextGroup->setEnabled(FALSE);
			}
			else
			{
				// Group owned, so "Info"
				mBtnProfile->setLabelSelected("Info...");
				mBtnProfile->setLabelUnselected("Info...");

				//mTextGroup->setText("HIPPOS!");//parcel->getGroupName());
				mTextGroup->setEnabled(TRUE);
			}

			// Display claim date
			time_t claim_date = parcel->getClaimDate();
			char time_buf[TIME_STR_LENGTH];
			mTextClaimDate->setText(formatted_time(claim_date, time_buf));
			mTextClaimDate->setEnabled(is_leased);

			BOOL enable_auction = (gAgent.getGodLevel() >= GOD_LIAISON)
								  && (owner_id == GOVERNOR_LINDEN_ID)
								  && (parcel->getAuctionID() == 0);
			mBtnStartAuction->setEnabled(enable_auction);
		}

		// Display options
		BOOL can_edit_identity = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_IDENTITY);
		mEditName->setEnabled(can_edit_identity);
		mEditDesc->setEnabled(can_edit_identity);

		BOOL can_edit_agent_only = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_NO_POWERS);
		mBtnSetGroup->setEnabled(can_edit_agent_only && !parcel->getIsGroupOwned());

		const LLUUID& group_id = parcel->getGroupID();

		// Can only allow deeding if you own it and it's got a group.
		BOOL enable_deed = (owner_id == gAgent.getID()
							&& group_id.notNull()
							&& gAgent.isInGroup(group_id));
		// You don't need special powers to allow your object to
		// be deeded to the group.
		mCheckDeedToGroup->setEnabled(enable_deed);
		mCheckDeedToGroup->set( parcel->getAllowDeedToGroup() );
		mCheckContributeWithDeed->setEnabled(enable_deed && parcel->getAllowDeedToGroup());
		mCheckContributeWithDeed->set(parcel->getContributeWithDeed());

		// Actually doing the deeding requires you to have GP_LAND_DEED
		// powers in the group.
		BOOL can_deed = gAgent.hasPowerInGroup(group_id, GP_LAND_DEED);
		mBtnDeedToGroup->setEnabled(   parcel->getAllowDeedToGroup()
									&& group_id.notNull()
									&& can_deed
									&& !parcel->getIsGroupOwned()
									);

		mEditName->setText( parcel->getName() );
		mEditDesc->setText( parcel->getDesc() );

		BOOL for_sale = parcel->getForSale();
				
		mBtnSellLand->setVisible(FALSE);
		mBtnStopSellLand->setVisible(FALSE);
		
		if (for_sale)
		{
			mSaleInfoForSale1->setVisible(TRUE);
			mSaleInfoForSale2->setVisible(TRUE);
			if (parcel->getSellWithObjects())
			{
				mSaleInfoForSaleObjects->setVisible(TRUE);
				mSaleInfoForSaleNoObjects->setVisible(FALSE);
			}
			else
			{
				mSaleInfoForSaleObjects->setVisible(FALSE);
				mSaleInfoForSaleNoObjects->setVisible(TRUE);
			}
			mSaleInfoNotForSale->setVisible(FALSE);
			mSaleInfoForSale1->setTextArg("[PRICE]", llformat("%d", parcel->getSalePrice()));
			if (can_be_sold)
			{
				mBtnStopSellLand->setVisible(TRUE);
			}
		}
		else
		{
			mSaleInfoForSale1->setVisible(FALSE);
			mSaleInfoForSale2->setVisible(FALSE);
			mSaleInfoForSaleObjects->setVisible(FALSE);
			mSaleInfoForSaleNoObjects->setVisible(FALSE);
			mSaleInfoNotForSale->setVisible(TRUE);
			if (can_be_sold)
			{
				mBtnSellLand->setVisible(TRUE);
			}
		}
		
		refreshNames();

		mBtnBuyLand->setEnabled(
			gParcelMgr->canAgentBuyParcel(parcel, false));
		mBtnBuyGroupLand->setEnabled(
			gParcelMgr->canAgentBuyParcel(parcel, true));

		// show pricing information
		char price[64];	
		const char* label = NULL;
		S32 area;
		S32 claim_price;
		S32 rent_price;
		F32 dwell;
		gParcelMgr->getDisplayInfo(&area,
								   &claim_price,
								   &rent_price,
								   &for_sale,
								   &dwell);

		// Area
		sprintf(price, "%d sq. m.", area);
		label = AREA;
		
		mTextPriceLabel->setText(label);
		mTextPrice->setText(price);
		
		sprintf(price, "%.0f", dwell);
		mTextDwell->setText(price);

		if(region_owner)
		{
			mBtnReclaimLand->setEnabled(
				!is_public && (parcel->getOwnerID() != gAgent.getID()));
		}
		else
		{
			BOOL is_owner_release = LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_RELEASE);
			BOOL is_manager_release = (gAgent.canManageEstate() && 
									regionp && 
									(parcel->getOwnerID() != regionp->getOwner()));
			BOOL can_release = is_owner_release || is_manager_release;
			mBtnReleaseLand->setEnabled( can_release );
		}

		BOOL use_pass = parcel->getParcelFlag(PF_USE_PASS_LIST) && !gParcelMgr->isCollisionBanned();;
		mBtnBuyPass->setEnabled(use_pass);
	}
}

// public
void LLPanelLandGeneral::refreshNames()
{
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		mTextOwner->setText("");
		return;
	}

	char buffer[MAX_STRING];
	if (parcel->getIsGroupOwned())
	{
		buffer[0] = '\0';
		strcat(buffer, "(Group Owned)");
	}
	else
	{
		// Figure out the owner's name
		char owner_first[MAX_STRING];
		char owner_last[MAX_STRING];
		gCacheName->getName(parcel->getOwnerID(), owner_first, owner_last);
		sprintf(buffer, "%s %s", owner_first, owner_last);
	}

	if(LLParcel::OS_LEASE_PENDING == parcel->getOwnershipStatus())
	{
		strcat(buffer, " (Sale Pending)");
	}
	mTextOwner->setText(buffer);

	if(!parcel->getGroupID().isNull())
	{
		gCacheName->getGroupName(parcel->getGroupID(), buffer);
	}
	else
	{
		buffer[0] = '\0';
	}
	mTextGroup->setText(buffer);

	const LLUUID& auth_buyer_id = parcel->getAuthorizedBuyerID();
	if(auth_buyer_id.notNull())
	{
		LLString name;
		char firstname[MAX_STRING];
		char lastname[MAX_STRING];
		gCacheName->getName(auth_buyer_id, firstname, lastname);
		name.assign(firstname);
		name.append(" ");
		name.append(lastname);

		mSaleInfoForSale2->setTextArg("[BUYER]", name);
	}
	else if(parcel->getReservedForNewbie())
	{
		mSaleInfoForSale2->setTextArg("[BUYER]", childGetText("new users only"));
	}
	else
	{
		mSaleInfoForSale2->setTextArg("[BUYER]", childGetText("anyone"));
	}
}


// virtual
void LLPanelLandGeneral::draw()
{
	refreshNames();
	LLPanel::draw();
}

// static
void LLPanelLandGeneral::onClickSetGroup(void* userdata)
{
	LLFloaterGroups* fg;
	fg = LLFloaterGroups::show(gAgent.getID(), LLFloaterGroups::CHOOSE_ONE);
	fg->setOkCallback( cbGroupID, userdata );
}

// static
void LLPanelLandGeneral::onClickProfile(void* data)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	if (parcel->getIsGroupOwned())
	{
		const LLUUID& group_id = parcel->getGroupID();
		LLFloaterGroupInfo::showFromUUID(group_id);
	}
	else
	{
		const LLUUID& avatar_id = parcel->getOwnerID();
		LLFloaterAvatarInfo::showFromObject(avatar_id);
	}
}

// static
void LLPanelLandGeneral::cbGroupID(LLUUID group_id, void* userdata)
{
	LLPanelLandGeneral* self = (LLPanelLandGeneral*)userdata;
	self->setGroup(group_id);
}

// public
void LLPanelLandGeneral::setGroup(const LLUUID& group_id)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	// Set parcel properties and send message
	parcel->setGroupID(group_id);
	//parcel->setGroupName(group_name);
	//mTextGroup->setText(group_name);

	// Send update
	gParcelMgr->sendParcelPropertiesUpdate(parcel, LLFloaterLand::sRequestReplyOnUpdate);

	// Update UI
	refresh();
}

// static
void LLPanelLandGeneral::onClickBuyLand(void* data)
{
	BOOL* for_group = (BOOL*)data;
	gParcelMgr->startBuyLand(*for_group);
}

BOOL LLPanelLandGeneral::enableDeedToGroup(void*)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	return (parcel != NULL) && (parcel->getParcelFlag(PF_ALLOW_DEED_TO_GROUP));
}

// static
void LLPanelLandGeneral::onClickDeed(void*)
{
	//LLParcel* parcel = gParcelMgr->getSelectedParcel();
	//if (parcel)
	//{
	gParcelMgr->startDeedLandToGroup();
	//}
}

// static
void LLPanelLandGeneral::onClickRelease(void*)
{
	gParcelMgr->startReleaseLand();
}

// static
void LLPanelLandGeneral::onClickReclaim(void*)
{
	lldebugs << "LLPanelLandGeneral::onClickReclaim()" << llendl;
	gParcelMgr->reclaimParcel();
}

// static
BOOL LLPanelLandGeneral::enableBuyPass(void*)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	return (parcel != NULL) && (parcel->getParcelFlag(PF_USE_PASS_LIST) && !gParcelMgr->isCollisionBanned());
}


// static
void LLPanelLandGeneral::onClickBuyPass(void* deselect_when_done)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	S32 pass_price = parcel->getPassPrice();
	const char* parcel_name = parcel->getName();
	F32 pass_hours = parcel->getPassHours();

	char cost[256], time[256];
	sprintf(cost, "%d", pass_price);
	sprintf(time, "%.2f", pass_hours);

	LLStringBase<char>::format_map_t args;
	args["[COST]"] = cost;
	args["[PARCEL_NAME]"] = parcel_name;
	args["[TIME]"] = time;
	
	gViewerWindow->alertXml("LandBuyPass", args, cbBuyPass, deselect_when_done);
}

// static
void LLPanelLandGeneral::onClickStartAuction(void*)
{
	LLParcel* parcelp = gParcelMgr->getSelectedParcel();
	if(parcelp)
	{
		if(parcelp->getForSale())
		{
			gViewerWindow->alertXml("CannotStartAuctionAlreadForSale");
		}
		else
		{
			LLFloaterAuction::show();
		}
	}
}

// static
void LLPanelLandGeneral::cbBuyPass(S32 option, void* data)
{
	BOOL deselect_when_done = (BOOL)(intptr_t)data;

	if (0 == option)
	{
		// User clicked OK
		gParcelMgr->buyPass();
	}

	if (deselect_when_done)
	{
		gParcelMgr->deselectLand();
	}
}


// static
void LLPanelLandGeneral::onCommitAny(LLUICtrl *ctrl, void *userdata)
{
	LLPanelLandGeneral *panelp = (LLPanelLandGeneral *)userdata;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	std::string name		= panelp->mEditName->getText();
	std::string desc		= panelp->mEditDesc->getText();

	// Valid data from UI

	// Stuff data into selected parcel
	parcel->setName(name.c_str());
	parcel->setDesc(desc.c_str());

	BOOL allow_deed_to_group= panelp->mCheckDeedToGroup->get();
	BOOL contribute_with_deed = panelp->mCheckContributeWithDeed->get();

	parcel->setParcelFlag(PF_ALLOW_DEED_TO_GROUP, allow_deed_to_group);
	parcel->setContributeWithDeed(contribute_with_deed);

	// Send update to server
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );

	// Might have changed properties, so let's redraw!
	panelp->refresh();
}

// static
void LLPanelLandGeneral::onClickSellLand(void* data)
{
	gParcelMgr->startSellLand();
}

// static
void LLPanelLandGeneral::onClickStopSellLand(void* data)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();

	parcel->setParcelFlag(PF_FOR_SALE, FALSE);
	parcel->setSalePrice(0);
	parcel->setAuthorizedBuyerID(LLUUID::null);

	gParcelMgr->sendParcelPropertiesUpdate(parcel, LLFloaterLand::sRequestReplyOnUpdate);
}

//---------------------------------------------------------------------------
// LLPanelLandObjects
//---------------------------------------------------------------------------
LLPanelLandObjects::LLPanelLandObjects()
:	LLPanel("land_objects_panel")
{
}



BOOL LLPanelLandObjects::postBuild()
{
	
	mFirstReply = TRUE;
	mParcelObjectBonus = LLUICtrlFactory::getTextBoxByName(this, "Simulator Primitive Bonus Factor: 1.00");
	
	mSWTotalObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Simulator primitive usage:");
	mSWTotalObjects = LLUICtrlFactory::getTextBoxByName(this, "0 out of 0 available");
	
	mObjectContributionLabel = LLUICtrlFactory::getTextBoxByName(this, "Primitives parcel supports:");
	mObjectContribution = LLUICtrlFactory::getTextBoxByName(this, "object_contrib_text");

	
	mTotalObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Primitives on parcel:");
	mTotalObjects = LLUICtrlFactory::getTextBoxByName(this, "total_objects_text");

	
	mOwnerObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Owned by parcel owner:");
	mOwnerObjects = LLUICtrlFactory::getTextBoxByName(this, "owner_objects_text");

	
	mBtnShowOwnerObjects = LLUICtrlFactory::getButtonByName(this, "ShowOwner");
	mBtnShowOwnerObjects->setClickedCallback(onClickShowOwnerObjects, this);

	mBtnReturnOwnerObjects = LLUICtrlFactory::getButtonByName(this, "ReturnOwner...");
	mBtnReturnOwnerObjects->setClickedCallback(onClickReturnOwnerObjects, this);

	
	mGroupObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Set to group:");
	mGroupObjects = LLUICtrlFactory::getTextBoxByName(this, "group_objects_text");

	
	mBtnShowGroupObjects = LLUICtrlFactory::getButtonByName(this, "ShowGroup");
	mBtnShowGroupObjects->setClickedCallback(onClickShowGroupObjects, this);

	mBtnReturnGroupObjects = LLUICtrlFactory::getButtonByName(this, "ReturnGroup...");
	mBtnReturnGroupObjects->setClickedCallback(onClickReturnGroupObjects, this);

	
	mOtherObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Owned by others:");
	mOtherObjects = LLUICtrlFactory::getTextBoxByName(this, "other_objects_text");
	
	mBtnShowOtherObjects = LLUICtrlFactory::getButtonByName(this, "ShowOther");
	mBtnShowOtherObjects->setClickedCallback(onClickShowOtherObjects, this);

	mBtnReturnOtherObjects = LLUICtrlFactory::getButtonByName(this, "ReturnOther...");
	mBtnReturnOtherObjects->setClickedCallback(onClickReturnOtherObjects, this);

	mSelectedObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Selected / sat upon:");
	mSelectedObjects = LLUICtrlFactory::getTextBoxByName(this, "selected_objects_text");
	
	mCleanOtherObjectsLabel = LLUICtrlFactory::getTextBoxByName(this, "Autoreturn other resident's objects (minutes, 0 for off):");

	mCleanOtherObjectsTime = LLUICtrlFactory::getLineEditorByName(this, "clean other time");
	mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus);	
	childSetPrevalidate("clean other time", LLLineEditor::prevalidatePrintableNotPipe);
	childSetUserData("clean other time", this);
	
	mOwnerListText = LLUICtrlFactory::getTextBoxByName(this, "Object Owners:");

	
	mBtnRefresh = LLUICtrlFactory::getButtonByName(this, "Refresh List");
	mBtnRefresh->setClickedCallback(onClickRefresh, this);

	
	mBtnReturnOwnerList = LLUICtrlFactory::getButtonByName(this, "Return objects...");
	mBtnReturnOwnerList->setClickedCallback(onClickReturnOwnerList, this);

	LLUUID image_id;

	image_id.set( gViewerArt.getString("icon_avatar_online.tga") );
	mIconAvatarOnline = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
	
	image_id.set( gViewerArt.getString("icon_avatar_offline.tga") );
	mIconAvatarOffline = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);

	image_id.set( gViewerArt.getString("icon_group.tga") );
	mIconGroup = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);

	mCurrentSortColumn = 3; // sort by number of objects by default.
	mCurrentSortAscending = FALSE;

	// Column widths for various columns
	const S32 SORTER_WIDTH		= 308;
	const S32 DESC_BTN_WIDTH	= 64;
	const S32 ICON_WIDTH		= 24;
	mColWidth[0] = ICON_WIDTH;	// type icon
	mColWidth[1] = -1;	// hidden type code
	mColWidth[2] = SORTER_WIDTH - mColWidth[0] - DESC_BTN_WIDTH;
	mColWidth[3] = DESC_BTN_WIDTH;			// info
	mColWidth[4] = -1;						// type data 1
	mColWidth[5] = -1;
	mColWidth[6] = -1;	// type data 3
	mColWidth[7] = -1;	// type data 4
	mColWidth[8] = -1;	// type data 5

	// Adjust description for other widths
	S32 sum = 0;
	for (S32 i = 0; i < 8; i++)
	{
		if (mColWidth[i] > 0)
		{
			sum += mColWidth[i];
		}
	}
	mColWidth[8] = mRect.getWidth() - HPAD - sum - HPAD - HPAD;

	mBtnType = LLUICtrlFactory::getButtonByName(this, "Type");
	mBtnType->setClickedCallback(onClickType, this);

	mBtnName = LLUICtrlFactory::getButtonByName(this, "Name");
	mBtnName->setClickedCallback(onClickName, this);

	mBtnDescription = LLUICtrlFactory::getButtonByName(this, "Count");
	mBtnDescription->setClickedCallback(onClickDesc, this);
	
	mOwnerList = LLUICtrlFactory::getNameListByName(this, "owner list");
	childSetCommitCallback("owner list", onCommitList, this);
	mOwnerList->setDoubleClickCallback(onDoubleClickOwner);

	return TRUE;
}




// virtual
LLPanelLandObjects::~LLPanelLandObjects()
{ }

// static
void LLPanelLandObjects::onDoubleClickOwner(void *userdata)
{
	LLPanelLandObjects *self = (LLPanelLandObjects *)userdata;

	LLScrollListItem* item = self->mOwnerList->getFirstSelected();
	if (item)
	{
		LLUUID owner_id = item->getUUID();
		// Look up the selected name, for future dialog box use.
		const LLScrollListCell* cell;
		cell = item->getColumn(1);
		if (!cell)
		{
			return;
		}
		// Is this a group?
		BOOL is_group = cell->getText() == OWNER_GROUP;
		if (is_group)
		{
			LLFloaterGroupInfo::showFromUUID(owner_id);
		}
		else
		{
			LLFloaterAvatarInfo::showFromDirectory(owner_id);
		}
	}
}

// public
void LLPanelLandObjects::refresh()
{
	LLParcel *parcel = gParcelMgr->getSelectedParcel();

	mBtnShowOwnerObjects->setEnabled(FALSE);
	mBtnShowGroupObjects->setEnabled(FALSE);
	mBtnShowOtherObjects->setEnabled(FALSE);
	mBtnReturnOwnerObjects->setEnabled(FALSE);
	mBtnReturnGroupObjects->setEnabled(FALSE);
	mBtnReturnOtherObjects->setEnabled(FALSE);
	mCleanOtherObjectsTime->setEnabled(FALSE);
	mBtnRefresh->			setEnabled(FALSE);
	mBtnReturnOwnerList->	setEnabled(FALSE);

	mSelectedOwners.clear();
	mOwnerList->deleteAllItems();
	mOwnerList->setEnabled(FALSE);

	if (!parcel)
	{
		mSWTotalObjects->setText("0 out of 0 available");
		mObjectContribution->setText("0");
		mTotalObjects->setText("0");
		mOwnerObjects->setText("0");
		mGroupObjects->setText("0");
		mOtherObjects->setText("0");
		mSelectedObjects->setText("0");
	}
	else
	{
		char count[MAX_STRING];
		S32 sw_max;
		S32 sw_total;
		S32 max;
		S32 total;
		S32 owned;
		S32 group;
		S32 other;
		S32 selected;
		F32 parcel_object_bonus;

		gParcelMgr->getPrimInfo(sw_max, sw_total, 
								  max, total, owned, group, other, selected,
								  parcel_object_bonus, mOtherTime);

		// Can't have more than region max tasks, regardless of parcel
		// object bonus factor.
		LLViewerRegion* region = gParcelMgr->getSelectionRegion();
		if (region)
		{
			S32 max_tasks_per_region = (S32)region->getMaxTasks();
			sw_max = llmin(sw_max, max_tasks_per_region);
			max = llmin(max, max_tasks_per_region);
		}

		if (parcel_object_bonus != 1.0f)
		{
			sprintf(count, "Region Object Bonus Factor: %.2f", 
					parcel_object_bonus);
			mParcelObjectBonus->setText(count);
		}
		else
		{
			mParcelObjectBonus->setText("");
		}

		if (sw_total > sw_max)
		{
			sprintf(count, "%d out of %d (%d will be deleted)", 
					sw_total, sw_max, sw_total - sw_max);
		}
		else
		{
			sprintf(count, "%d out of %d (%d available)", 
					sw_total, sw_max, sw_max - sw_total);
		}
		mSWTotalObjects->setText(count);

		sprintf(count, "%d", max);
		mObjectContribution->setText(count);

		sprintf(count, "%d", total);
		mTotalObjects->setText(count);

		sprintf(count, "%d", owned);
		mOwnerObjects->setText(count);

		sprintf(count, "%d", group);
		mGroupObjects->setText(count);

		sprintf(count, "%d", other);
		mOtherObjects->setText(count);

		sprintf(count, "%d", selected);
		mSelectedObjects->setText(count);

		sprintf(count, "%d", mOtherTime);
		mCleanOtherObjectsTime->setText(count);

		BOOL can_return_owned = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_RETURN_GROUP_OWNED);
		BOOL can_return_group_set = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_RETURN_GROUP_SET);
		BOOL can_return_other = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_RETURN_NON_GROUP);

		if (can_return_owned || can_return_group_set || can_return_other)
		{
			if (owned && can_return_owned)
			{
				mBtnShowOwnerObjects->setEnabled(TRUE);
				mBtnReturnOwnerObjects->setEnabled(TRUE);
			}
			if (group && can_return_group_set)
			{
				mBtnShowGroupObjects->setEnabled(TRUE);
				mBtnReturnGroupObjects->setEnabled(TRUE);
			}
			if (other && can_return_other)
			{
				mBtnShowOtherObjects->setEnabled(TRUE);
				mBtnReturnOtherObjects->setEnabled(TRUE);
			}

			mCleanOtherObjectsTime->setEnabled(TRUE);
			mBtnRefresh->setEnabled(TRUE);
		}
	}
}

// virtual
void LLPanelLandObjects::draw()
{
	LLPanel::draw();
}

void send_other_clean_time_message(S32 parcel_local_id, S32 other_clean_time)
{
	LLMessageSystem *msg = gMessageSystem;

	LLViewerRegion* region = gParcelMgr->getSelectionRegion();
	if (!region) return;

	msg->newMessageFast(_PREHASH_ParcelSetOtherCleanTime);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
	msg->nextBlockFast(_PREHASH_ParcelData);
	msg->addS32Fast(_PREHASH_LocalID, parcel_local_id);
	msg->addS32Fast(_PREHASH_OtherCleanTime, other_clean_time);

	msg->sendReliable(region->getHost());
}

void send_return_objects_message(S32 parcel_local_id, S32 return_type, 
								 uuid_list_t* owner_ids = NULL)
{
	LLMessageSystem *msg = gMessageSystem;

	LLViewerRegion* region = gParcelMgr->getSelectionRegion();
	if (!region) return;

	msg->newMessageFast(_PREHASH_ParcelReturnObjects);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID,	gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
	msg->nextBlockFast(_PREHASH_ParcelData);
	msg->addS32Fast(_PREHASH_LocalID, parcel_local_id);
	msg->addU32Fast(_PREHASH_ReturnType, (U32) return_type);

	// Dummy task id, not used
	msg->nextBlock("TaskIDs");
	msg->addUUID("TaskID", LLUUID::null);

	// Throw all return ids into the packet.
	// TODO: Check for too many ids.
	if (owner_ids)
	{
		uuid_list_t::iterator end = owner_ids->end();
		for (uuid_list_t::iterator it = owner_ids->begin();
			 it != end;
			 ++it)
		{
			msg->nextBlockFast(_PREHASH_OwnerIDs);
			msg->addUUIDFast(_PREHASH_OwnerID, (*it));
		}
	}
	else
	{
		msg->nextBlockFast(_PREHASH_OwnerIDs);
		msg->addUUIDFast(_PREHASH_OwnerID, LLUUID::null);
	}

	msg->sendReliable(region->getHost());
}

// static
void LLPanelLandObjects::callbackReturnOwnerObjects(S32 option, void* userdata)
{
	LLPanelLandObjects	*lop = (LLPanelLandObjects *)userdata;
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (0 == option)
	{
		if (parcel)
		{
			LLUUID owner_id = parcel->getOwnerID();	
			LLString::format_map_t args;
			if (owner_id == gAgentID)
			{
				LLNotifyBox::showXml("OwnedObjectsReturned");
			}
			else
			{
				char first[DB_FIRST_NAME_BUF_SIZE];
				char last[DB_LAST_NAME_BUF_SIZE];
				gCacheName->getName(owner_id, first, last);
				args["[FIRST]"] = first;
				args["[LAST]"] = last;
				LLNotifyBox::showXml("OtherObjectsReturned", args);
			}
			send_return_objects_message(parcel->getLocalID(), RT_OWNER);
		}
	}

	gSelectMgr->unhighlightAll();
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );
	lop->refresh();
}

// static
void LLPanelLandObjects::callbackReturnGroupObjects(S32 option, void* userdata)
{
	LLPanelLandObjects	*lop = (LLPanelLandObjects *)userdata;
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (0 == option)
	{
		if (parcel)
		{
			char group_name[MAX_STRING];
			gCacheName->getGroupName(parcel->getGroupID(), group_name);
			LLString::format_map_t args;
			args["[GROUPNAME]"] = group_name;
			LLNotifyBox::showXml("GroupObjectsReturned", args);
			send_return_objects_message(parcel->getLocalID(), RT_GROUP);
		}
	}
	gSelectMgr->unhighlightAll();
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );
	lop->refresh();
}

// static
void LLPanelLandObjects::callbackReturnOtherObjects(S32 option, void* userdata)
{
	LLPanelLandObjects	*lop = (LLPanelLandObjects *)userdata;
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (0 == option)
	{
		if (parcel)
		{
			LLNotifyBox::showXml("UnOwnedObjectsReturned");
			send_return_objects_message(parcel->getLocalID(), RT_OTHER);
		}
	}
	gSelectMgr->unhighlightAll();
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );
	lop->refresh();
}

// static
void LLPanelLandObjects::callbackReturnOwnerList(S32 option, void* userdata)
{
	LLPanelLandObjects	*self = (LLPanelLandObjects *)userdata;
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (0 == option)
	{
		if (parcel)
		{
			// Make sure we have something selected.
			uuid_list_t::iterator selected = self->mSelectedOwners.begin();
			if (selected != self->mSelectedOwners.end())
			{
				LLString::format_map_t args;
				if (self->mSelectedIsGroup)
				{
					args["[GROUPNAME]"] = self->mSelectedName;
					LLNotifyBox::showXml("GroupObjectsReturned", args);
				}
				else
				{
					// XUI:translate NAME -> FIRST LAST
					args["[NAME]"] = self->mSelectedName;
					LLNotifyBox::showXml("OtherObjectsReturned2", args);
				}

				send_return_objects_message(parcel->getLocalID(), RT_LIST, &(self->mSelectedOwners));
			}
		}
	}
	gSelectMgr->unhighlightAll();
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );
	self->refresh();
}


// static
void LLPanelLandObjects::onClickReturnOwnerList(void* userdata)
{
	LLPanelLandObjects	*self = (LLPanelLandObjects *)userdata;

	S32 sw_max, sw_total;
	S32 max, total;
	S32 owned, group, other, selected;
	F32 parcel_object_bonus;
	S32 other_time;

	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);

	LLParcel* parcelp = gParcelMgr->getSelectedParcel();
	if (!parcelp) return;

	// Make sure we have something selected.
	if (self->mSelectedOwners.empty())
	{
		return;
	}
	//uuid_list_t::iterator selected_itr = self->mSelectedOwners.begin();
	//if (selected_itr == self->mSelectedOwners.end()) return;

	send_parcel_select_objects(parcelp->getLocalID(), RT_LIST, &(self->mSelectedOwners));

	LLStringBase<char>::format_map_t args;
	args["[NAME]"] = self->mSelectedName;
	args["[N]"] = llformat("%d",self->mSelectedCount);
	if (self->mSelectedIsGroup)
	{
		gViewerWindow->alertXml("ReturnObjectsDeededToGroup", args, callbackReturnOwnerList, userdata);	
	}
	else 
	{
		gViewerWindow->alertXml("ReturnObjectsOwnedByUser", args, callbackReturnOwnerList, userdata);	
	}
}


// static
void LLPanelLandObjects::onClickRefresh(void* userdata)
{
	LLPanelLandObjects *self = (LLPanelLandObjects*)userdata;

	LLMessageSystem *msg = gMessageSystem;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	LLViewerRegion* region = gParcelMgr->getSelectionRegion();
	if (!region) return;

	// ready the list for results
	self->mOwnerList->deleteAllItems();
	self->mOwnerList->addSimpleItem("Searching...");
	self->mOwnerList->setEnabled(FALSE);
	self->mFirstReply = TRUE;

	// send the message
	msg->newMessageFast(_PREHASH_ParcelObjectOwnersRequest);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	msg->nextBlockFast(_PREHASH_ParcelData);
	msg->addS32Fast(_PREHASH_LocalID, parcel->getLocalID());

	msg->sendReliable(region->getHost());
}

// static
void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, void **)
{
	LLPanelLandObjects* self = LLFloaterLand::getCurrentPanelLandObjects();

	const LLFontGL* FONT = LLFontGL::sSansSerif;

	// Extract all of the owners.
	S32 rows = msg->getNumberOfBlocksFast(_PREHASH_Data);
	//uuid_list_t return_ids;
	LLUUID	owner_id;
	BOOL	is_group_owned;
	S32		object_count;
	BOOL	is_online;
	char object_count_str[MAX_STRING];
	//BOOL b_need_refresh = FALSE;

	// If we were waiting for the first reply, clear the "Searching..." text.
	if (self->mFirstReply)
	{
		self->mOwnerList->deleteAllItems();
		self->mFirstReply = FALSE;
	}

	for(S32 i = 0; i < rows; ++i)
	{
		msg->getUUIDFast(_PREHASH_Data, _PREHASH_OwnerID,		owner_id,		i);
		msg->getBOOLFast(_PREHASH_Data, _PREHASH_IsGroupOwned,	is_group_owned,	i);
		msg->getS32Fast (_PREHASH_Data, _PREHASH_Count,			object_count,	i);
		msg->getBOOLFast(_PREHASH_Data, _PREHASH_OnlineStatus,	is_online,		i);

		if (owner_id.isNull())
		{
			continue;
		}

		LLScrollListItem *row = new LLScrollListItem( TRUE, NULL, owner_id);
		if (is_group_owned)
		{
			row->addColumn(self->mIconGroup, self->mColWidth[0]);
			row->addColumn(OWNER_GROUP, FONT, self->mColWidth[1]);
		}
		else if (is_online)
		{
			row->addColumn(self->mIconAvatarOnline, self->mColWidth[0]);
			row->addColumn(OWNER_ONLINE, FONT, self->mColWidth[1]);
		}
		else  // offline
		{
			row->addColumn(self->mIconAvatarOffline, self->mColWidth[0]);
			row->addColumn(OWNER_OFFLINE, FONT, self->mColWidth[1]);
		}
		// Placeholder for name.
		row->addColumn("", FONT, self->mColWidth[2]);

		sprintf(object_count_str, "%d", object_count);
		row->addColumn(object_count_str, FONT, self->mColWidth[3]);

		if (is_group_owned)
		{
			self->mOwnerList->addGroupNameItem(row, ADD_BOTTOM);
		}
		else
		{
			self->mOwnerList->addNameItem(row, ADD_BOTTOM);
		}

		lldebugs << "object owner " << owner_id << " (" << (is_group_owned ? "group" : "agent")
				<< ") owns " << object_count << " objects." << llendl;
	}
	self->mOwnerList->sortByColumn(self->mCurrentSortColumn, self->mCurrentSortAscending);

	// check for no results
	if (0 == self->mOwnerList->getItemCount())
	{
		self->mOwnerList->addSimpleItem("None found.");
	}
	else
	{
		self->mOwnerList->setEnabled(TRUE);
	}
}

void LLPanelLandObjects::sortBtnCore(S32 column)
{
	if (column == (S32)mCurrentSortColumn)  // is this already our sorted column?
	{
		mCurrentSortAscending = !mCurrentSortAscending;
	}
	else  // default to ascending first time a column is clicked
	{
		mCurrentSortColumn = column;
		mCurrentSortAscending = TRUE;
	}

	mOwnerList->sortByColumn(column, mCurrentSortAscending);
}

// static
void LLPanelLandObjects::onCommitList(LLUICtrl* ctrl, void* data)
{
	LLPanelLandObjects* self = (LLPanelLandObjects*)data;

	if (FALSE == self->mOwnerList->getCanSelect())
	{
		return;
	}
	LLScrollListItem *item = self->mOwnerList->getFirstSelected();
	if (item)
	{
		// Look up the selected name, for future dialog box use.
		const LLScrollListCell* cell;
		cell = item->getColumn(1);
		if (!cell)
		{
			return;
		}
		// Is this a group?
		self->mSelectedIsGroup = cell->getText() == OWNER_GROUP;
		cell = item->getColumn(2);
		self->mSelectedName = cell->getText();
		cell = item->getColumn(3);
		self->mSelectedCount = atoi(cell->getText().c_str());

		// Set the selection, and enable the return button.
		self->mSelectedOwners.clear();
		self->mSelectedOwners.insert(item->getUUID());
		self->mBtnReturnOwnerList->setEnabled(TRUE);

		// Highlight this user's objects
		clickShowCore(RT_LIST, &(self->mSelectedOwners));
	}
}

// static
void LLPanelLandObjects::onClickType(void* userdata)
{
	// Sort on hidden type column
	LLPanelLandObjects* self = (LLPanelLandObjects*)userdata;
	self->sortBtnCore(1);
}

// static
void LLPanelLandObjects::onClickDesc(void* userdata)
{
	LLPanelLandObjects* self = (LLPanelLandObjects*)userdata;
	self->sortBtnCore(3);
}

// static
void LLPanelLandObjects::onClickName(void* userdata)
{
	LLPanelLandObjects* self = (LLPanelLandObjects*)userdata;
	self->sortBtnCore(2);
}

// static
void LLPanelLandObjects::clickShowCore(S32 return_type, uuid_list_t* list)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	send_parcel_select_objects(parcel->getLocalID(), return_type, list);
}

// static
void LLPanelLandObjects::onClickShowOwnerObjects(void*)
{
	clickShowCore(RT_OWNER);
}

// static
void LLPanelLandObjects::onClickShowGroupObjects(void*)
{
	clickShowCore(RT_GROUP);
}

// static
void LLPanelLandObjects::onClickShowOtherObjects(void*)
{
	clickShowCore(RT_OTHER);
}

// static
void LLPanelLandObjects::onClickReturnOwnerObjects(void* userdata)
{
	S32 sw_max=0, sw_total=0;
	S32 max=0, total=0;
	S32 owned=0, group=0, other=0, selected=0;
	F32 parcel_object_bonus=0;
	S32 other_time=0;

	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	send_parcel_select_objects(parcel->getLocalID(), RT_OWNER);

	LLUUID owner_id = parcel->getOwnerID();
	
	LLStringBase<char>::format_map_t args;
	args["[N]"] = llformat("%d",owned);

	if (owner_id == gAgent.getID())
	{
		gViewerWindow->alertXml("ReturnObjectsOwnedBySelf", args, callbackReturnOwnerObjects, userdata);
	}
	else
	{
		char first[DB_FIRST_NAME_BUF_SIZE];
		char last[DB_LAST_NAME_BUF_SIZE];
		gCacheName->getName(owner_id, first, last);
		std::string name = first;
		name += " ";
		name += last;
		args["[NAME]"] = name;
		gViewerWindow->alertXml("ReturnObjectsOwnedByUser", args, callbackReturnOwnerObjects, userdata);
	}
}

// static
void LLPanelLandObjects::onClickReturnGroupObjects(void* userdata)
{
	S32 sw_max=0, sw_total=0;
	S32 max=0, total=0;
	S32 owned=0, group=0, other=0, selected=0;
	F32 parcel_object_bonus=0;
	S32 other_time=0;
	
	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	send_parcel_select_objects(parcel->getLocalID(), RT_GROUP);

	char group_name[MAX_STRING];
	gCacheName->getGroupName(parcel->getGroupID(), group_name);
	
	LLStringBase<char>::format_map_t args;
	args["[NAME]"] = group_name;
	args["[N]"] = llformat("%d",group);

	// create and show confirmation textbox
	gViewerWindow->alertXml("ReturnObjectsDeededToGroup", args, callbackReturnGroupObjects, userdata);
}

// static
void LLPanelLandObjects::onClickReturnOtherObjects(void* userdata)
{
	S32 sw_max=0, sw_total=0;
	S32 max=0, total=0;
	S32 owned=0, group=0, other=0, selected=0;
	F32 parcel_object_bonus=0;
	S32 other_time=0;

	gParcelMgr->getPrimInfo(sw_max, sw_total, max, total, owned, group, other, selected, parcel_object_bonus, other_time);

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	send_parcel_select_objects(parcel->getLocalID(), RT_OTHER);

	LLStringBase<char>::format_map_t args;
	args["[N]"] = llformat("%d", other);
	
	if (parcel->getIsGroupOwned())
	{
		char group_name[MAX_STRING];
		gCacheName->getGroupName(parcel->getGroupID(), group_name);
		args["[NAME]"] = group_name;

		gViewerWindow->alertXml("ReturnObjectsNotOwnedByGroup", args, callbackReturnOtherObjects, userdata);
	}
	else
	{
		LLUUID owner_id = parcel->getOwnerID();

		if (owner_id == gAgent.getID())
		{
			gViewerWindow->alertXml("ReturnObjectsNotOwnedBySelf", args, callbackReturnOtherObjects, userdata);
		}
		else
		{
			char first[DB_FIRST_NAME_BUF_SIZE];
			char last[DB_LAST_NAME_BUF_SIZE];
			gCacheName->getName(owner_id, first, last);
			std::string name;
			name += first;
			name += " ";
			name += last;
			args["[NAME]"] = name;

			gViewerWindow->alertXml("ReturnObjectsNotOwnedByUser", args, callbackReturnOtherObjects, userdata);
		}
	}
}

// static
void LLPanelLandObjects::onLostFocus(LLLineEditor *caller, void* user_data)
{
	LLPanelLandObjects	*lop = (LLPanelLandObjects *)user_data;
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	if (parcel)
	{
		lop->mOtherTime = atoi(lop->mCleanOtherObjectsTime->getText().c_str());

		parcel->setCleanOtherTime(lop->mOtherTime);
		send_other_clean_time_message(parcel->getLocalID(), lop->mOtherTime);
	}
}


//---------------------------------------------------------------------------
// LLPanelLandOptions
//---------------------------------------------------------------------------

LLPanelLandOptions::LLPanelLandOptions()
:	LLPanel("land_options_panel"),
	mCheckEditObjects(NULL),
	mCheckEditGroupObjects(NULL),
	mCheckAllObjectEntry(NULL),
	mCheckGroupObjectEntry(NULL),
	mCheckEditLand(NULL),
	mCheckSafe(NULL),
	mCheckFly(NULL),
	mCheckGroupScripts(NULL),
	mCheckOtherScripts(NULL),
	mCheckLandmark(NULL),
	mCheckShowDirectory(NULL),
	mCategoryCombo(NULL),
	mLandingTypeCombo(NULL),
	mSnapshotCtrl(NULL),
	mLocationText(NULL),
	mSetBtn(NULL),
	mClearBtn(NULL),
	mAllowPublishCtrl(NULL),
	mMatureCtrl(NULL),
	mPushRestrictionCtrl(NULL),
	mPublishHelpButton(NULL)
{

}


BOOL LLPanelLandOptions::postBuild()
{

	
	mCheckEditObjects = LLUICtrlFactory::getCheckBoxByName(this, "edit objects check");
	childSetCommitCallback("edit objects check", onCommitAny, this);
	
	mCheckEditGroupObjects = LLUICtrlFactory::getCheckBoxByName(this, "edit group objects check");
	childSetCommitCallback("edit group objects check", onCommitAny, this);

	mCheckAllObjectEntry = LLUICtrlFactory::getCheckBoxByName(this, "all object entry check");
	childSetCommitCallback("all object entry check", onCommitAny, this);

	mCheckGroupObjectEntry = LLUICtrlFactory::getCheckBoxByName(this, "group object entry check");
	childSetCommitCallback("group object entry check", onCommitAny, this);
	
	mCheckEditLand = LLUICtrlFactory::getCheckBoxByName(this, "edit land check");
	childSetCommitCallback("edit land check", onCommitAny, this);

	
	mCheckLandmark = LLUICtrlFactory::getCheckBoxByName(this, "check landmark");
	childSetCommitCallback("check landmark", onCommitAny, this);

	
	mCheckGroupScripts = LLUICtrlFactory::getCheckBoxByName(this, "check group scripts");
	childSetCommitCallback("check group scripts", onCommitAny, this);

	
	mCheckFly = LLUICtrlFactory::getCheckBoxByName(this, "check fly");
	childSetCommitCallback("check fly", onCommitAny, this);

	
	mCheckOtherScripts = LLUICtrlFactory::getCheckBoxByName(this, "check other scripts");
	childSetCommitCallback("check other scripts", onCommitAny, this);

	
	mCheckSafe = LLUICtrlFactory::getCheckBoxByName(this, "check safe");
	childSetCommitCallback("check safe", onCommitAny, this);

	
	mPushRestrictionCtrl = LLUICtrlFactory::getCheckBoxByName(this, "PushRestrictCheck");
	childSetCommitCallback("PushRestrictCheck", onCommitAny, this);

	mCheckShowDirectory = LLUICtrlFactory::getCheckBoxByName(this, "ShowDirectoryCheck");
	childSetCommitCallback("ShowDirectoryCheck", onCommitAny, this);

	
	mCategoryCombo = LLUICtrlFactory::getComboBoxByName(this, "land category");
	childSetCommitCallback("land category", onCommitAny, this);

	mAllowPublishCtrl = LLUICtrlFactory::getCheckBoxByName(this, "PublishCheck");
	childSetCommitCallback("PublishCheck", onCommitAny, this);

	
	mMatureCtrl = LLUICtrlFactory::getCheckBoxByName(this, "MatureCheck");
	childSetCommitCallback("MatureCheck", onCommitAny, this);
	
	mPublishHelpButton = LLUICtrlFactory::getButtonByName(this, "?");
	mPublishHelpButton->setClickedCallback(onClickPublishHelp, this);


	if (gAgent.mAccess < SIM_ACCESS_MATURE)
	{
		// Disable these buttons if they are PG (Teen) users
		mAllowPublishCtrl->setVisible(FALSE);
		mAllowPublishCtrl->setEnabled(FALSE);
		mPublishHelpButton->setVisible(FALSE);
		mPublishHelpButton->setEnabled(FALSE);
		mMatureCtrl->setVisible(FALSE);
		mMatureCtrl->setEnabled(FALSE);
	}

		// Load up the category list
	//now in xml file
	/*
	S32 i;
	for (i = 0; i < LLParcel::C_COUNT; i++)
	{
		LLParcel::ECategory cat = (LLParcel::ECategory)i;

		// Selecting Linden Location when you're not a god
		// is also blocked on the server.
		BOOL enabled = TRUE;
		if (!gAgent.isGodlike()
			&& i == LLParcel::C_LINDEN) 
		{
			enabled = FALSE;
		}

		mCategoryCombo->add( LLParcel::getCategoryUIString(cat), ADD_BOTTOM, enabled );
	}*/

	
	mSnapshotCtrl = LLUICtrlFactory::getTexturePickerByName(this, "snapshot_ctrl");
	mSnapshotCtrl->setCommitCallback( onCommitAny );
	mSnapshotCtrl->setCallbackUserData( this );
	mSnapshotCtrl->setAllowNoTexture ( TRUE );
	mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
	mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);



	mLocationText = LLUICtrlFactory::getTextBoxByName(this, "Landing Point: (none)");

	mSetBtn = LLUICtrlFactory::getButtonByName(this, "Set");
	mSetBtn->setClickedCallback(onClickSet, this);

	
	mClearBtn = LLUICtrlFactory::getButtonByName(this, "Clear");
	mClearBtn->setClickedCallback(onClickClear, this);


	mLandingTypeCombo = LLUICtrlFactory::getComboBoxByName(this, "landing type");
	childSetCommitCallback("landing type", onCommitAny, this);

	return TRUE;
}


// virtual
LLPanelLandOptions::~LLPanelLandOptions()
{ }


// public
void LLPanelLandOptions::refresh()
{
	LLParcel *parcel = gParcelMgr->getSelectedParcel();
	
	if (!parcel)
	{
		mCheckEditObjects	->set(FALSE);
		mCheckEditObjects	->setEnabled(FALSE);

		mCheckEditGroupObjects	->set(FALSE);
		mCheckEditGroupObjects	->setEnabled(FALSE);

		mCheckAllObjectEntry	->set(FALSE);
		mCheckAllObjectEntry	->setEnabled(FALSE);

		mCheckGroupObjectEntry	->set(FALSE);
		mCheckGroupObjectEntry	->setEnabled(FALSE);

		mCheckEditLand		->set(FALSE);
		mCheckEditLand		->setEnabled(FALSE);

		mCheckSafe			->set(FALSE);
		mCheckSafe			->setEnabled(FALSE);

		mCheckFly			->set(FALSE);
		mCheckFly			->setEnabled(FALSE);

		mCheckLandmark		->set(FALSE);
		mCheckLandmark		->setEnabled(FALSE);

		mCheckGroupScripts	->set(FALSE);
		mCheckGroupScripts	->setEnabled(FALSE);

		mCheckOtherScripts	->set(FALSE);
		mCheckOtherScripts	->setEnabled(FALSE);

		mCheckShowDirectory	->set(FALSE);
		mCheckShowDirectory	->setEnabled(FALSE);

		mPushRestrictionCtrl->set(FALSE);
		mPushRestrictionCtrl->setEnabled(FALSE);

		const char* none_string = LLParcel::getCategoryUIString(LLParcel::C_NONE);
		mCategoryCombo->setSimple(none_string);
		mCategoryCombo->setEnabled(FALSE);

		mLandingTypeCombo->setCurrentByIndex(0);
		mLandingTypeCombo->setEnabled(FALSE);

		mSnapshotCtrl->setImageAssetID(LLUUID::null);
		mSnapshotCtrl->setEnabled(FALSE);

		mLocationText->setText("Landing Point: (none)");
		mSetBtn->setEnabled(FALSE);
		mClearBtn->setEnabled(FALSE);

		mAllowPublishCtrl->setEnabled(FALSE);
		mMatureCtrl->setEnabled(FALSE);
		mPublishHelpButton->setEnabled(FALSE);
	}
	else
	{
		// something selected, hooray!

		// Display options
		BOOL can_change_options = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_OPTIONS);
		mCheckEditObjects	->set( parcel->getAllowModify() );
		mCheckEditObjects	->setEnabled( can_change_options );
		
		mCheckEditGroupObjects	->set( parcel->getAllowGroupModify() ||  parcel->getAllowModify());
		mCheckEditGroupObjects	->setEnabled( can_change_options && !parcel->getAllowModify() );		// If others edit is enabled, then this is explicitly enabled.

		mCheckAllObjectEntry	->set( parcel->getAllowAllObjectEntry() );
		mCheckAllObjectEntry	->setEnabled( can_change_options );

		mCheckGroupObjectEntry	->set( parcel->getAllowGroupObjectEntry() ||  parcel->getAllowAllObjectEntry());
		mCheckGroupObjectEntry	->setEnabled( can_change_options && !parcel->getAllowAllObjectEntry() );

		BOOL can_change_terraform = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_EDIT);
		mCheckEditLand		->set( parcel->getAllowTerraform() );
		mCheckEditLand		->setEnabled( can_change_terraform );

		mCheckSafe			->set( !parcel->getAllowDamage() );
		mCheckSafe			->setEnabled( can_change_options );

		mCheckFly			->set( parcel->getAllowFly() );
		mCheckFly			->setEnabled( can_change_options );

		mCheckLandmark		->set( parcel->getAllowLandmark() );
		mCheckLandmark		->setEnabled( can_change_options );

		mCheckGroupScripts	->set( parcel->getAllowGroupScripts() || parcel->getAllowOtherScripts());
		mCheckGroupScripts	->setEnabled( can_change_options && !parcel->getAllowOtherScripts());

		mCheckOtherScripts	->set( parcel->getAllowOtherScripts() );
		mCheckOtherScripts	->setEnabled( can_change_options );

		BOOL can_change_identity = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, 
														GP_LAND_CHANGE_IDENTITY);
		mCheckShowDirectory	->set( parcel->getParcelFlag(PF_SHOW_DIRECTORY));
		mCheckShowDirectory	->setEnabled( can_change_identity );

		mPushRestrictionCtrl->set( parcel->getRestrictPushObject() );
		if(parcel->getRegionPushOverride())
		{
			mPushRestrictionCtrl->setLabel("Restrict Pushing (Region Override)");
			mPushRestrictionCtrl->setEnabled(false);
			mPushRestrictionCtrl->set(TRUE);
		}
		else
		{
			mPushRestrictionCtrl->setLabel("Restrict Pushing");
			mPushRestrictionCtrl->setEnabled(can_change_options);
		}

		// Set by string in case the order in UI doesn't match the order
		// by index.
		LLParcel::ECategory cat = parcel->getCategory();
		const char* category_string = LLParcel::getCategoryUIString(cat);
		mCategoryCombo->setSimple(category_string);
		mCategoryCombo->setEnabled( can_change_identity );

		BOOL can_change_landing_point = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, 
														GP_LAND_SET_LANDING_POINT);
		mLandingTypeCombo->setCurrentByIndex((S32)parcel->getLandingType());
		mLandingTypeCombo->setEnabled( can_change_landing_point );

		mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID());
		mSnapshotCtrl->setEnabled( can_change_identity );

		LLVector3 pos = parcel->getUserLocation();
		if (pos.isExactlyZero())
		{
			mLocationText->setText("Landing Point: (none)");
		}
		else
		{
			char buffer[256];
			sprintf(buffer, "Landing Point: %d, %d, %d",
					llround(pos.mV[VX]),
					llround(pos.mV[VY]),
					llround(pos.mV[VZ]));
			mLocationText->setText(buffer);
		}

		mSetBtn->setEnabled( can_change_landing_point );
		mClearBtn->setEnabled( can_change_landing_point );

		mAllowPublishCtrl->set(parcel->getAllowPublish());
		mAllowPublishCtrl->setEnabled( can_change_identity );
		mMatureCtrl->set(parcel->getMaturePublish());
		mMatureCtrl->setEnabled( can_change_identity );
		mPublishHelpButton->setEnabled( can_change_identity );

		if (gAgent.mAccess < SIM_ACCESS_MATURE)
		{
			// Disable these buttons if they are PG (Teen) users
			mAllowPublishCtrl->setVisible(FALSE);
			mAllowPublishCtrl->setEnabled(FALSE);
			mPublishHelpButton->setVisible(FALSE);
			mPublishHelpButton->setEnabled(FALSE);
			mMatureCtrl->setVisible(FALSE);
			mMatureCtrl->setEnabled(FALSE);
		}
	}
}


// static
void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata)
{
	LLPanelLandOptions *self = (LLPanelLandOptions *)userdata;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL create_objects		= self->mCheckEditObjects->get();
	BOOL create_group_objects	= self->mCheckEditGroupObjects->get() || self->mCheckEditObjects->get();
	BOOL all_object_entry		= self->mCheckAllObjectEntry->get();
	BOOL group_object_entry	= self->mCheckGroupObjectEntry->get() || self->mCheckAllObjectEntry->get();
	BOOL allow_terraform	= self->mCheckEditLand->get();
	BOOL allow_damage		= !self->mCheckSafe->get();
	BOOL allow_fly			= self->mCheckFly->get();
	BOOL allow_landmark		= self->mCheckLandmark->get();
	BOOL allow_group_scripts	= self->mCheckGroupScripts->get() || self->mCheckOtherScripts->get();
	BOOL allow_other_scripts	= self->mCheckOtherScripts->get();
	BOOL allow_publish		= self->mAllowPublishCtrl->get();
	BOOL mature_publish		= self->mMatureCtrl->get();
	BOOL push_restriction	= self->mPushRestrictionCtrl->get();
	BOOL show_directory		= self->mCheckShowDirectory->get();
	S32  category_index		= self->mCategoryCombo->getCurrentIndex();
	S32  landing_type_index	= self->mLandingTypeCombo->getCurrentIndex();
	LLUUID snapshot_id		= self->mSnapshotCtrl->getImageAssetID();
	LLViewerRegion* region;
	region = gParcelMgr->getSelectionRegion();

	if (!allow_other_scripts && region && region->getAllowDamage())
	{

		gViewerWindow->alertXml("UnableToDisableOutsideScripts");
		return;
	}

	// Push data into current parcel
	parcel->setParcelFlag(PF_CREATE_OBJECTS, create_objects);
	parcel->setParcelFlag(PF_CREATE_GROUP_OBJECTS, create_group_objects);
	parcel->setParcelFlag(PF_ALLOW_ALL_OBJECT_ENTRY, all_object_entry);
	parcel->setParcelFlag(PF_ALLOW_GROUP_OBJECT_ENTRY, group_object_entry);
	parcel->setParcelFlag(PF_ALLOW_TERRAFORM, allow_terraform);
	parcel->setParcelFlag(PF_ALLOW_DAMAGE, allow_damage);
	parcel->setParcelFlag(PF_ALLOW_FLY, allow_fly);
	parcel->setParcelFlag(PF_ALLOW_LANDMARK, allow_landmark);
	parcel->setParcelFlag(PF_ALLOW_GROUP_SCRIPTS, allow_group_scripts);
	parcel->setParcelFlag(PF_ALLOW_OTHER_SCRIPTS, allow_other_scripts);
	parcel->setParcelFlag(PF_SHOW_DIRECTORY, show_directory);
	parcel->setParcelFlag(PF_ALLOW_PUBLISH, allow_publish);
	parcel->setParcelFlag(PF_MATURE_PUBLISH, mature_publish);
	parcel->setParcelFlag(PF_RESTRICT_PUSHOBJECT, push_restriction);
	parcel->setCategory((LLParcel::ECategory)category_index);
	parcel->setLandingType((LLParcel::ELandingType)landing_type_index);
	parcel->setSnapshotID(snapshot_id);

	// Send current parcel data upstream to server
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );

	// Might have changed properties, so let's redraw!
	self->refresh();
}


// static
void LLPanelLandOptions::onClickSet(void* userdata)
{
	LLPanelLandOptions* self = (LLPanelLandOptions*)userdata;

	LLParcel* selected_parcel = gParcelMgr->getSelectedParcel();
	if (!selected_parcel) return;

	LLParcel* agent_parcel = gParcelMgr->getAgentParcel();
	if (!agent_parcel) return;

	if (agent_parcel->getLocalID() != selected_parcel->getLocalID())
	{
		gViewerWindow->alertXml("MustBeInParcel");
		return;
	}

	LLVector3 pos_region = gAgent.getPositionAgent();
	selected_parcel->setUserLocation(pos_region);
	selected_parcel->setUserLookAt(gAgent.getFrameAgent().getAtAxis());

	gParcelMgr->sendParcelPropertiesUpdate(selected_parcel, LLFloaterLand::sRequestReplyOnUpdate);

	self->refresh();
}

void LLPanelLandOptions::onClickClear(void* userdata)
{
	LLPanelLandOptions* self = (LLPanelLandOptions*)userdata;

	LLParcel* selected_parcel = gParcelMgr->getSelectedParcel();
	if (!selected_parcel) return;

	// yes, this magic number of 0,0,0 means that it is clear
	LLVector3 zero_vec(0.f, 0.f, 0.f);
	selected_parcel->setUserLocation(zero_vec);
	selected_parcel->setUserLookAt(zero_vec);

	gParcelMgr->sendParcelPropertiesUpdate(selected_parcel, LLFloaterLand::sRequestReplyOnUpdate);

	self->refresh();
}

// static
void LLPanelLandOptions::onClickPublishHelp(void*)
{
	gViewerWindow->alertXml("ClickPublishHelpLand");
}

//---------------------------------------------------------------------------
// LLPanelLandMedia
//---------------------------------------------------------------------------

LLPanelLandMedia::LLPanelLandMedia()
:	LLPanel("land_media_panel")
{
}




BOOL LLPanelLandMedia::postBuild()
{
		
	mCheckSoundLocal = LLUICtrlFactory::getCheckBoxByName(this, "check sound local");
	childSetCommitCallback("check sound local", onCommitAny, this);

	mMusicURLEdit = LLUICtrlFactory::getLineEditorByName(this, "music_url");
	childSetCommitCallback("music_url", onCommitAny, this);


	mMediaTextureCtrl = LLUICtrlFactory::getTexturePickerByName(this, "media texture");
	mMediaTextureCtrl->setCommitCallback( onCommitAny );
	mMediaTextureCtrl->setCallbackUserData( this );
	mMediaTextureCtrl->setAllowNoTexture ( TRUE );
	mMediaTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
	mMediaTextureCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);

	mMediaAutoScaleCheck = LLUICtrlFactory::getCheckBoxByName(this, "media_auto_scale");
	childSetCommitCallback("media_auto_scale", onCommitAny, this);

	mMediaURLEdit = LLUICtrlFactory::getLineEditorByName(this, "media_url");
	childSetCommitCallback("media_url", onCommitAny, this);
	
	return TRUE;
}


// virtual
LLPanelLandMedia::~LLPanelLandMedia()
{ }


// public
void LLPanelLandMedia::refresh()
{
	LLParcel *parcel = gParcelMgr->getSelectedParcel();

	if (!parcel)
	{
		mCheckSoundLocal->set(FALSE);
		mCheckSoundLocal->setEnabled(FALSE);

		mMusicURLEdit->setText("");
		mMusicURLEdit->setEnabled(FALSE);

		mMediaURLEdit->setText("");
		mMediaURLEdit->setEnabled(FALSE);

		mMediaAutoScaleCheck->set ( FALSE );
		mMediaAutoScaleCheck->setEnabled(FALSE);

		mMediaTextureCtrl->clear();
		mMediaTextureCtrl->setEnabled(FALSE);

		#if 0
		mMediaStopButton->setEnabled ( FALSE );
		mMediaStartButton->setEnabled ( FALSE );
		#endif
	}
	else
	{
		// something selected, hooray!

		// Display options
		BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA);

		mCheckSoundLocal->set( parcel->getSoundLocal() );
		mCheckSoundLocal->setEnabled( can_change_media );

		// don't display urls if you're not able to change it
		// much requested change in forums so people can't 'steal' urls
		// NOTE: bug#2009 means this is still vunerable - however, bug 
		// should be closed since this bug opens up major security issues elsewhere.
		if ( can_change_media )
		{
			mMusicURLEdit->setDrawAsterixes ( FALSE );
			mMediaURLEdit->setDrawAsterixes ( FALSE );
		}
		else
		{
				mMusicURLEdit->setDrawAsterixes ( TRUE );
				mMediaURLEdit->setDrawAsterixes ( TRUE );
			}

		mMusicURLEdit->setText(parcel->getMusicURL());
		mMusicURLEdit->setEnabled( can_change_media );

		mMediaURLEdit->setText(parcel->getMediaURL());
		mMediaURLEdit->setEnabled( can_change_media );

		mMediaAutoScaleCheck->set ( parcel->getMediaAutoScale () );
		mMediaAutoScaleCheck->setEnabled ( can_change_media );

		LLUUID tmp = parcel->getMediaID();
		mMediaTextureCtrl->setImageAssetID ( parcel->getMediaID() );
		mMediaTextureCtrl->setEnabled( can_change_media );

		#if 0
		// there is a media url and a media texture selected
		if ( ( ! ( std::string ( parcel->getMediaURL() ).empty () ) ) && ( ! ( parcel->getMediaID ().isNull () ) ) )
		{
			// turn on transport controls if allowed for this parcel
			mMediaStopButton->setEnabled ( editable );
			mMediaStartButton->setEnabled ( editable );
		}
		else
		{
			// no media url or no media texture
			mMediaStopButton->setEnabled ( FALSE );
			mMediaStartButton->setEnabled ( FALSE );
		};
		#endif
	}
}

// static
void LLPanelLandMedia::onCommitAny(LLUICtrl *ctrl, void *userdata)
{
	LLPanelLandMedia *self = (LLPanelLandMedia *)userdata;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL sound_local		= self->mCheckSoundLocal->get();
	std::string music_url	= self->mMusicURLEdit->getText();
	std::string media_url	= self->mMediaURLEdit->getText();
	U8 media_auto_scale		= self->mMediaAutoScaleCheck->get();
	LLUUID media_id			= self->mMediaTextureCtrl->getImageAssetID();

	// Push data into current parcel
	parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local);
	parcel->setMusicURL(music_url.c_str());
	parcel->setMediaURL(media_url.c_str());
	parcel->setMediaID(media_id);
	parcel->setMediaAutoScale ( media_auto_scale );

	// Send current parcel data upstream to server
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );

	// Might have changed properties, so let's redraw!
	self->refresh();
}

void LLPanelLandMedia::onClickStopMedia ( void* data )
{
	LLMediaEngine::getInstance ()->stop ();
}

void LLPanelLandMedia::onClickStartMedia ( void* data )
{
	// force a commit
	gFocusMgr.setKeyboardFocus ( NULL, NULL );

	// force a reload
	LLMediaEngine::getInstance ()->convertImageAndLoadUrl ( true, false, std::string());
}

//---------------------------------------------------------------------------
// LLPanelLandAccess
//---------------------------------------------------------------------------

LLPanelLandAccess::LLPanelLandAccess()
:	LLPanel("land_access_panel")
{
}



BOOL LLPanelLandAccess::postBuild()
{

	
	mCheckGroup = LLUICtrlFactory::getCheckBoxByName(this, "GroupCheck");
	childSetCommitCallback("GroupCheck", onCommitAny, this);
	
	mCheckAccess = LLUICtrlFactory::getCheckBoxByName(this, "AccessCheck");
	childSetCommitCallback("AccessCheck", onCommitAny, this);

	mListAccess = LLUICtrlFactory::getNameListByName(this, "AccessList");

	mBtnAddAccess = LLUICtrlFactory::getButtonByName(this, "Add...");

	mBtnAddAccess->setClickedCallback(onClickAdd, this);

	mBtnRemoveAccess = LLUICtrlFactory::getButtonByName(this, "Remove");

	mBtnRemoveAccess->setClickedCallback(onClickRemove, this);
	
	mCheckPass = LLUICtrlFactory::getCheckBoxByName(this, "PassCheck");
	childSetCommitCallback("PassCheck", onCommitAny, this);

	
	mSpinPrice = LLUICtrlFactory::getSpinnerByName(this, "PriceSpin");
	childSetCommitCallback("PriceSpin", onCommitAny, this);
	
	mSpinHours = LLUICtrlFactory::getSpinnerByName(this, "HoursSpin");
	childSetCommitCallback("HoursSpin", onCommitAny, this);


	return TRUE;
}


LLPanelLandAccess::~LLPanelLandAccess()
{ }

void LLPanelLandAccess::refresh()
{
	mListAccess->deleteAllItems();

	LLParcel *parcel = gParcelMgr->getSelectedParcel();

	if (parcel)
	{
		char label[256];

		// Display options
		BOOL use_group = parcel->getParcelFlag(PF_USE_ACCESS_GROUP);
		mCheckGroup->set( use_group );

		char group_name[MAX_STRING];
		gCacheName->getGroupName(parcel->getGroupID(), group_name);
		sprintf(label, "Group: %s", group_name);
		mCheckGroup->setLabel( label );

		S32 count = parcel->mAccessList.size();

		BOOL use_list = parcel->getParcelFlag(PF_USE_ACCESS_LIST);
		mCheckAccess->set( use_list );
		sprintf(label, "Avatars: (%d listed, %d max)",
				count, PARCEL_MAX_ACCESS_LIST);
		mCheckAccess->setLabel( label );

		access_map_const_iterator cit = parcel->mAccessList.begin();
		access_map_const_iterator end = parcel->mAccessList.end();

		for (; cit != end; ++cit)
		{
			const LLAccessEntry& entry = (*cit).second;
			LLString suffix;
			if (entry.mTime != 0)
			{
				S32 now = time(NULL);
				S32 seconds = entry.mTime - now;
				if (seconds < 0) seconds = 0;
				suffix.assign(" (");
				if (seconds >= 120)
				{
					char buf[30];
					sprintf(buf, "%d minutes", (seconds/60));
					suffix.append(buf);
				}
				else if (seconds >= 60)
				{
					suffix.append("1 minute");
				}
				else
				{
					char buf[30];
					sprintf(buf, "%d seconds", seconds);
					suffix.append(buf);
				}
				suffix.append(" remaining)");
			}
			mListAccess->addNameItem(entry.mID, ADD_BOTTOM, TRUE, suffix);
		}

		BOOL can_manage_allowed = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_ALLOWED);

		BOOL enable_add = can_manage_allowed && (count < PARCEL_MAX_ACCESS_LIST);
		mBtnAddAccess->setEnabled(enable_add);

		BOOL enable_remove = can_manage_allowed && (count > 0);
		mBtnRemoveAccess->setEnabled(enable_remove);

		// Can only sell passes when limiting the access.
		BOOL can_manage_passes = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_PASSES);
		mCheckPass->setEnabled( (use_group || use_list) && can_manage_passes );

		BOOL use_pass = parcel->getParcelFlag(PF_USE_PASS_LIST);
		mCheckPass->set( use_pass );

		BOOL enable_pass = can_manage_passes && use_pass;
		mSpinPrice->setEnabled( enable_pass );
		mSpinHours->setEnabled( enable_pass );

		S32 pass_price = parcel->getPassPrice();
		mSpinPrice->set( F32(pass_price) );

		F32 pass_hours = parcel->getPassHours();
		mSpinHours->set( pass_hours );

		mCheckGroup->setEnabled( can_manage_allowed );
		mCheckAccess->setEnabled( can_manage_allowed );

	}
	else
	{
		mCheckGroup->set(FALSE);
		mCheckGroup->setLabel("Group:");
		mCheckAccess->set(FALSE);
		mCheckAccess->setLabel("Avatars:");
		mBtnAddAccess->setEnabled(FALSE);
		mBtnRemoveAccess->setEnabled(FALSE);
		mSpinPrice->set((F32)PARCEL_PASS_PRICE_DEFAULT);
		mSpinPrice->setEnabled(FALSE);
		mSpinHours->set( PARCEL_PASS_HOURS_DEFAULT );
		mSpinHours->setEnabled(FALSE);
		mCheckGroup->setEnabled(FALSE);
		mCheckAccess->setEnabled(FALSE);
	}
}

// public
void LLPanelLandAccess::refreshNames()
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	char group_name[DB_GROUP_NAME_BUF_SIZE];
	group_name[0] = '\0';
	if(parcel)
	{
		gCacheName->getGroupName(parcel->getGroupID(), group_name);
	}
	char label[MAX_STRING];
	snprintf(label, MAX_STRING, "Group: %s", group_name);
	mCheckGroup->setLabel(label);
}


// virtual
void LLPanelLandAccess::draw()
{
	refreshNames();
	LLPanel::draw();
}


void LLPanelLandAccess::onAccessLevelChange(LLUICtrl*, void *userdata)
{
	LLPanelLandAccess::onCommitAny(NULL, userdata);
}

// static
void LLPanelLandAccess::onCommitAny(LLUICtrl *ctrl, void *userdata)
{
	LLPanelLandAccess *self = (LLPanelLandAccess *)userdata;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL use_access_group	= self->mCheckGroup->get();
	BOOL use_access_list	= self->mCheckAccess->get();
	BOOL use_pass_list		= self->mCheckPass->get();
	


	// Must be limiting access to sell passes
	if (!use_access_group && !use_access_list)
	{
		use_pass_list = FALSE;
	}

	S32 pass_price = llfloor(self->mSpinPrice->get());
	F32 pass_hours = self->mSpinHours->get();

	// Validate extracted data

	// Push data into current parcel
	parcel->setParcelFlag(PF_USE_ACCESS_GROUP,	use_access_group);
	parcel->setParcelFlag(PF_USE_ACCESS_LIST,	use_access_list);
	parcel->setParcelFlag(PF_USE_PASS_LIST,		use_pass_list);

	parcel->setPassPrice( pass_price );
	parcel->setPassHours( pass_hours );

	// Send current parcel data upstream to server
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );

	// Might have changed properties, so let's redraw!
	self->refresh();
}

// static
void LLPanelLandAccess::onClickAdd(void* data)
{
	LLPanelLandAccess* panelp = (LLPanelLandAccess*)data;
	gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, data) );
}

// static
void LLPanelLandAccess::callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata)
{
	LLPanelLandAccess* self = (LLPanelLandAccess*)userdata;
	if (names.empty() || ids.empty()) return;
	self->addAvatar(ids[0]);
}


void LLPanelLandAccess::addAvatar(LLUUID id)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	parcel->addToAccessList(id, 0);

	gParcelMgr->sendParcelAccessListUpdate(AL_ACCESS);

	refresh();
}


// static
void LLPanelLandAccess::onClickRemove(void* data)
{
	LLPanelLandAccess* self = (LLPanelLandAccess*)data;
	if (!self) return;

	LLScrollListItem* item = self->mListAccess->getFirstSelected();
	if (!item) return;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	const LLUUID& agent_id = item->getUUID();

	parcel->removeFromAccessList(agent_id);

	gParcelMgr->sendParcelAccessListUpdate(AL_ACCESS);

	self->refresh();
}



//---------------------------------------------------------------------------
// LLPanelLandBan
//---------------------------------------------------------------------------
LLPanelLandBan::LLPanelLandBan()
:	LLPanel("land_ban_panel")
{

}



BOOL LLPanelLandBan::postBuild()
{

	mCheck = LLUICtrlFactory::getCheckBoxByName(this, "LandBanCheck");
	childSetCommitCallback("LandBanCheck", onCommitAny, this);
	
	mList = LLUICtrlFactory::getNameListByName(this, "LandBanList");

	mBtnAdd = LLUICtrlFactory::getButtonByName(this, "Add...");
	
	mBtnAdd->setClickedCallback(onClickAdd, this);

	mBtnRemove = LLUICtrlFactory::getButtonByName(this, "Remove");
	
	mBtnRemove->setClickedCallback(onClickRemove, this);

	mCheckDenyAnonymous = LLUICtrlFactory::getCheckBoxByName(this, "DenyAnonymousCheck");
	childSetCommitCallback("DenyAnonymousCheck", onCommitAny, this);

	mCheckDenyIdentified = LLUICtrlFactory::getCheckBoxByName(this, "DenyIdentifiedCheck");
	childSetCommitCallback("DenyIdentifiedCheck", onCommitAny, this);

	mCheckDenyTransacted = LLUICtrlFactory::getCheckBoxByName(this, "DenyTransactedCheck");
	childSetCommitCallback("DenyTransactedCheck", onCommitAny, this);

	return TRUE;

}


LLPanelLandBan::~LLPanelLandBan()
{ }

void LLPanelLandBan::refresh()
{
	mList->deleteAllItems();

	LLParcel *parcel = gParcelMgr->getSelectedParcel();

	if (parcel)
	{
		char label[256];

		// Display options

		S32 count = parcel->mBanList.size();

		BOOL use_ban = parcel->getParcelFlag(PF_USE_BAN_LIST);
		mCheck->set( use_ban );

		sprintf(label, "Ban these avatars: (%d listed, %d max)",
				count, PARCEL_MAX_ACCESS_LIST);
		mCheck->setLabel( label );

		access_map_const_iterator cit = parcel->mBanList.begin();
		access_map_const_iterator end = parcel->mBanList.end();
		for ( ; cit != end; ++cit)
		{
			const LLAccessEntry& entry = (*cit).second;
			LLString suffix;
			if (entry.mTime != 0)
			{
				S32 now = time(NULL);
				S32 seconds = entry.mTime - now;
				if (seconds < 0) seconds = 0;
				suffix.assign(" (");
				if (seconds >= 120)
				{
					char buf[30];
					sprintf(buf, "%d minutes", (seconds/60));
					suffix.append(buf);
				}
				else if (seconds >= 60)
				{
					suffix.append("1 minute");
				}
				else
				{
					char buf[30];
					sprintf(buf, "%d seconds", seconds);
					suffix.append(buf);
				}
				suffix.append(" remaining)");
			}
			mList->addNameItem(entry.mID, ADD_BOTTOM, TRUE, suffix);
		}

		BOOL can_manage_banned = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_MANAGE_BANNED);
		mCheck->setEnabled( can_manage_banned );
		mCheckDenyAnonymous->setEnabled( FALSE );
		mCheckDenyIdentified->setEnabled( FALSE );
		mCheckDenyTransacted->setEnabled( FALSE );

		if(parcel->getRegionDenyAnonymousOverride())
		{
			mCheckDenyAnonymous->set(TRUE);
		}
		else if(can_manage_banned)
		{
			mCheckDenyAnonymous->setEnabled(TRUE);
			mCheckDenyAnonymous->set(parcel->getParcelFlag(PF_DENY_ANONYMOUS));
		}
		if(parcel->getRegionDenyIdentifiedOverride())
		{
			mCheckDenyIdentified->set(TRUE);
		}
		else if(can_manage_banned)
		{
			mCheckDenyIdentified->setEnabled(TRUE);
			mCheckDenyIdentified->set(parcel->getParcelFlag(PF_DENY_IDENTIFIED));
		}
		if(parcel->getRegionDenyTransactedOverride())
		{
			mCheckDenyTransacted->set(TRUE);
		}
		else if(can_manage_banned)
		{
			mCheckDenyTransacted->setEnabled(TRUE);
			mCheckDenyTransacted->set(parcel->getParcelFlag(PF_DENY_TRANSACTED));
		}


		BOOL enable_add = can_manage_banned && (count < PARCEL_MAX_ACCESS_LIST);
		mBtnAdd->setEnabled(enable_add);

		BOOL enable_remove = can_manage_banned && (count > 0);
		mBtnRemove->setEnabled(enable_remove);
	}
	else
	{
		mCheck->set(FALSE);
		mCheck->setLabel("Ban these avatars:");
		mCheck->setEnabled(FALSE);
		mBtnAdd->setEnabled(FALSE);
		mBtnRemove->setEnabled(FALSE);
		mCheckDenyAnonymous->set(FALSE);
		mCheckDenyAnonymous->setEnabled(FALSE);
		mCheckDenyIdentified->set(FALSE);
		mCheckDenyIdentified->setEnabled(FALSE);
		mCheckDenyTransacted->set(FALSE);
		mCheckDenyTransacted->setEnabled(FALSE);
	}
}

// static
void LLPanelLandBan::onCommitAny(LLUICtrl *ctrl, void *userdata)
{
	LLPanelLandBan *self = (LLPanelLandBan*)userdata;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel)
	{
		return;
	}

	// Extract data from UI
	BOOL use_ban_list = self->mCheck->get();
	BOOL deny_access_anonymous = self->mCheckDenyAnonymous->get();
	BOOL deny_access_identified = self->mCheckDenyIdentified->get();
	BOOL deny_access_transacted = self->mCheckDenyTransacted->get();	

	// Push data into current parcel
	parcel->setParcelFlag(PF_USE_BAN_LIST,		use_ban_list);
	parcel->setParcelFlag(PF_DENY_ANONYMOUS, deny_access_anonymous);
	parcel->setParcelFlag(PF_DENY_IDENTIFIED, deny_access_identified);
	parcel->setParcelFlag(PF_DENY_TRANSACTED, deny_access_transacted);

	// Send current parcel data upstream to server
	gParcelMgr->sendParcelPropertiesUpdate( parcel, LLFloaterLand::sRequestReplyOnUpdate );

	// Might have changed properties, so let's redraw!
	self->refresh();
}

// static
void LLPanelLandBan::onClickAdd(void* data)
{
	LLPanelLandBan* panelp = (LLPanelLandBan*)data;
	gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, data) );
}

// static
void LLPanelLandBan::callbackAvatarID(const std::vector<std::string>& names, const std::vector<LLUUID>& ids, void* userdata)
{
	LLPanelLandBan* self = (LLPanelLandBan*)userdata;
	if (names.empty() || ids.empty()) return;
	self->addAvatar(ids[0]);
}


void LLPanelLandBan::addAvatar(LLUUID id)
{
	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	parcel->addToBanList(id, 0);

	gParcelMgr->sendParcelAccessListUpdate(AL_BAN);

	refresh();
}


// static
void LLPanelLandBan::onClickRemove(void* data)
{
	LLPanelLandBan* self = (LLPanelLandBan*)data;
	if (!self) return;

	LLScrollListItem* item = self->mList->getFirstSelected();
	if (!item) return;

	LLParcel* parcel = gParcelMgr->getSelectedParcel();
	if (!parcel) return;

	const LLUUID& agent_id = item->getUUID();

	parcel->removeFromBanList(agent_id);

	gParcelMgr->sendParcelAccessListUpdate(AL_BAN);

	self->refresh();
}

//---------------------------------------------------------------------------
// LLPanelLandRenters
//---------------------------------------------------------------------------
LLPanelLandRenters::LLPanelLandRenters()
:	LLPanel("landrenters", LLRect(0,500,500,0))
{
	const S32 BTN_WIDTH = 64;

	S32 x = LEFT;
	S32 y = mRect.getHeight() - VPAD;

	LLCheckBoxCtrl* check = NULL;
	LLButton* btn = NULL;
	LLNameListCtrl* list = NULL;

	check = new LLCheckBoxCtrl("RentersCheck",
							LLRect(RULER0, y, RIGHT, y-LINE),
							"Rent space to these avatars:");
	addChild(check);
	mCheckRenters = check;

	y -= VPAD + LINE;

	const S32 ITEMS = 5;
	const BOOL NO_MULTIPLE_SELECT = FALSE;

	list = new LLNameListCtrl("RentersList",
							LLRect(RULER05, y, RIGHT, y-LINE*ITEMS),
							NULL, NULL,
							NO_MULTIPLE_SELECT);
	list->addSimpleItem("foo tester");
	list->addSimpleItem("bar tester");
	list->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
	addChild(list);
	mListRenters = list;

	y -= VPAD + LINE*ITEMS;

	x = RULER05;
	btn = new LLButton("Add...",
						LLRect(x, y, x+BTN_WIDTH, y-LINE),
						"",
						onClickAdd, this);
	btn->setFont( LLFontGL::sSansSerifSmall );
	btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
	addChild(btn);
	mBtnAddRenter = btn;

	x += HPAD + BTN_WIDTH;

	btn = new LLButton("Remove",
						LLRect(x, y, x+BTN_WIDTH, y-LINE),
						"",
						onClickRemove, this);
	btn->setFont( LLFontGL::sSansSerifSmall );
	btn->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
	addChild(btn);
	mBtnRemoveRenter = btn;
}

LLPanelLandRenters::~LLPanelLandRenters()
{ }

void LLPanelLandRenters::refresh()
{ }

// static
void LLPanelLandRenters::onClickAdd(void*)
{
}

// static
void LLPanelLandRenters::onClickRemove(void*)
{
}

//---------------------------------------------------------------------------
// LLPanelLandCovenant
//---------------------------------------------------------------------------
LLPanelLandCovenant::LLPanelLandCovenant()
:	LLPanel("land_covenant_panel")
{	
}

LLPanelLandCovenant::~LLPanelLandCovenant()
{
}

BOOL LLPanelLandCovenant::postBuild()
{
	refresh();
	return TRUE;
}

// virtual
void LLPanelLandCovenant::refresh()
{
	LLViewerRegion* region = gParcelMgr->getSelectionRegion();
	if(!region) return;
		
	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"));
		}
	}
	
	// send EstateCovenantInfo message
	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());
}

// static
void LLPanelLandCovenant::updateCovenantText(const std::string &string)
{
	LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant();
	if (self)
	{
		LLViewerTextEditor* editor = (LLViewerTextEditor*)self->getChildByName("covenant_editor");
		if (editor)
		{
			editor->setHandleEditKeysDirectly(TRUE);
			editor->setText(string);
		}
	}
}

// static
void LLPanelLandCovenant::updateEstateName(const std::string& name)
{
	LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant();
	if (self)
	{
		LLTextBox* editor = (LLTextBox*)self->getChildByName("estate_name_text");
		if (editor) editor->setText(name);
	}
}

// static
void LLPanelLandCovenant::updateLastModified(const std::string& text)
{
	LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant();
	if (self)
	{
		LLTextBox* editor = (LLTextBox*)self->getChildByName("covenant_timestamp_text");
		if (editor) editor->setText(text);
	}
}

// static
void LLPanelLandCovenant::updateEstateOwnerName(const std::string& name)
{
	LLPanelLandCovenant* self = LLFloaterLand::getCurrentPanelLandCovenant();
	if (self)
	{
		LLTextBox* editor = (LLTextBox*)self->getChildByName("estate_owner_text");
		if (editor) editor->setText(name);
	}
}
