#region Using ステートメント

using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

#endregion

namespace MikuMikuDance.XNA.Debug.Utils
{
    /// <summary>
    /// レイアウトのアライメント位置
    /// </summary>
    [Flags]
    public enum Alignment
    {
        /// <summary>
        /// レイアウトなし
        /// </summary>
        None = 0,

        // 水平方向のレイアウト群
        /// <summary>
        /// 左側
        /// </summary>
        Left = 1,
        /// <summary>
        /// 右側
        /// </summary>
        Right = 2,
        /// <summary>
        /// 水平方向中央
        /// </summary>
        HorizontalCenter = 4,

        // 垂直方向のレイアウト群
        /// <summary>
        /// 上側
        /// </summary>
        Top = 8,
        /// <summary>
        /// 下側
        /// </summary>
        Bottom = 16,
        /// <summary>
        /// 垂直方向中央
        /// </summary>
        VerticalCenter = 32,

        /// <summary>
        /// 左上
        /// </summary>
        TopLeft = Top | Left,
        /// <summary>
        /// 右上
        /// </summary>
        TopRight = Top | Right,
        /// <summary>
        /// 上側、中央
        /// </summary>
        TopCenter = Top | HorizontalCenter,

        /// <summary>
        /// 左下
        /// </summary>
        BottomLeft = Bottom | Left,
        /// <summary>
        /// 右下
        /// </summary>
        BottomRight = Bottom | Right,
        /// <summary>
        /// 下側、中央
        /// </summary>
        BottomCenter = Bottom | HorizontalCenter,

        /// <summary>
        /// 中央、左側
        /// </summary>
        CenterLeft = VerticalCenter | Left,
        /// <summary>
        /// 中央、右側
        /// </summary>
        CenterRight = VerticalCenter | Right,
        /// <summary>
        /// 中央
        /// </summary>
        Center = VerticalCenter | HorizontalCenter
    }

    /// <summary>
    /// セーフエリアに対応したレイアウト構造体
    /// </summary>
    /// <remarks>
    /// Windows、Xbox 360の両プラットフォームで動作するゲームは様々な解像度、
    /// アスペクト比に対応する必要がある。加えてXbox 360で動作するゲームは
    /// タイトルセーフエリアにも対応する必要がある。
    /// 
    /// この構造体では、レイアウト対象領域(クライアントエリア)と、
    /// セーフエリア領域を保持しAligmentと水平垂直のマージン値から
    /// 指定した矩形を配置する。
    /// 配置後の矩形がセーフエリア外にある場合はセーフエリア内に再配置される。
    /// 
    /// マージンはクライアントエリアの割合で示す。
    /// 
    /// 使用例:
    /// 
    /// Place( region, 0.1f, 0.2f, Aligment.TopLeft );
    /// 
    /// クライアントエリアの左端から10%、上端から20%の部分にregionを配置する
    /// 
    /// 
    /// Place( region, 0.3f, 0.4f, Aligment.BottomRight );
    /// 
    /// クライアントエリアの右端から30%、下端から40%の部分にregionを配置する
    /// 
    /// 
    /// クライアントエリアとセーフエリアを別々に指定できるので、
    /// 画面分割時にも、セーフエリアにタイトルセーフエリアを指定し、
    /// クライアントエリアに分割した画面の領域を指定することで、レイアウトは
    /// 画面分割領域ベースで行いつつも、タイトルセーフエリア内に正しく配置することが
    /// できる。
    /// 
    /// 
    /// セーフエリアについては以下のURLを参照
    /// http://blogs.msdn.com/ito/archive/2008/11/21/safearea-sample.aspx
    ///     /// </remarks>
    public struct Layout
    {
        #region フィールド

        /// <summary>
        /// クライアントエリアの取得と設定
        /// </summary>
        public Rectangle ClientArea;

        /// <summary>
        /// セーフエリアの取得と設定
        /// </summary>
        public Rectangle SafeArea;

        #endregion

        #region 初期化

