using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace window
{
    public partial class FormString : Form
    {
        #region スタティック
        private int MARGIN = 20;//画像(縁あり)として描画した場合の画像回りの余白
        #endregion

        #region 変数・インスタンス
        private bool rightClicked;//右クリックされたかフラグ
        private Point mousePoint;//ドラッグで移動用
        #endregion

        #region コンストラクタ
        public FormString()
        {
            InitializeComponent();
            richTextBox1.LanguageOption = RichTextBoxLanguageOptions.UIFonts;
        }
        #endregion

        #region プロパティ
        public Point showPoint { get; set; } // 表示始点
        public Size showSize { get; set; }//表示範囲
        public string text { get; set; }//文字列
        public Font font { get; set; }//フォント
        public Color foreColor { get; set; }//フォント色
        public Color backColor { get; set; }//背景色
        public int magnifications { get; set; }//フォント倍率(49pt以上にしたい時用
        public float borderWidth1 { get; set; }//縁(内)の太さ
        public float borderWidth2 { get; set; }//縁(中)の太さ
        public float borderWidth3 { get; set; }//縁(外)の太さ
        public Color borderColor1 { get; set; }//縁(内)の色
        public Color borderColor2 { get; set; }//縁(中)の色
        public Color borderColor3 { get; set; }//縁(外)の色
        public bool enableBorder { get; set; }//縁
        public int type { get; set; }//ウィンドウ形式、リージョン形式、レイヤード形式、オーバーレイ形式
        public bool region { get; set; }//型
        public bool topMost { get; set; }//最前面(オーバーレイ以外)
        public float opacity { get; set; }//不透明度(レイヤード時)
        public bool transparencyKey { get; set; }//通過色
        public bool notClose { get; set; }
        public int timeLimit { get; set; }//消滅までの時間
        public int layout { get; set; }//表示エリアのどの位置に表示するか
        public int decoration { get; set; }//左寄せ、センタリング、右寄せ
        public int maxStringCount { get; set; }//表示文字数
        public string soundFile { get; set; }//表示時に鳴らす音声ファイル
        public int soundVolume { get; set; }//表示時に鳴らす音のボリューム
        #endregion

        #region プライベート

        private void DecorationTextReflect(int decoration)
        {
            switch (decoration)
            {
                case 1:
                    label1.TextAlign = ContentAlignment.TopCenter;
                    break;
                case 2:
                    label1.TextAlign = ContentAlignment.TopRight;
                    break;
                default:
                    break;
            }
        }

        private void TopMostReflect()
        {
            if (topMost)
            {
                //最前面は ShowWithoutActivation をオーバーライドして非アクティブで起動するようにする
                //上記のままでは最前面にならない(するとアクティブになってしまう)ので、次で TOPMOST にする
                Win32.User.SetWindowPos(this.Handle, Win32.User.HWND_TOPMOST, 0, 0, 0, 0,
                  (Win32.User.SWP_NOMOVE | Win32.User.SWP_NOSIZE | Win32.User.SWP_NOACTIVATE));
            }
        }

        private void LayoutReflect(Rectangle winRect, RectangleF rectfGraphicsPath)
        {
            Rectangle rectShow = ShowRectReflect();
            /// レイアウト
            switch (layout)
            {
                case 0://左上
                    this.Location = new Point(rectShow.Left - (int)rectfGraphicsPath.Left, rectShow.Top - (int)rectfGraphicsPath.Top);
                    break;
                case 1://上
                    rectShow.X = (rectShow.Left + (rectShow.Width / 2)) - (this.Size.Width / 2);
                    this.Location = new Point(rectShow.Left, rectShow.Top - (int)rectfGraphicsPath.Top);
                    break;
                case 2://右上
                    rectShow.X = (rectShow.Left + rectShow.Width) - this.Size.Width;
                    this.Location = new Point(rectShow.Left + (winRect.Width - (int)rectfGraphicsPath.Width - (int)rectfGraphicsPath.Left), rectShow.Top - (int)rectfGraphicsPath.Top);
                    break;
                case 3://左
                    rectShow.Y = (rectShow.Top + (rectShow.Height / 2)) - (this.Size.Height / 2);
                    this.Location = new Point(rectShow.Left - (int)rectfGraphicsPath.Left, rectShow.Top);
                    break;
                case 4://中央
                    rectShow.X = (rectShow.Left + (rectShow.Width / 2)) - (this.Size.Width / 2);
                    rectShow.Y = (rectShow.Top + (rectShow.Height / 2)) - (this.Size.Height / 2);
                    this.Location = new Point(rectShow.Left, rectShow.Top);
                    break;
                case 5://右
                    rectShow.X = (rectShow.Left + rectShow.Width) - this.Size.Width;
                    rectShow.Y = (rectShow.Top + (rectShow.Height / 2)) - (this.Size.Height / 2);
                    this.Location = new Point(rectShow.Left + (winRect.Width - (int)rectfGraphicsPath.Width - (int)rectfGraphicsPath.Left), rectShow.Top);
                    break;
                case 6://左下
                    rectShow.Y = (rectShow.Top + rectShow.Height) - this.Size.Height;
                    this.Location = new Point(rectShow.Left - (int)rectfGraphicsPath.Left, rectShow.Top + (winRect.Height - (int)rectfGraphicsPath.Height - (int)rectfGraphicsPath.Top));
                    break;
                case 7://下
                    rectShow.X = (rectShow.Left + (rectShow.Width / 2)) - (this.Size.Width / 2);
                    rectShow.Y = (rectShow.Top + rectShow.Height) - this.Size.Height;
                    this.Location = new Point(rectShow.Left, rectShow.Top + (winRect.Height - (int)rectfGraphicsPath.Height - (int)rectfGraphicsPath.Top));
                    break;
                default://右下
                    rectShow.X = (rectShow.Left + rectShow.Width) - this.Size.Width;
                    rectShow.Y = (rectShow.Top + rectShow.Height) - this.Size.Height;
                    this.Location = new Point(rectShow.Left + (winRect.Width - (int)rectfGraphicsPath.Width - (int)rectfGraphicsPath.Left), rectShow.Top + (winRect.Height - (int)rectfGraphicsPath.Height - (int)rectfGraphicsPath.Top));
                    break;
            }
        }

        private Rectangle ShowRectReflect()
        {
            return new Rectangle(showPoint, showSize);
        }

        private void TimerReflect()
        {
            //表示を消すまでの時限タイマー
            if (timeLimit != 0)
            {
                timer1.Interval = timeLimit;
                timer1.Enabled = true;
            }
        }

        private void LayeredReflect()
        {
            /// レイヤード化
            if (type == 2)
            {
                //不透明色と通過色を適用
                this.Opacity = opacity;
                if (region) this.TransparencyKey = backColor;
            }
        }

        private StringFormat DecorationBorderingReflect()
        {
            StringFormat sf = StringFormat.GenericDefault;
            switch (decoration)
            {
                case 1:
                    sf.Alignment = StringAlignment.Center;
                    break;
                case 2:
                    sf.Alignment = StringAlignment.Far;
                    break;
                default:
                    sf.Alignment = StringAlignment.Near;
                    break;
            }
            return sf;
        }

        private void FontReflect()
        {
            //フォントサイズの修正
            font = new Font(font.Name, font.Size * magnifications, font.Style, font.Unit, font.GdiCharSet, font.GdiVerticalFont);
        }

        private string MaxStringCountReflect()
        {
            //表示文字数の修正
            if (text.Length <= maxStringCount)
                return text;
            else
                return (text.Remove(maxStringCount) + "★切捨");
        }

        private void Recovery()
        {
            label1.Visible = false;
            rightClicked = false;
            timer1.Enabled = false;
            richTextBox1.Anchor = AnchorStyles.Left | AnchorStyles.Top;
            richTextBox1.Visible = false;
            richTextBox1.Size = new Size(0, 54);
            richTextBox1.Location = new Point(0, 0);
            label1.Size = new Size(0, 12);
            this.Region = null;
            this.FormBorderStyle = FormBorderStyle.None;
            Graphics g = Graphics.FromHwnd(this.Handle);
            g.Clear(Color.FromArgb(79, 80, 81));
            g.Dispose();
            g = null;
            this.BackgroundImage = null;
            this.Size = new Size(10, 10);

        }
        #endregion

        #region パブリック
        public void StringUpdate()
        {
            if (rightClicked) Recovery();
            timer1.Enabled = false;

            string fixtext = MaxStringCountReflect();
            FontReflect();

            Rectangle winRect = new Rectangle();
            GraphicsPath grpPathResult = new GraphicsPath();
            //縁取りか型抜きが有効ならグラフィック処理
            //どちらも無効ならラベルコントロールに文字列表示
            if (enableBorder || region)
            {
                Graphics g = Graphics.FromHwnd(IntPtr.Zero);
                g.SmoothingMode = SmoothingMode.None;
                g.InterpolationMode = InterpolationMode.Default;
                StringFormat stringFormat = DecorationBorderingReflect();
                SizeF fontMeasureSizeF = g.MeasureString(fixtext, font, 2048, stringFormat);
                RectangleF fontDrawRectF = new RectangleF(new PointF((float)(MARGIN / 2), (float)(MARGIN / 2)), fontMeasureSizeF);
                winRect = new Rectangle(0, 0, (int)fontMeasureSizeF.Width + MARGIN, (int)fontMeasureSizeF.Height + MARGIN);

                SolidBrush sbrushFore = new SolidBrush(foreColor);
                Color transparentDummy = Color.FromArgb(79, 80, 81);//GraphicsPath用通過色
                SolidBrush sbrushTransparent = new SolidBrush(transparentDummy);

                Bitmap bmp = new Bitmap((int)fontMeasureSizeF.Width + MARGIN, (int)fontMeasureSizeF.Height + MARGIN);
                g = Graphics.FromImage(bmp);
                g.SmoothingMode = SmoothingMode.None;
                g.InterpolationMode = InterpolationMode.Default;

                //描画
                g.FillRectangle(sbrushTransparent, winRect);
                g.DrawString(fixtext, font, sbrushFore, fontDrawRectF, stringFormat);
                GraphicsPath grpPathString = QuickCalculateGraphicsPath.Calculate(bmp, transparentDummy);
                //縁取りが有効なら
                if (enableBorder)
                {
                    SolidBrush sbrush1 = new SolidBrush(borderColor1);
                    SolidBrush sbrush2 = new SolidBrush(borderColor2);
                    SolidBrush sbrush3 = new SolidBrush(borderColor3);
                    Pen pen1 = new Pen(sbrush1, borderWidth1);
                    Pen pen2 = new Pen(sbrush2, borderWidth2);
                    Pen pen3 = new Pen(sbrush3, borderWidth3);
                    g.FillRectangle(sbrushTransparent, winRect);
                    if ((borderWidth3 != 0) && (borderWidth2 < borderWidth3) && (borderWidth1 < borderWidth3))
                        g.DrawPath(pen3, grpPathString);
                    if ((borderWidth2 != 0) && (borderWidth1 < borderWidth2))
                        g.DrawPath(pen2, grpPathString);
                    if (borderWidth1 != 0)
                        g.DrawPath(pen1, grpPathString);
                    g.DrawString(fixtext, font, sbrushFore, fontDrawRectF, stringFormat);
                    pen1.Dispose();
                    pen2.Dispose();
                    pen3.Dispose();
                }
                g.Dispose();

                //フォームに反映
                grpPathResult = QuickCalculateGraphicsPath.Calculate(bmp, transparentDummy);

                this.Location = new Point(9999, 9999);

                winRect = new Rectangle(0, 0, bmp.Width, bmp.Height);//CHECK この行いらんかも
                this.BackgroundImage = bmp;
                if (region)
                {
                    this.Region = new Region(grpPathResult);
                }
                else
                {
                    this.Region = new Region();
                }
                this.Width = bmp.Width;
                this.Height = bmp.Height;
                this.BackColor = backColor;
            }
            else
            {
                label1.Text = fixtext;
                DecorationTextReflect(decoration);

                label1.AutoSize = true;
                label1.Font = font;
                label1.ForeColor = foreColor;
                label1.Visible = true;
                this.Size = new Size(label1.Size.Width, label1.Size.Height);
                label1.BackColor = backColor;
            }

            TopMostReflect();//最前面
            LayoutReflect(winRect, grpPathResult.GetBounds());//レイアウト反映
            LayeredReflect();//レイヤード反映
            TimerReflect();//タイマー開始
        }
        #endregion

        #region オーバーライド
        protected override bool ShowWithoutActivation
        {
            get
            {
                return true;
            }
        }
        protected override void OnVisibleChanged(EventArgs e)
        {
            if (this.Visible == false)
                this.Location = new Point(9999, 9999);
            base.OnVisibleChanged(e);
        }
        #endregion

        #region イベント
        private void timer1_Tick(object sender, EventArgs e)
        {
            this.Visible = false;
        }

        private void FormString_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Visible = false;
        }

        private void FormString_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                mousePoint = new Point(-e.X, -e.Y);
            }

            if (e.Button == MouseButtons.Right)
            {
                // ここ考える
                //右クリックされたら枠付きのウインドウにする
                //すでに枠付き化されていたら非表示にする
                if (rightClicked == false)
                {
                    rightClicked = true;
                    if (timer1.Enabled) timer1.Enabled = false;

                    //リッチテキストボックス更新
                    richTextBox1.Text = text;
                    //幅（調べるだけ）
                    Graphics g = Graphics.FromHwnd(IntPtr.Zero);
                    SizeF textSizeF = g.MeasureString(text, richTextBox1.Font);
                    g.Dispose();
                    g = null;
                    //高さ
                    richTextBox1.Height = (richTextBox1.Font.Height * richTextBox1.Lines.Length) + 17;//17は下スクロールバーの高さ
                    //消去できるように選択選択
                    richTextBox1.SelectAll();
                    //可視化
                    richTextBox1.Visible = true;

                    //フォーム更新
                    int noneWidth = this.Width;//サイズ変更線を含まないウィンドウ幅
                    int noneHeight = this.Height;//サイズ変更線を含まないウィンドウ高さ
                    int thisLocationX = this.Location.X;//横位置のバックアップ
                    this.Location = new Point(9999, this.Location.Y);//画面外へ
                    if (this.Opacity != 1F) this.Opacity = 1F;//レイヤード解除
                    if (this.TransparencyKey != Color.Empty) this.TransparencyKey = Color.Empty;//レイヤード解除
                    if (this.Region != null) this.Region = null;//リージョン解除
                    //サイズ変更線の幅取得
                    this.Width = 200;
                    this.FormBorderStyle = FormBorderStyle.Sizable;
                    int border = this.Width - 200;
                    //位置
                    this.Location = new Point(thisLocationX - (border / 2), this.Location.Y - (border / 2));
                    //高さ
                    this.Height = noneHeight + border + richTextBox1.Height;
                    //幅
                    if (noneWidth < textSizeF.Width)//元の幅よりテキストの幅が大きければ
                        this.Width = (int)textSizeF.Width + border;
                    else
                        this.Width = noneWidth + border;

                    //位置
                    richTextBox1.Location = new Point(0, noneHeight);
                    //リッチテキストボックスの幅を更新
                    richTextBox1.Width = this.Width - border;
                    //アンカー
                    richTextBox1.Anchor =
                        System.Windows.Forms.AnchorStyles.Top |
                        System.Windows.Forms.AnchorStyles.Bottom |
                        System.Windows.Forms.AnchorStyles.Left |
                        System.Windows.Forms.AnchorStyles.Right;
                    //
                    richTextBox1.Focus();
                    //richTextBox1.ScrollBars = RichTextBoxScrollBars.None;
                    //richTextBox1.ScrollBars = RichTextBoxScrollBars.Vertical | RichTextBoxScrollBars.Horizontal;
                    richTextBox1.ScrollBars = RichTextBoxScrollBars.Both;
                    //フォーカス設定

                }
                else
                {
                    this.Visible = false;
                }
            }
        }

        private void FormString_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                this.SetDesktopLocation(
                    this.Left + mousePoint.X + e.X,
                    this.Top + mousePoint.Y + e.Y);
            }

        }

        private void FormString_VisibleChanged(object sender, EventArgs e)
        {
            if (this.Visible == false)
                Recovery();
        }
        #endregion
    }

}
