/** 
 * @file llpanelavatar.cpp
 * @brief LLPanelAvatar and related class implementations
 *
 * Copyright (c) 2004-2007, Linden Research, Inc.
 * 
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 */

#include "llviewerprecompiledheaders.h"

#include "llpanelavatar.h"

#include "llfontgl.h"
#include "llcachename.h"

#include "llavatarconstants.h"
#include "lluiconstants.h"
#include "lltextbox.h"
#include "llviewertexteditor.h"
#include "lltexturectrl.h"
#include "llagent.h"
#include "llviewerwindow.h"
#include "llbutton.h"
#include "llcallingcard.h"
#include "llcheckboxctrl.h"
#include "llfloater.h"
#include "llfloatergroupinfo.h"
#include "llfloaterworldmap.h"
#include "llfloatermute.h"
#include "llfloaterrate.h"
#include "llfloateravatarinfo.h"
#include "lliconctrl.h"
#include "llinventoryview.h"
#include "lllineeditor.h"
#include "llnameeditor.h"
#include "llmutelist.h"
#include "llpanelclassified.h"
#include "llpanelpick.h"
#include "llscrolllistctrl.h"
#include "llstatusbar.h"
#include "lltabcontainer.h"
#include "lltabcontainervertical.h"
#include "llimview.h"
#include "lltooldraganddrop.h"
#include "lluiconstants.h"
#include "llvoavatar.h"
#include "llviewermenu.h"		// *FIX: for is_agent_friend()
#include "llviewerobjectlist.h"
#include "llviewerregion.h"
#include "llviewborder.h"
#include "llweb.h"
#include "llinventorymodel.h"
#include "viewer.h"				// for gUserServer
#include "roles_constants.h"

#define	kArraySize( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) )

#include "llvieweruictrlfactory.h"

// Statics
LLLinkedList<LLPanelAvatar> LLPanelAvatar::sAllPanels;
BOOL LLPanelAvatar::sAllowFirstLife = FALSE;

//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

// RN: move these to lldbstrings.h
static const S32 DB_USER_FAVORITES_STR_LEN = 254;

static const char IM_DISABLED_TOOLTIP[] = "Instant Message (IM).\nDisabled because you do not have their card.";
static const char IM_ENABLED_TOOLTIP[] = "Instant Message (IM)";
static const S32 LEFT = HPAD;

static const S32 RULER0 = 65;
static const S32 RULER1 = RULER0 + 5;
static const S32 RULER2 = RULER1 + 90;
static const S32 RULER3 = RULER2 + 90;
static const S32 RULER4 = RULER3 + 10;

static const S32 PICT_WIDTH  = 180;
static const S32 PICT_HEIGHT = 135;

static const S32 RULER5  = RULER4 + 140;
static const S32 WIDTH = RULER5 + 16;

static const S32 MAX_CHARS = 254;

static const LLColor4 WHITE(1,1,1,1);
static const LLColor4 BLACK(0,0,0,1);
static const LLColor4 CLEAR(0,0,0,0);

extern void handle_lure(const LLUUID& invitee);
extern void handle_pay_by_id(const LLUUID& payee);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLDropTarget
//
// This handy class is a simple way to drop something on another
// view. It handles drop events, always setting itself to the size of
// its parent.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class LLDropTarget : public LLView
{
public:
	LLDropTarget(const std::string& name, const LLRect& rect, const LLUUID& agent_id);
	~LLDropTarget();

	virtual EWidgetType getWidgetType() const;
	virtual LLString getWidgetTag() const;

	void doDrop(EDragAndDropType cargo_type, void* cargo_data);

	//
	// LLView functionality
	virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
								   EDragAndDropType cargo_type,
								   void* cargo_data,
								   EAcceptance* accept,
								   LLString& tooltip_msg);
	void setAgentID(const LLUUID &agent_id)		{ mAgentID = agent_id; }
protected:
	LLUUID mAgentID;
};


LLDropTarget::LLDropTarget(const std::string& name, const LLRect& rect,
						   const LLUUID& agent_id) :
	LLView(name, rect, NOT_MOUSE_OPAQUE, FOLLOWS_ALL),
	mAgentID(agent_id)
{
}

LLDropTarget::~LLDropTarget()
{
}

EWidgetType LLDropTarget::getWidgetType() const
{
	return WIDGET_TYPE_DROP_TARGET;
}

LLString LLDropTarget::getWidgetTag() const
{
	return LL_DROP_TARGET_TAG;
}

void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data)
{
	llinfos << "LLDropTarget::doDrop()" << llendl;
}

BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
									 EDragAndDropType cargo_type,
									 void* cargo_data,
									 EAcceptance* accept,
									 LLString& tooltip_msg)
{
	BOOL handled = FALSE;
	if(getParent())
	{
		// check if inside
		//LLRect parent_rect = mParentView->getRect();
		//mRect.set(0, parent_rect.getHeight(), parent_rect.getWidth(), 0);
		handled = TRUE;

		// check the type
		switch(cargo_type)
		{
		case DAD_TEXTURE:
		case DAD_SOUND:
		case DAD_LANDMARK:
		case DAD_SCRIPT:
		case DAD_OBJECT:
		case DAD_NOTECARD:
		case DAD_CLOTHING:
		case DAD_BODYPART:
		case DAD_ANIMATION:
		case DAD_GESTURE:
		{
			LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
			if(gInventory.getItem(inv_item->getUUID())
				&& LLToolDragAndDrop::isInventoryGiveAcceptable(inv_item))
			{
				// *TODO: get multiple object transfers working
				*accept = ACCEPT_YES_COPY_SINGLE;
				if(drop)
				{
					LLToolDragAndDrop::giveInventory(mAgentID, inv_item);
				}
			}
			else
			{
				// It's not in the user's inventory (it's probably
				// in an object's contents), so disallow dragging
				// it here.  You can't give something you don't
				// yet have.
				*accept = ACCEPT_NO;
			}
			break;
		}
		case DAD_CATEGORY:
		{
			LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data;
			if( gInventory.getCategory( inv_cat->getUUID() ) )
			{
				// *TODO: get multiple object transfers working
				*accept = ACCEPT_YES_COPY_SINGLE;
				if(drop)
				{
					LLToolDragAndDrop::giveInventoryCategory(mAgentID,
																inv_cat);
				}
			}
			else
			{
				// It's not in the user's inventory (it's probably
				// in an object's contents), so disallow dragging
				// it here.  You can't give something you don't
				// yet have.
				*accept = ACCEPT_NO;
			}
			break;
		}
		case DAD_CALLINGCARD:
		default:
			*accept = ACCEPT_NO;
			break;
		}
	}
	return handled;
}


//-----------------------------------------------------------------------------
// LLPanelAvatarSecondLife()
//-----------------------------------------------------------------------------
LLPanelAvatarSecondLife::LLPanelAvatarSecondLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar ) 
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar),
	mPartnerID()
{
}

LLPanelAvatarSecondLife::~LLPanelAvatarSecondLife()
{
}

void LLPanelAvatarSecondLife::draw()
{
	if (getVisible())
	{
		updatePartnerName();
	}

	LLPanel::draw();
}

void LLPanelAvatarSecondLife::updatePartnerName()
{
	if (mPartnerID.notNull())
	{
		char first[128];
		char last[128];
		BOOL found = gCacheName->getName(mPartnerID, first, last);
		if (found)
		{
			childSetTextArg("partner_edit", "[FIRST]", first);
			childSetTextArg("partner_edit", "[LAST]", last);
		}
	}
}

//-----------------------------------------------------------------------------
// clearControls()
// Empty the data out of the controls, since we have to wait for new
// data off the network.
//-----------------------------------------------------------------------------
void LLPanelAvatarSecondLife::clearControls()
{
	LLTextureCtrl*	image_ctrl = LLUICtrlFactory::getTexturePickerByName(this,"img");
	if(image_ctrl)
	{
		image_ctrl->setImageAssetID(LLUUID::null);
	}
	childSetValue("about", "");
	childSetValue("born", "");
	childSetValue("acct", "");

	childSetTextArg("partner_edit", "[FIRST]", "");
	childSetTextArg("partner_edit", "[LAST]", "");

	mPartnerID = LLUUID::null;
	
	LLScrollListCtrl*	group_list = LLUICtrlFactory::getScrollListByName(this,"groups"); 
	if(group_list)
	{
		group_list->deleteAllItems();
	}
	LLScrollListCtrl*	ratings_list = LLUICtrlFactory::getScrollListByName(this,"ratings"); 
	if(ratings_list)
	{
		ratings_list->deleteAllItems();
	}

}


//-----------------------------------------------------------------------------
// enableControls()
//-----------------------------------------------------------------------------
void LLPanelAvatarSecondLife::enableControls(BOOL self)
{
	childSetEnabled("img", self);
	childSetEnabled("about", self);
	childSetVisible("allow_publish", self);
	childSetEnabled("allow_publish", self);
	childSetVisible("?", self);
	childSetEnabled("?", self);

	if (!self)
	{
		// This is because the LLTextEditor
		// appears to reset the read only background color when
		// setEnable is called, for some reason
		LLTextEditor* about = LLUICtrlFactory::getTextEditorByName(this,"about");
		if (about) about->setReadOnlyBgColor(CLEAR);
	}
}


