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

namespace Yamalib.Draw
{

    /// <summary>
    /// テクスチャをタイル行がするユーティリティクラス
    /// </summary>
    public class TileTexture
    {
        /// 行ID
        public enum ROW : int
        {
            TOP = 0, MIDDLE = 3, BOTTOM = 6
        };
        /// 列ID
        public enum COL : int
        {
            LEFT = 0, CENTER = 1, RIGHT = 2
        };
        /// タイルの繰り返しパターン
        public enum TILE_TYPE : int
        {
            SQUARE4,	// 四角で、４パターンのもの
            SQUARE9,	// ４角で、９パターンで実装されているもの
            V_LINE3,	// 垂直タイルの一列３パターン
            H_LINE3,	// 水平タイルの一列３パターン
        }


        private TextureLoader textureLoader;
        private TILE_TYPE tileType;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="textureLoader">タイルの部品となる画像を指定したローダ</param>
        /// <param name="type_">タイルの形式</param>
        public TileTexture(TextureLoader tl, TILE_TYPE type_)
        {
            textureLoader = tl;
            tileType = type_;
        }

        /// <summary>
        /// タイルテクスチャを描画する
        /// </summary>
        /// <param name="screen">描画先スクリーン</param>
        /// <param name="X">描画位置x</param>
        /// <param name="Y">描画位置y</param>
        /// <param name="sx">全体の幅</param>
        /// <param name="sy">全体の高さ</param>
        public void OnPaint(IScreen screen, int x, int y, int sx, int sy)
        {
            switch (this.tileType)
            {
                case TILE_TYPE.SQUARE4:
                    // todo
                    Debug.Assert(false);
                    break;
                case TILE_TYPE.SQUARE9:
                    BltSquare9(screen, x, y, sx, sy);
                    break;
                case TILE_TYPE.V_LINE3:
                    // todo
                    Debug.Assert(false);
                    break;
                case TILE_TYPE.H_LINE3:
                    BltHLine3(screen, x, y, sx, sy);
                    break;
                default:
                    Debug.Assert(false);
                    break;
            }
        }


        /// 四角９パターン描画
        private void BltSquare9(IScreen screen, int x, int y, int sx, int sy)
        {
            int ltWidth = (int)this.lt.Width;
            int ltHeight = (int)this.lt.Height;

            int lbWidth = (int)this.lb.Width;
            int lbHeight = (int)this.lb.Height;

            int rtWidth = (int)this.rt.Width;

            int crWidth = (int)this.cr.Width;
            int crHeight = (int)this.cr.Height;

            int baseWidth = (int)this.basis.Width;
            int baseHeight = (int)this.basis.Height;

            int ctWidth = (int)this.ct.Width;
            int ctHeight = (int)this.ct.Height;

            int rbWidth = (int)this.rb.Width;
            int rbHeight = (int)this.rb.Height;

            int clHeight = (int)this.cl.Height;
            int leftx = (x + sx) - rtWidth;

            int cbWidth = (int)this.cb.Width;

            // トップ描画
            screen.Blt(this.lt, x, y);

            // 中央繰り返し
            for (int i = ltWidth; i < sx - rtWidth; i += ctWidth)
            {
                if (i + ctWidth > (sx - rtWidth))
                {
                    DrawTextureWidth(screen, this.ct, x + i, y, (sx - rtWidth) - i);
                }
                else
                {
                    screen.Blt(this.ct, x + i, y);
                }
            }
            // 右上
            screen.Blt(this.rt, leftx, y);

            // 内部描画
            for (int i = ltHeight; i < sy - lbHeight; i += baseHeight)
            {
                for (int j = ltWidth; j < sx - crWidth; j += baseWidth)
                {
                    int width = (sx - crWidth) - j;
                    int height = (sy - lbHeight) - i;

                    if (width > baseWidth)
                    {
                        width = baseWidth;
                    }

                    if (height > baseHeight)
                    {
                        height = baseHeight;
                    }

                    DrawTexture(screen, this.basis, x + j, i + y, width, height);
                }
            }

            // 左枠
            for (int i = ltHeight; i < sy - lbHeight; i += clHeight)
            {
                if (i + clHeight > (sy - lbHeight))
                {
                    DrawTextureHeight(screen, this.cl, x, i + y, (sy - lbHeight) - i);
                }
                else
                {
                    screen.Blt(this.cl, x, i + y);
                }
            }

            // 右枠
            leftx = (x + sx) - crWidth;
            for (int i = ltHeight; i < sy - rbHeight; i += clHeight)
            {
                if (i + crHeight > (sy - rbHeight))
                {
                    DrawTextureHeight(screen, this.cr, leftx, i + y, (sy - rbHeight) - i);
                }
                else
                {
                    screen.Blt(this.cr, leftx, i + y);
                }
            }

            // 下枠
            int bottomy = (sy - lbHeight) + y;
            screen.Blt(this.lb, x, bottomy);

            // 中央繰り返し
            for (int i = lbWidth; i < sx - rbWidth; i += cbWidth)
            {
                if (i + cbWidth > (sx - rbWidth))
                {
                    DrawTextureWidth(screen, this.cb, x + i, bottomy, (sx - rbWidth) - i);
                }
                else
                {
                    screen.Blt(this.cb, x + i, bottomy);
                }
            }

            // 右下
            leftx = (x + sx) - rbWidth;
            bottomy = (y + sy) - rbHeight;
            screen.Blt(this.rb, leftx, bottomy);
        }

