using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;
using PostCardHitsuji.Models.Contents;
using Hitsuji.Framework.Models.ContentModels;

namespace PostCardHitsuji.Ui.Controls
{
    public class NewPaperLayer :  UserControl
    {
        public enum DrawTypes
        {
            /// <summary>
            /// イメージファイル出力タイプ
            /// ・文字列アイテム
            /// ・イラストアイテム
            /// </summary>
            SAVE_IMG,
            /// <summary>
            /// イラスト面作成タイプ
            /// ・文字列アイテム
            /// ・イラストアイテム
            /// ・レクタングル
            /// </summary>
            ILLUST_LAYOUT,
            /// <summary>
            /// 宛名面作成タイプ
            /// ・文字列アイテム
            /// ・イラストアイテム
            /// ・レクタングル
            /// ・宛先レイヤー
            /// </summary>
            RESEIVER_LAYOUT
        }

        public event MouseEventHandler OnSelectedItemChangedEvent;

        public DrawTypes DrawType { get; set; }

        private ILayoutItem selectedItem { get; set; }

        private bool isMouseDown
        {
            get;
            set;
        }

//        public Dictionary<string, IllustRectangle> illustItems { get; set; }
        public Dictionary<string, IllustRectangle> illustItems 
        {
            get { return illustItems_; }
            set { illustItems_ = value; }
        }
        private Dictionary<string, IllustRectangle> illustItems_ = new Dictionary<string,IllustRectangle>(); 
        public Dictionary<string, MsgRectangle> msgItems { get; set; }

        public Dictionary<string, IllustItemContentModel> IllustItemContentModels
        {
            get
            {
                Dictionary<string, IllustItemContentModel> list = new Dictionary<string, IllustItemContentModel>();
                foreach (KeyValuePair<string, IllustRectangle> kvp in illustItems)
                    list.Add(kvp.Key, kvp.Value.model as IllustItemContentModel);
                return list;
            }
        }

        public Dictionary<string, MsgItemContentModel> MsgItemContentModels
        {
            get
            {
                Dictionary<string, MsgItemContentModel> list = new Dictionary<string, MsgItemContentModel>();
                foreach (KeyValuePair<string, MsgRectangle> kvp in msgItems)
                    list.Add(kvp.Key, kvp.Value.model as MsgItemContentModel);
                return list;
            }
        }

        private Graphics graphics_;
        private Pen layerPen_;
        private Pen vhPen_;
        private Rectangle RectBaseOuter_;

        private Rectangle RectBasePre1_;
        private Rectangle RectBasePre2_;
        private Rectangle RectBasePre3_;
        private Rectangle RectBasePost1_;
        private Rectangle RectBasePost2_;
        private Rectangle RectBasePost3_;
        private Rectangle RectBasePost4_;

        private Rectangle RectBaseSenderPre1_;
        private Rectangle RectBaseSenderPre2_;
        private Rectangle RectBaseSenderPre3_;
        private Rectangle RectBaseSenderPost1_;
        private Rectangle RectBaseSenderPost2_;
        private Rectangle RectBaseSenderPost3_;
        private Rectangle RectBaseSenderPost4_;


        public NewPaperLayer()
        {
            InitializeComponent();

            this.Size = new System.Drawing.Size(Global.GlobalSettings.PaperVertical.PAPER_WIDTH,
                                                Global.GlobalSettings.PaperVertical.PAPER_HEIGHT);
            graphics_ = this.CreateGraphics();

            illustItems = new Dictionary<string, IllustRectangle>();
            msgItems = new Dictionary<string, MsgRectangle>();

            //this.BackColor = Color.WhiteSmoke;
            
            layerPen_ = new Pen(Brushes.Orange, 2);
            vhPen_ = new Pen(new SolidBrush(Color.FromArgb(64, Color.LightGray)));

            illustItems = new Dictionary<string, IllustRectangle>();
            msgItems = new Dictionary<string, MsgRectangle>();

            RectBaseOuter_ = new Rectangle();
            
            RectBasePre1_ = new Rectangle();
            RectBasePre2_ = new Rectangle();
            RectBasePre3_ = new Rectangle();
            RectBasePost1_ = new Rectangle();
            RectBasePost2_ = new Rectangle();
            RectBasePost3_ = new Rectangle();
            RectBasePost4_ = new Rectangle();

            RectBaseSenderPre1_ = new Rectangle();
            RectBaseSenderPre2_ = new Rectangle();
            RectBaseSenderPre3_ = new Rectangle();
            RectBaseSenderPost1_ = new Rectangle();
            RectBaseSenderPost2_ = new Rectangle();
            RectBaseSenderPost3_ = new Rectangle();
            RectBaseSenderPost4_ = new Rectangle();

            adjustLayer();


            Resize += new EventHandler(onResized);
            Paint += new PaintEventHandler(paint);
            MouseDown += new MouseEventHandler(onMouseDownMethod);
            MouseUp += new MouseEventHandler(onMouseUpMethod);
            MouseMove += new MouseEventHandler(onMouseMoveMethod);

        }

