//#define USE_ENCRYPT_AB

using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using Giant.Common;
//using Cinder;

namespace Giant.Resource {

    public delegate void SceneLoadingFinishedCallback(float fMinX, float fMinY, float fMinZ, float fMaxX, float fMaxY, float fMaxZ);
    public delegate void LoadCallback(UnityEngine.Object o);
    public delegate void ShaderLoadCallback(UnityEngine.Shader o);

    public class ResourceLoadAsync : CustomYieldInstruction//, Cinder.IAsyncAssetRequest
    {
        private bool _isdone = false;
        public bool isDone {
            get { return _isdone; }
            set {
                _isdone = value;
                if (_isdone) {
                    if(oncomplete != null) oncomplete(asset);
                }
            }
        }
        public UnityEngine.Object asset;

        public override bool keepWaiting => !isDone;

        private Action<UnityEngine.Object> _oncomplete;
        public Action<UnityEngine.Object> oncomplete {
            get {
                return _oncomplete;
            }
            set {
                _oncomplete = value;
                if (isDone) {
                    _oncomplete(asset);
                }
            }
        }



        
    }
    public class SceneLoadAsync : CustomYieldInstruction//, Cinder.IAsyncAssetRequest
    {
        private bool _isdone = false;
        public bool isDone
        {
            get { return _isdone; }
            set
            {
                _isdone = value;
                if (_isdone)
                {
                    if (oncomplete != null) oncomplete(scene);
                }
            }
        }
        public UnityEngine.SceneManagement.Scene scene;

        public override bool keepWaiting => !isDone;

        public Action<UnityEngine.SceneManagement.Scene> oncomplete;

        public AsyncOperation _asyncOperation;

        public float progress
        {
            get
            {
                if (_asyncOperation != null)
                {
                    return _asyncOperation.progress;
                }
                else
                {
                    return 100;
                }
            }
        }

        public bool allowSceneActivation
        {
            get
            {
                if (_asyncOperation == null)
                {
                    return false;
                }
                else
                {

                    return _asyncOperation.allowSceneActivation;
                }

            }
            set
            {
                if (_asyncOperation != null)
                    _asyncOperation.allowSceneActivation = value;

            }

        }

    }

    public class AssetBundleResource
    {
        #region Variate
        /// the platform to run. 
#if UNITY_STANDALONE
        static string m_platform = "win";
#elif UNITY_ANDROID
        static string m_platform = "android";
#elif UNITY_IOS
		static string m_platform = "ios";
#endif

        /// relative path of all downloaded assetbundles.
        static VString m_assetsBundlesPath;

        /// relative path of all assetbundles shipped with the project.
        static VString m_assetsBundlesPath2;

        /// relative path of the manifest file for the SceneEditor.
        static string m_strSceneManifestPath = IResourceLoader.abpath +  IResourceLoader.abmf;

        /// internal cache for all assetbundle loading requests, <assetbundle name hashID, assetbundle object>.
        Dictionary<Int32, AssetBundleCreateRequest> m_requestedAB = new Dictionary<Int32, AssetBundleCreateRequest>(50);

        ListMap<Int32, AssetBundleLoadingList> m_loadingAssetBundle = new ListMap<Int32, AssetBundleLoadingList>(50);
        List<AssetBundleRequestInfo> m_tmpList = new List<AssetBundleRequestInfo>(20);
        #endregion

        /// all loaded manifest configs.
        Dictionary<VString, AssetBundleManifest> m_loadedManifest = new Dictionary<VString, AssetBundleManifest>(20);
        List<AssetBundle> m_manifestBundles = new List<AssetBundle>(10);
        Dictionary<int, AssetBundle> m_allAssetbundle = new Dictionary<int, AssetBundle>((int)ResourceloadConfig.PackageNum);
#if USE_ENCRYPT_AB
        List<Stream> m_allLoadedStream = new List<Stream>((int)ResourceloadConfig.PackageNum);
#endif
        /// assetbundle manifest for the scene editor.
        AssetBundleManifest m_sceneManifest;
        AssetBundle m_shaderBundle;