// static
void LLPanelAvatarSecondLife::onClickImage(void *)
{ }

// static
void LLPanelAvatarSecondLife::onDoubleClickGroup(void* data)
{
	LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*)data;

	
	LLScrollListCtrl*	group_list =  LLUICtrlFactory::getScrollListByName(self,"groups"); 
	if(group_list)
	{
		LLScrollListItem* item = group_list->getFirstSelected();
		if(item && item->getUUID().notNull())
		{
			llinfos << "Show group info " << item->getUUID() << llendl;

			LLFloaterGroupInfo::showFromUUID(item->getUUID());
		}
	}
}

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

//-----------------------------------------------------------------------------
// LLPanelAvatarFirstLife()
//-----------------------------------------------------------------------------
LLPanelAvatarFirstLife::LLPanelAvatarFirstLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar ) 
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar)
{
}


LLPanelAvatarFirstLife::~LLPanelAvatarFirstLife()
{
}


void LLPanelAvatarFirstLife::enableControls(BOOL self)
{
	childSetEnabled("img", self);
	childSetEnabled("about", self);
}

//-----------------------------------------------------------------------------
// postBuild
//-----------------------------------------------------------------------------

BOOL LLPanelAvatarSecondLife::postBuild(void)
{
	childSetEnabled("born", FALSE);
	childSetEnabled("partner_edit", FALSE);
	
	childSetAction("?",onClickPublishHelp,this);
	BOOL own_avatar = (mPanelAvatar->getAvatarID() == gAgent.getID() );
	enableControls(own_avatar);

	childSetVisible("About:",LLPanelAvatar::sAllowFirstLife);
	childSetVisible("(500 chars)",LLPanelAvatar::sAllowFirstLife);
	childSetVisible("about",LLPanelAvatar::sAllowFirstLife);
	
	childSetVisible("allow_publish",LLPanelAvatar::sAllowFirstLife);
	childSetVisible("?",LLPanelAvatar::sAllowFirstLife);

	childSetVisible("online_unknown",TRUE);
	childSetVisible("online_yes",FALSE);
	childSetVisible("online_no",FALSE);

	childSetAction("Show on Map", LLPanelAvatar::onClickTrack, mPanelAvatar);
	childSetAction("Instant Message...", LLPanelAvatar::onClickIM, mPanelAvatar);
	childSetAction("Rate...", LLPanelAvatar::onClickRate, mPanelAvatar);
	childSetAction("Pay...", LLPanelAvatar::onClickPay, mPanelAvatar);
	childSetAction("Mute", LLPanelAvatar::onClickMute, mPanelAvatar );	

	childSetAction("Offer Teleport...", LLPanelAvatar::onClickOfferTeleport, mPanelAvatar);

	childSetDoubleClickCallback("groups", onDoubleClickGroup, this );

	return TRUE;
}
BOOL LLPanelAvatarFirstLife::postBuild(void)
{
	BOOL own_avatar = (mPanelAvatar->getAvatarID() == gAgent.getID() );
	enableControls(own_avatar);
	return TRUE;
}
BOOL LLPanelAvatarNotes::postBuild(void)
{	childSetCommitCallback("notes edit",onCommitNotes,this);
	
	LLTextEditor*	te = LLUICtrlFactory::getTextEditorByName(this,"notes edit");
	if(te) te->setCommitOnFocusLost(TRUE);
	return TRUE;
}

BOOL LLPanelAvatarWeb::postBuild(void)
{
	childSetAction("load",onClickLoad,this);
	childSetAction("open",onClickOpen,this);
	childSetAction("home",onClickLoad,this);
	childSetAction("web_profile_help",onClickWebProfileHelp,this);

	childSetCommitCallback("url_edit",onCommitURL,this);

	childSetControlName("auto_load","AutoLoadWebProfiles");

#if LL_LIBXUL_ENABLED
	mWebBrowser = (LLWebBrowserCtrl*)getChildByName("profile_html");

	// links open in internally 
	mWebBrowser->setOpenInExternalBrowser( false );

	// observe browser events
	mWebBrowser->addObserver( this );
#endif // LL_LIBXUL_ENABLED

	return TRUE;
}

BOOL LLPanelAvatarClassified::postBuild(void)
{
	childSetAction("New...",onClickNew,NULL);
	childSetAction("Delete...",onClickDelete,NULL);
	return TRUE;
}
BOOL LLPanelAvatarPicks::postBuild(void)
{
	childSetAction("New...",onClickNew,NULL);
	childSetAction("Delete...",onClickDelete,NULL);
	return TRUE;
}

BOOL	LLPanelAvatarAdvanced::postBuild()
{
	for( S32 i = 0; i < kArraySize(mWantToCheck); i++ )
		mWantToCheck[i] = NULL;
	for( S32 i = 0; i < kArraySize(mSkillsCheck); i++ )
		mSkillsCheck[i] = NULL;
	mWantToCount = (8>kArraySize(mWantToCheck))?kArraySize(mWantToCheck):8;
	for(int t=0;t < mWantToCount ;t++)
	{	
		LLString ctlname = llformat("chk%d",t);
		mWantToCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
	}	
	mSkillsCount = (6>kArraySize(mSkillsCheck))?kArraySize(mSkillsCheck):6;

	for(int t=0;t<mSkillsCount;t++)
	{
		//Find the Skills checkboxes and save off thier controls
		LLString ctlname = llformat("schk%d",t);
		mSkillsCheck[t] = LLUICtrlFactory::getCheckBoxByName(this,ctlname);
	}

	mWantToEdit = LLUICtrlFactory::getLineEditorByName(this,"want_to_edit");
	mSkillsEdit = LLUICtrlFactory::getLineEditorByName(this,"skills_edit");
	childSetVisible("skills_edit",LLPanelAvatar::sAllowFirstLife);
	childSetVisible("want_to_edit",LLPanelAvatar::sAllowFirstLife);

	return TRUE;
}

LLPanelAvatarWeb::LLPanelAvatarWeb(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar)
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar),
	mWebBrowser(NULL)
{
}

LLPanelAvatarWeb::~LLPanelAvatarWeb()
{
#if LL_LIBXUL_ENABLED
	// stop observing browser events
	if  ( mWebBrowser )
	{
		mWebBrowser->remObserver( this );
	};
#endif
}

void LLPanelAvatarWeb::enableControls(BOOL self)
{	
	childSetEnabled("url_edit",self);
	childSetVisible("status_text",!self);
}

void LLPanelAvatarWeb::setWebURL(std::string url)
{
	bool changed_url = (mURL != url);

	mURL = url;
	bool have_url = !mURL.empty();
	
	childSetText("url_edit",mURL);

	childSetEnabled("load",have_url);
	childSetEnabled("open",have_url);

	childSetVisible("home",false);
	childSetVisible("load",true);

	if (have_url
		&& gSavedSettings.getBOOL("AutoLoadWebProfiles"))
	{
		if (changed_url)
		{
			load();
		}
	}
	else
	{
		childSetVisible("profile_html",false);
	}
	
#if !LL_LIBXUL_ENABLED
	childSetVisible("load",false);
	childSetVisible("profile_html",false);
	childSetVisible("status_text",false);
#endif

}

// static
void LLPanelAvatarWeb::onCommitURL(LLUICtrl* ctrl, void* data)
{
	LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data;

	if (!self) return;
	
	self->load( self->childGetText("url_edit") );
}

// static
void LLPanelAvatarWeb::onClickWebProfileHelp(void *)
{
#if LL_LIBXUL_ENABLED
	gViewerWindow->alertXml("ClickWebProfileHelpAvatar");
#else
	gViewerWindow->alertXml("ClickWebProfileNoWebHelpAvatar");
#endif
}

void LLPanelAvatarWeb::load(std::string url)
{
	bool have_url = (!url.empty());

#if LL_LIBXUL_ENABLED
	if (have_url)
	{
		llinfos << "Loading " << url << llendl;
		mWebBrowser->navigateTo( url );
	}

	// If we have_url then we loaded so use the home button
	// Or if the url in address bar is not the home url show the home button.
	bool use_home = (have_url
					 || url != mURL);
					 
	childSetVisible("profile_html",have_url);
	childSetVisible("load",!use_home);	
	childSetVisible("home",use_home);

	childSetEnabled("load",!use_home);
	childSetEnabled("home",use_home);
	childSetEnabled("open",have_url);
	
#else
	childSetEnabled("open",have_url);
#endif
}

void LLPanelAvatarWeb::load()
{
	load(mURL);
}

// static
void LLPanelAvatarWeb::onClickLoad(void* data)
{
	LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data;

	if (!self) return;
	
	self->load();
}

