/// <summary>
        /// Callback invoked when an item is received from an async request to the inventory service.
        ///
        /// We're assuming here that items are always received after all the folders
        /// received.
        /// If folder is null, we will search for it starting from RootFolder (an O(n) operation),
        /// otherwise we'll just put it into folder
        /// </summary>
        /// <param name="folderInfo"></param>
        private void ItemReceive(InventoryItemBase itemInfo, InventoryFolderImpl folder)
        {
            //            m_log.DebugFormat(
            //                "[INVENTORY CACHE]: Received item {0} {1} for user {2}",
            //                itemInfo.Name, itemInfo.ID, userID);

            if (folder == null && RootFolder != null)
            {
                folder = RootFolder.FindFolder(itemInfo.Folder);
            }

            if (null == folder)
            {
                m_log.WarnFormat(
                    "Received item {0} {1} but its folder {2} does not exist",
                    itemInfo.Name, itemInfo.ID, itemInfo.Folder);

                return;
            }

            lock (folder.Items)
            {
                folder.Items[itemInfo.ID] = itemInfo;
            }

            if (OnItemReceived != null)
            {
                OnItemReceived(itemInfo.ID);
            }
        }
        /// <summary>
        /// Create a folder in this agent's inventory.
        /// </summary>
        ///
        /// If the inventory service has not yet delievered the inventory
        /// for this user then the request will be queued.
        ///
        /// <param name="parentID"></param>
        /// <returns></returns>
        public bool CreateFolder(string folderName, UUID folderID, ushort folderType, UUID parentID)
        {
            //            m_log.DebugFormat(
            //                "[AGENT INVENTORY]: Creating inventory folder {0} {1} for {2} {3}", folderID, folderName, remoteClient.Name, remoteClient.AgentId);

            if (m_hasReceivedInventory)
            {
                InventoryFolderImpl parentFolder = RootFolder.FindFolder(parentID);

                if (null == parentFolder)
                {
                    m_log.WarnFormat(
                        "[AGENT INVENTORY]: Tried to create folder {0} {1} but the parent {2} does not exist",
                        folderName, folderID, parentID);

                    return(false);
                }

                InventoryFolderImpl createdFolder = parentFolder.CreateChildFolder(folderID, folderName, folderType);

                if (createdFolder != null)
                {
                    InventoryFolderBase createdBaseFolder = new InventoryFolderBase();
                    createdBaseFolder.Owner    = createdFolder.Owner;
                    createdBaseFolder.ID       = createdFolder.ID;
                    createdBaseFolder.Name     = createdFolder.Name;
                    createdBaseFolder.ParentID = createdFolder.ParentID;
                    createdBaseFolder.Type     = createdFolder.Type;
                    createdBaseFolder.Version  = createdFolder.Version;

                    m_InventoryService.AddFolder(createdBaseFolder);

                    return(true);
                }
                else
                {
                    m_log.WarnFormat(
                        "[AGENT INVENTORY]: Tried to create folder {0} {1} but the folder already exists",
                        folderName, folderID);

                    return(false);
                }
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(CreateFolderDelegate), this, "CreateFolder"),
                        new object[] { folderName, folderID, folderType, parentID }));

                return(true);
            }
        }
        /// <summary>
        /// Handle an inventory folder move request from the client.
        ///
        /// If the inventory service has not yet delievered the inventory
        /// for this user then the request will be queued.
        /// </summary>
        ///
        /// <param name="folderID"></param>
        /// <param name="parentID"></param>
        /// <returns>
        /// true if the delete was successful, or if it was queued pending folder receipt
        /// false if the folder to be deleted did not exist.
        /// </returns>
        public bool MoveFolder(UUID folderID, UUID parentID)
        {
            //            m_log.DebugFormat(
            //                "[AGENT INVENTORY]: Moving inventory folder {0} into folder {1} for {2} {3}",
            //                parentID, remoteClient.Name, remoteClient.Name, remoteClient.AgentId);

            if (m_hasReceivedInventory)
            {
                InventoryFolderBase baseFolder = new InventoryFolderBase();
                baseFolder.Owner    = m_userProfile.ID;
                baseFolder.ID       = folderID;
                baseFolder.ParentID = parentID;

                m_InventoryService.MoveFolder(baseFolder);

                InventoryFolderImpl folder       = RootFolder.FindFolder(folderID);
                InventoryFolderImpl parentFolder = RootFolder.FindFolder(parentID);
                if (parentFolder != null && folder != null)
                {
                    InventoryFolderImpl oldParentFolder = RootFolder.FindFolder(folder.ParentID);

                    if (oldParentFolder != null)
                    {
                        oldParentFolder.RemoveChildFolder(folderID);
                        parentFolder.AddChildFolder(folder);
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(false);
                }

                return(true);
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(MoveFolderDelegate), this, "MoveFolder"),
                        new object[] { folderID, parentID }));

                return(true);
            }
        }
        public bool QueryFolder(InventoryFolderBase folder)
        {
            if (m_hasReceivedInventory)
            {
                InventoryFolderBase invFolder = RootFolder.FindFolder(folder.ID);

                if (invFolder != null)
                {
                    // Folder is in local cache, just update client
                    //
                    return(true);
                }

                InventoryFolderBase folderInfo = null;

                folderInfo = m_InventoryService.QueryFolder(folder);

                if (folderInfo != null)
                {
                    InventoryFolderImpl createdFolder = RootFolder.CreateChildFolder(folderInfo.ID, folderInfo.Name, (ushort)folderInfo.Type);

                    createdFolder.Version  = folderInfo.Version;
                    createdFolder.Owner    = folderInfo.Owner;
                    createdFolder.ParentID = folderInfo.ParentID;

                    return(true);
                }

                return(false);
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(QueryFolderDelegate), this, "QueryFolder"),
                        new object[] { folder.ID }));

                return(true);
            }
        }
        /// <summary>
        /// This method will delete all the items and folders in the given folder.
        /// </summary>
        /// If the inventory service has not yet delievered the inventory
        /// for this user then the request will be queued.
        ///
        /// <param name="folderID"></param>
        public bool PurgeFolder(UUID folderID)
        {
            //            m_log.InfoFormat("[AGENT INVENTORY]: Purging folder {0} for {1} uuid {2}",
            //                folderID, remoteClient.Name, remoteClient.AgentId);

            if (m_hasReceivedInventory)
            {
                InventoryFolderImpl purgedFolder = RootFolder.FindFolder(folderID);

                if (purgedFolder != null)
                {
                    // XXX Nasty - have to create a new object to hold details we already have
                    InventoryFolderBase purgedBaseFolder = new InventoryFolderBase();
                    purgedBaseFolder.Owner    = purgedFolder.Owner;
                    purgedBaseFolder.ID       = purgedFolder.ID;
                    purgedBaseFolder.Name     = purgedFolder.Name;
                    purgedBaseFolder.ParentID = purgedFolder.ParentID;
                    purgedBaseFolder.Type     = purgedFolder.Type;
                    purgedBaseFolder.Version  = purgedFolder.Version;

                    m_InventoryService.PurgeFolder(purgedBaseFolder);

                    purgedFolder.Purge();

                    return(true);
                }
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(PurgeFolderDelegate), this, "PurgeFolder"),
                        new object[] { folderID }));

                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Handle a client request to update the inventory folder
        /// </summary>
        ///
        /// If the inventory service has not yet delievered the inventory
        /// for this user then the request will be queued.
        ///
        /// FIXME: We call add new inventory folder because in the data layer, we happen to use an SQL REPLACE
        /// so this will work to rename an existing folder.  Needless to say, to rely on this is very confusing,
        /// and needs to be changed.
        ///
        /// <param name="folderID"></param>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <param name="parentID"></param>
        public bool UpdateFolder(string name, UUID folderID, ushort type, UUID parentID)
        {
            //            m_log.DebugFormat(
            //                "[AGENT INVENTORY]: Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId);

            if (m_hasReceivedInventory)
            {
                InventoryFolderImpl folder = RootFolder.FindFolder(folderID);

                // Delegate movement if updated parent id isn't the same as the existing parentId
                if (folder.ParentID != parentID)
                {
                    MoveFolder(folderID, parentID);
                }

                InventoryFolderBase baseFolder = new InventoryFolderBase();
                baseFolder.Owner    = m_userProfile.ID;
                baseFolder.ID       = folderID;
                baseFolder.Name     = name;
                baseFolder.ParentID = parentID;
                baseFolder.Type     = (short)type;
                baseFolder.Version  = RootFolder.Version;

                m_InventoryService.UpdateFolder(baseFolder);

                folder.Name = name;
                folder.Type = (short)type;
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(UpdateFolderDelegate), this, "UpdateFolder"),
                        new object[] { name, folderID, type, parentID }));
            }

            return(true);
        }
        /// <summary>
        /// Send details of the inventory items and/or folders in a given folder to the client.
        /// </summary>
        /// <param name="client"></param>
        /// <param name="folderID"></param>
        /// <param name="fetchFolders"></param>
        /// <param name="fetchItems"></param>
        /// <returns>true if the request was queued or successfully processed, false otherwise</returns>
        public bool SendInventoryDecendents(IClientAPI client, UUID folderID, bool fetchFolders, bool fetchItems)
        {
            if (m_hasReceivedInventory)
            {
                InventoryFolderImpl folder;

                if ((folder = RootFolder.FindFolder(folderID)) != null)
                {
                    //                            m_log.DebugFormat(
                    //                                "[AGENT INVENTORY]: Found folder {0} for client {1}",
                    //                                folderID, remoteClient.AgentId);

                    client.SendInventoryFolderDetails(
                        client.AgentId, folderID, folder.RequestListOfItems(),
                        folder.RequestListOfFolders(), fetchFolders, fetchItems);

                    return(true);
                }
                else
                {
                    m_log.WarnFormat(
                        "[AGENT INVENTORY]: Could not find folder {0} requested by user {1} {2}",
                        folderID, client.Name, client.AgentId);

                    return(false);
                }
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(SendInventoryDescendentsDelegate), this, "SendInventoryDecendents", false, false),
                        new object[] { client, folderID, fetchFolders, fetchItems }));

                return(true);
            }
        }
        // Load additional items that other regions have put into the database
        // The item will be added tot he local cache. Returns true if the item
        // was found and can be sent to the client
        //
        public bool QueryItem(InventoryItemBase item)
        {
            if (m_hasReceivedInventory)
            {
                InventoryItemBase invItem = RootFolder.FindItem(item.ID);

                if (invItem != null)
                {
                    // Item is in local cache, just update client
                    //
                    return(true);
                }

                InventoryItemBase itemInfo = null;

                itemInfo = m_InventoryService.QueryItem(item);

                if (itemInfo != null)
                {
                    InventoryFolderImpl folder = RootFolder.FindFolder(itemInfo.Folder);
                    ItemReceive(itemInfo, folder);
                    return(true);
                }

                return(false);
            }
            else
            {
                AddRequest(
                    new InventoryRequest(
                        Delegate.CreateDelegate(typeof(QueryItemDelegate), this, "QueryItem"),
                        new object[] { item.ID }));

                return(true);
            }
        }