        public AssetBundle ShaderBundle
        {
            get { return m_shaderBundle; }
        }

        /// Singleton instance.
        static AssetBundleResource m_sInstance = null;
        public static AssetBundleResource Instance
        {
            get
            {
                if (m_sInstance == null)
                {
                    m_sInstance = new AssetBundleResource();
                    //m_sInstance.DoStart();
                }
                return m_sInstance;
            }
        }

        public Dictionary<int, AssetBundle> AllBundles
        {
            get { return m_allAssetbundle; }
        }

        /// for loading assetbundle resource
        struct AssetBundleLoadingList
        {
            public int Key;
            public AssetBundleCreateRequest BundleRequest;
            public List<LoadCallback> CallbackList;
            public List<AssetBundleRequestInfo> RequestList;

        }

        /// for loading assetbundle resource
        struct AssetBundleRequestInfo
        {
            public Int32 HashCode;
            public Int32 OwnerKey;
            public AssetBundleCreateRequest Request;
        }


        /// gets the manifest config for the scene editor.
        public AssetBundleManifest DataManifest
        {
            get
            {
                return m_sceneManifest;
            }
        }


        /// Unload all loaded manifest configs.
        public void UnloadManifest()
        {
            if (m_sceneManifest)
            {
                Resources.UnloadAsset(m_sceneManifest);
            }
            foreach (var mani in m_loadedManifest)
            {
                if(mani.Value != null)
                    Resources.UnloadAsset(mani.Value);
            }

            for (int i = 0; i < m_manifestBundles.Count; i++) {
                if (m_manifestBundles[i] != null) {
                    m_manifestBundles[i].Unload(true);
                }
            }
            m_manifestBundles.Clear();

            m_loadedManifest.Clear();
            m_loadingAssetBundle.Release();
            m_sceneManifest = null;


        }


        /// Load manifest config. 
        /// <param name="strManifestName"> The manifest file relative path. Like, "scenes\scenes" or "ui\ui"</param>
        private AssetBundleManifest LoadManifest(VString strManifestName)
        {
            // load the assetbundle which includes the manifest file
            VString strManifestPath = VString.Concat(m_assetsBundlesPath, strManifestName, AllocType.Tmp);
            AssetBundle ab = null;
            string strFileName = strManifestPath.ToString();
            strManifestPath.Dispose();
            if (!IFile.IsFileExist(strFileName))
            {
                strManifestPath = VString.Concat(m_assetsBundlesPath2, strManifestName, AllocType.Tmp);
                strFileName = strManifestPath.ToString();
                strManifestPath.Dispose();
                if (!IFile.IsFileExist(strFileName))
                {
                    //LogHelper.Log(LogCategory.Framework, "AssetBundleManifest not found!", strFileName);
                    return null;
                }
            }
            ab = LoadAB(strFileName);

            // load the manifest file from the assetbundle
            if (ab != null)
            {
                m_manifestBundles.Add(ab);
                AssetBundleManifest manifest = ab.LoadAsset("AssetBundleManifest") as AssetBundleManifest;
                if (manifest)
                {
                    m_loadedManifest.Add(strManifestName, manifest);
                    return manifest;
                }
                else
                {
                    LogHelper.Log("AssetBundleManifest load failed: ", strFileName);
                }
            }
            else
            {
                LogHelper.Log(" AssetBundleManifest load failed: ", strFileName);
            }

            return null;
        }


        /// Get a manifest config.
        /// <param name="strManifest">The manifest file relative path. Like, "scenes\scenes" or "ui\ui".</param>
        public AssetBundleManifest GetManifest(VString strManifest)
        {
            AssetBundleManifest manifest;
            if (m_loadedManifest.TryGetValue(strManifest, out manifest))
                return manifest;

            return null;
        }