// static
void LLPanelAvatarWeb::onClickOpen(void* data)
{
	LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data;

	if (!self) return;

	std::string url = self->childGetText("url_edit");
	if (!url.empty())
	{
		LLWeb::loadURLExternal(url);
	}
}

#if LL_LIBXUL_ENABLED
void LLPanelAvatarWeb::onStatusTextChange( const EventType& eventIn )
{
	childSetText("status_text", eventIn.getStringValue() );
}

void LLPanelAvatarWeb::onLocationChange( const EventType& eventIn )
{
	childSetText("url_edit", eventIn.getStringValue() );
}
#endif

LLPanelAvatarAdvanced::LLPanelAvatarAdvanced(
	const std::string& name,
	const LLRect& rect,
	LLPanelAvatar* panel_avatar)
	:
	LLPanel(name, rect),
	mPanelAvatar(panel_avatar),
	mWantToCount(0),
	mSkillsCount(0),
	mWantToEdit( NULL ),
	mSkillsEdit( NULL )
{
}

LLPanelAvatarAdvanced::~LLPanelAvatarAdvanced()
{
}


void LLPanelAvatarAdvanced::enableControls(BOOL self)
{	int t;
	for(t=0;t<mWantToCount;t++)
	{
		if(mWantToCheck[t])mWantToCheck[t]->setEnabled(self);
	}
	for(t=0;t<mSkillsCount;t++)
	{
		if(mSkillsCheck[t])mSkillsCheck[t]->setEnabled(self);
	}

	if (mWantToEdit) mWantToEdit->setEnabled(self);
	if (mSkillsEdit) mSkillsEdit->setEnabled(self);
	childSetEnabled("languages_edit",self);

	if (!self)
	{
		// This is because the LLTextEditor
		// appears to reset the read only background color when
		// setEnable is called, for some reason
		if (mWantToEdit) mWantToEdit->setReadOnlyBgColor(CLEAR);
		if (mSkillsEdit) mSkillsEdit->setReadOnlyBgColor(CLEAR);
		LLLineEditor* languages_edit = (LLLineEditor*)getChildByName("languages_edit");
		languages_edit->setReadOnlyBgColor(CLEAR);
	}
}

void LLPanelAvatarAdvanced::setWantSkills(U32 want_to_mask, const std::string& want_to_text,
										  U32 skills_mask, const std::string& skills_text,
										  const std::string& languages_text)
{
	for(int id =0;id<mWantToCount;id++)
	{
		mWantToCheck[id]->set( want_to_mask & 1<<id );
	}
	for(int id =0;id<mSkillsCount;id++)
	{
		mSkillsCheck[id]->set( skills_mask & 1<<id );
	}
	if (mWantToEdit && mSkillsEdit)
	{
		mWantToEdit->setText( want_to_text );
		mSkillsEdit->setText( skills_text );
	}

	childSetText("languages_edit",languages_text);
}

void LLPanelAvatarAdvanced::getWantSkills(U32* want_to_mask, std::string& want_to_text,
										  U32* skills_mask, std::string& skills_text,
										  std::string& languages_text)
{
	if (want_to_mask)
	{
		*want_to_mask = 0;
		for(int t=0;t<mWantToCount;t++)
		{
			if(mWantToCheck[t]->get())
				*want_to_mask |= 1<<t;
		}
	}
	if (skills_mask)
	{
		*skills_mask = 0;
		for(int t=0;t<mSkillsCount;t++)
		{
			if(mSkillsCheck[t]->get())
				*skills_mask |= 1<<t;
		}
	}
	if (mWantToEdit)
	{
		want_to_text = mWantToEdit->getText();
	}

	if (mSkillsEdit)
	{
		skills_text = mSkillsEdit->getText();
	}

	languages_text = childGetText("languages_edit");
}	

//-----------------------------------------------------------------------------
// LLPanelAvatarNotes()
//-----------------------------------------------------------------------------
LLPanelAvatarNotes::LLPanelAvatarNotes(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar)
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar)
{
}

LLPanelAvatarNotes::~LLPanelAvatarNotes()
{
}


void LLPanelAvatarNotes::enableControls(BOOL self)
{ }

// static
void LLPanelAvatarNotes::onCommitNotes(LLUICtrl*, void* userdata)
{
	LLPanelAvatarNotes* self = (LLPanelAvatarNotes*)userdata;

	self->mPanelAvatar->sendAvatarNotesUpdate();
}


//-----------------------------------------------------------------------------
// LLPanelAvatarClassified()
//-----------------------------------------------------------------------------
LLPanelAvatarClassified::LLPanelAvatarClassified(const LLString& name, const LLRect& rect,
									   LLPanelAvatar* panel_avatar)
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar)
{
}


LLPanelAvatarClassified::~LLPanelAvatarClassified()
{
	// children deleted by view destructor
}


void LLPanelAvatarClassified::draw()
{
	if (getVisible())
	{
		refresh();

		LLPanel::draw();
	}
}


void LLPanelAvatarClassified::refresh()
{
	BOOL self = (gAgent.getID() == mPanelAvatar->getAvatarID());

	
	LLTabContainerCommon* tabs = LLUICtrlFactory::getTabContainerByName(this,"classified tab");
	
	S32 tab_count = tabs ? tabs->getTabCount() : 0;

	BOOL allow_new = TRUE; //tab_count < MAX_CLASSIFIEDS;
	BOOL allow_delete = (tab_count > 0);
	BOOL show_help = (tab_count == 0);

	childSetEnabled("New...",self && allow_new);
	childSetEnabled("Delete...",self && allow_delete);
	childSetVisible("help_text",self && show_help);
	childSetVisible("classified tab",!show_help);
}


void LLPanelAvatarClassified::enableControls(BOOL self)
{
}

BOOL LLPanelAvatarClassified::titleIsValid()
{
	LLTabContainerCommon* tabs = LLViewerUICtrlFactory::getTabContainerByName(this, "classified tab");
	if ( tabs )
	{
		LLPanelClassified* panel = (LLPanelClassified*)tabs->getCurrentPanel();
		if ( panel )
		{
			if ( ! panel->titleIsValid() )
			{
				return FALSE;
			};
		};
	};

	return TRUE;
}

void LLPanelAvatarClassified::apply()
{
	LLTabContainerCommon* tabs = LLViewerUICtrlFactory::getTabContainerByName(this, "classified tab");
	for (S32 i = 0; i < tabs->getTabCount(); i++)
	{
		LLPanelClassified* panel = (LLPanelClassified*)tabs->getPanelByIndex(i);
		panel->apply();
	}
}


void LLPanelAvatarClassified::deleteClassifiedPanels()
{
	LLTabContainerCommon* tabs = LLViewerUICtrlFactory::getTabContainerByName(this,"classified tab");
	if (tabs)
	{
		tabs->deleteAllTabs();
	}
}


void LLPanelAvatarClassified::processAvatarClassifiedReply(LLMessageSystem* msg, void**)
{
	S32 block = 0;
	S32 block_count = 0;
	LLUUID classified_id;
	char classified_name[DB_PICK_NAME_SIZE];
	LLPanelClassified* panel_classified = NULL;

	LLTabContainerCommon* tabs = LLViewerUICtrlFactory::getTabContainerByName(this,"classified tab");

	// Clear out all the old panels.
	// We'll replace them with the correct number of new panels.
	deleteClassifiedPanels();

	block_count = msg->getNumberOfBlocksFast(_PREHASH_Data);
	for (block = 0; block < block_count; block++)
	{
		msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id, block);
		msg->getStringFast(_PREHASH_Data, _PREHASH_Name, DB_PICK_NAME_SIZE, classified_name, block);

		panel_classified = new LLPanelClassified(FALSE);

		panel_classified->setClassifiedID(classified_id);

		// This will request data from the server when the pick is first drawn.
		panel_classified->markForServerRequest();

		// The button should automatically truncate long names for us
		if(tabs)
		{
			tabs->addTabPanel(panel_classified, classified_name);
		}
	}

	// Make sure somebody is highlighted.  This works even if there
	// are no tabs in the container.
	if(tabs)
	{
		tabs->selectFirstTab();
	}
}


// Create a new classified panel.  It will automatically handle generating
// its own id when it's time to save.
// static
void LLPanelAvatarClassified::onClickNew(void* data)
{
	LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data;

	gViewerWindow->alertXml("AddClassified",callbackNew,self);
		
}

// static
void LLPanelAvatarClassified::callbackNew(S32 option, void* data)
{
	LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data;

	if (0 == option)
	{
		LLPanelClassified* panel_classified = new LLPanelClassified(FALSE);
		panel_classified->initNewClassified();
		LLTabContainerCommon*	tabs = LLViewerUICtrlFactory::getTabContainerByName(self,"classified tab");
		if(tabs)
		{
			tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName());
			tabs->selectLastTab();
		}
	}
}


