using System;
using System.Collections.Generic;
using System.Text;
using Yanesdk.System;
using Yanesdk.Draw;
using System.Diagnostics;

namespace Yamalib.Yanesdkext.Draw
{
    /// <summary>
    /// Surfaceクラスを必要に応じてfactoryで生成して、
    /// ファイルを読み込み、返す。
    /// 
    /// また、CacheSystemクラスを利用して、cacheを行なう。
    /// SoundLoaderのSurface版だと考えると良いだろう。
    /// 
    /// SoundLoaderの説明も読むこと。
    /// </summary>
    /// <remarks>
    /// SmartSurfaceLoaderを用いるときは、
    /// SurfaceLoaderが勝手にSurfaceを解放するとSmartSurfaceLoaderが困るので
    /// SurfaceLoader.Disposeは呼び出さないこと。
    /// </remarks>
    public class SurfaceLoader : CachedObjectLoader
    {
        #region ctor
        /// <summary>
        /// SurfaceFactoryを渡さないコンストラクタ。
        /// Factoryプロパティでfactoryのdelegateを渡して。
        /// 
        /// ※ defaultではSurfaceをnewするようにしてある
        /// </summary>
        public SurfaceLoader()
        {
            Factory = delegate { return new Surface(); };
        }

        /// <summary>
        /// コンストラクタで、SurfaceCachedObject派生クラスを生成するfactoryを渡してやる。
        /// 
        /// 例)
        ///		SurfaceLoader loader = new SurfaceLoader(delegate {
        ///           return new Surface(); });
        /// </summary>
        /// <remarks>
        /// ディフォルトではcache size = 64MB
        /// OpenGLを描画に使っている場合、テクスチャサイズは2のべき乗でalignされる。
        /// たとえば、640×480の画像ならば1024×512(32bpp)になる。
        /// よって、1024×512×4byte = 2097152 ≒ 2MB消費する。
        /// 50MBだと640×480の画像をおおよそ25枚読み込めると考えて良いだろう。
        /// </remarks>
        /// <param name="factory"></param>
        public SurfaceLoader(CachedObjectFactory factory)
        {
            Factory = factory;
        }
        #endregion

        #region methods
        /// <summary>
        ///	指定された番号のオブジェクトを構築して画像を読み込み返す
        /// </summary>
        /// 暗黙のうちにオブジェクトは構築され、Loadされる。
        ///	定義ファイル上に存在しない番号を指定した場合はnullが返る
        ///	ファイルの読み込みに失敗した場合は、nullは返らない。
        ///	定義ファイル上に存在しない番号のものを読み込むことは
        ///	考慮しなくてもいいと思われる．．。
        /// 
        /// Loadするときに、Win32Windowなどでは、Screen.Selectされて
        /// いないとまずいので、
        /// 
        /// Surface GetSurface(int no){
        ///     window.Screen.Select();
        ///     Surface texture = loader.GetSurface(no);
        ///     window.Screen.Unselect();
        ///     return texture;
        /// }
        /// と書くべき。すなわち、GetSurfaceを呼び出すときは、
        /// Screen.Select〜Unselect/Updateで囲まれた領域でなければならない。
        /// 
        /// <param name="no"></param>
        /// <returns></returns>
        public Surface GetSurface(int no)
        {
            return GetCachedObjectHelper(no) as Surface;
        }
        #endregion

        #region properties
        /// <summary>
        /// 抜き色(カラーキー)の指定。
        /// LoadDefFileで定義ファイルを読み込む前に設定しなければ効果が無いので注意。
        /// </summary>
        public ColorKey ColorKey
        {
            get { return colorKey; }
            set
            {
                Debug.Assert(colorKey != null, "ColorKeyとしてnullが設定された");
                colorKey = value;
            }
        }
        private ColorKey colorKey = new ColorKey();
        #endregion

        #region overridden from base class
        /// <summary>
        /// 
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        protected override ICachedObject OnDefFileLoaded(FilenamelistReader.Info info)
        {
            if (Factory == null)
                return null; //  YanesdkResult.PreconditionError; // factoryが設定されていない

            ICachedObject obj = Factory();

            // info.name, ColorKey を渡したい
            obj.Construct(info.name);

            return obj;
        }
        #endregion
    }

    /// <summary>
    /// SurfaceLoaderのSmartLoader版
    /// 
    /// defaultではSurfaceをnewする。
    /// </summary>
    /// <remarks>
    /// SmartSurfaceLoaderを用いるときは、
    /// SurfaceLoaderが勝手にSurfaceを解放するとSmartSurfaceLoaderが困るので
    /// SurfaceLoader.Disposeは呼び出さないこと。
    /// </remarks>
    public class SmartSurfaceLoader : CachedObjectSmartLoader<SurfaceLoader>
    {
        /// <summary>
        /// ディフォルトではSurfaceを生成するFactoryを設定してある。
        /// </summary>
        public SmartSurfaceLoader()
        {
            Factory = delegate { return new Surface(); };
        }
    }
}