        /// Unload a manifest config.
        /// <param name="strManifest"> The name of manifest</param>
        public void UnLoadManifest(VString strManifest)
        {
            AssetBundleManifest manifest;
            if (m_loadedManifest.TryGetValue(strManifest, out manifest))
            {
                manifest = null;
                m_loadedManifest.Remove(strManifest);
            }
        }

        /// Load all manifest configs for the project.
        protected void LoadManifest()
        {
            VString strSceneManifestPath = VString.From(m_strSceneManifestPath, AllocType.Tmp);
            m_sceneManifest = LoadManifest(strSceneManifestPath);
            strSceneManifestPath.Dispose();
        }

        /// Called when the instance will be destroyed.
        public void DoDestroy()
        {
            m_sInstance = null;
            m_assetsBundlesPath?.Dispose();
            m_assetsBundlesPath2?.Dispose();

            foreach (var ab in m_allAssetbundle) {
                if (ab.Value != null) {
                    ab.Value.Unload(true);
                }
            }
            m_allAssetbundle.Clear();
            /*for (int i = 0; i < m_allAssetbundle.Count; ++i)
            {
                m_allAssetbundle[i].Unload(true);
            }
            m_allAssetbundle.Clear();
            */
            if (m_shaderBundle != null)
            {
                m_shaderBundle.Unload(true);
            }

            UnloadManifest();
            Resources.UnloadUnusedAssets();

            CloseAllFileStream();
        }

        private void CloseAllFileStream() {
#if USE_ENCRYPT_AB
            for (int i = 0; i < m_allLoadedStream.Count; i++)
            {
                m_allLoadedStream[i].Dispose();
            }
            m_allLoadedStream.Clear();
#endif
        }

        public void DoStart()
        {
            // file path of all downloaded assetbundles

            if (IResourceLoader.donotUsePersistentFolderResource)
            {
                // file path of all assetbundles shipped with the product
                m_assetsBundlesPath = VString.Concat(IResourceLoader.streamingAssetsPath, "/AssetBundles/", m_platform, "/", AllocType.Persistent);

            }
            else
            {
                // file path of all assetbundles shipped with the product
                m_assetsBundlesPath = VString.Concat(IResourceLoader.persistentDataPath, "/AssetBundles/", m_platform, "/", AllocType.Persistent);

            }


            // file path of all assetbundles shipped with the product
            m_assetsBundlesPath2 = VString.Concat(IResourceLoader.streamingAssetsPath, "/AssetBundles/", m_platform, "/", AllocType.Persistent);

            // load all manifest configs for the project.
#if UNITY_EDITOR
            if (AssetBundleManager.UseAssetBundle)
            {
#endif
                LoadManifest();

                LoadAllAssetbundle();
#if UNITY_EDITOR
            }
#endif
        }

        void LoadAllAssetbundle()
        {
            VString strSceneFolder = VString.From(IResourceLoader.abpath, AllocType.Tmp);
            m_allAssetbundle.Clear();
            uint packcount = ResourceloadConfig.PackageNum;
            for (uint i = 0; i < packcount; ++i)
            {
                VString assetbundleName = VString.From(i.ToString("x2"), AllocType.Tmp);
                LoadAssetBundleSync(m_sceneManifest, strSceneFolder, assetbundleName, (UnityEngine.Object o) =>
                {
                    AssetBundle bundle = o as AssetBundle;
                    if (bundle != null)
                    {
                        m_allAssetbundle.Add((int)i, o as AssetBundle);
                    }
                    assetbundleName.Dispose();
                });
            }

            VString assetbundleName1 = VString.From("shaders", AllocType.Tmp);
            LoadAssetBundleSync(m_sceneManifest, strSceneFolder, assetbundleName1, (UnityEngine.Object o) =>
            {
                m_shaderBundle = o as AssetBundle;
                assetbundleName1.Dispose();
                //Shader.WarmupAllShaders();
            });

            strSceneFolder.Dispose();
        }