// static
void LLPanelAvatarClassified::onClickDelete(void* data)
{
	LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data;

	LLTabContainerCommon*	tabs = LLViewerUICtrlFactory::getTabContainerByName(self,"classified tab");
	LLPanelClassified* panel_classified = NULL;
	if(tabs)
	{
		panel_classified = (LLPanelClassified*)tabs->getCurrentPanel();
	}
	if (!panel_classified) return;

	LLStringBase<char>::format_map_t args;
	args["[NAME]"] = panel_classified->getClassifiedName();
	gViewerWindow->alertXml("DeleteClassified", args, callbackDelete, self);
		
}


// static
void LLPanelAvatarClassified::callbackDelete(S32 option, void* data)
{
	LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data;
	LLTabContainerCommon*	tabs = LLViewerUICtrlFactory::getTabContainerByName(self,"classified tab");
	LLPanelClassified* panel_classified=NULL;
	if(tabs)
	{
		panel_classified = (LLPanelClassified*)tabs->getCurrentPanel();
	}
	
	LLMessageSystem* msg = gMessageSystem;

	if (!panel_classified) return;

	if (0 == option)
	{
		msg->newMessageFast(_PREHASH_ClassifiedDelete);
		msg->nextBlockFast(_PREHASH_AgentData);
		msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
		msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
		msg->nextBlockFast(_PREHASH_Data);
		msg->addUUIDFast(_PREHASH_ClassifiedID, panel_classified->getClassifiedID());
		gAgent.sendReliableMessage();

		if(tabs)
		{
			tabs->removeTabPanel(panel_classified);
		}
		delete panel_classified;
		panel_classified = NULL;
	}
}


//-----------------------------------------------------------------------------
// LLPanelAvatarPicks()
//-----------------------------------------------------------------------------
LLPanelAvatarPicks::LLPanelAvatarPicks(const std::string& name, const LLRect& rect,
									   LLPanelAvatar* panel_avatar)
:	LLPanel(name, rect),
	mPanelAvatar(panel_avatar)
{
}


LLPanelAvatarPicks::~LLPanelAvatarPicks()
{
	// children deleted by view destructor
}


void LLPanelAvatarPicks::draw()
{
	if (getVisible())
	{
		refresh();

		LLPanel::draw();
	}
}


void LLPanelAvatarPicks::refresh()
{
	BOOL self = (gAgent.getID() == mPanelAvatar->getAvatarID());

	LLTabContainerCommon*	tabs = LLViewerUICtrlFactory::getTabContainerByName(this,"picks tab");
	S32 tab_count = tabs ? tabs->getTabCount() : 0;
	BOOL allow_new = (tab_count < MAX_AVATAR_PICKS);
	BOOL allow_delete = (tab_count > 0);

	childSetEnabled("New...",self && allow_new);
	childSetEnabled("Delete...",self && allow_delete);
}


// You are only allowed 10 picks.
void LLPanelAvatarPicks::enableControls(BOOL self)
{
}


void LLPanelAvatarPicks::deletePickPanels()
{
	LLTabContainerCommon* tabs = LLUICtrlFactory::getTabContainerByName(this,"picks tab");
	if(tabs)
	{
		tabs->deleteAllTabs();
	}
}


void LLPanelAvatarPicks::processAvatarPicksReply(LLMessageSystem* msg, void**)
{
	S32 block = 0;
	S32 block_count = 0;
	LLUUID pick_id;
	char pick_name[DB_PICK_NAME_SIZE];
	LLPanelPick* panel_pick = NULL;

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

	// Clear out all the old panels.  We'll replace them with the correct
	// number of new panels.
	deletePickPanels();

	block_count = msg->getNumberOfBlocks("Data");
	for (block = 0; block < block_count; block++)
	{
		msg->getUUID("Data", "PickID", pick_id, block);
		msg->getString("Data", "PickName", DB_PICK_NAME_SIZE, pick_name, block);

		panel_pick = new LLPanelPick(FALSE);

		panel_pick->setPickID(pick_id);

		// This will request data from the server when the pick is first
		// drawn.
		panel_pick->markForServerRequest();

		// The button should automatically truncate long names for us
		if(tabs)
		{
			tabs->addTabPanel(panel_pick, pick_name);
		}
	}

	// Make sure somebody is highlighted.  This works even if there
	// are no tabs in the container.
	if(tabs)
	{
		tabs->selectFirstTab();
	}
}


// Create a new pick panel.  It will automatically handle generating
// its own id when it's time to save.
// static
void LLPanelAvatarPicks::onClickNew(void* data)
{
	LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data;
	LLPanelPick* panel_pick = new LLPanelPick(FALSE);
	LLTabContainerCommon* tabs =  LLUICtrlFactory::getTabContainerByName(self,"picks tab");

	panel_pick->initNewPick();
	if(tabs)
	{
		tabs->addTabPanel(panel_pick, panel_pick->getPickName());
		tabs->selectLastTab();
	}
}


// static
void LLPanelAvatarPicks::onClickDelete(void* data)
{
	LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data;
	LLTabContainerCommon* tabs =  LLUICtrlFactory::getTabContainerByName(self,"picks tab");
	LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL;

	if (!panel_pick) return;

	LLString::format_map_t args;
	args["[PICK]"] = panel_pick->getPickName();

	gViewerWindow->alertXml("DeleteAvatarPick", args,
		callbackDelete,
		self);
}


// static
void LLPanelAvatarPicks::callbackDelete(S32 option, void* data)
{
	LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data;
	LLTabContainerCommon* tabs = LLUICtrlFactory::getTabContainerByName(self,"picks tab");
	LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL;
	LLMessageSystem* msg = gMessageSystem;

	if (!panel_pick) return;

	if (0 == option)
	{
		// If the viewer has a hacked god-mode, then this call will
		// fail.
		if(gAgent.isGodlike())
		{
			msg->newMessage("PickGodDelete");			
		}
		else
		{
			msg->newMessage("PickDelete");
		}
		msg->nextBlock("AgentData");
		msg->addUUID("AgentID", gAgent.getID());
		msg->addUUID("SessionID", gAgent.getSessionID());
		msg->nextBlock("Data");
		msg->addUUID("PickID", panel_pick->getPickID());
		
		//God delete receiving end expects a query ID but we dont need it, so send a null.
		//This is to resolve SL-24170 God Picks Delete results in crash.
		if(gAgent.isGodlike())
			msg->addUUID( "QueryID", LLUUID::null );
		

		gAgent.sendReliableMessage();

		if(tabs)
		{
			tabs->removeTabPanel(panel_pick);
		}
		delete panel_pick;
		panel_pick = NULL;
	}
}


//-----------------------------------------------------------------------------
// LLPanelAvatar
//-----------------------------------------------------------------------------
LLPanelAvatar::LLPanelAvatar(
	const std::string& name,
	const LLRect &rect,
	BOOL allow_edit)
	:
	LLPanel(name, rect, FALSE),
	mPanelSecondLife(NULL),
	mPanelAdvanced(NULL),
	mPanelClassified(NULL),
	mPanelPicks(NULL),
	mPanelNotes(NULL),
	mPanelFirstLife(NULL),
	mPanelWeb(NULL),
	mDropTarget(NULL),
	mAvatarID( LLUUID::null ),	// mAvatarID is set with 'setAvatar' or 'setAvatarID'
	mHaveProperties(FALSE),
	mHaveStatistics(FALSE),
	mAllowEdit(allow_edit),
	mDisableRate(FALSE)
{

	sAllPanels.addData(this);

	LLCallbackMap::map_t factory_map;

	factory_map["2nd Life"] = LLCallbackMap(createPanelAvatarSecondLife, this);
	factory_map["WebProfile"] = LLCallbackMap(createPanelAvatarWeb, this);
	factory_map["Interests"] = LLCallbackMap(createPanelAvatarInterests, this);
	factory_map["Picks"] = LLCallbackMap(createPanelAvatarPicks, this);
	factory_map["Classified"] = LLCallbackMap(createPanelAvatarClassified, this);
	factory_map["1st Life"] = LLCallbackMap(createPanelAvatarFirstLife, this);
	factory_map["My Notes"] = LLCallbackMap(createPanelAvatarNotes, this);
	
	gUICtrlFactory->buildPanel(this, "panel_avatar.xml", &factory_map);

	selectTab(0);
	

}

BOOL LLPanelAvatar::postBuild(void)
{
	mTab = LLUICtrlFactory::getTabContainerByName(this,"tab");
	childSetAction("Kick",onClickKick,this);
	childSetAction("Freeze",onClickFreeze, this);
	childSetAction("Unfreeze", onClickUnfreeze, this);
	childSetAction("csr_btn", onClickCSR, this);
	childSetAction("OK", onClickOK, this);
	childSetAction("Cancel", onClickCancel, this);

	if(mTab && !sAllowFirstLife)
	{
		LLPanel* panel = mTab->getPanelByName("1st Life");
		if (panel) mTab->removeTabPanel(panel);

		panel = mTab->getPanelByName("WebProfile");
		if (panel) mTab->removeTabPanel(panel);
	}
	childSetVisible("Kick",FALSE);
	childSetEnabled("Kick",FALSE);
	childSetVisible("Freeze",FALSE);
	childSetEnabled("Freeze",FALSE);
	childSetVisible("Unfreeze",FALSE);
	childSetEnabled("Unfreeze",FALSE);
	childSetVisible("csr_btn", FALSE);
	childSetEnabled("csr_btn", FALSE);

	return TRUE;
}


