/** 
 * @file llagentwearables.cpp
 * @brief LLAgentWearables class implementation
 *
 * $LicenseInfo:firstyear=2001&license=viewergpl$
 * 
 * Copyright (c) 2001-2009, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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.
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llagent.h" 
#include "llagentwearables.h"

#include "llfloatercustomize.h"
#include "llfloaterinventory.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llnotify.h"
#include "llviewerregion.h"
#include "llvoavatarself.h"
#include "llwearable.h"
#include "llwearablelist.h"
#include "llgesturemgr.h"

#include <boost/scoped_ptr.hpp>

#define USE_CURRENT_OUTFIT_FOLDER

//--------------------------------------------------------------------
// Classes for fetching initial wearables data
//--------------------------------------------------------------------
// Outfit folder fetching callback structure.
class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver
{
public:
	LLInitialWearablesFetch() {}
	~LLInitialWearablesFetch() {}
	virtual void done();

	struct InitialWearableData
	{
		EWearableType mType;
		U32 mIndex;
		LLUUID mItemID;
		LLUUID mAssetID;
		InitialWearableData(EWearableType type, U32 index, LLUUID itemID, LLUUID assetID) :
			mType(type), mIndex(index), mItemID(itemID), mAssetID(assetID) { }
	};

	typedef std::vector<InitialWearableData> initial_wearable_data_vec_t;
	initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder
	initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg

protected:
	void processInitialWearables();
};



LLAgentWearables gAgentWearables;

BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE;

using namespace LLVOAvatarDefines;

void LLAgentWearables::dump()
{
	llinfos << "LLAgentWearablesDump" << llendl;
	for (S32 i = 0; i < WT_COUNT; i++)
	{
		U32 count = getWearableCount((EWearableType)i);
		llinfos << "Type: " << i << " count " << count << llendl;
		for (U32 j=0; j<count; j++)
		{
			LLWearable* wearable = getWearable((EWearableType)i,j);
			if (wearable == NULL)
			{
				llinfos << "    " << j << " NULL wearable" << llendl;
			}
			llinfos << "    " << j << " Name " << wearable->getName()
					<< " description " << wearable->getDescription() << llendl;
			
		}
	}
	llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl;
	for (std::set<LLUUID>::iterator it = mItemsAwaitingWearableUpdate.begin();
		 it != mItemsAwaitingWearableUpdate.end();
		 ++it)
	{
		llinfos << (*it).asString() << llendl;
	}
}

// MULTI-WEARABLE: debugging
struct LLAgentDumper
{
	LLAgentDumper(std::string name):
		mName(name)
	{
		llinfos << llendl;
		llinfos << "LLAgentDumper " << mName << llendl;
		gAgentWearables.dump();
	}

	~LLAgentDumper()
	{
		llinfos << llendl;
		llinfos << "~LLAgentDumper " << mName << llendl;
		gAgentWearables.dump();
	}

	std::string mName;
};

LLAgentWearables::LLAgentWearables() :
	mWearablesLoaded(FALSE),
	mAvatarObject(NULL)
{
	// MULTI-WEARABLE: TODO remove null entries.
	for (U32 i = 0; i < WT_COUNT; i++)
	{
		mWearableDatas[(EWearableType)i].push_back(NULL);
	}
}

LLAgentWearables::~LLAgentWearables()
{
	cleanup();
}

void LLAgentWearables::cleanup()
{
	mAvatarObject = NULL;
}

void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
{ 
	mAvatarObject = avatar;
	if (avatar)
	{
		sendAgentWearablesRequest();
	}
}

// wearables
LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
{
	gAgentWearables.createStandardWearablesAllDone();
}

LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
{
	gAgentWearables.sendAgentWearablesUpdate();
}

/**
 * @brief Construct a callback for dealing with the wearables.
 *
 * Would like to pass the agent in here, but we can't safely
 * count on it being around later.  Just use gAgent directly.
 * @param cb callback to execute on completion (??? unused ???)
 * @param type Type for the wearable in the agent
 * @param wearable The wearable data.
 * @param todo Bitmask of actions to take on completion.
 */
LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
	LLPointer<LLRefCount> cb, S32 type, U32 index, LLWearable* wearable, U32 todo) :
	mType(type),
	mIndex(index),	
	mWearable(wearable),
	mTodo(todo),
	mCB(cb)
{
}

void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
{
	if (inv_item.isNull())
		return;

	gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable);

	if (mTodo & CALL_UPDATE)
	{
		gAgentWearables.sendAgentWearablesUpdate();
	}
	if (mTodo & CALL_RECOVERDONE)
	{
		gAgentWearables.recoverMissingWearableDone();
	}
	/*
	 * Do this for every one in the loop
	 */
	if (mTodo & CALL_CREATESTANDARDDONE)
	{
		gAgentWearables.createStandardWearablesDone(mType, mIndex);
	}
	if (mTodo & CALL_MAKENEWOUTFITDONE)
	{
		gAgentWearables.makeNewOutfitDone(mType, mIndex);
	}
}

void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
													   const U32 index,
													   const LLUUID& item_id,
													   LLWearable* wearable)
{
	if (item_id.isNull())
		return;

	LLUUID old_item_id = getWearableItemID((EWearableType)type,index);
	if (wearable)
	{
		wearable->setItemID(item_id);
	}
	setWearable((EWearableType)type,index,wearable);

	if (old_item_id.notNull())
		gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
	gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
	LLViewerInventoryItem* item = gInventory.getItem(item_id);
	if (item && wearable)
	{
		// We're changing the asset id, so we both need to set it
		// locally via setAssetUUID() and via setTransactionID() which
		// will be decoded on the server. JC
		item->setAssetUUID(wearable->getAssetID());
		item->setTransactionID(wearable->getTransactionID());
		gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
		item->updateServer(FALSE);
	}
	gInventory.notifyObservers();
}