        /// Update asynchronous loading reource
        public void DoUpdate()
        {
            for (int i = 0; i < m_loadingAssetBundle.ValueList.Count; ++i)
            {
                // assetbundle load finished
                m_tmpList.Clear();
                int hashcode = 0;
                AssetBundleLoadingList loadinginfo = m_loadingAssetBundle.ValueList[i];
                List<AssetBundleRequestInfo> tmpList = loadinginfo.RequestList;
                for (int j = 0; j < tmpList.Count; ++j)
                {
                    if (tmpList[j].Request.isDone)
                    {
                        hashcode = tmpList[j].HashCode;
                        m_requestedAB.Remove(hashcode);
                        m_tmpList.Add(tmpList[j]);

                        AssetBundleManager.Instance.AddAssetBundle(hashcode, tmpList[j].Request.assetBundle, tmpList[j].OwnerKey);
                    }

                }

                for (int j = 0; j < m_tmpList.Count; ++j)
                {
                    if (loadinginfo.RequestList.Count == 1)
                    {
                        m_loadingAssetBundle.CachedRemove(loadinginfo.Key);
                        for (int k = 0; k < loadinginfo.CallbackList.Count; ++k)
                        {
                            loadinginfo.CallbackList[k](loadinginfo.BundleRequest.assetBundle); // even it's null, to indicate failed attempt
                        }
                    }
                    loadinginfo.RequestList.Remove(m_tmpList[j]);
                }
            }

            m_loadingAssetBundle.RemoveFromCache();
        }

        /// Load an assetbundle resouce with sync
        /// <param name="strManifest">The manifest name.</param>
        /// <param name="strFolder">  The resource folder name. Like: "ui/"</param>
        /// <param name="strAssetBundleName"> The assetbundle name. </param>
        /// <param name="callback">   The callback function will do when load asset finished.</pOaram>
        public void LoadAssetBundleAsync(VString strManifest, VString strFolder, VString strAssetBundleName, LoadCallback callback)
        {
            AssetBundleManifest manifest;
            if (!m_loadedManifest.TryGetValue(strManifest, out manifest))
                return;

            LoadAssetBundleAsync(manifest, strFolder, strAssetBundleName, callback);
        }



        /// Load an assetbundle in synchronous mode.
        /// <param name="manifest"> The manifest pointer.</param>
        /// <param name="strFolder">Relative path under the root assetbundle path, to load the assetbundle, like "ui/".</param>
        /// <param name="strAssetBundleName"> The assetbundle name. </param>
        /// <param name="callback"> The callback function will do when load asset finished.</param>
        public void LoadAssetBundleSync(AssetBundleManifest manifest, VString strFolder, VString strAssetBundleName, LoadCallback callback)
        {
            // NOTICE: get the assetbundle from the internal cache 
            // (To avoid loaded assets to get dependencies again with gc. When depends were removed, they won't be loaded.)
            LoadedAssetBundle loadedAssetBundle;
            Int32 hashCode = strAssetBundleName.GetHashCode();
            if (AssetBundleManager.Instance.LoadedAssetBundles.TryGetValue(hashCode, out loadedAssetBundle))
            {
                loadedAssetBundle.ReferencedCount++;
                AssetBundleManager.Instance.AddDepencyRef(hashCode);
                if (callback != null)
                    callback(loadedAssetBundle.Bundle);
                return;
            }

            var depends = manifest.GetAllDependencies(strAssetBundleName.ToString());

            // if no dependency, load the assetbundle directly
            if (depends.Length == 0)
            {
                LoadAssetBundleSyncInternal(strFolder, strAssetBundleName, callback, 0);
            }
            // dependenciy existed, load all dependency assetbundles and the assetbundle itself
            else
            {
                hashCode = strAssetBundleName.GetHashCode();

                for (int i = 0; i < depends.Length; i++)
                {
                    VString tmpDepends = VString.From(depends[i], AllocType.Tmp);
                    LoadAssetBundleSyncInternal(strFolder, tmpDepends, null, hashCode);
                    tmpDepends.Dispose();
                }
                LoadAssetBundleSyncInternal(strFolder, strAssetBundleName, callback, 0);
            }
            strAssetBundleName.Dispose();
        }