LLPanelAvatar::~LLPanelAvatar()
{
	sAllPanels.removeData(this);
}


void LLPanelAvatar::setAvatar(LLViewerObject *avatarp)
{
	// find the avatar and grab the name
	LLNameValue *firstname = avatarp->getNVPair("FirstName");
	LLNameValue *lastname = avatarp->getNVPair("LastName");

	LLString name;
	if (firstname && lastname)
	{
		name.assign( firstname->getString() );
		name.append(" ");
		name.append( lastname->getString() );
	}
	else
	{
		name.assign("");
	}

	// If we have an avatar pointer, they must be online.
	setAvatarID(avatarp->getID(), name, ONLINE_STATUS_YES);
}


void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const LLString &name,
								EOnlineStatus online_status)
{
	if (avatar_id.isNull()) return;

	BOOL avatar_changed = FALSE;
	if (avatar_id != mAvatarID)
	{
		avatar_changed = TRUE;
	}
	mAvatarID = avatar_id;

	// Determine if we have their calling card.
	mIsFriend = is_agent_friend(mAvatarID); 

	if (ONLINE_STATUS_UNKNOWN == online_status)
	{
		// Determine if we know that they are online.  If we can see them,
		// we know they're online.  Likewise, if we have a calling card,
		// we know.  Otherwise we don't.
		LLViewerObject* object = gObjectList.findObject( mAvatarID );
		if (object && !object->isDead())
		{
			online_status = ONLINE_STATUS_YES;
		}
		else if (mIsFriend)
		{
			if (LLAvatarTracker::instance().isBuddyOnline( mAvatarID ))
			{
				online_status = ONLINE_STATUS_YES;
			}
			else
			{
				online_status = ONLINE_STATUS_NO;
			}
		}
		else
		{
			// Don't actually know if they are online.
		}
	}

	mPanelSecondLife->childSetVisible("online_unknown",FALSE);
	mPanelSecondLife->childSetVisible("online_yes",FALSE);
	mPanelSecondLife->childSetVisible("online_no",FALSE);

	switch(online_status)
	{
	  case ONLINE_STATUS_YES:
		mPanelSecondLife->childSetVisible("online_yes",TRUE);
		break;
	  case ONLINE_STATUS_NO:
		mPanelSecondLife->childSetVisible("online_no",TRUE);
		break;
	  case ONLINE_STATUS_UNKNOWN:
	  default:
		mPanelSecondLife->childSetVisible("online_unknown",TRUE);
		break;
	}
	
	BOOL own_avatar = (mAvatarID == gAgent.getID() );

	mPanelSecondLife->enableControls(own_avatar && mAllowEdit);
	mPanelWeb->enableControls(own_avatar && mAllowEdit);
	mPanelAdvanced->enableControls(own_avatar && mAllowEdit);
	mPanelPicks->enableControls(own_avatar && mAllowEdit);
	mPanelClassified->enableControls(own_avatar && mAllowEdit);
	// Teens don't have this.
	if (mPanelFirstLife) mPanelFirstLife->enableControls(own_avatar && mAllowEdit);
	mPanelNotes->enableControls(own_avatar && mAllowEdit);


	LLView *target_view = getChildByName("drop_target_rect", TRUE);
	if(target_view)
	{
		if (mDropTarget)
		{
			delete mDropTarget;
		}
		mDropTarget = new LLDropTarget("drop target", target_view->getRect(), mAvatarID);
		addChild(mDropTarget);
		mDropTarget->setAgentID(mAvatarID);
	}

	LLNameEditor*	NameEdit = LLViewerUICtrlFactory::getNameEditorByName(this, "name");
	if(NameEdit)
	{
		if (name.empty())
		{
			NameEdit->setNameID(avatar_id, FALSE);
		}
		else
		{
			NameEdit->setText(name);
		}
	}
// 	if (avatar_changed)
	{
		// While we're waiting for data off the network, clear out the
		// old data.
		mPanelSecondLife->clearControls();
		mPanelPicks->deletePickPanels();
		mPanelClassified->deleteClassifiedPanels();

		sendAvatarPropertiesRequest();

		if (own_avatar)
		{
			if (mAllowEdit)
			{
				// OK button disabled until properties data arrives
				childSetVisible("OK",TRUE);
				childSetEnabled("OK",TRUE);
				childSetVisible("Cancel",TRUE);
				childSetEnabled("Cancel",TRUE);
			}
			else
			{
				childSetVisible("OK",FALSE);
				childSetEnabled("OK",FALSE);
			}
			childSetVisible("Instant Message...",FALSE);
			childSetEnabled("Instant Message...",FALSE);
			childSetVisible("Mute",FALSE);
			childSetEnabled("Mute",FALSE);
			childSetVisible("Offer Teleport...",FALSE);
			childSetEnabled("Offer Teleport...",FALSE);
			childSetVisible("drop target",FALSE);
			childSetEnabled("drop target",FALSE);
			childSetVisible("Show on Map",FALSE);
			childSetEnabled("Show on Map",FALSE);
			childSetVisible("Rate...",FALSE);
			childSetEnabled("Rate...",FALSE);
			childSetVisible("Pay...",FALSE);
			childSetEnabled("Pay...",FALSE);
		}
		else
		{
			childSetVisible("OK",FALSE);
			childSetEnabled("OK",FALSE);

			childSetVisible("Cancel",FALSE);
			childSetEnabled("Cancel",FALSE);

			childSetVisible("Instant Message...",TRUE);
			childSetEnabled("Instant Message...",FALSE);
			childSetToolTip("Instant Message...",IM_ENABLED_TOOLTIP);
			childSetVisible("Mute",TRUE);
			childSetEnabled("Mute",FALSE);

			childSetVisible("Offer Teleport...",TRUE);
			BOOL in_prelude = gAgent.inPrelude();
			if(gAgent.isGodlike())
			{
				childSetEnabled("Offer Teleport...", TRUE);
				childSetToolTip("Offer Teleport...", childGetValue("TeleportGod").asString());
			}
			else if (in_prelude)
			{
				childSetEnabled("Offer Teleport...",FALSE);
				childSetToolTip("Offer Teleport...",childGetValue("TeleportPrelude").asString());
			}
			else
			{
				// Even if user might be offline, allow a teleport offer.
				BOOL maybe_online = (online_status != ONLINE_STATUS_NO);
				childSetEnabled("Offer Teleport...", maybe_online);
				childSetToolTip("Offer Teleport...", childGetValue("TeleportNormal").asString());
			}
			childSetVisible("drop target",TRUE);
			childSetEnabled("drop target",FALSE);

			childSetVisible("Show on Map",TRUE);
			// Note: we don't always know online status, so always allow gods to try to track
			BOOL enable_track = gAgent.isGodlike() || is_agent_mappable(mAvatarID);
			childSetEnabled("Show on Map",enable_track);
			if (!mIsFriend)
			{
				childSetToolTip("Show on Map",childGetValue("ShowOnMapNonFriend").asString());
			}
			else if (ONLINE_STATUS_YES != online_status)
			{
				childSetToolTip("Show on Map",childGetValue("ShowOnMapFriendOffline").asString());
			}
			else
			{
				childSetToolTip("Show on Map",childGetValue("ShowOnMapFriendOnline").asString());
			}
			childSetVisible("Rate...",TRUE);
			childSetEnabled("Rate...",FALSE);
			childSetVisible("Pay...",TRUE);
			childSetEnabled("Pay...",FALSE);
		}
	}
	
	BOOL is_god = FALSE;
	if (gAgent.isGodlike()) is_god = TRUE;
	
	childSetVisible("Kick", is_god);
	childSetEnabled("Kick", is_god);
	childSetVisible("Freeze", is_god);
	childSetEnabled("Freeze", is_god);
	childSetVisible("Unfreeze", is_god);
	childSetEnabled("Unfreeze", is_god);
	childSetVisible("csr_btn", is_god);
	childSetEnabled("csr_btn", is_god);
}