void LLAgentWearables::sendAgentWearablesUpdate()
{
	// MULTI-WEARABLE: call i "type" or something.
	// First make sure that we have inventory items for each wearable
	for (S32 i=0; i < WT_COUNT; ++i)
	{
		for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
		{
			LLWearable* wearable = getWearable((EWearableType)i,j);
			if (wearable)
			{
				if (wearable->getItemID().isNull())
				{
					LLPointer<LLInventoryCallback> cb =
						new addWearableToAgentInventoryCallback(
							LLPointer<LLRefCount>(NULL),
							i,
							j,
							wearable,
							addWearableToAgentInventoryCallback::CALL_NONE);
					addWearableToAgentInventory(cb, wearable);
				}
				else
				{
					gInventory.addChangedMask(LLInventoryObserver::LABEL,
											  wearable->getItemID());
				}
			}
		}
	}

	// Then make sure the inventory is in sync with the avatar.
	gInventory.notifyObservers();

	// Send the AgentIsNowWearing 
	gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);

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

	lldebugs << "sendAgentWearablesUpdate()" << llendl;
	// MULTI-WEARABLE: update for multi-wearables after server-side support is in.
	for (S32 i=0; i < WT_COUNT; ++i)
	{
		gMessageSystem->nextBlockFast(_PREHASH_WearableData);

		U8 type_u8 = (U8)i;
		gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);

		// MULTI-WEARABLE: TODO: hacked index to 0, needs to loop over all once messages support this.
		LLWearable* wearable = getWearable((EWearableType)i, 0);
		if (wearable)
		{
			//llinfos << "Sending wearable " << wearable->getName() << llendl;
			gMessageSystem->addUUIDFast(_PREHASH_ItemID, wearable->getItemID());
		}
		else
		{
			//llinfos << "Not wearing wearable type " << LLWearableDictionary::getInstance()->getWearable((EWearableType)i) << llendl;
			gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null);
		}

		lldebugs << "       " << LLWearableDictionary::getTypeLabel((EWearableType)i) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl;
	}
	gAgent.sendReliableMessage();
}

// MULTI-WEARABLE: add index.
void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, BOOL send_update)
{
	LLWearable* old_wearable = getWearable(type, index);
	if (old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()))
	{
		LLUUID old_item_id = old_wearable->getItemID();
		LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar(old_wearable);
		new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()?
		setWearable(type,index,new_wearable);

		LLInventoryItem* item = gInventory.getItem(old_item_id);
		if (item)
		{
			// Update existing inventory item
			LLPointer<LLViewerInventoryItem> template_item =
				new LLViewerInventoryItem(item->getUUID(),
										  item->getParentUUID(),
										  item->getPermissions(),
										  new_wearable->getAssetID(),
										  new_wearable->getAssetType(),
										  item->getInventoryType(),
										  item->getName(),
										  item->getDescription(),
										  item->getSaleInfo(),
										  item->getFlags(),
										  item->getCreationDate());
			template_item->setTransactionID(new_wearable->getTransactionID());
			template_item->updateServer(FALSE);
			gInventory.updateItem(template_item);
		}
		else
		{
			// Add a new inventory item (shouldn't ever happen here)
			U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
			if (send_update)
			{
				todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
			}
			LLPointer<LLInventoryCallback> cb =
				new addWearableToAgentInventoryCallback(
					LLPointer<LLRefCount>(NULL),
					(S32)type,
					index,
					new_wearable,
					todo);
			addWearableToAgentInventory(cb, new_wearable);
			return;
		}

		gAgent.getAvatarObject()->wearableUpdated( type );

		if (send_update)
		{
			sendAgentWearablesUpdate();
		}
	}
}

// MULTI-WEARABLE: add index
void LLAgentWearables::saveWearableAs(const EWearableType type,
									  const U32 index,
									  const std::string& new_name,
									  BOOL save_in_lost_and_found)
{
	if (!isWearableCopyable(type, index))
	{
		llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
		return;
	}
	LLWearable* old_wearable = getWearable(type, index);
	if (!old_wearable)
	{
		llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
		return;
	}

	LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index));
	if (!item)
	{
		llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
		return;
	}
	std::string trunc_name(new_name);
	LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
	LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar(
		old_wearable,
		trunc_name);
	LLPointer<LLInventoryCallback> cb =
		new addWearableToAgentInventoryCallback(
			LLPointer<LLRefCount>(NULL),
			type,
			index,
			new_wearable,
			addWearableToAgentInventoryCallback::CALL_UPDATE);
	LLUUID category_id;
	if (save_in_lost_and_found)
	{
		category_id = gInventory.findCategoryUUIDForType(
			LLAssetType::AT_LOST_AND_FOUND);
	}
	else
	{
		// put in same folder as original
		category_id = item->getParentUUID();
	}

	copy_inventory_item(
		gAgent.getID(),
		item->getPermissions().getOwner(),
		item->getUUID(),
		category_id,
		new_name,
		cb);
}

void LLAgentWearables::revertWearable(const EWearableType type, const U32 index)
{
	LLWearable* wearable = getWearable(type, index);
	if (wearable)
	{
		wearable->writeToAvatar(TRUE);
	}
	gAgent.sendAgentSetAppearance();
}

void LLAgentWearables::saveAllWearables()
{
	//if (!gInventory.isLoaded())
	//{
	//	return;
	//}

	for (S32 i=0; i < WT_COUNT; i++)
	{
		for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
			saveWearable((EWearableType)i, j, FALSE);
	}
	sendAgentWearablesUpdate();
}

// Called when the user changes the name of a wearable inventory item that is currently being worn.
void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& new_name)
{
	for (S32 i=0; i < WT_COUNT; i++)
	{
		for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
		{
			LLUUID curr_item_id = getWearableItemID((EWearableType)i,j);
			if (curr_item_id == item_id)
			{
				LLWearable* old_wearable = getWearable((EWearableType)i,j);
				llassert(old_wearable);

				std::string old_name = old_wearable->getName();
				old_wearable->setName(new_name);
				LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable);
				new_wearable->setItemID(item_id);
				LLInventoryItem* item = gInventory.getItem(item_id);
				if (item)
				{
					new_wearable->setPermissions(item->getPermissions());
				}
				old_wearable->setName(old_name);

				setWearable((EWearableType)i,j,new_wearable);
				sendAgentWearablesUpdate();
				break;
			}
		}
	}
}


BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const
{
	LLUUID item_id = getWearableItemID(type, index);
	if (!item_id.isNull())
	{
		LLInventoryItem* item = gInventory.getItem(item_id);
		if (item && item->getPermissions().allowModifyBy(gAgent.getID(),
														 gAgent.getGroupID()))
		{
			return TRUE;
		}
	}
	return FALSE;
}

BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const
{
	LLUUID item_id = getWearableItemID(type, index);
	if (!item_id.isNull())
	{
		LLInventoryItem* item = gInventory.getItem(item_id);
		if (item && item->getPermissions().allowCopyBy(gAgent.getID(),
													   gAgent.getGroupID()))
		{
			return TRUE;
		}
	}
	return FALSE;
}

/*
  U32 LLAgentWearables::getWearablePermMask(EWearableType type)
  {
  LLUUID item_id = getWearableItemID(type);
  if (!item_id.isNull())
  {
  LLInventoryItem* item = gInventory.getItem(item_id);
  if (item)
  {
  return item->getPermissions().getMaskOwner();
  }
  }
  return PERM_NONE;
  }
*/

LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type, U32 index)
{
	LLUUID item_id = getWearableItemID(type,index);
	LLInventoryItem* item = NULL;
	if (item_id.notNull())
	{
		item = gInventory.getItem(item_id);
	}
	return item;
}

const LLWearable* LLAgentWearables::getWearableFromWearableItem(const LLUUID& item_id) const
{
	for (S32 i=0; i < WT_COUNT; i++)
	{
		for (U32 j=0; j < getWearableCount((EWearableType)i); j++)
		{
			LLUUID curr_item_id = getWearableItemID((EWearableType)i, j);
			if (curr_item_id == item_id)
			{
				return getWearable((EWearableType)i, j);
			}
		}
	}
	return NULL;
}

void LLAgentWearables::sendAgentWearablesRequest()
{
	gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	gAgent.sendReliableMessage();
}

// MULTI-WEARABLE: update for multiple items per type.
// Used to enable/disable menu items.
// static
BOOL LLAgentWearables::selfHasWearable(EWearableType type)
{
	// MULTI-WEARABLE: TODO could be getWearableCount > 0, once null entries have been eliminated.
	return gAgentWearables.getWearable(type,0) != NULL;
}

LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index)
{
	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
	if (wearable_iter == mWearableDatas.end())
	{
		return NULL;
	}
	wearableentry_vec_t& wearable_vec = wearable_iter->second;
	if (index>=wearable_vec.size())
	{
		return NULL;
	}
	else
	{
		return wearable_vec[index];
	}
}

void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable)
{
	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
	if (wearable_iter == mWearableDatas.end())
	{
		llwarns << "invalid type, type " << type << " index " << index << llendl; 
		return;
	}
	wearableentry_vec_t& wearable_vec = wearable_iter->second;
	if (index>=wearable_vec.size())
	{
		llwarns << "invalid index, type " << type << " index " << index << llendl; 
	}
	else
	{
		wearable_vec[index] = wearable;
	}
}

const LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) const
{
	wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
	if (wearable_iter == mWearableDatas.end())
	{
		return NULL;
	}
	const wearableentry_vec_t& wearable_vec = wearable_iter->second;
	if (index>=wearable_vec.size())
	{
		return NULL;
	}
	else
	{
		return wearable_vec[index];
	}
}

//MULTI-WEARABLE: this will give wrong values until we get rid of the "always one empty object" scheme.
U32 LLAgentWearables::getWearableCount(const EWearableType type) const
{
	wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type);
	if (wearable_iter == mWearableDatas.end())
	{
		return 0;
	}
	const wearableentry_vec_t& wearable_vec = wearable_iter->second;
	return wearable_vec.size();
}

BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
{
	return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end();
}

U32 LLAgentWearables::itemUpdatePendingCount() const
{
	return mItemsAwaitingWearableUpdate.size();
}

const LLUUID LLAgentWearables::getWearableItemID(EWearableType type, U32 index) const
{
	const LLWearable *wearable = getWearable(type,index);
	if (wearable)
		return wearable->getItemID();
	else
		return LLUUID();
}

// Warning: include_linked_items = TRUE makes this operation expensive.
BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_items) const
{
	if (getWearableFromWearableItem(item_id) != NULL) return TRUE;
	if (include_linked_items)
	{
		LLInventoryModel::item_array_t item_array;
		gInventory.collectLinkedItems(item_id, item_array);
		for (LLInventoryModel::item_array_t::iterator iter = item_array.begin();
			 iter != item_array.end();
			 iter++)
		{
			LLViewerInventoryItem *linked_item = (*iter);
			const LLUUID &item_id = linked_item->getUUID();
			if (getWearableFromWearableItem(item_id) != NULL) return TRUE;
		}
	}
	return FALSE;
}

// MULTI-WEARABLE: update for multiple
// static
// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
// that viewers have a Current Outfit Folder and won't need this message, and thus
// we can remove/ignore this whole function.
void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data)
{
	// We should only receive this message a single time.  Ignore subsequent AgentWearablesUpdates
	// that may result from AgentWearablesRequest having been sent more than once.
	if (mInitialWearablesUpdateReceived)
		return;
	mInitialWearablesUpdateReceived = true;

	LLUUID agent_id;
	gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);

	LLVOAvatar* avatar = gAgent.getAvatarObject();
	if (avatar && (agent_id == avatar->getID()))
	{
		gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum);
		
		S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
		if (num_wearables < 4)
		{
			// Transitional state.  Avatars should always have at least their body parts (hair, eyes, shape and skin).
			// The fact that they don't have any here (only a dummy is sent) implies that this account existed
			// before we had wearables, or that the database has gotten messed up.
			return;
		}

		// Get the UUID of the current outfit folder (will be created if it doesn't exist)
		LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
		
		LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch();
		
		//lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
		// Add wearables
		// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element.
		gAgentWearables.mItemsAwaitingWearableUpdate.clear();
		for (S32 i=0; i < num_wearables; i++)
		{
			// Parse initial werables data from message system
			U8 type_u8 = 0;
			gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
			if (type_u8 >= WT_COUNT)
			{
				continue;
			}
			const EWearableType type = (EWearableType) type_u8;
			
			LLUUID item_id;
			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
			
			LLUUID asset_id;
			gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);
			if (asset_id.isNull())
			{
				LLWearable::removeFromAvatar(type, FALSE);
			}
			else
			{
				LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(type);
				if (asset_type == LLAssetType::AT_NONE)
				{
					continue;
				}
				
				// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element.
				
				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
				LLInitialWearablesFetch::InitialWearableData wearable_data(type, 0, item_id, asset_id); // MULTI-WEARABLE: update
				outfit->mAgentInitialWearables.push_back(wearable_data);
				
			}
			
			lldebugs << "       " << LLWearableDictionary::getTypeLabel(type) << llendl;
		}
		
		// What we do here is get the complete information on the items in
		// the inventory, and set up an observer that will wait for that to
		// happen.
		LLInventoryFetchDescendentsObserver::folder_ref_t folders;
		folders.push_back(current_outfit_id);
		outfit->fetchDescendents(folders);
		if(outfit->isEverythingComplete())
		{
			// everything is already here - call done.
			outfit->done();
		}
		else
		{
			// it's all on it's way - add an observer, and the inventory
			// will call done for us when everything is here.
			gInventory.addObserver(outfit);
		}
	}
}

