/// <summary>
/// 凡例表示画面
/// </summary>
/// <create>2010/01/26</create>
/// <modifier></modifier>
/// <modify></modify>
/// <modification></modification>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace lsor
{
    /// <summary><para>class outline:</para>
    /// <para>凡例表示画面出力制御クラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[ver 1.0.0][2010/02/02][新規作成]</para>
    /// </remarks>
    public partial class GraphNotes : Form
    {
        #region プライベート変数

        /// <summary>プロジェクト共通データ</summary>
        private CommonData _commonData;

        /// <summary>現在の河川名</summary>
        private string currentRiver;

        #endregion

        #region コンストラクタ

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>GraphNotes csGraphNotes = new GraphNotes(commonData)</para>
        /// </example>
        /// <param name="commonData">共通データ</param>
        /// <returns>凡例表示画面出力制御クラス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public GraphNotes(CommonData commonData)
        {
            _commonData = commonData;
            if (_commonData == null)
            {
                _commonData = new CommonData();
            }

            InitializeComponent();

            pboxLegend.Image = new Bitmap(1000, 1000);
        }

        #endregion

        #region パブリックメソッド

        /// <summary><para>method outline:</para>
        /// <para>共通データを設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetCommonData(commonData)</para>
        /// </example>
        /// <param name="commonData">共通データ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetCommonData(CommonData commonData)
        {
            _commonData = commonData;
        }

        #endregion

        #region プライベートメソッド

        #region 表示座標

        /// <summary><para>method outline:</para>
        /// <para>表示座標のラインの左端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iSx = sx()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>表示座標のラインの左端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int sx()
        {
            return (20);
        }

        /// <summary><para>method outline:</para>
        /// <para>表示座標のラインの右端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iEx = ex()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>表示座標のラインの右端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int ex()
        {
            return (50);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標の文字列の左端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iLx = lx()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>表示座標の文字列の左端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int lx()
        {
            return (60);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のシンボルの中心を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iCx = cx()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>表示座標のシンボルの中心</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int cx()
        {
            return ((sx() + ex()) / 2);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のシンボルの左端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iSsx = ssx()</para>
        /// </example>
        /// <param name="wid">幅</param>
        /// <returns>表示座標のシンボルの左端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int ssx(int wid)
        {
            return (cx() - wid / 2);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のシンボルの右端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iEsx = esx()</para>
        /// </example>
        /// <param name="wid">幅</param>
        /// <returns>表示座標のシンボルの右端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int esx(int wid)
        {
            return (cx() + wid / 2);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のラインのY座標=シンボルの中心を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iCy = cy()</para>
        /// </example>
        /// <param name="row">行</param>
        /// <returns>表示座標のラインのY座標=シンボルの中心</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int cy(int row)
        {
            return (20 * (row + 1));
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のシンボルの上端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iSsy = ssy()</para>
        /// </example>
        /// <param name="row">行番号</param>
        /// <param name="wid">幅</param>
        /// <returns>表示座標のシンボルの上端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int ssy(int row, int wid)
        {
            return (cy(row) - wid / 2);
        }
        /// <summary><para>method outline:</para>
        /// <para>表示座標のシンボルの下端を取得する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>int iEsy = esy()</para>
        /// </example>
        /// <param name="row">行</param>
        /// <param name="wid">幅</param>
        /// <returns>表示座標のシンボルの下端</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private int esy(int row, int wid)
        {
            return (cy(row) + wid / 2);
        }

        #endregion

        #region 凡例の描画

        /// <summary><para>method outline:</para>
        /// <para>凡例の描画をする</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = drawLegend(g, row, prop)</para>
        /// </example>
        /// <param name="g">グラフィックス</param>
        /// <param name="row">行</param>
        /// <param name="prop">描画設定</param>
        /// <returns>bool true:描画、false:スキップ</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private bool drawLegend(Graphics g, int row, GraphPropData prop)
        {
            // row=-1 の場合は全行描画(再帰呼び出し)
            if (row < 0)
            {
                // 画面のクリア
                g.Clear(Color.White);

                if (!Util.IsBlank(currentRiver))
                {
                    // 河川データの取得
                    RiverData rd = Util.GetRiverData(_commonData, currentRiver);

                    if (rd != null && rd.GraphPropList != null)
                    {
                        // データ系列一行ごとに凡例を描画
                        row = 0;
                        foreach (GraphPropData data in rd.GraphPropList)
                        {
                            // 凡例の描画
                            if (drawLegend(g, row, data) == true)
                            {
                                row++;
                            }
                        }
                    }
                }
                return (true);
            }

            if (prop == null || (!prop.LineDisp && !prop.SymbolDisp))
            {
                // 描画しなかった場合
                return (false);
            }

            // 線の描画
            if (prop.LineDisp)
            {
                Pen pen = new Pen(System.Drawing.Color.FromArgb(prop.LineColor));
                // 線種の設定
                switch (prop.LineType)
                {
                    case (int)Util.LINESTYLE.Solid:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; break;
                    case (int)Util.LINESTYLE.Dash:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; break;
                    case (int)Util.LINESTYLE.Dot:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; break;
                    case (int)Util.LINESTYLE.DashDot:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot; break;
                    case (int)Util.LINESTYLE.DashDotDot:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDotDot; break;
                    default:
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid; break;
                }
                // 太さの設定
                switch (prop.LineSize)
                {
                    case (int)Util.LINEWIDTH.Thin: pen.Width = 1; break;
                    case (int)Util.LINEWIDTH.Middle: pen.Width = 2; break;
                    case (int)Util.LINEWIDTH.Thick: pen.Width = 4; break;
                    default: pen.Width = 1; break;
                }
                // 線の描画
                g.DrawLine(pen, sx(), cy(row), ex(), cy(row));
                pen.Dispose();
            }

            // シンボルの描画
            if (prop.SymbolDisp)
            {
                Pen pen = new Pen(System.Drawing.Color.FromArgb(prop.SymbolColor));
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Solid;
                pen.Width = 1;

                SolidBrush brush = new SolidBrush(System.Drawing.Color.FromArgb(prop.SymbolColor));

                // シンボルサイズ
                int wid;
                switch (prop.SymbolSize)
                {
                    case (int)Util.SYMBOLSIZE.Small: wid = 6; break;
                    case (int)Util.SYMBOLSIZE.Medium: wid = 8; break;
                    case (int)Util.SYMBOLSIZE.Large: wid = 10; break;
                    default: wid = 6; break;
                }

                // シンボル形状に応じて描画
                switch (prop.SymbolType)
                {
                    case (int)Util.SYMBOLSTYLE.Cross:       // ＋
                        g.DrawLine(pen, cx(), ssy(row, wid), cx(), esy(row, wid));
                        g.DrawLine(pen, ssx(wid), cy(row), esx(wid), cy(row));
                        break;
                    case (int)Util.SYMBOLSTYLE.Cross2:      // ×
                        g.DrawLine(pen, ssx(wid), ssy(row, wid), esx(wid), esy(row, wid));
                        g.DrawLine(pen, esx(wid), ssy(row, wid), ssx(wid), esy(row, wid));
                        break;
                    case (int)Util.SYMBOLSTYLE.Circle:      // ○
                        g.DrawEllipse(pen, ssx(wid), ssy(row, wid), wid, wid);
                        break;
                    case (int)Util.SYMBOLSTYLE.CircleF:     // ●
                        g.FillEllipse(brush, ssx(wid), ssy(row, wid), wid, wid);
                        break;
                    case (int)Util.SYMBOLSTYLE.Triangle:    // △
                        Point[] p1 = {
                            new Point(cx(), ssy(row, wid)),
                            new Point(ssx(wid), esy(row, wid)),
                            new Point(esx(wid), esy(row, wid))
                                    };
                        g.DrawPolygon(pen, p1);
                        break;
                    case (int)Util.SYMBOLSTYLE.TriangleF:   // ▲
                        Point[] p2 = {
                            new Point(cx(), ssy(row, wid)),
                            new Point(ssx(wid), esy(row, wid)),
                            new Point(esx(wid), esy(row, wid))
                                    };
                        g.FillPolygon(brush, p2);
                        break;
                    case (int)Util.SYMBOLSTYLE.Triangle2:   // ▽
                        Point[] p3 = {
                            new Point(ssx(wid), ssy(row, wid)),
                            new Point(esx(wid), ssy(row, wid)),
                            new Point(cx(), esy(row, wid))
                                    };
                        g.DrawPolygon(pen, p3);
                        break;
                    case (int)Util.SYMBOLSTYLE.Triangle2F:  // ▼
                        Point[] p4 = {
                            new Point(ssx(wid), ssy(row, wid)),
                            new Point(esx(wid), ssy(row, wid)),
                            new Point(cx(), esy(row, wid))
                                    };
                        g.FillPolygon(brush, p4);
                        break;
                    case (int)Util.SYMBOLSTYLE.Square:      // □
                        g.DrawRectangle(pen, ssx(wid), ssy(row, wid), wid, wid);
                        break;
                    case (int)Util.SYMBOLSTYLE.SquareF:     // ■
                        g.FillRectangle(brush, ssx(wid), ssy(row, wid), wid, wid);
                        break;
                    case (int)Util.SYMBOLSTYLE.Square2:     // ◇
                        Point[] p5 = {
                            new Point(cx(), ssy(row, wid)),
                            new Point(esx(wid), cy(row)),
                            new Point(cx(), esy(row, wid)),
                            new Point(ssx(wid), cy(row))
                                    };
                        g.DrawPolygon(pen, p5);
                        break;
                    case (int)Util.SYMBOLSTYLE.Square2F:    // ◆
                        Point[] p6 = {
                            new Point(cx(), ssy(row, wid)),
                            new Point(esx(wid), cy(row)),
                            new Point(cx(), esy(row, wid)),
                            new Point(ssx(wid), cy(row))
                                    };
                        g.FillPolygon(brush, p6);
                        break;
                    default:        // ×
                        g.DrawLine(pen, ssx(wid), ssy(row, wid), esx(wid), esy(row, wid));
                        g.DrawLine(pen, esx(wid), ssy(row, wid), ssx(wid), esy(row, wid));
                        break;
                }
            }

            // 凡例名の描画
            string legend = prop.NotesNm;
            if (legend == null || legend.Length <= 0)
            {
                // 凡例用表示名が空の場合は項目名を使用
                legend = prop.ColumnNm;
            }
            if (legend != null && legend.Length > 0)
            {
                Brush brush = new SolidBrush(Color.Black);

                StringFormat sf = new StringFormat();
                sf.Alignment = StringAlignment.Near;
                sf.LineAlignment = StringAlignment.Center;

                // 凡例名の描画
                g.DrawString(legend, this.Font, brush, lx(), cy(row), sf);

                brush.Dispose();
                sf.Dispose();
            }

            // 凡例を描画した
            return (true);
        }

        #endregion

        #region 凡例の再描画

        /// <summary><para>method outline:</para>
        /// <para>凡例ウィンドウを再描画する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>UpdateLegend(river)</para>
        /// </example>
        /// <param name="river">河川名</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void UpdateLegend(string river)
        {
            // 河川名の保存
            currentRiver = river;

            Graphics g = Graphics.FromImage(pboxLegend.Image);
            // 凡例の描画
            drawLegend(g, -1, null);
            // PictureBoxを更新（再描画させる
            pboxLegend.Refresh();
            g.Dispose();
        }

        #endregion

        #endregion

        #region イベントメソッド

        #region フォームロード時

        /// <summary><para>method outline:</para>
        /// <para>フォームロード時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void GraphNotes_Load(object sender, EventArgs e)
        {
            // 凡例の描画
            UpdateLegend(currentRiver);
        }

        #endregion

        #region [ファイル]-[閉じる]選択時

        /// <summary><para>method outline:</para>
        /// <para>[ファイル]-[閉じる]選択時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void CloseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        #endregion

        #region クリップボード関連の定義

        private const int CF_ENHMETAFILE = 14;

        /// <summary>クリップボードを開く</summary>
        /// <param name="hWndNewOwner">ウィンドウのハンドル</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool OpenClipboard(IntPtr hWndNewOwner);
        /// <summary>クリップボードを閉じる</summary>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool CloseClipboard();
        /// <summary>データがクリップボードに格納されているか調べる</summary>
        /// <param name="wFormat">クリップボードのデータ形式</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern int IsClipboardFormatAvailable(int wFormat);
        /// <summary>クリップボードからデータを取得する</summary>
        /// <param name="wFormat">クリップボードのデータ形式</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern IntPtr GetClipboardData(int wFormat);
        /// <summary>拡張メタファイルの内容を指定されたファイルへコピーする</summary>
        /// <param name="hemfSrc">コピー元の拡張メタファイルのハンドル</param>
        /// <param name="hNULL">コピー先のファイル名へのポインタ</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("gdi32.dll")]
        private static extern IntPtr CopyEnhMetaFile(IntPtr hemfSrc, IntPtr hNULL);
        /// <summary>クリップボードを空にする</summary>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("user32.dll")]
        private static extern bool EmptyClipboard();
        /// <summary>クリップボードに指定されたデータ形式でデータを格納する</summary>
        /// <param name="uFormat">クリップボードのデータ形式</param>
        /// <param name="hMem">指定されたデータ形式のデータのハンドル</param>
        /// <returns>成功:データのハンドル、失敗:NULL</returns>
        [DllImport("user32.dll")]
        private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
        /// <summary>張メタファイルまたは拡張メタファイルのハンドルを削除する</summary>
        /// <param name="hemf">拡張メタファイルのハンドル</param>
        /// <returns>bool true:成功、false:失敗</returns>
        [DllImport("gdi32.dll")]
        private static extern bool DeleteEnhMetaFile(IntPtr hemf);

        #endregion

        #region [emf形式でコピー]時

        /// <summary><para>method outline:</para>
        /// <para>コンテキストメニューで[emf形式でコピー]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void CopyEmfFormatEToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Metafile mf = null;

            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    using (Graphics g = CreateGraphics())
                    {
                        IntPtr ipHdc = g.GetHdc();
                        mf = new Metafile(ms, ipHdc, EmfType.EmfPlusDual);
                        g.ReleaseHdc(ipHdc);
                    }

                    using (Graphics g2 = Graphics.FromImage(mf))
                    {
                        drawLegend(g2, -1, null);
                    }

                    IntPtr hEMF, hEMF2;
                    hEMF = mf.GetHenhmetafile();
                    if (!hEMF.Equals(new IntPtr(0)))
                    {
                        hEMF2 = CopyEnhMetaFile(hEMF, new IntPtr(0));
                        if (!hEMF2.Equals(new IntPtr(0)))
                        {
                            if (OpenClipboard(this.Handle))
                            {
                                if (EmptyClipboard())
                                {
                                    IntPtr hRes = SetClipboardData(CF_ENHMETAFILE, hEMF2);
                                    hRes.Equals(hEMF2);
                                }
                                CloseClipboard();
                            }
                        }
                    }
                    DeleteEnhMetaFile(hEMF);
                }
            }
            catch { }
            mf.Dispose();
        }

        #endregion

        #region [ファイル]-[emf形式で保存]時

        /// <summary><para>method outline:</para>
        /// <para>[ファイル]-[emf形式で保存]が選択された時の処理</para>
        /// </summary>
        /// <param name="sender">発生元オブジェクト</param>
        /// <param name="e">イベントの追加情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        private void SaveEmfFormatEToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            saveFileDialog1.Filter = Properties.HySAddinLsor2VieweEXEResources.FILE_DLG_FILTER_EMF_ALL;
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Metafile mf = null;

                try
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (Graphics g = CreateGraphics())
                        {
                            IntPtr ipHdc = g.GetHdc();
                            mf = new Metafile(ms, ipHdc, EmfType.EmfPlusDual);
                            g.ReleaseHdc(ipHdc);
                        }

                        using (Graphics g2 = Graphics.FromImage(mf))
                        {
                            drawLegend(g2, -1, null);
                        }

                        using (FileStream fsm = new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.Write))
                        {
                            fsm.Write(ms.GetBuffer(), 0, (int)ms.Length);
                            fsm.Close();
                        }
                    }
                    // メッセージ:ファイルを保存しました。
                    MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_INFO_FILE_SAVED,
                        Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE,
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                catch
                {
                    // メッセージ:ファイルが保存できませんでした。
                    MessageBox.Show(Properties.HySAddinLsor2VieweEXEResources.MSG_ERROR_FAILED_TO_SAVE_FILE,
                        Properties.HySAddinLsor2VieweEXEResources.CAPTION_SAVE_FILE,
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    if (mf != null)
                    {
                        mf.Dispose();
                    }
                }
            }
            saveFileDialog1.Dispose();
        }

        #endregion

        #endregion
    }
}