void LLPanelAvatar::resetGroupList()
{
	// only get these updates asynchronously via the group floater, which works on the agent only
	if (mAvatarID != gAgent.getID())
	{
		return;
	}
	LLScrollListCtrl*	group_list = LLUICtrlFactory::getScrollListByName(mPanelSecondLife,"groups");
		
	if (mPanelSecondLife && group_list)
	{
		group_list->deleteAllItems();
		LLScrollListItem* item;

		S32 count = gAgent.mGroups.count();
		LLUUID id;

		for(S32 i = 0; i < count; ++i)
		{
			LLGroupData group_data = gAgent.mGroups.get(i);
			id = group_data.mID;
			std::string group_string;
			/* Show group title?  DUMMY_POWER for Don Grep
			if(group_data.mOfficer)
			{
				group_string = "Officer of ";
			}
			else
			{
				group_string = "Member of ";
			}
			*/

			group_string += group_data.mName;
			item = new LLScrollListItem(TRUE, NULL, id);
			item->addColumn(group_string, LLFontGL::sSansSerifSmall, 0, LLFontGL::NORMAL);
			group_list->addItem(item);
		}
		group_list->sortByColumn(0, TRUE);
	}
}

// static
//-----------------------------------------------------------------------------
// onClickIM()
//-----------------------------------------------------------------------------
void LLPanelAvatar::onClickIM(void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;
	gIMView->setFloaterOpen(TRUE);

	std::string name;
	LLNameEditor* nameedit = LLViewerUICtrlFactory::getNameEditorByName(self->mPanelSecondLife, "name");
	if (nameedit) name = nameedit->getText();
	gIMView->addSession(name, IM_NOTHING_SPECIAL, self->mAvatarID);
}


// static
//-----------------------------------------------------------------------------
// onClickTrack()
//-----------------------------------------------------------------------------
void LLPanelAvatar::onClickTrack(void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;
	
	if( gFloaterWorldMap )
	{
		std::string name;
		LLNameEditor* nameedit = LLViewerUICtrlFactory::getNameEditorByName(self->mPanelSecondLife, "name");
		if (nameedit) name = nameedit->getText();
		gFloaterWorldMap->trackAvatar(self->mAvatarID, name);
		LLFloaterWorldMap::show(NULL, TRUE);
	}
}

// static
//-----------------------------------------------------------------------------
// onClickRate()
//-----------------------------------------------------------------------------
void LLPanelAvatar::onClickRate(void *userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	LLFloaterRate::show(self->mAvatarID);
}

//-----------------------------------------------------------------------------
// onClickMute()
//-----------------------------------------------------------------------------
void LLPanelAvatar::onClickMute(void *userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;
	
	LLUUID agent_id = self->getAvatarID();
	LLNameEditor* name_edit = LLViewerUICtrlFactory::getNameEditorByName(self->mPanelSecondLife, "name");
	
	if (name_edit)
	{
		std::string agent_name = name_edit->getText();
		gFloaterMute->show();
		
		if (gMuteListp->isMuted(agent_id))
		{
			gFloaterMute->selectMute(agent_id);
		}
		else
		{
			LLMute mute(agent_id, agent_name, LLMute::AGENT);
			gMuteListp->add(mute);
		}
	}
}


void LLPanelAvatar::disableRate()
{
	// Force off the rate button, but enable IM.
	// Note that these buttons may not exist if it is your own profile.
	childSetEnabled("Rate...",FALSE);
	mDisableRate = TRUE;
}


// static
void LLPanelAvatar::onClickOfferTeleport(void *userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	handle_lure(self->mAvatarID);
}


// static
void LLPanelAvatar::onClickPay(void *userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;
	handle_pay_by_id(self->mAvatarID);
}


// static
void LLPanelAvatar::onClickOK(void *userdata)
{
	LLPanelAvatar *self = (LLPanelAvatar *)userdata;

	// JC: Only save the data if we actually got the original
	// properties.  Otherwise we might save blanks into
	// the database.
	if (self
		&& self->mHaveProperties)
	{
		self->sendAvatarPropertiesUpdate();

		LLTabContainerCommon* tabs = LLUICtrlFactory::getTabContainerByName(self,"tab");
		if ( tabs->getCurrentPanel() != self->mPanelClassified )
		{
			self->mPanelClassified->apply();

			LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID);
			if (infop)
			{
				infop->close();
			}
		}
		else
		{
			if ( self->mPanelClassified->titleIsValid() )
			{
				self->mPanelClassified->apply();

				LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID);
				if (infop)
				{
					infop->close();
				}
			}
		}
	}
}

// static
void LLPanelAvatar::onClickCancel(void *userdata)
{
	LLPanelAvatar *self = (LLPanelAvatar *)userdata;

	if (self)
	{
		self->sendAvatarPropertiesRequest();
		LLFloaterAvatarInfo *infop;
		if ((infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID)))
		{
			infop->close();
		}
	}
}


void LLPanelAvatar::sendAvatarPropertiesRequest()
{
	lldebugs << "LLPanelAvatar::sendAvatarPropertiesRequest()" << llendl; 
	LLMessageSystem *msg = gMessageSystem;

	msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
	msg->nextBlockFast( _PREHASH_AgentData);
	msg->addUUIDFast(   _PREHASH_AgentID, gAgent.getID() );
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	msg->addUUIDFast(   _PREHASH_AvatarID, mAvatarID);
	gAgent.sendReliableMessage();
}

void LLPanelAvatar::sendAvatarNotesUpdate()
{
	std::string notes = mPanelNotes->childGetValue("notes edit").asString();
	
	LLMessageSystem *msg = gMessageSystem;

	msg->newMessage("AvatarNotesUpdate");
	msg->nextBlock("AgentData");
	msg->addUUID("AgentID", gAgent.getID());
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	msg->nextBlock("Data");
	msg->addUUID("TargetID", mAvatarID);
	msg->addString("Notes", notes);

	gAgent.sendReliableMessage();
}


// static
void LLPanelAvatar::processAvatarPropertiesReply(LLMessageSystem *msg, void**)
{
	LLPanelAvatar* self = NULL;

	LLUUID	agent_id;	// your id
	LLUUID	avatar_id;	// target of this panel
	LLUUID	image_id;
	LLUUID	fl_image_id;
	LLUUID	partner_id;
	char	about_text[DB_USER_ABOUT_BUF_SIZE];
	char	fl_about_text[DB_USER_FL_ABOUT_BUF_SIZE];
	char	born_on[DB_BORN_BUF_SIZE];
	S32		charter_member_size = 0;
	BOOL	allow_publish = FALSE;
	//BOOL	mature = FALSE;
	BOOL	identified = FALSE;
	BOOL	transacted = FALSE;
	char	profile_url[DB_USER_PROFILE_URL_BUF_SIZE];

	//llinfos << "properties packet size " << msg->getReceiveSize() << llendl;

	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id );

	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != avatar_id)
		{
			continue;
		}
		self->childSetEnabled("Instant Message...",TRUE);
		self->childSetEnabled("Pay...",TRUE);
		self->childSetEnabled("Mute",TRUE);

		if (!self->mDisableRate) 
		{
			self->childSetEnabled("Rate...",TRUE);
		}
		lldebugs << "!!!!!!!!!!!!!!!!!!!!!!Enabling drop target" << llendl;
		self->childSetEnabled("drop target",TRUE);

		self->mHaveProperties = TRUE;
		self->enableOKIfReady();

		msg->getUUIDFast(  _PREHASH_PropertiesData,	_PREHASH_ImageID,		image_id );
		msg->getUUIDFast(  _PREHASH_PropertiesData,	_PREHASH_FLImageID,	fl_image_id );
		msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_PartnerID, partner_id);
		msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_AboutText,	DB_USER_ABOUT_BUF_SIZE,		about_text );
		msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_FLAboutText,	DB_USER_FL_ABOUT_BUF_SIZE,		fl_about_text );
		msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_BornOn, DB_BORN_BUF_SIZE, born_on);
		msg->getBOOLFast(_PREHASH_PropertiesData, _PREHASH_Identified,  identified);
		msg->getBOOLFast(_PREHASH_PropertiesData, _PREHASH_Transacted,  transacted);
		msg->getString("PropertiesData","ProfileURL", DB_USER_PROFILE_URL_BUF_SIZE, profile_url);

		self->mPanelWeb->setWebURL(std::string(profile_url));
		U8 caption_index = 0;
		LLString caption_text;
		charter_member_size = msg->getSize("PropertiesData", "CharterMember");
		if(1 == charter_member_size)
		{
			msg->getBinaryData("PropertiesData", "CharterMember", &caption_index, 1);
		}
		else if(1 < charter_member_size)
		{
			char caption[MAX_STRING];
			msg->getString("PropertiesData", "CharterMember", MAX_STRING, caption);
			caption_text = caption;
		}
		
		LLTextureCtrl*	image_ctrl = LLUICtrlFactory::getTexturePickerByName(self->mPanelSecondLife,"img");
		if(image_ctrl)
		{
			image_ctrl->setImageAssetID(image_id);
		}
		self->childSetValue("about", about_text);

		if(caption_text.empty())
		{
			LLString::format_map_t args;
			caption_text = self->mPanelSecondLife->childGetValue("CaptionTextAcctInfo").asString();
			
			const char* ACCT_TYPE[] = {
				"AcctTypeResident",
				"AcctTypeTrial",
				"AcctTypeCharterMember",
				"AcctTypeEmployee"
			};
			caption_index = llclamp(caption_index, (U8)0, (U8)(sizeof(ACCT_TYPE)/sizeof(ACCT_TYPE[0])-1));
			args["[ACCTTYPE]"] = self->mPanelSecondLife->childGetValue(ACCT_TYPE[caption_index]).asString();

			LLString payment_text = " ";
			const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3;
			if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX)
			{			
				if(transacted)
				{
					payment_text = "PaymentInfoUsed";
				}
				else if (identified)
				{
					payment_text = "PaymentInfoOnFile";
				}
				else
				{
					payment_text = "NoPaymentInfoOnFile";
				}
				args["[PAYMENTINFO]"] = self->mPanelSecondLife->childGetValue(payment_text).asString();
			}
			else
			{
				args["[PAYMENTINFO]"] = " ";
			}
			LLString::format(caption_text, args);
		}
		
		self->mPanelSecondLife->childSetValue("acct", caption_text);
		self->mPanelSecondLife->childSetValue("born", born_on);
		
		self->mPanelSecondLife->setPartnerID(partner_id);
		self->mPanelSecondLife->updatePartnerName();
		
		if (self->mPanelFirstLife)
		{
			// Teens don't get these
			self->mPanelFirstLife->childSetValue("about", fl_about_text);
			LLTextureCtrl*	image_ctrl = LLUICtrlFactory::getTexturePickerByName(self->mPanelFirstLife,"img");
			if(image_ctrl)
			{
				image_ctrl->setImageAssetID(fl_image_id);
			}
			msg->getBOOL("PropertiesData", "AllowPublish", allow_publish);

			self->mPanelSecondLife->childSetValue("allow_publish", allow_publish);

		}
	}
}