// A single wearable that the avatar was wearing on start-up has arrived from the database.
// static
void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata)
{
	boost::scoped_ptr<LLInitialWearablesFetch::InitialWearableData> wear_data((LLInitialWearablesFetch::InitialWearableData*)userdata); 
	const EWearableType type = wear_data->mType;
	const U32 index = wear_data->mIndex;

	LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
	if (!avatar)
	{
		return;
	}

	if (wearable)
	{
		llassert(type == wearable->getType());
		// MULTI-WEARABLE: is this always zeroth element?  Change sometime.
		wearable->setItemID(wear_data->mItemID);
		gAgentWearables.setWearable(type, index, wearable);
		gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID);

		// disable composites if initial textures are baked
		avatar->setupComposites();

		wearable->writeToAvatar(FALSE);
		avatar->setCompositeUpdatesEnabled(TRUE);
		gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID());
	}
	else
	{
		// Somehow the asset doesn't exist in the database.
		// MULTI-WEARABLE: assuming zeroth elt
		gAgentWearables.recoverMissingWearable(type,index);
	}

	gInventory.notifyObservers();

	// Have all the wearables that the avatar was wearing at log-in arrived?
	// MULTI-WEARABLE: update when multiple wearables can arrive per type.

	gAgentWearables.updateWearablesLoaded();
	if (gAgentWearables.areWearablesLoaded())
	{

		// Can't query cache until all wearables have arrived, so calling this earlier is a no-op.
		gAgentWearables.queryWearableCache();

		// Make sure that the server's idea of the avatar's wearables actually match the wearables.
		gAgent.sendAgentSetAppearance();

		// Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
		// If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
		if (gAgent.cameraCustomizeAvatar())
		{
			avatar->requestLayerSetUploads();
		}
	}
}

// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
// database.  If for some reason, we can't load one of those assets, we can try to reconstruct it so that
// the user isn't left without a shape, for example.  (We can do that only after the inventory has loaded.)
void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 index)
{
	// Try to recover by replacing missing wearable with a new one.
	LLNotifications::instance().add("ReplacedMissingWearable");
	lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded.  Replaced inventory item with default wearable." << llendl;
	LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type);

	S32 type_s32 = (S32) type;
	setWearable(type,index,new_wearable);
	new_wearable->writeToAvatar(TRUE);

	// Add a new one in the lost and found folder.
	// (We used to overwrite the "not found" one, but that could potentially
	// destory content.) JC
	LLUUID lost_and_found_id = 
		gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
	LLPointer<LLInventoryCallback> cb =
		new addWearableToAgentInventoryCallback(
			LLPointer<LLRefCount>(NULL),
			type_s32,
			index,
			new_wearable,
			addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
	addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE);
}

void LLAgentWearables::recoverMissingWearableDone()
{
	// Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
	updateWearablesLoaded();
	if (areWearablesLoaded())
	{
		// Make sure that the server's idea of the avatar's wearables actually match the wearables.
		gAgent.sendAgentSetAppearance();
	}
	else
	{
		gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null);
		gInventory.notifyObservers();
	}
}

void LLAgentWearables::addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index)
{
	LLWearable* wearable = getWearable((EWearableType)wearable_type, wearable_index);
	if (!wearable)
	{
		llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl;
	}
	
	wearable->setLocalTextureObject(texture_type, new LLLocalTextureObject());
}

void LLAgentWearables::createStandardWearables(BOOL female)
{
	llwarns << "Creating Standard " << (female ? "female" : "male")
			<< " Wearables" << llendl;

	if (mAvatarObject.isNull())
	{
		return;
	}

	mAvatarObject->setSex(female ? SEX_FEMALE : SEX_MALE);

	const BOOL create[WT_COUNT] = 
		{
			TRUE,  //WT_SHAPE
			TRUE,  //WT_SKIN
			TRUE,  //WT_HAIR
			TRUE,  //WT_EYES
			TRUE,  //WT_SHIRT
			TRUE,  //WT_PANTS
			TRUE,  //WT_SHOES
			TRUE,  //WT_SOCKS
			FALSE, //WT_JACKET
			FALSE, //WT_GLOVES
			TRUE,  //WT_UNDERSHIRT
			TRUE,  //WT_UNDERPANTS
			FALSE  //WT_SKIRT
		};

	for (S32 i=0; i < WT_COUNT; i++)
	{
		bool once = false;
		LLPointer<LLRefCount> donecb = NULL;
		if (create[i])
		{
			if (!once)
			{
				once = true;
				donecb = new createStandardWearablesAllDoneCallback;
			}
			// MULTI_WEARABLE: only elt 0, may be the right thing?
			llassert(getWearable((EWearableType)i,0) == NULL);
			LLWearable* wearable = LLWearableList::instance().createNewWearable((EWearableType)i);
			setWearable((EWearableType)i,0,wearable);
			// no need to update here...
			// MULTI_WEARABLE: hardwired index = 0 here.
			LLPointer<LLInventoryCallback> cb =
				new addWearableToAgentInventoryCallback(
					donecb,
					i,
					0,
					wearable,
					addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
			addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
		}
	}
}

void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index)
{
	LLWearable* wearable = getWearable((EWearableType)type, index);

	if (wearable)
	{
		wearable->writeToAvatar(TRUE);
	}
}

void LLAgentWearables::createStandardWearablesAllDone()
{
	// ... because sendAgentWearablesUpdate will notify inventory
	// observers.
	mWearablesLoaded = TRUE; 
	checkWearablesLoaded();
	
	updateServer();

	// Treat this as the first texture entry message, if none received yet
	mAvatarObject->onFirstTEMessageReceived();
}

