/// <summary>
        /// request a texture file to appear in the cache.
        /// </summary>
        /// <param name="ent">Entity the provides context for the request (asset server)</param>
        /// <param name="worldID">The world ID for the requested texture</param>
        /// <param name="finishCall">Where to call when the texture is in the cache</param>
        // TODO: if we get a request for the same texture by two different routines
        // at the same time, this doesn't do all the callbacks
        // To enable this feature, remove the dictionary and checks for already fetching
        public override void DoTextureLoad(EntityName textureEntityName, AssetType typ, DownloadFinishedCallback finishCall)
        {
            EntityNameLL textureEnt = new EntityNameLL(textureEntityName);
            string       worldID    = textureEnt.EntityPart;

            OMV.UUID binID = new OMV.UUID(worldID);

            // do we already have the file?
            string textureFilename = Path.Combine(CacheDirBase, textureEnt.CacheFilename);

            lock (FileSystemAccessLock) {
                if (File.Exists(textureFilename))
                {
                    m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Texture file alreayd exists for " + worldID);
                    bool hasTransparancy = CheckTextureFileForTransparancy(textureFilename);
                    // make the callback happen on a new thread so things don't get tangled (caller getting the callback)
                    Object[] finishCallParams = { finishCall, textureEntityName.Name, hasTransparancy };
                    m_completionWork.DoLater(FinishCallDoLater, finishCallParams);
                    // m_completionWork.DoLater(new FinishCallDoLater(finishCall, textureEntityName.Name, hasTransparancy));
                }
                else
                {
                    bool sendRequest = false;
                    lock (m_waiting) {
                        // if this is already being requested, don't waste our time
                        if (m_waiting.ContainsKey(binID))
                        {
                            m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Already waiting for " + worldID);
                        }
                        else
                        {
                            WaitingInfo wi = new WaitingInfo(binID, finishCall);
                            wi.filename = textureFilename;
                            wi.type     = typ;
                            m_waiting.Add(binID, wi);
                            sendRequest = true;
                        }
                    }
                    if (sendRequest)
                    {
                        // this is here because RequestTexture might immediately call the callback
                        //   and we should be outside the lock
                        m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Requesting: " + textureEntityName);
                        // m_texturePipe.RequestTexture(binID, OMV.ImageType.Normal, 50f, 0, 0, OnACDownloadFinished, false);
                        // m_comm.GridClient.Assets.RequestImage(binID, OMV.ImageType.Normal, 101300f, 0, 0, OnACDownloadFinished, false);
                        // m_comm.GridClient.Assets.RequestImage(binID, OMV.ImageType.Normal, 50f, 0, 0, OnACDownloadFinished, false);
                        ThrottleTextureRequests(binID);
                    }
                }
            }
            return;
        }
        public string ComputeTextureFilename(string cacheDir, OMV.UUID textureID)
        {
            EntityNameLL entName         = EntityNameLL.ConvertTextureWorldIDToEntityName(this, textureID);
            string       textureFilename = Path.Combine(CacheDirBase, entName.CacheFilename);

            // m_log.Log(LogLevel.DTEXTUREDETAIL, "ComputeTextureFilename: " + textureFilename);

            // make sure the recieving directory is there for the texture
            MakeParentDirectoriesExist(textureFilename);

            // m_log.Log(LogLevel.DTEXTUREDETAIL, "ComputerTextureFilename: returning " + textureFilename);
            return(textureFilename);
        }
        public override void DoTextureLoad(EntityName textureEntityName, AssetType typ, DownloadFinishedCallback finishCall)
        {
            EntityNameLL textureEnt = new EntityNameLL(textureEntityName);
            string worldID = textureEnt.EntityPart;
            OMV.UUID binID = new OMV.UUID(worldID);

            if (m_basePath == null) return;

            // do we already have the file?
            string textureFilename = Path.Combine(CacheDirBase, textureEnt.CacheFilename);
            lock (FileSystemAccessLock) {
            if (File.Exists(textureFilename)) {
                m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Texture file already exists for " + worldID);
                bool hasTransparancy = CheckTextureFileForTransparancy(textureFilename);
                // make the callback happen on a new thread so things don't get tangled (caller getting the callback)
                Object[] finishCallParams = { finishCall, textureEntityName.Name, hasTransparancy };
                m_completionWork.DoLater(FinishCallDoLater, finishCallParams);
                // m_completionWork.DoLater(new FinishCallDoLater(finishCall, textureEntityName.Name, hasTransparancy));
            }
            else {
                bool sendRequest = false;
                lock (m_waiting) {
                    // if this is already being requested, don't waste our time
                    if (m_waiting.ContainsKey(binID)) {
                        m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Already waiting for " + worldID);
                    }
                    else {
                        WaitingInfo wi = new WaitingInfo(binID, finishCall);
                        wi.filename = textureFilename;
                        wi.type = typ;
                        m_waiting.Add(binID, wi);
                        sendRequest = true;
                    }
                }
                if (sendRequest) {
                    // this is here because RequestTexture might immediately call the callback
                    //   and we should be outside the lock
                    m_log.Log(LogLevel.DTEXTUREDETAIL, "DoTextureLoad: Requesting: " + textureEntityName);
                    // m_texturePipe.RequestTexture(binID, OMV.ImageType.Normal, 50f, 0, 0, OnACDownloadFinished, false);
                    // m_comm.GridClient.Assets.RequestImage(binID, OMV.ImageType.Normal, 101300f, 0, 0, OnACDownloadFinished, false);
                    // m_comm.GridClient.Assets.RequestImage(binID, OMV.ImageType.Normal, 50f, 0, 0, OnACDownloadFinished, false);
                    ThrottleTextureRequests(binID);
                }
            }
            }
            return;
        }
 /// <summary>
 /// Implementation routine that the parent class uses to create communication specific entity
 /// names.
 /// </summary>
 /// <param name="acb"></param>
 /// <param name="at"></param>
 protected override EntityName ConvertToEntityName(AssetContextBase acb, string worldID)
 {
     return(EntityNameLL.ConvertTextureWorldIDToEntityName(acb, worldID));
 }