// static
void LLPanelAvatar::processAvatarInterestsReply(LLMessageSystem *msg, void**)
{
	LLPanelAvatar* self = NULL;

	LLUUID	agent_id;	// your id
	LLUUID	avatar_id;	// target of this panel

	U32		want_to_mask;
	char	want_to_text[DB_USER_WANT_TO_BUF_SIZE];
	U32		skills_mask;
	char	skills_text[DB_USER_SKILLS_BUF_SIZE];
	char	languages_text[DB_USER_SKILLS_BUF_SIZE];

	//llinfos << "properties packet size " << msg->getReceiveSize() << llendl;

	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id );

	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != avatar_id)
		{
			continue;
		}

		msg->getU32Fast(   _PREHASH_PropertiesData,	_PREHASH_WantToMask,	want_to_mask );
		msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_WantToText,	DB_USER_WANT_TO_BUF_SIZE,	want_to_text );
		msg->getU32Fast(   _PREHASH_PropertiesData,	_PREHASH_SkillsMask,	skills_mask );
		msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_SkillsText,	DB_USER_SKILLS_BUF_SIZE,	skills_text );
		msg->getString(_PREHASH_PropertiesData, "LanguagesText",	DB_USER_SKILLS_BUF_SIZE,	languages_text );

		self->mPanelAdvanced->setWantSkills(want_to_mask, want_to_text, skills_mask, skills_text, languages_text);
	}
}

// Separate function because the groups list can be very long, almost
// filling a packet. JC
// static
void LLPanelAvatar::processAvatarGroupsReply(LLMessageSystem *msg, void**)
{
	LLUUID	agent_id;	// your id
	LLUUID	avatar_id;	// target of this panel
	U64		group_powers;
	char	group_title[DB_GROUP_TITLE_BUF_SIZE];
	LLUUID	group_id;
	char	group_name[DB_GROUP_NAME_BUF_SIZE];
	LLUUID	group_insignia_id;
	const LLFontGL* FONT = LLFontGL::sSansSerifSmall;

	llinfos << "groups packet size " << msg->getReceiveSize() << llendl;

	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id );

	for (LLPanelAvatar* self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != avatar_id)
		{
			continue;
		}
		
		LLScrollListCtrl*	group_list = LLUICtrlFactory::getScrollListByName(self->mPanelSecondLife,"groups"); 
// 		if(group_list)
// 		{
// 			group_list->deleteAllItems();
// 		}
		
		S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
		if (0 == group_count)
		{
			if(group_list) group_list->addSimpleItem("None");
		}
		else
		{
			for(S32 i = 0; i < group_count; ++i)
			{
				msg->getU64(    _PREHASH_GroupData, "GroupPowers",	group_powers, i );
				msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle,	DB_GROUP_TITLE_BUF_SIZE,	group_title, i );
				msg->getUUIDFast(  _PREHASH_GroupData, _PREHASH_GroupID,		group_id, i);
				msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName,	DB_GROUP_NAME_BUF_SIZE,		group_name, i );
				msg->getUUIDFast(  _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_insignia_id, i );

				LLString group_string;
				if (group_id.notNull())
				{
					group_string.assign("Member of ");
					group_string.append(group_name);
				}
				else
				{
					group_string.assign("");
				}

				// Is this really necessary?  Remove existing entry if it exists.
				// TODO: clear the whole list when a request for data is made
				if (group_list)
				{
					S32 index = group_list->getItemIndex(group_id);
					if ( index >= 0 )
					{
						group_list->deleteSingleItem(index);
					}
				}
				LLScrollListItem *group_item = new LLScrollListItem(TRUE, NULL, group_id);
				group_item->addColumn(group_string, FONT);
				if(group_list) group_list->addItem(group_item);
			}
		}
		if(group_list) group_list->sortByColumn(0, TRUE);
	}
}

// Don't enable the OK button until you actually have the data.
// Otherwise you will write blanks back into the database.
void LLPanelAvatar::enableOKIfReady()
{
	if(mHaveProperties && mHaveStatistics && childIsVisible("OK"))
	{
		childSetEnabled("OK", TRUE);
	}
	else
	{
		childSetEnabled("OK", FALSE);
	}
}

void LLPanelAvatar::sendAvatarPropertiesUpdate()
{
	llinfos << "Sending avatarinfo update" << llendl;
	BOOL allow_publish = FALSE;
	BOOL mature = FALSE;
	if (LLPanelAvatar::sAllowFirstLife)
	{
		allow_publish = childGetValue("allow_publish");
		//A profile should never be mature.
		mature = FALSE;
	}
	U32 want_to_mask = 0x0;
	U32 skills_mask = 0x0;
	std::string want_to_text;
	std::string skills_text;
	std::string languages_text;
	mPanelAdvanced->getWantSkills(&want_to_mask, want_to_text, &skills_mask, skills_text, languages_text);

	LLUUID first_life_image_id;
	LLString first_life_about_text;
	if (mPanelFirstLife)
	{
		first_life_about_text = mPanelFirstLife->childGetValue("about").asString();
		LLTextureCtrl*	image_ctrl = LLUICtrlFactory::getTexturePickerByName(mPanelFirstLife,"img");
		if(image_ctrl)
		{
			first_life_image_id = image_ctrl->getImageAssetID();
		}
	}

	LLString about_text = mPanelSecondLife->childGetValue("about").asString();

	LLMessageSystem *msg = gMessageSystem;

	msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate);
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(	_PREHASH_AgentID,		gAgent.getID() );
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
	msg->nextBlockFast(_PREHASH_PropertiesData);
	
	LLTextureCtrl*	image_ctrl = LLUICtrlFactory::getTexturePickerByName(mPanelSecondLife,"img");
	if(image_ctrl)
	{
		msg->addUUIDFast(	_PREHASH_ImageID,	image_ctrl->getImageAssetID());
	}
	else
	{
		msg->addUUIDFast(	_PREHASH_ImageID,	LLUUID::null);
	}
//	msg->addUUIDFast(	_PREHASH_ImageID,		mPanelSecondLife->mimage_ctrl->getImageAssetID()	);
	msg->addUUIDFast(	_PREHASH_FLImageID,		first_life_image_id);
	msg->addStringFast(	_PREHASH_AboutText,		about_text);
	msg->addStringFast(	_PREHASH_FLAboutText,	first_life_about_text);

	msg->addBOOL("AllowPublish", allow_publish);
	msg->addBOOL("MaturePublish", mature);
	msg->addString("ProfileURL", mPanelWeb->childGetText("url_edit"));
	gAgent.sendReliableMessage();

	msg->newMessage("AvatarInterestsUpdate");
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(	_PREHASH_AgentID,		gAgent.getID() );
	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
	msg->nextBlockFast(_PREHASH_PropertiesData);
	msg->addU32Fast(	_PREHASH_WantToMask,	want_to_mask);
	msg->addStringFast(	_PREHASH_WantToText,	want_to_text);
	msg->addU32Fast(	_PREHASH_SkillsMask,	skills_mask);
	msg->addStringFast(	_PREHASH_SkillsText,	skills_text);
	msg->addString( "LanguagesText",			languages_text);
	gAgent.sendReliableMessage();
}

void LLPanelAvatar::selectTab(S32 tabnum)
{
	if(mTab)
	{
		mTab->selectTab(tabnum);
	}
}