        public void clearMsgItemsAbsolutory()
        {
            this.msgItems.Clear();
            this.MsgItemContentModels.Clear();
        }

        private void onResized(object sender, EventArgs ev)
        {
            adjustLayer();
        }

        private void adjustLayer()
        {
            //ベース
            RectBaseOuter_.Location = new Point(1, 1);
            RectBaseOuter_.Width = Width - 2;
            RectBaseOuter_.Height = Height - 2;
            
            //〒番号（前）
            RectBasePre1_.Location = new Point(170, 48);
            RectBasePre1_.Width = 23;
            RectBasePre1_.Height = 32;
            RectBasePre2_.Location = new Point(198, 48);
            RectBasePre2_.Width = 23;
            RectBasePre2_.Height = 32;
            RectBasePre3_.Location = new Point(226, 48);
            RectBasePre3_.Width = 23;
            RectBasePre3_.Height = 32;
            //〒番号（後）
            RectBasePost1_.Location = new Point(255, 50);
            RectBasePost1_.Width = 23;
            RectBasePost1_.Height = 30;
            RectBasePost2_.Location = new Point(282, 50);
            RectBasePost2_.Width = 23;
            RectBasePost2_.Height = 30;
            RectBasePost3_.Location = new Point(309, 50);
            RectBasePost3_.Width = 23;
            RectBasePost3_.Height = 30;
            RectBasePost4_.Location = new Point(336, 50);
            RectBasePost4_.Width = 23;
            RectBasePost4_.Height = 30;

            //送付者〒番号（前）
            RectBaseSenderPre1_.Location = new Point(27, 478);
            RectBaseSenderPre1_.Width = 16;
            RectBaseSenderPre1_.Height = 26;
            RectBaseSenderPre2_.Location = new Point(43, 478);
            RectBaseSenderPre2_.Width = 16;
            RectBaseSenderPre2_.Height = 26;
            RectBaseSenderPre3_.Location = new Point(59, 478);
            RectBaseSenderPre3_.Width = 16;
            RectBaseSenderPre3_.Height = 26;
            //送付者〒番号（後）
            RectBaseSenderPost1_.Location = new Point(78, 478);
            RectBaseSenderPost1_.Width = 16;
            RectBaseSenderPost1_.Height = 26;
            RectBaseSenderPost2_.Location = new Point(94, 478);
            RectBaseSenderPost2_.Width = 16;
            RectBaseSenderPost2_.Height = 26;
            RectBaseSenderPost3_.Location = new Point(110, 478);
            RectBaseSenderPost3_.Width = 16;
            RectBaseSenderPost3_.Height = 26;
            RectBaseSenderPost4_.Location = new Point(126, 478);
            RectBaseSenderPost4_.Width = 16;
            RectBaseSenderPost4_.Height = 26;

            //graphics_ = this.CreateGraphics();
            drawLayout();
        }

        private void paint(object sender, PaintEventArgs ev)
        {
            drawLayout();
        }

        public void addMsgItem(string itemKey, MsgItemContentModel item, Color rectColor)
        {
            if (!msgItems.ContainsKey(itemKey))
            {
                var rect = new MsgRectangle();
                rect.SolidBrush_.Color = rectColor;
                rect.model = item;
                rect.RectWidth = item.width;
                rect.RectHeight = item.height;
                msgItems.Add(itemKey, rect);
                rect.move(item.x, item.y);
            }
        }

        public void removeMsgItem(string itemKey)
        {
            if (msgItems.ContainsKey(itemKey))
            {
                var rect = msgItems[itemKey];
                msgItems.Remove(itemKey);
                rect.model = null;
                rect = null;
            }
        }