void LLAgentWearables::getAllWearablesArray(LLDynamicArray<S32>& wearables)
{
	for( S32 i = 0; i < WT_COUNT; ++i )
	{
		// MULTI-WEARABLE: Properly handle multiwearables later.
		if (getWearable( (EWearableType) i, 0 ) != NULL)
		{
			wearables.push_back(i);
		}
	}
}

// Note:	wearables_to_include should be a list of EWearableType types
//			attachments_to_include should be a list of attachment points
void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
									 const LLDynamicArray<S32>& wearables_to_include,
									 const LLDynamicArray<S32>& attachments_to_include,
									 BOOL rename_clothing)
{
	if (mAvatarObject.isNull())
	{
		return;
	}

	// First, make a folder in the Clothes directory.
	LLUUID folder_id = gInventory.createNewCategory(
		gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
		LLAssetType::AT_NONE,
		new_folder_name);

	bool found_first_item = false;

	///////////////////
	// Wearables

	if (wearables_to_include.count())
	{
		// Then, iterate though each of the wearables and save copies of them in the folder.
		S32 i;
		S32 count = wearables_to_include.count();
		LLDynamicArray<LLUUID> delete_items;
		LLPointer<LLRefCount> cbdone = NULL;
		for (i = 0; i < count; ++i)
		{
			const S32 type = wearables_to_include[i];
			for (U32 j=0; j<getWearableCount((EWearableType)i); j++)
			{
				LLWearable* old_wearable = getWearable((EWearableType)type, j);
				if (old_wearable)
				{
					std::string new_name;
					LLWearable* new_wearable;
					new_wearable = LLWearableList::instance().createCopy(old_wearable);
					if (rename_clothing)
					{
						new_name = new_folder_name;
						new_name.append(" ");
						new_name.append(old_wearable->getTypeLabel());
						LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
						new_wearable->setName(new_name);
					}

					LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType)type,j));
					S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
					if (!found_first_item)
					{
						found_first_item = true;
						/* set the focus to the first item */
						todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
						/* send the agent wearables update when done */
						cbdone = new sendAgentWearablesUpdateCallback;
					}
					LLPointer<LLInventoryCallback> cb =
						new addWearableToAgentInventoryCallback(
							cbdone,
							type,
							j,
							new_wearable,
							todo);
					if (isWearableCopyable((EWearableType)type, j))
					{
						copy_inventory_item(
							gAgent.getID(),
							item->getPermissions().getOwner(),
							item->getUUID(),
							folder_id,
							new_name,
							cb);
					}
					else
					{
						move_inventory_item(
							gAgent.getID(),
							gAgent.getSessionID(),
							item->getUUID(),
							folder_id,
							new_name,
							cb);
					}
				}
			}
		}
		gInventory.notifyObservers();
	}


	///////////////////
	// Attachments

	if (attachments_to_include.count())
	{
		BOOL msg_started = FALSE;
		LLMessageSystem* msg = gMessageSystem;
		for (S32 i = 0; i < attachments_to_include.count(); i++)
		{
			S32 attachment_pt = attachments_to_include[i];
			LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
			if (!attachment) continue;
			LLViewerObject* attached_object = attachment->getObject();
			if (!attached_object) continue;
			const LLUUID& item_id = attachment->getItemID();
			if (item_id.isNull()) continue;
			LLInventoryItem* item = gInventory.getItem(item_id);
			if (!item) continue;
			if (!msg_started)
			{
				msg_started = TRUE;
				msg->newMessage("CreateNewOutfitAttachments");
				msg->nextBlock("AgentData");
				msg->addUUID("AgentID", gAgent.getID());
				msg->addUUID("SessionID", gAgent.getSessionID());
				msg->nextBlock("HeaderData");
				msg->addUUID("NewFolderID", folder_id);
			}
			msg->nextBlock("ObjectData");
			msg->addUUID("OldItemID", item_id);
			msg->addUUID("OldFolderID", item->getParentUUID());
		}

		if (msg_started)
		{
			gAgent.sendReliableMessage();
		}

	} 
}

LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name)
{
	if (mAvatarObject.isNull())
	{
		return LLUUID::null;
	}

	LLDynamicArray<S32> wearables_to_include;
	getAllWearablesArray(wearables_to_include);
	
	LLDynamicArray<S32> attachments_to_include;
	mAvatarObject->getAllAttachmentsArray(attachments_to_include);

	return makeNewOutfitLinks(new_folder_name, wearables_to_include, attachments_to_include);
}

// Note:	wearables_to_include should be a list of EWearableType types
//			attachments_to_include should be a list of attachment points
LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name,
											 const LLDynamicArray<S32>& wearables_to_include,
											 const LLDynamicArray<S32>& attachments_to_include)
{
	if (mAvatarObject.isNull())
	{
		return LLUUID::null;
	}

	// First, make a folder in the Clothes directory.
	LLUUID folder_id = gInventory.createNewCategory(
		gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS),
		LLAssetType::AT_OUTFIT,
		new_folder_name);