        /// 一行３パターンタイルの描画
        private void BltHLine3(IScreen screen, int x, int y, int sx, int sy)
        {
            int lWidth = (int)GetTexture(0).Width;
            int cWidth = (int)GetTexture(1).Width;
            int rWidth = (int)GetTexture(2).Width;

            // 左
            screen.Blt(GetTexture(0), x, y);

            // 中央
            int ox;
            for (ox = lWidth; ox < sx - rWidth - cWidth; ox += cWidth)
            {
                screen.Blt(GetTexture(1), x + ox, y);
            }
            // 中央余り
            Rect rc = new Rect();
            rc.Right = GetTexture(1).Width;
            rc.Bottom = GetTexture(1).Height;
            rc.Right = rc.Left + ((sx - rWidth) - ox);
            screen.Blt(GetTexture(1), x + ox, y, rc);

            // 右
            screen.Blt(GetTexture(2), x + sx - rWidth, y);
        }

        /// <summary>
        /// テクスチャの幅、高さをRect表現で返却する。
        /// つまり、常にleft = 0, top = 0 
        /// </summary>
        /// <param name="Texture"></param>
        /// <returns></returns>
        private static Rect GetTextureRect(ITexture texture)
        {
            return new Rect(0.0f, 0.0f, texture.Width, texture.Height);
        }

        /// 描画
        private static void DrawTextureWidth(IScreen screen, ITexture sprite, int x, int y, int width)
        {
            Rect rc = GetTextureRect(sprite);
            rc.Right -= (sprite.Width - width);
            screen.Blt(sprite, x, y, rc);
        }

        /// 描画
        private static void DrawTextureHeight(IScreen screen, ITexture sprite, int x, int y, int height)
        {
            Rect rc = GetTextureRect(sprite); // copy
            rc.Bottom -= (sprite.Height - height);
            screen.Blt(sprite, x, y, rc);
        }

        /// 描画サイズ指定
        private static void DrawTexture(IScreen screen, ITexture sprite, int x, int y, int width, int height)
        {
            Rect rc = GetTextureRect(sprite); // copy
            rc.Right -= (sprite.Width - width);
            rc.Bottom -= (sprite.Height - height);
            screen.Blt(sprite, x, y, rc);
        }


        private ITexture lt
        {
            get
            {
                return GetTexture(ROW.TOP, COL.LEFT);
            }
        }
        private ITexture ct
        {
            get
            {
                return GetTexture(ROW.TOP, COL.CENTER);
            }
        }
        private ITexture rt
        {
            get
            {
                return GetTexture(ROW.TOP, COL.RIGHT);
            }
        }

        private ITexture lb
        {
            get
            {
                return GetTexture(ROW.BOTTOM, COL.LEFT);
            }
        }
        private ITexture cb
        {
            get
            {
                return GetTexture(ROW.BOTTOM, COL.CENTER);
            }
        }
        private ITexture rb
        {
            get
            {
                return GetTexture(ROW.BOTTOM, COL.RIGHT);
            }
        }

        private ITexture cl
        {
            get
            {
                return GetTexture(ROW.MIDDLE, COL.LEFT);
            }
        }

        private ITexture cr
        {
            get
            {
                return GetTexture(ROW.MIDDLE, COL.RIGHT);
            }
        }

        private ITexture basis
        {
            get
            {
                return GetTexture(ROW.MIDDLE, COL.CENTER);
            }
        }

        /// <summary>
        /// 指定したテクスチャを取得する
        /// </summary>
        /// <param name="rOW">行</param>
        /// <param name="cOL">列</param>
        /// <returns></returns>
        private ITexture GetTexture(ROW rOW, COL cOL)
        {
            return GetTexture((int)rOW + (int)cOL);
        }

        /// 指定したテクスチャを取得
        private ITexture GetTexture(int no)
        {
            return textureLoader.GetTexture(no);
        }
    }

}