void LLPanelAvatar::selectTabByName(std::string tab_name)
{
	if (mTab)
	{
		if (tab_name.empty())
		{
			mTab->selectFirstTab();
		}
		else
		{
			mTab->selectTabByName(tab_name);
		}
	}
}


// static
void LLPanelAvatar::processAvatarStatisticsReply(LLMessageSystem *msg, void**)
{
	// extract the agent id
	LLUUID agent_id;
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );

	LLUUID avatar_id;
	msg->getUUIDFast(_PREHASH_AvatarData, _PREHASH_AvatarID, avatar_id);

	// look up all panels which have this avatar
	LLPanelAvatar *self = NULL;

	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != avatar_id)
		{
			continue;
		}

		self->mHaveStatistics = TRUE;
		self->enableOKIfReady();

		// clear out list
		LLScrollListCtrl*	ratings_list = LLUICtrlFactory::getScrollListByName(self->mPanelSecondLife,"ratings"); 
		if (ratings_list)
		{
			ratings_list->deleteAllItems();
		}
		// build the item list
		LLFontGL *font = LLFontGL::sSansSerifSmall;

		S32 items = msg->getNumberOfBlocksFast(_PREHASH_StatisticsData);
		for (S32 i = 0; i < items; i++)
		{
			char name[MAX_STRING];
			S32 positive;
			S32 negative;
			char value_string[MAX_STRING];

			msg->getStringFast(	_PREHASH_StatisticsData, 
								_PREHASH_Name, MAX_STRING, name, i);
			msg->getS32(	"StatisticsData", "Positive", positive, i);
			msg->getS32(	"StatisticsData", "Negative", negative, i);

			LLScrollListItem *item = NULL;

			const S32	TEXT_WIDTH = 75;

			item = new LLScrollListItem();
			item->addColumn( name, font, TEXT_WIDTH );

			sprintf( value_string, "+%d", positive);
			item->addColumn( value_string, font, 50 );

			item->addColumn("", font);	// extra column to force striped appearance
			if(ratings_list) ratings_list->addItem( item );
		}
	}
}


void LLPanelAvatar::processAvatarNotesReply(LLMessageSystem *msg, void**)
{
	// extract the agent id
	LLUUID agent_id;
	msg->getUUID("AgentData", "AgentID", agent_id);

	LLUUID target_id;
	msg->getUUID("Data", "TargetID", target_id);

	// look up all panels which have this avatar
	LLPanelAvatar *self = NULL;

	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != target_id)
		{
			continue;
		}

		char text[DB_USER_NOTE_SIZE];
		msg->getString("Data", "Notes", DB_USER_NOTE_SIZE, text);
		self->childSetValue("notes edit", text);
	}
}


void LLPanelAvatar::processAvatarClassifiedReply(LLMessageSystem *msg, void** userdata)
{
	LLPanelAvatar *self = NULL;
	LLUUID agent_id;
	LLUUID target_id;

	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
	msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TargetID, target_id);

	// look up all panels which have this avatar target
	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != target_id)
		{
			continue;
		}

		self->mPanelClassified->processAvatarClassifiedReply(msg, userdata);
	}
}

void LLPanelAvatar::processAvatarPicksReply(LLMessageSystem *msg, void** userdata)
{
	LLPanelAvatar *self = NULL;
	LLUUID agent_id;
	LLUUID target_id;

	msg->getUUID("AgentData", "AgentID", agent_id);
	msg->getUUID("AgentData", "TargetID", target_id);

	// look up all panels which have this avatar target
	for (self = sAllPanels.getFirstData(); self; self = sAllPanels.getNextData())
	{
		if (self->mAvatarID != target_id)
		{
			continue;
		}

		self->mPanelPicks->processAvatarPicksReply(msg, userdata);
	}
}

// static
void LLPanelAvatar::onClickKick(void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	S32 left, top;
	gFloaterView->getNewFloaterPosition(&left, &top);
	LLRect rect(left, top, left+400, top-300);

	gViewerWindow->alertXmlEditText("KickUser", LLString::format_map_t(),
									NULL, NULL,
									LLPanelAvatar::finishKick, self);
}

// static
void LLPanelAvatar::finishKick(S32 option, const LLString& text, void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	if (option == 0)
	{
		LLMessageSystem* msg = gMessageSystem;

		msg->newMessageFast(_PREHASH_GodKickUser);
		msg->nextBlockFast(_PREHASH_UserInfo);
		msg->addUUIDFast(_PREHASH_GodID,		gAgent.getID() );
		msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID());
		msg->addUUIDFast(_PREHASH_AgentID,   self->mAvatarID );
		msg->addU32("KickFlags", KICK_FLAGS_DEFAULT );
		msg->addStringFast(_PREHASH_Reason,    text );
		gAgent.sendReliableMessage();
	}
}

// static
void LLPanelAvatar::onClickFreeze(void* userdata)
{
	gViewerWindow->alertXmlEditText("FreezeUser", LLString::format_map_t(),
									NULL, NULL,
									LLPanelAvatar::finishFreeze, userdata);
}

// static
void LLPanelAvatar::finishFreeze(S32 option, const LLString& text, void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	if (option == 0)
	{
		LLMessageSystem* msg = gMessageSystem;

		msg->newMessageFast(_PREHASH_GodKickUser);
		msg->nextBlockFast(_PREHASH_UserInfo);
		msg->addUUIDFast(_PREHASH_GodID,		gAgent.getID() );
		msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID());
		msg->addUUIDFast(_PREHASH_AgentID,   self->mAvatarID );
		msg->addU32("KickFlags", KICK_FLAGS_FREEZE );
		msg->addStringFast(_PREHASH_Reason,    text );
		gAgent.sendReliableMessage();
	}
}

// static
void LLPanelAvatar::onClickUnfreeze(void* userdata)
{
	gViewerWindow->alertXmlEditText("UnFreezeUser", LLString::format_map_t(),
									NULL, NULL,
									LLPanelAvatar::finishUnfreeze, userdata);
}

// static
void LLPanelAvatar::finishUnfreeze(S32 option, const LLString& text, void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*) userdata;

	if (option == 0)
	{
		LLMessageSystem* msg = gMessageSystem;

		msg->newMessageFast(_PREHASH_GodKickUser);
		msg->nextBlockFast(_PREHASH_UserInfo);
		msg->addUUIDFast(_PREHASH_GodID,		gAgent.getID() );
		msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID());
		msg->addUUIDFast(_PREHASH_AgentID,   self->mAvatarID );
		msg->addU32("KickFlags", KICK_FLAGS_UNFREEZE );
		msg->addStringFast(_PREHASH_Reason,    text );
		gAgent.sendReliableMessage();
	}
}

// static
void LLPanelAvatar::onClickCSR(void* userdata)
{
	LLPanelAvatar* self = (LLPanelAvatar*)userdata;
	if (!self) return;
	
	LLNameEditor* name_edit = LLViewerUICtrlFactory::getNameEditorByName(self, "name");
	if (!name_edit) return;

	LLString name = name_edit->getText();
	if (name.empty()) return;
	
	LLString url = "http://csr.lindenlab.com/agent/";
	
	// slow and stupid, but it's late
	S32 len = name.length();
	for (S32 i = 0; i < len; i++)
	{
		if (name[i] == ' ')
		{
			url += "%20";
		}
		else
		{
			url += name[i];
		}
	}
	
	LLWeb::loadURL(url);
}


void*	LLPanelAvatar::createPanelAvatarSecondLife(void* data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelSecondLife = new LLPanelAvatarSecondLife("2nd Life",LLRect(),self);
	return self->mPanelSecondLife;
}

void*	LLPanelAvatar::createPanelAvatarWeb(void*	data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelWeb = new LLPanelAvatarWeb("Web",LLRect(),self);
	return self->mPanelWeb;
}

void*	LLPanelAvatar::createPanelAvatarInterests(void*	data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelAdvanced = new LLPanelAvatarAdvanced("Interests",LLRect(),self);
	return self->mPanelAdvanced;
}


void*	LLPanelAvatar::createPanelAvatarPicks(void*	data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelPicks = new LLPanelAvatarPicks("Picks",LLRect(),self);
	return self->mPanelPicks;
}

void*	LLPanelAvatar::createPanelAvatarClassified(void* data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelClassified = new LLPanelAvatarClassified("Classified",LLRect(),self);
	return self->mPanelClassified;
}

void*	LLPanelAvatar::createPanelAvatarFirstLife(void*	data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelFirstLife = new LLPanelAvatarFirstLife("1st Life", LLRect(), self);
	return self->mPanelFirstLife;
}

void*	LLPanelAvatar::createPanelAvatarNotes(void*	data)
{
	LLPanelAvatar* self = (LLPanelAvatar*)data;
	self->mPanelNotes = new LLPanelAvatarNotes("My Notes",LLRect(),self);
	return self->mPanelNotes;
}