//	bool found_first_item = false;

	///////////////////
	// Wearables

	if (wearables_to_include.count())
	{
		// Then, iterate though each of the wearables and save links to them in the folder.
		S32 i;
		S32 count = wearables_to_include.count();
		LLDynamicArray<LLUUID> delete_items;
		LLPointer<LLRefCount> cbdone = NULL;
		for (i = 0; i < count; ++i)
		{
			const S32 type = wearables_to_include[i];
			for (U32 j=0; j<getWearableCount((EWearableType)i); j++)
			{
				LLWearable* old_wearable = getWearable((EWearableType)type,j);
				if (old_wearable)
				{
					LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType) type, j));
					if (!item) continue;
					LLPointer<LLInventoryCallback> cb = NULL;
					link_inventory_item(gAgent.getID(),
										item->getUUID(),
										folder_id,
										item->getName(),
										LLAssetType::AT_LINK,
										cb);
				}
			}
		}
		gInventory.notifyObservers();
	}


	///////////////////
	// Attachments

	if (attachments_to_include.count())
	{
		for (S32 i = 0; i < attachments_to_include.count(); i++)
		{
			S32 attachment_pt = attachments_to_include[i];
			LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
			if (!attachment) continue;
			LLViewerObject* attached_object = attachment->getObject();
			if (!attached_object) continue;
			const LLUUID& item_id = attachment->getItemID();
			if (item_id.isNull()) continue;
			LLInventoryItem* item = gInventory.getItem(item_id);
			if (!item) continue;

			LLPointer<LLInventoryCallback> cb = NULL;
			link_inventory_item(gAgent.getID(),
								item->getUUID(),
								folder_id,
								item->getName(),
								LLAssetType::AT_LINK,
								cb);
		}
	} 

	///////////////////
	// Gestures

	/* Disabling this for now, otherwise this adds all your default gestures and all previous
	   active gestures.  Need to rethink the intended behavior.
	for (LLGestureManager::item_map_t::iterator iter = LLGestureManager::instance().mActive.begin();
		 iter != LLGestureManager::instance().mActive.end();
		 ++iter)
	{
		const LLUUID &gesture_id = (*iter).first;
		LLViewerInventoryItem* item = gInventory.getItem(gesture_id);
		if (item)
		{
			LLPointer<LLInventoryCallback> cb = NULL;
			link_inventory_item(gAgent.getID(),
								item->getUUID(),
								folder_id,
								item->getName(),
								LLAssetType::AT_LINK,
								cb);
		}
	}
	*/
	
	return folder_id;
}

void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
{
	LLUUID first_item_id = getWearableItemID((EWearableType)type, index);
	// Open the inventory and select the first item we added.
	if (first_item_id.notNull())
	{
		LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
		if (view)
		{
			view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
		}
	}
}


void LLAgentWearables::addWearableToAgentInventory(LLPointer<LLInventoryCallback> cb,
												   LLWearable* wearable,
												   const LLUUID& category_id,
												   BOOL notify)
{
	create_inventory_item(gAgent.getID(),
						  gAgent.getSessionID(),
						  category_id,
						  wearable->getTransactionID(),
						  wearable->getName(),
						  wearable->getDescription(),
						  wearable->getAssetType(),
						  LLInventoryType::IT_WEARABLE,
						  wearable->getType(),
						  wearable->getPermissions().getMaskNextOwner(),
						  cb);
}

void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_all, U32 index)
{

	if (do_remove_all)
	{
		removeWearableFinal(type, do_remove_all, index);
	}
	else
	{
// MULTI_WEARABLE: handle vector changes from arbitrary removal.
		LLWearable* old_wearable = getWearable(type,index);
		
		if ((gAgent.isTeen())
			&& (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
		{
			// Can't take off underclothing in simple UI mode or on PG accounts
			return;
		}
		
		if (old_wearable)
		{
			if (old_wearable->isDirty())
			{
				LLSD payload;
				payload["wearable_type"] = (S32)type;
				// Bring up view-modal dialog: Save changes? Yes, No, Cancel
				LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog);
				return;
			}
			else
			{
				removeWearableFinal(type, do_remove_all, index);
			}
		}
	}
}


// MULTI_WEARABLE: assuming one wearable per type.
// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change.
// static 
bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response)
{
	S32 option = LLNotification::getSelectedOption(notification, response);
	EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
	switch(option)
	{
		case 0:  // "Save"
			gAgentWearables.saveWearable(type, 0);
			gAgentWearables.removeWearableFinal(type, false, 0);
			break;

		case 1:  // "Don't Save"
			gAgentWearables.removeWearableFinal(type, false, 0);
			break;

		case 2: // "Cancel"
			break;

		default:
			llassert(0);
			break;
	}
	return false;
}

// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_remove_all, U32 index)
{
	//LLAgentDumper dumper("removeWearable");
	if (do_remove_all)
	{
		S32 max_entry = mWearableDatas[type].size()-1;
		for (S32 i=max_entry; i>=0; i--)
		{
			LLWearable* old_wearable = getWearable(type,i);
			gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,i));
			setWearable(type,i,NULL);

			//queryWearableCache(); // moved below
			// MULTI_WEARABLE: FIXME - currently we keep a null entry, so can't delete the last one.
			if (i>0)
			{
				mWearableDatas[type].pop_back();
			}
			if (old_wearable)
			{
				old_wearable->removeFromAvatar(TRUE);
			}
		}
	}
	else
	{
		LLWearable* old_wearable = getWearable(type, index);

		gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,index));
		setWearable(type,index,NULL);

		//queryWearableCache(); // moved below

		if (old_wearable)
		{
			old_wearable->removeFromAvatar(TRUE);
		}

		// MULTI_WEARABLE: logic changes if null entries go away
		if (getWearableCount(type)>1)
		{
			// Have to shrink the vector and clean up the item.
			wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type);
			llassert_always(wearable_iter != mWearableDatas.end());
			wearableentry_vec_t& wearable_vec = wearable_iter->second;
			wearable_vec.erase( wearable_vec.begin() + index );
		}
	}

	queryWearableCache();

	// Update the server
	updateServer();
	gInventory.notifyObservers();
}

