using CommonLang.IO;
using CommonLang.Log;
using MPQ.FileSystem;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace MPQ.Resource
{
    public class MPQResourceLoader : DefaultResourceLoader
    {
        public const string PREFIX_MPQ = "mpq://";

        protected MPQFileSystem mFileSystem;

        public MPQResourceLoader(string root = ".", MPQFileSystem fs = null)
            : base(root)
        {
            mFileSystem = fs;
            CommonLang.IO.Resource.SetLoader(this);
        }

        //------------------------------------------------------------------------------
        #region MPQ

        protected virtual bool _TryLoadFromMPQ(string path, ref byte[] ret)
        {
            if (mFileSystem != null)
            {
                ret = mFileSystem.getData(path);
                return ret != null;
            }
            return false;
        }
        protected virtual bool _TryLoadFromMPQ(string path, ref Stream ret)
        {
            if (mFileSystem != null)
            {
                ret = mFileSystem.openStream(path);
                return ret != null;
            }
            return false;
        }
        protected virtual bool _ExistWithMPQ(string path)
        {
            if (mFileSystem != null)
            {
                return mFileSystem.findEntry(path) != null;
            }
            return false;
        }

        #endregion
        //------------------------------------------------------------------------------

        public override bool ExistData(string path)
        {
            if (path.StartsWith(PREFIX_MPQ))
            {
                return _ExistWithMPQ(path.Substring(PREFIX_MPQ.Length));
            }
            if (path.StartsWith(PREFIX_FILE))
            {
                return _ExistWithFileSystem(path.Substring(PREFIX_FILE.Length));
            }
            if (path.StartsWith(PREFIX_RES))
            {
                return false;
            }
            if (mFileSystem != null && _ExistWithMPQ(path))
            {
                return true;
            }
            if (File.Exists(path) && _ExistWithFileSystem(path))
            {
                return true;
            }
            return false;
        }

        public override byte[] LoadData(string path)
        {
            byte[] ret = null;

            // Specify Prefix
            if (path.StartsWith(PREFIX_MPQ))
            {
                _TryLoadFromMPQ(path.Substring(PREFIX_MPQ.Length), ref ret);
                return ret;
            }
            if (path.StartsWith(PREFIX_FILE))
            {
                _TryLoadFromFileSystem(path.Substring(PREFIX_FILE.Length), ref ret);
                return ret;
            }
            if (path.StartsWith(PREFIX_RES))
            {
                return ret;
            }
            // MPQ
            if (mFileSystem != null && _TryLoadFromMPQ(path, ref ret))
            {
                return ret;
            }
            // File
            if (File.Exists(path) && _TryLoadFromFileSystem(path, ref ret))
            {
                return ret;
            }
            return ret;
        }

        public override Stream LoadDataAsStream(string path)
        {
            Stream ret = null;

            // Specify Prefix
            if (path.StartsWith(PREFIX_MPQ))
            {
                _TryLoadFromMPQ(path.Substring(PREFIX_MPQ.Length), ref ret);
                return ret;
            }
            if (path.StartsWith(PREFIX_FILE))
            {
                _TryLoadFromFileSystem(path.Substring(PREFIX_FILE.Length), ref ret);
                return ret;
            }
            if (path.StartsWith(PREFIX_RES))
            {
                return ret;
            }
            // MPQ
            if (mFileSystem != null && _TryLoadFromMPQ(path, ref ret))
            {
                return ret;
            }
            // File
            if (File.Exists(path) && _TryLoadFromFileSystem(path, ref ret))
            {
                return ret;
            }
            return ret;
        }
    }
}