        public bool CheckAssetBundleExist(VString strFolder, VString strAssetBundleName)
        {
            //using (VString tmpSuffix = VString.From(IResourceLoader.strAssetBundleSuffix, AllocType.Tmp))
            using (VString Path = VString.Concat(strFolder, strAssetBundleName))
            {
                using (VString fileName = VString.Concat(m_assetsBundlesPath, Path, AllocType.Tmp))
                {
                    if (IFile.IsFileExist(fileName.ToString()))
                    {
                        return true;
                    }
                }
                using (VString fileName = VString.Concat(m_assetsBundlesPath2, Path, AllocType.Tmp))
                {
                    if (IFile.IsFileExist(fileName.ToString()))
                    {
                        return true;
                    }
                }
                return false;
            }


        }


        /// Load an assetbundle resouce with sync
        /// <param name="strFolder">The resource folder name. Like: "ui/"</param>
        /// <param name="strAssetBundleName"> The assetbundle name. </param>
        /// <param name="callback"> The callback function will do when load asset finished.</param>
        private void LoadAssetBundleSyncInternal(VString strFolder, VString strAssetBundleName, LoadCallback callback, int ownerKey)
        {
            // load the assetbundle from the internal cache
            LoadedAssetBundle loadedAssetBundle = null;
            Int32 hashCode = strAssetBundleName.GetHashCode();
            if (AssetBundleManager.Instance.LoadedAssetBundles.TryGetValue(hashCode, out loadedAssetBundle))
            {
                loadedAssetBundle.ReferencedCount++;
                AssetBundleManager.Instance.AddDenpency(ownerKey, loadedAssetBundle);
                if (null != callback)
                    callback(loadedAssetBundle.Bundle);
                return;
            }

            AssetBundle ab = null;
            // load the assetbundle from the local storage
            VString fileName = VString.Concat(m_assetsBundlesPath, strFolder, strAssetBundleName, AllocType.Tmp);
            string abpath = fileName.ToString();
            fileName.Dispose();
            if (IFile.IsFileExist(abpath))
            {
                ab = LoadAB(abpath);
            }
            if (ab == null)
            {
                fileName = VString.Concat(m_assetsBundlesPath2, strFolder, strAssetBundleName, AllocType.Tmp);
                abpath = fileName.ToString();
                fileName.Dispose();
                if (IFile.IsFileExist(abpath)) {
                    ab = LoadAB(abpath);
                }

            }

            if (ab != null)
                AssetBundleManager.Instance.AddAssetBundle(hashCode, ab, ownerKey);
            else
                LogHelper.Log("[ResourceManager]: Load assetbundle failed, name= ", abpath);

            if (null != callback)
                callback(ab);
        }