// Assumes existing wearables are not dirty.
// MULTI_WEARABLE: assumes one wearable per type.
void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items,
										 const LLDynamicArray< LLWearable* >& wearables,
										 BOOL remove)
{
	lldebugs << "setWearableOutfit() start" << llendl;

	BOOL wearables_to_remove[WT_COUNT];
	wearables_to_remove[WT_SHAPE]		= FALSE;
	wearables_to_remove[WT_SKIN]		= FALSE;
	wearables_to_remove[WT_HAIR]		= FALSE;
	wearables_to_remove[WT_EYES]		= FALSE;
	wearables_to_remove[WT_SHIRT]		= remove;
	wearables_to_remove[WT_PANTS]		= remove;
	wearables_to_remove[WT_SHOES]		= remove;
	wearables_to_remove[WT_SOCKS]		= remove;
	wearables_to_remove[WT_JACKET]		= remove;
	wearables_to_remove[WT_GLOVES]		= remove;
	wearables_to_remove[WT_UNDERSHIRT]	= (!gAgent.isTeen()) & remove;
	wearables_to_remove[WT_UNDERPANTS]	= (!gAgent.isTeen()) & remove;
	wearables_to_remove[WT_SKIRT]		= remove;

	S32 count = wearables.count();
	llassert(items.count() == count);

	S32 i;
	for (i = 0; i < count; i++)
	{
		LLWearable* new_wearable = wearables[i];
		LLPointer<LLInventoryItem> new_item = items[i];

		const EWearableType type = new_wearable->getType();
		wearables_to_remove[type] = FALSE;

		// MULTI_WEARABLE: using 0th
		LLWearable* old_wearable = getWearable(type, 0);
		if (old_wearable)
		{
			const LLUUID& old_item_id = getWearableItemID(type, 0);
			if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
				(old_item_id == new_item->getUUID()))
			{
				lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
				continue;
			}

			gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);

			// Assumes existing wearables are not dirty.
			if (old_wearable->isDirty())
			{
				llassert(0);
				continue;
			}
		}

		setWearable(type,0,new_wearable);
		if (new_wearable)
			new_wearable->setItemID(new_item->getUUID());
	}

	std::vector<LLWearable*> wearables_being_removed;

	for (i = 0; i < WT_COUNT; i++)
	{
		if (wearables_to_remove[i])
		{
			// MULTI_WEARABLE: assuming 0th
			LLWearable* wearable = getWearable((EWearableType)i, 0);
			gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID((EWearableType)i,0));
			if (wearable)
			{
				wearables_being_removed.push_back(wearable);
			}
			setWearable((EWearableType)i,0,NULL);
		}
	}

	gInventory.notifyObservers();

	queryWearableCache();

	std::vector<LLWearable*>::iterator wearable_iter;

	for (wearable_iter = wearables_being_removed.begin(); 
		 wearable_iter != wearables_being_removed.end();
		 ++wearable_iter)
	{
		LLWearable* wearablep = *wearable_iter;
		if (wearablep)
		{
			wearablep->removeFromAvatar(TRUE);
		}
	}

	for (i = 0; i < count; i++)
	{
		wearables[i]->writeToAvatar(TRUE);
	}

	// Start rendering & update the server
	mWearablesLoaded = TRUE; 
	checkWearablesLoaded();
	updateServer();

	lldebugs << "setWearableOutfit() end" << llendl;
}


// User has picked "wear on avatar" from a menu.
void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append)
{
	//LLAgentDumper dumper("setWearableItem");
	if (isWearingItem(new_item->getUUID()))
	{
		llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl;
		return;
	}
	
	const EWearableType type = new_wearable->getType();

	if (!do_append)
	{
		// Remove old wearable, if any
		// MULTI_WEARABLE: hardwired to 0
		LLWearable* old_wearable = getWearable(type,0);
		if (old_wearable)
		{
			const LLUUID& old_item_id = old_wearable->getItemID();
			if ((old_wearable->getAssetID() == new_wearable->getAssetID()) &&
				(old_item_id == new_item->getUUID()))
			{
				lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl;
				return;
			}
			
			if (old_wearable->isDirty())
			{
				// Bring up modal dialog: Save changes? Yes, No, Cancel
				LLSD payload;
				payload["item_id"] = new_item->getUUID();
				LLNotifications::instance().add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable));
				return;
			}
		}
	}

	setWearableFinal(new_item, new_wearable, do_append);
}

// static 
bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable)
{
	S32 option = LLNotification::getSelectedOption(notification, response);
	LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID());
	if (!new_item)
	{
		delete wearable;
		return false;
	}

	switch(option)
	{
		case 0:  // "Save"
// MULTI_WEARABLE: assuming 0th
			gAgentWearables.saveWearable(wearable->getType(),0);
			gAgentWearables.setWearableFinal(new_item, wearable);
			break;

		case 1:  // "Don't Save"
			gAgentWearables.setWearableFinal(new_item, wearable);
			break;

		case 2: // "Cancel"
			break;

		default:
			llassert(0);
			break;
	}

	delete wearable;
	return false;
}

// Called from setWearableItem() and onSetWearableDialog() to actually set the wearable.
// MULTI_WEARABLE: unify code after null objects are gone.
void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append)
{
	const EWearableType type = new_wearable->getType();

	if (do_append && getWearableItemID(type,0).notNull())
	{
		new_wearable->setItemID(new_item->getUUID());
		mWearableDatas[type].push_back(new_wearable);
		llinfos << "Added additional wearable for type " << type
				<< " size is now " << mWearableDatas[type].size() << llendl;
	}
	else
	{
		// Replace the old wearable with a new one.
		llassert(new_item->getAssetUUID() == new_wearable->getAssetID());

		LLWearable *old_wearable = getWearable(type,0);
		LLUUID old_item_id;
		if (old_wearable)
		{
			old_item_id = old_wearable->getItemID();
		}
		new_wearable->setItemID(new_item->getUUID());
		setWearable(type,0,new_wearable);

		if (old_item_id.notNull())
		{
			gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
			gInventory.notifyObservers();
		}
		llinfos << "Replaced current element 0 for type " << type
				<< " size is now " << mWearableDatas[type].size() << llendl;
	}

	//llinfos << "LLVOAvatar::setWearableItem()" << llendl;
	queryWearableCache();
	new_wearable->writeToAvatar(TRUE);

	updateServer();
}

void LLAgentWearables::queryWearableCache()
{
	if (!areWearablesLoaded())
	{
		return;
	}

	// Look up affected baked textures.
	// If they exist:
	//		disallow updates for affected layersets (until dataserver responds with cache request.)
	//		If cache miss, turn updates back on and invalidate composite.
	//		If cache hit, modify baked texture entries.
	//
	// Cache requests contain list of hashes for each baked texture entry.
	// Response is list of valid baked texture assets. (same message)

	gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
	gMessageSystem->nextBlockFast(_PREHASH_AgentData);
	gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
	gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID);

	S32 num_queries = 0;
	for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
	{
		const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index);
		LLUUID hash;
		for (U8 i=0; i < baked_dict->mWearables.size(); i++)
		{
			// EWearableType baked_type = gBakedWearableMap[baked_index][baked_num];
			const EWearableType baked_type = baked_dict->mWearables[i];
			// MULTI_WEARABLE: assuming 0th
			const LLWearable* wearable = getWearable(baked_type,0);
			if (wearable)
			{
				hash ^= wearable->getAssetID();
			}
		}
		if (hash.notNull())
		{
			hash ^= baked_dict->mWearablesHashID;
			num_queries++;
			// *NOTE: make sure at least one request gets packed

			//llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
			gMessageSystem->nextBlockFast(_PREHASH_WearableData);
			gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
			gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
		}

		gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID;
	}

	llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
	gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
	gAgentQueryManager.mNumPendingQueries++;
	gAgentQueryManager.mWearablesCacheQueryID++;
}