        public void addIllustItem(string itemKey, IllustItemContentModel item)
        {
            if (!illustItems.ContainsKey(itemKey))
            {
                var rect = new IllustRectangle();
                rect.model = item;
                rect.RectWidth = item.width;
                rect.RectHeight = item.height;
                illustItems.Add(itemKey, rect);
                rect.move(item.x, item.y);
            }
        }

        public void removeIllustItem(string itemKey)
        {
            if (illustItems.ContainsKey(itemKey))
            {
                var rect = illustItems[itemKey];
                illustItems.Remove(itemKey);
                rect.model = null;
                rect = null;
            }
        }

        public void forceRefreshLayoutMethod()
        {
            refreshLayout();
        }

        public void forceCreateGraphics()
        {
            graphics_ = this.CreateGraphics();
        }

        private void refreshLayout()
        {
            Refresh();
            drawLayout();
        }

        private void drawLayoutWrapMethod(object sender, PaintEventArgs ev)
        {
            drawLayout();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="pe"></param>
        private void drawLayout()
        {
            //イラスト, ラベルアイテム描画
            drawIllustLabels(graphics_);
            drawMsgLabels(graphics_);
            
            //縦線・横線
            drawVH(graphics_);

            //ベース関連のレイヤー描画
            drawLayer(graphics_);

        }

        private void drawIllustLabels(Graphics graphics)
        {
            graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            foreach (KeyValuePair<string, IllustRectangle> kvp in illustItems)
            {
                var rect = kvp.Value;
                if (DrawType == DrawTypes.ILLUST_LAYOUT || 
                    DrawType == DrawTypes.RESEIVER_LAYOUT)
                    rect.drawWithinRectangle(graphics);
                else
                    rect.draw(graphics);
            }
        }

        private void drawMsgLabels(Graphics graphics)
        {
            graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            foreach (KeyValuePair<string, MsgRectangle> kvp in msgItems)
            {
                var rect = kvp.Value;
                if (DrawType == DrawTypes.ILLUST_LAYOUT ||
                    DrawType == DrawTypes.RESEIVER_LAYOUT)
                    rect.drawWithinRectangle(graphics);
                else
                    rect.draw(graphics);
            }
        }

        /// <summary>
        /// ベースレイヤー
        /// </summary>
        /// <param name="graphics"></param>
        private void drawLayer(Graphics graphics)
        {
            if (DrawType == DrawTypes.RESEIVER_LAYOUT)
            {
                graphics.DrawRectangle(layerPen_, RectBasePre1_);
                graphics.DrawRectangle(layerPen_, RectBasePre2_);
                graphics.DrawRectangle(layerPen_, RectBasePre3_);
                graphics.DrawRectangle(layerPen_, RectBasePost1_);
                graphics.DrawRectangle(layerPen_, RectBasePost2_);
                graphics.DrawRectangle(layerPen_, RectBasePost3_);
                graphics.DrawRectangle(layerPen_, RectBasePost4_);

                graphics.DrawRectangle(layerPen_, RectBaseSenderPre1_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPre2_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPre3_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPost1_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPost2_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPost3_);
                graphics.DrawRectangle(layerPen_, RectBaseSenderPost4_);

                //切手
                drawKitte(graphics);

                //最外枠
                graphics.DrawRectangle(layerPen_, RectBaseOuter_);
            }
        }

        private void drawVH(Graphics graphics)
        {
            //Vertical line
            for (int index = 0; index < Width; index += 10)
                graphics_.DrawLine(vhPen_, index, 0, index, Height);
            //Horizonal line
            for (int index = 0; index < Height; index += 15)
                graphics_.DrawLine(vhPen_, 0, index, Width, index);

        }

        private void drawKitte(Graphics graphics)
        {
            graphics.FillRectangle(Brushes.Orange, 20, 20, 80, 100);
        }

        private void fixLocation(ref int x, ref int y)
        {
            x = x % 5 != 0 ? x - (x % 5) : x;
            y = y % 10 != 0 ? y - (y % 10) : y;
        }

        private void showLocationToolTip(ILayoutItem item, int x, int y)
        {
            if (item.IsHitting(x, y))
                    tooltip.Show("位置 X:" + item.X.ToString() +
                                    ", Y:" + item.Y.ToString(),
                                  this, x, y);
        }

        protected void onMouseDownMethod(object sender, MouseEventArgs ev)
        {
            isMouseDown = true;
            ILayoutItem selection = null;
            foreach (KeyValuePair<string, MsgRectangle> kvp in msgItems)
            {
                //最前面のメッセージアイテムを取得
                var rect = kvp.Value;
                if (rect.IsHitting(ev.X, ev.Y))
                    selection = rect;
            }
            selectedItem = selection;
            //メッセージアイテムが選択されていたら、選択アイテムを移動可能状態に設定して処理を抜ける
            if (selectedItem != null)
            {
                selectedItem.IsMoveable = true;
                if (selectedItem.IsMoveable)
                {
                    selectedItem.MouseLocationX = ev.X;
                    selectedItem.MouseLocationY = ev.Y;
                    if (OnSelectedItemChangedEvent != null)
                        OnSelectedItemChangedEvent(selectedItem, ev);
                    showLocationToolTip(selectedItem, ev.X, ev.Y);
                }
            }
            else
            {
                foreach (KeyValuePair<string, IllustRectangle> kvp in illustItems)
                {
                    var rect = kvp.Value;
                    if (rect.IsHitting(ev.X, ev.Y))
                        selection = rect;
                }
                selectedItem = selection;
                if (selectedItem != null)
                {
                    selectedItem.IsMoveable = selectedItem.IsHitting(ev.X, ev.Y);
                    if (selectedItem.IsMoveable)
                    {
                        selectedItem.MouseLocationX = ev.X;
                        selectedItem.MouseLocationY = ev.Y;
                        showLocationToolTip(selectedItem, ev.X, ev.Y);
                    }
                }
            }
        }

        protected void onMouseUpMethod(object sender, MouseEventArgs ev)
        {   
            isMouseDown = false;
            tooltip.Hide(this);
            foreach (var msgItem in msgItems) msgItem.Value.IsMoveable = false;
            foreach (var illItem in illustItems) illItem.Value.IsMoveable = false;
            if (selectedItem != null) Refresh();
            selectedItem = null;
        }

        private ToolTip tooltip = new ToolTip();
        private void onMouseMoveMethod(object sender, MouseEventArgs ev)
        {
            if (!isMouseDown || selectedItem == null) return;
            int newX = ev.X, newY = ev.Y;
            showLocationToolTip(selectedItem, ev.X, ev.Y);
            selectedItem.move(newX, newY);
        }

        public Image saveImage(bool isVisibleBack)
        {
            Image bmp = new Bitmap(this.Width, this.Height);
            using(var grp = Graphics.FromImage(bmp))
            {
                var brush = new SolidBrush(isVisibleBack ? Color.White : Color.FromArgb(1, Color.White));
                grp.FillRectangle(brush, -1, -1, this.Width + 2, this.Height + 2);

                grp.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                grp.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                //イラスト, ラベルアイテム描画
                drawIllustLabels(grp);
                drawMsgLabels(grp);

                drawLayer(grp);
            }
            return new Bitmap(bmp);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // NewPaperLayer
            // 
            this.Name = "NewPaperLayer";
            this.Size = new System.Drawing.Size(394, 583);
            this.illustItems_ = new Dictionary<string, IllustRectangle>();
            this.ResumeLayout(false);

        }

    }