        /// Load an assetbundle in asynchronous mode.
        /// <param name="manifest"> The manifest pointer.</param>
        /// <param name="strFolder">Relative path under the root assetbundle path, to load the assetbundle, like "ui/".</param>
        /// <param name="strAssetBundleName"> The assetbundle name. </param>
        /// <param name="callback"> The callback function will do when load asset finished.</param>
        public void LoadAssetBundleAsync(AssetBundleManifest manifest, VString strFolder, VString strAssetBundleName, LoadCallback callback)
        {
            // NOTICE: get the assetbundle from the internal cache 
            // (To avoid loaded assets to get dependencies again with gc. When depends were removed, they won't be loaded.)
            // get the assetbundle from the internal cache
            LoadedAssetBundle loadedAssetBundle;
            Int32 hashCode = strAssetBundleName.GetHashCode();
            if (AssetBundleManager.Instance.LoadedAssetBundles.TryGetValue(hashCode, out loadedAssetBundle))
            {
                loadedAssetBundle.ReferencedCount++;
                AssetBundleManager.Instance.AddDepencyRef(hashCode);

                if (callback != null)
                    callback(loadedAssetBundle.Bundle);
                return;
            }

            var depends = manifest.GetAllDependencies(strAssetBundleName.ToString());

            // if no dependency, load the assetbundle directly
            if (depends.Length == 0)
            {
                LoadAssetBundleAsync(strFolder, strAssetBundleName, callback);
            }
            // dependenciy existed, load all dependency assetbundles and the assetbundle itself
            else
            {
                LoadAssetBundleAsync(strFolder, strAssetBundleName, callback);

                AssetBundleLoadingList loadingList;

                hashCode = strAssetBundleName.GetHashCode();
                if (m_loadingAssetBundle.TryGetValue(hashCode, out loadingList))
                {
                    VString tmpDepends = new VString(2, AllocType.Tmp);
                    for (int i = 0; i < depends.Length; i++)
                    {
                        tmpDepends.CopyFrom(depends[i]);
                        LoadAssetBundleDependsAsync(strFolder, tmpDepends, ref loadingList, hashCode);
                    }
                    tmpDepends.Dispose();
                }
            }

            strAssetBundleName.Dispose();
        }

        /// Load assetbundle resource, asynchronously, We will call the callback function when loading finished.
        /// <param name="strFolder">The resource folder.Like, "scenes/".</param>
        /// <param name="strAssetBundleName">The assetbundle name.</param>
        /// <param name="callback"> The callback function will do when load asset finished.</param>
        void LoadAssetBundleAsync(VString strFolder, VString strAssetBundleName, LoadCallback callback)
        {
            // get the assetbundle from the internal cache
            LoadedAssetBundle loadedAssetBundle;
            Int32 hashCode = strAssetBundleName.GetHashCode();
            if (AssetBundleManager.Instance.LoadedAssetBundles.TryGetValue(hashCode, out loadedAssetBundle))
            {
                loadedAssetBundle.ReferencedCount++;
                AssetBundleManager.Instance.AddDepencyRef(hashCode);

                if (callback != null)
                    callback(loadedAssetBundle.Bundle);
                return;
            }

            // whether the load quest has already existed
            UnityEngine.AssetBundleCreateRequest requestAB = null;

            if (m_requestedAB.TryGetValue(hashCode, out requestAB))
            {
                AssetBundleLoadingList loadingList;
                if (m_loadingAssetBundle.TryGetValue(hashCode, out loadingList))
                {
                    loadingList.CallbackList.Add(callback);
                }
                return;
            }

            // load the assetbundle from local storage


            VString tmp = VString.Concat(m_assetsBundlesPath, strFolder, strAssetBundleName, AllocType.Tmp);
            string abpath = tmp.ToString();
            tmp.Dispose();
            if (IFile.IsFileExist(abpath))
            {
                requestAB = LoadABAsync(abpath);
            }
            if (requestAB == null)
            {
                tmp = VString.Concat(m_assetsBundlesPath2, strFolder, strAssetBundleName, AllocType.Tmp);
                abpath = tmp.ToString();
                tmp.Dispose();
                if (IFile.IsFileExist(abpath))
                {
                    requestAB = LoadABAsync(abpath);
                }
                else
                {
                    LogHelper.Log("Load asset bundle failed: ", abpath);
                    if (callback != null)
                        callback(null);
                    return;
                }
            }
            if (requestAB == null)
            {
                LogHelper.Log("Load asset bundle failed: ", abpath);
                if (callback != null)
                {
                    callback(null);
                }

                return;
            }

            AssetBundleLoadingList loadinfo;
            // load assetbundle from a remote storage
            loadinfo.RequestList = new List<AssetBundleRequestInfo>(50);
            loadinfo.CallbackList = new List<LoadCallback>(5);
            loadinfo.CallbackList.Add(callback);
            loadinfo.Key = hashCode;
            loadinfo.BundleRequest = requestAB;

            AssetBundleRequestInfo info;
            info.HashCode = hashCode;
            info.Request = requestAB;
            info.OwnerKey = 0;
            loadinfo.RequestList.Add(info);

            m_loadingAssetBundle[hashCode] = loadinfo;
            m_requestedAB.Add(hashCode, requestAB);
        }