// MULTI_WEARABLE: need a way to specify by wearable rather than by type.
// User has picked "remove from avatar" from a menu.
// static
void LLAgentWearables::userRemoveWearable(void* userdata)
{
	EWearableType type = (EWearableType)(intptr_t)userdata;
	
	if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR)) //&&
		//!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT)))
	{
		// MULTI_WEARABLE: fixed to 0th for now.
		gAgentWearables.removeWearable(type,false,0);
	}
}

// static
void LLAgentWearables::userRemoveAllClothes(void* userdata)
{
	// We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
	if (gFloaterCustomize)
	{
		gFloaterCustomize->askToSaveIfDirty(userRemoveAllClothesStep2);
	}
	else
	{
		userRemoveAllClothesStep2(TRUE);
	}
}

// static
// MULTI_WEARABLE: removing all here.
void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed)
{
	if (proceed)
	{
		gAgentWearables.removeWearable(WT_SHIRT,true,0);
		gAgentWearables.removeWearable(WT_PANTS,true,0);
		gAgentWearables.removeWearable(WT_SHOES,true,0);
		gAgentWearables.removeWearable(WT_SOCKS,true,0);
		gAgentWearables.removeWearable(WT_JACKET,true,0);
		gAgentWearables.removeWearable(WT_GLOVES,true,0);
		gAgentWearables.removeWearable(WT_UNDERSHIRT,true,0);
		gAgentWearables.removeWearable(WT_UNDERPANTS,true,0);
		gAgentWearables.removeWearable(WT_SKIRT,true,0);
	}
}

void LLAgentWearables::userRemoveAllAttachments(void* userdata)
{
	LLVOAvatar* avatarp = gAgent.getAvatarObject();
	if (!avatarp)
	{
		llwarns << "No avatar found." << llendl;
		return;
	}

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

	for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); 
		 iter != avatarp->mAttachmentPoints.end();)
	{
		LLVOAvatar::attachment_map_t::iterator curiter = iter++;
		LLViewerJointAttachment* attachment = curiter->second;
		LLViewerObject* objectp = attachment->getObject();
		if (objectp)
		{
			gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
			gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
		}
	}
	gMessageSystem->sendReliable(gAgent.getRegionHost());
}

void LLAgentWearables::checkWearablesLoaded() const
{
#ifdef SHOW_ASSERT
	U32 item_pend_count = itemUpdatePendingCount();
	if (mWearablesLoaded)
	{
		llassert(item_pend_count==0);
	}
#endif
}

BOOL LLAgentWearables::areWearablesLoaded() const
{
	checkWearablesLoaded();
	return mWearablesLoaded;
}

// MULTI-WEARABLE: update for multiple indices.
void LLAgentWearables::updateWearablesLoaded()
{
	mWearablesLoaded = (itemUpdatePendingCount()==0);
}

void LLAgentWearables::updateServer()
{
	sendAgentWearablesUpdate();
	gAgent.sendAgentSetAppearance();
}

void LLInitialWearablesFetch::done()
{
	// Get the complete information on the items in the library, 
	// and set up an observer that will wait for that to happen.
	LLInventoryModel::cat_array_t cat_array;
	LLInventoryModel::item_array_t item_array;

	LLFindWearables is_wearable;
	gInventory.collectDescendentsIf(mCompleteFolders.front(),
									cat_array,
									item_array,
									LLInventoryModel::EXCLUDE_TRASH,
									is_wearable);
	S32 count = item_array.count();
	mCOFInitialWearables.reserve(count);
	
	for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin();
		 iter != item_array.end();
		 iter++)
	{
		const LLViewerInventoryItem *item = (*iter).get();
		// We're only concerned with linked items in the COF.  Ignore
		// any non-link items or links to folders.
		if (item->getActualType() != LLAssetType::AT_LINK)
		{
			continue;
		}
		EWearableType type = (EWearableType) (item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK);
		// MULTI-WEARABLE: update
		InitialWearableData wearable_data(type, 0, item->getUUID(), item->getAssetUUID());
		mCOFInitialWearables.push_back(wearable_data);
	}
	
	gInventory.removeObserver(this);
	processInitialWearables();
	delete this;
}

// This will either grab the contents of the Current Outfit Folder if they exist,
// or use the old-style initial agent wearables message.  
void LLInitialWearablesFetch::processInitialWearables()
{
#ifdef USE_CURRENT_OUTFIT_FOLDER
	if (!mCOFInitialWearables.empty())
	{
		for (U8 i = 0; i < mCOFInitialWearables.size(); ++i)
		{
			// Fetch the wearables in the current outfit folder
			InitialWearableData *wearable_data = new InitialWearableData(mCOFInitialWearables[i]); // This will be deleted in the callback.
			if (wearable_data->mAssetID.notNull())
			{
				LLWearableList::instance().getAsset(wearable_data->mAssetID,
													LLStringUtil::null,
													LLWearableDictionary::getAssetType(wearable_data->mType),
													LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data));			
			}
			else
			{
				llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
						<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
			}
		}
	}
	else 
#endif
	if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead.
	{
		LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
		for (U8 i = 0; i < mAgentInitialWearables.size(); ++i)
		{
			// Populate the current outfit folder with links to the wearables passed in the message
			InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback.

			if (wearable_data->mAssetID.notNull())
			{
#ifdef USE_CURRENT_OUTFIT_FOLDER
				const std::string link_name = "WearableLink"; // Unimportant what this is named, it isn't exposed.
				link_inventory_item(gAgent.getID(), wearable_data->mItemID, current_outfit_id, link_name,
									LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
#endif
				// Fetch the wearables
				LLWearableList::instance().getAsset(wearable_data->mAssetID,
													LLStringUtil::null,
													LLWearableDictionary::getAssetType(wearable_data->mType),
													LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data));
			}
			else
			{
				llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID "
						<< wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl;
			}
		}
	}
	else
	{
		LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL;
	}
}