    public abstract class ILayoutItem
    {
        public IContentModel model;
        public Rectangle Rect;
        public SolidBrush SolidBrush_;
        public Pen Pen_;
        public string Name { get; set; }
        public bool IsMoveable { get; set; }

        public int MouseLocationX
        {
            get;
            set;
        }
        public int MouseLocationY
        {
            get;
            set;
        }

        public int X
        {
            get { return Rect.Location.X; }
            protected set
            { 
                Rect.X = value;
            }

        }
        public int Y
        {
            get { return Rect.Location.Y; }
            protected set
            {
                Rect.Y = value; 
            }
        }

        public int RectWidth
        {
            get { return Rect.Width; }
            set { Rect.Width = value; }
        }
        public int RectHeight
        {
            get { return Rect.Height; }
            set { Rect.Height = value; }
        }

        public virtual bool IsHitting(int x, int y)
        {
            return false;
            //return Rect.Contains(x, y);
        }

        public void move(int xMouseLocation, int yMouseLocation)
        {
            moveLocation(xMouseLocation - MouseLocationX, yMouseLocation - MouseLocationY);
            updateLayoutModelLocation();
        }

        private void moveLocation(int xLength, int yLength)
        {
            X += xLength;
            Y += yLength;
            updateMouseLocation(xLength, yLength);
        }