        /// Load asset bundle depends resource, asynchronously, using coroutines.We will call the callback function when loading finished.
        /// <param name="strFolder">The resource folder.Like, "scenes/".</param>
        /// <param name="strAssetBundleName">The assetbundle name.</param>
        /// <param name="callback"> The callback function will do when load asset finished.</param>
        void LoadAssetBundleDependsAsync(VString strFolder, VString strAssetBundleName, ref AssetBundleLoadingList loadingList, int ownerKey)
        {
            // get the assetbundle from the internal cache
            LoadedAssetBundle loadedAssetBundle;
            Int32 hashCode = strAssetBundleName.GetHashCode();
            if (AssetBundleManager.Instance.LoadedAssetBundles.TryGetValue(hashCode, out loadedAssetBundle))
            {
                loadedAssetBundle.ReferencedCount++;
                AssetBundleManager.Instance.AddDenpency(ownerKey, loadedAssetBundle);
                return;
            }

            // whether the load quest has already existed
            UnityEngine.AssetBundleCreateRequest requestAB = null;
            if (m_requestedAB.TryGetValue(hashCode, out requestAB))
            {
                AssetBundleRequestInfo info;
                info.HashCode = hashCode;
                info.Request = requestAB;
                info.OwnerKey = ownerKey;
                loadingList.RequestList.Add(info);
                return;
            }

            // load the assetbundle from local storage

            VString tmpPath = VString.Concat(m_assetsBundlesPath, strFolder, strAssetBundleName, AllocType.Tmp);
            string abpath = tmpPath.ToString();
            tmpPath.Dispose();
            if (IFile.IsFileExist(abpath))
            {
                requestAB = LoadABAsync(abpath);

            }
            if (requestAB == null)
            {
                tmpPath = VString.Concat(m_assetsBundlesPath2, strFolder, strAssetBundleName, AllocType.Tmp);
                abpath = tmpPath.ToString();
                tmpPath.Dispose();
                if (IFile.IsFileExist(abpath))
                {
                    requestAB = LoadABAsync(abpath);
                }
                else
                {
                    LogHelper.Log("Load asset bundle failed: ", abpath);
                    return;
                }
            }
            if (requestAB == null)
            {
                LogHelper.Log("Load asset bundle failed: ", abpath);
                return;
            }

            // load assetbundle from a remote storage
            AssetBundleRequestInfo info1;
            info1.HashCode = hashCode;
            info1.Request = requestAB;
            info1.OwnerKey = ownerKey;
            loadingList.RequestList.Add(info1);
            m_requestedAB.Add(hashCode, requestAB);
        }

        private AssetBundleCreateRequest LoadABAsync(string abpath) {
            AssetBundleCreateRequest requestAB;
#if !USE_ENCRYPT_AB
            requestAB = AssetBundle.LoadFromFileAsync(abpath);
#else
            var fs = getStream(abpath);
            requestAB = AssetBundle.LoadFromStreamAsync(fs);
            //fs.Dispose();
#endif
            return requestAB;
        }

        private AssetBundle LoadAB(string abpath) {
            AssetBundle ab = null;
#if !USE_ENCRYPT_AB
            ab = AssetBundle.LoadFromFile(abpath);
#else
            var fs = getStream(abpath);
            ab = AssetBundle.LoadFromStream(fs);
            //fs.Dispose();
#endif
            return ab;
        }
    }

#if USE_ENCRYPT_AB
        AssetBundleStream getStream(string name)
        {
            var stream = new AssetBundleStream(name);

            m_allLoadedStream.Add(stream);
            return stream;
        }
#endif

}
