/// <summary>
        /// Equivalent to the SL "Replace Outfit" command.  All clothing is removed, and replaced with wearables in given folder.  Body wearables will be replaced if provided.
        /// </summary>
        /// <param name="outfitFolder">Contains the wearable items to put on.</param>
        /// <param name="TimeOut">How long to wait for outfit directory information to download</param>
        public void WearOutfit(InventoryFolder outfitFolder, int TimeOut)
        {
            // Refresh download of outfit folder
            if (!outfitFolder.RequestDownloadContents(false).RequestComplete.WaitOne(TimeOut, false))
            {
                Console.WriteLine("An error occured while downloads the folder contents of : " + outfitFolder.Name);
            }

            // Make sure we have some Wearable Data to start with.
            if ((AgentWearablesData == null) || (AgentWearablesData.Length == 0))
            {
                GetWearables();
            }

            // Flush the cached clothing wearables so we can redefine them
            for (byte i = 4; i <= 12; i++)
            {
                AgentWearablesData[i].ItemID  = LLUUID.Zero;
                AgentWearablesData[i].AssetID = LLUUID.Zero;
            }

            // Replace with wearables from Outfit folder
            foreach (InventoryBase ib in outfitFolder.GetContents())
            {
                if (ib is InventoryWearable)
                {
                    InventoryWearable iw = (InventoryWearable)ib;
                    byte type = ((AssetWearable)iw.Asset).TypeFromAsset;
                    AgentWearablesData[type].ItemID  = iw.ItemID;
                    AgentWearablesData[type].AssetID = iw.AssetID;
                }
            }

            // Create AgentIsNowWearing Packet, and send it
            SendAgentIsNowWearing();

            // Update local Appearance Info
            GetAvatarAppearanceInfoFromWearableAssets();

            // Send updated AgentSetAppearance to the grid
            SendAgentSetAppearance();
        }
        /// <summary>
        /// Equivalent to the SL "Replace Outfit" command.  All clothing is removed, and replaced with wearables in given folder.  Body wearables will be replaced if provided.
        /// </summary>
        /// <param name="outfitFolder">Contains the wearable items to put on.</param>
        /// <param name="TimeOut">How long to wait for outfit directory information to download</param>
        public void WearOutfit(InventoryFolder outfitFolder, int TimeOut, bool removeExistingAttachments)
        {
            // Refresh download of outfit folder
            if (!outfitFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(TimeOut, false))
            {
                Client.Log("Outfit not changed. An error occured while downloads the folder contents of : " + outfitFolder.Name, Helpers.LogLevel.Error);
                return;
            }

            // Make sure we have some Wearable Data to start with.
            if (AgentWearablesSignal.WaitOne(1000, false) == false)
            {
                Client.Log("You must have set appearance at least once, before calling WearOutfit().  AgentWearablesSignal not set.", Helpers.LogLevel.Error);
                return;
            }

            // Flush the cached clothing wearables so we can redefine them
            for (byte i = 4; i <= 12; i++)
            {
                AgentWearablesData[i].ItemID  = LLUUID.Zero;
                AgentWearablesData[i].AssetID = LLUUID.Zero;
            }

            List<InventoryItem> attachments = new List<InventoryItem>();

            // Replace with wearables from Outfit folder
            foreach (InventoryBase ib in outfitFolder.GetContents())
            {
                if (ib is InventoryWearable)
                {
                    try
                    {
                        InventoryWearable iw = (InventoryWearable)ib;
                        Client.Log("Retrieving asset for " + iw.Name + "("+iw.AssetID+")", Helpers.LogLevel.Info);
                        AssetWearable.AppearanceLayerType AppearanceLayer = ((AssetWearable)iw.Asset).AppearanceLayer;

                        Client.Log("Adding skin/clothing layer for " + AppearanceLayer, Helpers.LogLevel.Info);
                        AgentWearablesData[(byte)AppearanceLayer].ItemID = iw.ItemID;
                        AgentWearablesData[(byte)AppearanceLayer].AssetID = iw.AssetID;
                    }
                    catch (Exception e)
                    {
                        Client.Log("Asset for " + ib._Name + " unavailable: " + e.Message, Helpers.LogLevel.Error);
                    }
                }
                else if (ib is InventoryItem)
                {
                    InventoryItem ii = (InventoryItem)ib;
                    attachments.Add(ii);
                }
            }

            // Change attachments
            AddAttachments(attachments, removeExistingAttachments);

            // Create AgentIsNowWearing Packet, and send it
            SendAgentIsNowWearing();

            // Send updated AgentSetAppearance to the grid
            SendAgentSetAppearance();
        }
        /// <summary>
        /// Delete/Remove a folder
        /// </summary>
        /// <param name="ifolder"></param>
        internal void FolderRemove(InventoryFolder ifolder)
        {
            // Need to recursively remove children
            foreach (InventoryBase ib in ifolder.GetContents())
            {
                if (ib is InventoryFolder)
                {
                    InventoryFolder ifChild = (InventoryFolder)ib;
                    FolderRemove(ifChild);
                }
            }

            // Remove from parent
            if (FoldersByUUID.ContainsKey(ifolder.ParentID))
            {
                InventoryFolder ifParent = FoldersByUUID[ifolder.ParentID];
                if (ifParent._Contents.Contains(ifolder))
                {
                    ifParent._Contents.Remove(ifolder);
                }
            }

            // Remove from lookup cache
            if (FoldersByUUID.ContainsKey(ifolder.FolderID))
            {
                FoldersByUUID.Remove(ifolder.FolderID);
            }

            Packet packet = InvPacketHelper.RemoveInventoryFolder(ifolder.FolderID);
            slClient.Network.SendPacket(packet);
        }