        private void updateMouseLocation(int xLength, int yLength)
        {
            MouseLocationX += xLength;
            MouseLocationY += yLength;
        }

        protected abstract void updateLayoutModelLocation();
        public abstract void drawWithinRectangle(Graphics g);
        public abstract void draw(Graphics g);
    }

    public class MsgRectangle : ILayoutItem
    {
        private SolidBrush fontBrush = new SolidBrush(Color.Black);

        public MsgRectangle()
        {
            Rect = new Rectangle();
            Pen_ = new Pen(Brushes.LightGreen);
            SolidBrush_ = new SolidBrush(Color.LightGreen);
            IsMoveable = false;

            MouseLocationX = MouseLocationY= 0;
            X = Y = 0;
            Rect.Width = 15;
            Rect.Height = 20;
        }

        public override bool IsHitting(int x, int y)
        {
            return Rect.Contains(x, y) && (model as MsgItemContentModel).Enable.ToUpper().Equals(true.ToString().ToUpper());
        }

        protected override void updateLayoutModelLocation()
        {
            (model as MsgItemContentModel).x = X;
            (model as MsgItemContentModel).y = Y;
        }

        public override void drawWithinRectangle(Graphics g)
        {
            var model_ = model as MsgItemContentModel;
            if (model_.Enable.ToUpper().Equals("FALSE")) return;

            if (!string.IsNullOrEmpty(model_.message))
            {
                Rect.X = model_.x;
                Rect.Y = model_.y;
                g.FillRectangle(SolidBrush_, Rect);
                
                fontBrush.Color = model_.FontColor;
                if (model_.isMsgDirectVertical)
                    g.DrawString(model_.messageMirror, model_.font, fontBrush, model_.x, model_.y, model_.msgFormat);
                else
                    g.DrawString(model_.message, model_.font, fontBrush, model_.x, model_.y, model_.msgFormat);
            }
        }

        public override void draw(Graphics g)
        {
            var model_ = model as MsgItemContentModel;
            if (model_.Enable.ToUpper().Equals("FALSE")) return;

            if (!string.IsNullOrEmpty(model_.message))
            {
                //Rect.X = model_.x;
                //Rect.Y = model_.y;
                fontBrush.Color = model_.FontColor;
                if (model_.isMsgDirectVertical)
                    g.DrawString(model_.messageMirror, model_.font, fontBrush, model_.x, model_.y, model_.msgFormat);
                else
                    g.DrawString(model_.message, model_.font, fontBrush, model_.x, model_.y, model_.msgFormat);
            }
        }
    }

    public class IllustRectangle : ILayoutItem
    {
        public IllustRectangle()
        {
            Rect = new Rectangle();
            IsMoveable = false;

            MouseLocationX = MouseLocationY= 0;
            X = Y = 0;
            Rect.Width = 10;
            Rect.Height = 50;
        }

        public override bool IsHitting(int x, int y)
        {
            return Rect.Contains(x, y) && (model as IllustItemContentModel).Enable.ToUpper().Equals(true.ToString().ToUpper());
        }

        protected override void updateLayoutModelLocation()
        {
            (model as IllustItemContentModel).x = X;
            (model as IllustItemContentModel).y = Y;
        }

        public override void drawWithinRectangle(Graphics g)
        {
            var model_ = model as IllustItemContentModel;
            if (model_.Enable.ToUpper().Equals("FALSE")) return;
            
            Rect.X = model_.x;
            Rect.Y = model_.y;
            Rect.Width = model_.illust == null ? 100 : model_.illust.Width;
            Rect.Height = model_.illust == null ? 100 : model_.illust.Height;
            if (model_.illust != null)
                g.DrawImage(model_.illust, model_.x, model_.y);
            g.DrawRectangle(new Pen(Brushes.Gray, 2), Rect);
        }

        public override void draw(Graphics g)
        {
            var model_ = model as IllustItemContentModel;
            if (model_.Enable.ToUpper().Equals("FALSE")) return;
            
            //Rect.X = model_.x;
            //Rect.Y = model_.y;
            //Rect.Width = model_.illust == null ? 100 :  model_.illust.Width;
            //Rect.Height = model_.illust == null ? 100 : model_.illust.Height;
            if (model_.illust != null)
                g.DrawImage(model_.illust, model_.x, model_.y);
        }
    }

}