        /// <summary>
        /// クライアントエリアとセーフエリアを別々に指定して初期化する
        /// </summary>
        /// <param name="clientArea">クライアントエリア</param>
        /// <param name="safeArea">セーフエリア</param>
        public Layout( Rectangle clientArea, Rectangle safeArea )
        {
            ClientArea = clientArea;
            SafeArea = safeArea;
        }

        /// <summary>
        /// クライアントエリアのみを指定して初期化する
        /// セーフエリアはクライアントエリアと同じサイズになる
        /// </summary>
        /// <param name="clientArea">クライアントエリア</param>
        public Layout( Rectangle clientArea )
            : this( clientArea, clientArea )
        {
        }

        /// <summary>
        /// Viewportを指定して初期化する
        /// セーフエリアはViewport.TitleSafeAreaになる
        /// </summary>
        /// <param name="viewport">ビューポート</param>
        public Layout( Viewport viewport )
        {
            ClientArea = new Rectangle( (int)viewport.X, (int)viewport.Y,
                                        (int)viewport.Width, (int)viewport.Height );
            SafeArea = viewport.TitleSafeArea;
        }

        #endregion

        /// <summary>
        /// 指定したサイズ矩形のレイアウト
        /// </summary>
        /// <param name="size">配置する矩形サイズ</param>
        /// <param name="horizontalMargin">垂直方向のマージン</param>
        /// <param name="verticalMargine">水平方向のマージン</param>
        /// <param name="alignment">アライメント</param>
        /// <returns>配置された矩形</returns>
        public Vector2 Place( Vector2 size, float horizontalMargin,
                                            float verticalMargine, Alignment alignment )
        {
            Rectangle rc = new Rectangle( 0, 0, (int)size.X, (int)size.Y );
            rc = Place( rc, horizontalMargin, verticalMargine, alignment );
            return new Vector2( rc.X, rc.Y );
        }

        /// <summary>
        /// 指定した矩形のレイアウト
        /// </summary>
        /// <param name="region">配置する矩形</param>
        /// <param name="horizontalMargin">垂直方向のマージン</param>
        /// <param name="verticalMargine">水平方向のマージン</param>
        /// <param name="alignment">アライメント</param>
        /// <returns>配置された矩形</returns>
        public Rectangle Place( Rectangle region, float horizontalMargin,
                                            float verticalMargine, Alignment alignment )
        {
            // 水平方向のレイアウト
            if ( ( alignment & Alignment.Left ) != 0 )
            {
                region.X = ClientArea.X + (int)( ClientArea.Width * horizontalMargin );
            }
            else if ( ( alignment & Alignment.Right ) != 0 )
            {
                region.X = ClientArea.X +
                            (int)( ClientArea.Width * ( 1.0f - horizontalMargin ) ) -
                            region.Width;
            }
            else if ( ( alignment & Alignment.HorizontalCenter ) != 0 )
            {
                region.X = ClientArea.X + ( ClientArea.Width - region.Width ) / 2 +
                            (int)( horizontalMargin * ClientArea.Width );
            }
            else
            {
                // レイアウトなし
            }

            // 垂直方向のレイアウト
            if ( ( alignment & Alignment.Top ) != 0 )
            {
                region.Y = ClientArea.Y + (int)( ClientArea.Height * verticalMargine );
            }
            else if ( ( alignment & Alignment.Bottom ) != 0 )
            {
                region.Y = ClientArea.Y +
                            (int)( ClientArea.Height * ( 1.0f - verticalMargine ) ) -
                            region.Height;
            }
            else if ( ( alignment & Alignment.VerticalCenter ) != 0 )
            {
                region.Y = ClientArea.Y + ( ClientArea.Height - region.Height ) / 2 +
                            (int)( verticalMargine * ClientArea.Height );
            }
            else
            {
                // レイアウトなし
            }

            // レイアウトした領域をセーフエリア内にあるか確かめる
            if ( region.Left < SafeArea.Left )
                region.X = SafeArea.Left;

            if ( region.Right > SafeArea.Right )
                region.X = SafeArea.Right - region.Width;

            if ( region.Top < SafeArea.Top )
                region.Y = SafeArea.Top;

            if ( region.Bottom > SafeArea.Bottom )
                region.Y = SafeArea.Bottom - region.Height;

            return region;
        }

    }
}