// Copyright (C) 2008, 2010 panacoran <panacoran@users.sourceforge.jp>
// 
// This program is part of Protra.
//
// Protra is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
// 
// $Id: ChartPanel.cs 343 2010-04-11 07:30:17Z panacoran $

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Protra.Lib;
using Protra.Lib.Data;

namespace Protra.Controls
{
    /// <summary>
    /// 複数のChartBoxを管理するクラス。
    /// </summary>
    class ChartPanel : UserControl
    {
        private int chartNum;
        private ChartBox[] chartBoxes;
        private int chartMode;
        private Color foreColor, backColor;
        private string code;
        private List<Price>[] priceLists = new List<Price>[2];
        private bool drawLastWeek;
        private HScrollBar hScrollBar;
        private int prevHeight;
        private ChartBox activeChartBox;

        /// <summary>
        /// ChartBoxの数を取得または設定する。
        /// </summary>
        [DefaultValue(0)]
        public int ChartNum
        {
            get
            {
                return chartNum;
            }
            set
            {
                SuspendLayout();
                if (chartNum > value)
                {
                    for (int i = 0; i < (chartNum - value) * 2; i++)
                        Controls.RemoveAt(0);
                    chartBoxes[value - 1].Dock = DockStyle.Fill;
                }
                else if (value > chartNum)
                {
                    ChartBox[] newChartBoxes = new ChartBox[value];
                    if (chartBoxes != null)
                        chartBoxes.CopyTo(newChartBoxes, 0);
                    chartBoxes = newChartBoxes;
                    if (chartNum > 0)
                       chartBoxes[chartNum - 1].Dock = DockStyle.Top;
                    for (int i = chartNum; i < value; i++)
                    {
                        Splitter splitter = new Splitter();
                        splitter.Dock = DockStyle.Top;
                        splitter.BorderStyle = BorderStyle.Fixed3D;
                        Controls.Add(splitter);
                        Controls.SetChildIndex(splitter, 0);
                        ChartBox chartBox = new ChartBox();
                        chartBox.ForeColor = foreColor;
                        chartBox.BackColor = backColor;
                        chartBox.Dock = (i == value - 1) ? DockStyle.Fill : DockStyle.Top;
                        chartBox.MouseDown += new MouseEventHandler(chartBox_MouseDown);
                        chartBox.MouseMove += new MouseEventHandler(chartBox_MouseMove);
                        Controls.Add(chartBox);
                        Controls.SetChildIndex(chartBox, 0);
                        chartBoxes[i] = chartBox;
                        chartBox.ChartMode = chartMode;
                        chartBox.SetPrices(0, priceLists[0]);
                        chartBox.SetPrices(1, priceLists[1]);
                    }
                }
                if (chartNum != value)
                    foreach (ChartBox box in chartBoxes)
                        box.Height = Size.Height / value;
                chartNum = value;
                ResumeLayout();
            }
        }

        /// <summary>
        /// MainFormのHScrollBarを設定する。
        /// </summary>
        public HScrollBar HScrollBar
        {
            set
            {
                hScrollBar = value;
                value.Scroll += new ScrollEventHandler(hScrollBar_Scroll);
            }
        }

        /// <summary>
        /// ChartBoxの前景色を設定する。
        /// </summary>
        public Color ChartForeColor
        {
            set
            {
                foreColor = value;
                if (chartBoxes == null)
                    return;
                foreach (ChartBox box in chartBoxes)
                    box.ForeColor = foreColor;
            }
            get { return foreColor; }
        }

        /// <summary>
        /// ChartBoxの背景色を設定する。
        /// </summary>
        public Color ChartBackColor
        {
            set
            {
                backColor = value;
                if (chartBoxes == null)
                    return;
                foreach (ChartBox box in chartBoxes)
                    box.BackColor = backColor;
            }
            get { return backColor; }
        }

        /// <summary>
        /// ChartBoxの表示モードを取得または設定する。
        /// </summary>
        [DefaultValue(0)]
        public int ChartMode
        {
            get
            {
                return chartMode;
            }
            set
            {
                chartMode = value;
                if (code != null)
                {
                    if (priceLists[chartMode] == null)
                    {
                        priceLists[chartMode] = (chartMode == 0) ? PriceData.Prices(code)
                            : PriceData.WeeklyPrices(code, drawLastWeek);
                        if (chartBoxes == null)
                            return;
                        foreach (ChartBox box in chartBoxes)
                            box.SetPrices(chartMode, priceLists[chartMode]);
                    }
                }
                if (chartBoxes == null)
                    return;
                foreach (ChartBox box in chartBoxes)
                    box.ChartMode = value;
                if (!chartBoxes[0].NeedScrollBar)
                    hScrollBar.Enabled = false;
                else
                {
                    hScrollBar.Enabled = true;
                    hScrollBar.Maximum = priceLists[chartMode].Count - 1;
                    hScrollBar.LargeChange = chartBoxes[0].Count;
                    hScrollBar.Value = chartBoxes[0].RightIndex - chartBoxes[0].Count; 
                }
            }
        }

        /// <summary>
        /// ChartBoxで表示する銘柄を取得または設定する。
        /// </summary>
        [DefaultValue(null)]
        public string SelectedCode
        {
            get
            {
                return code;
            }
            set
            {
                code = value;
                UpdatePrices();
            }
         
        }

        /// <summary>
        /// 価格情報を表示するデリゲート
        /// </summary>
        public Action<Price> SetPriceInfo { get; set; }

        /// <summary>
        /// 価格リストを更新する。
        /// </summary>
        public void UpdatePrices()
        {
            priceLists[0] = null;
            priceLists[1] = null;

            if (code != null)
                priceLists[chartMode] = (chartMode == 0) ? PriceData.Prices(code)
                    : PriceData.WeeklyPrices(code, drawLastWeek);
            if (chartBoxes == null)
                return;
            foreach (ChartBox box in chartBoxes)
                box.SetPrices(chartMode, priceLists[chartMode]);
            if (!chartBoxes[0].NeedScrollBar)
                hScrollBar.Enabled = false;
            else
            {
                hScrollBar.Enabled = true;
                hScrollBar.Maximum = Prices.Count - 1;
                hScrollBar.Value = Prices.Count - chartBoxes[0].Count;
                hScrollBar.LargeChange = chartBoxes[0].Count;
            }
            if (Prices == null || Prices.Count == 0)
                return;
            SetPriceInfo(Prices[Prices.Count - 1]);
        }

        /// <summary>
        /// 現在の表示モードの価格リストを取得する。
        /// </summary>
        public List<Price> Prices
        {
            get
            {
                return priceLists[chartMode];
            }
        }

        /// <summary>
        /// 終わっていない週の週足を描画するかを取得あるいは設定する。
        /// </summary>
        [DefaultValue(false)]
        public bool DrawLastWeek
        {
            get
            {
                return drawLastWeek;
            }
            set
            {
                if (drawLastWeek == value)
                    return;
                drawLastWeek = value;
                UpdatePrices();
            }
        }

        /// <summary>
        /// 日足と週足で異なるチャートを使用するかを設定する。
        /// </summary>
        public bool UseDifferentChart
        {
            set
            {
                foreach (ChartBox box in chartBoxes)
                    box.UseDifferentChart = value;
            }
        }

        /// <summary>
        /// ChartBoxの配列を取得する。
        /// </summary>
        public ChartBox[] ChartBoxes
        {
            get
            {
                return chartBoxes;
            }
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (chartBoxes == null)
            {
                prevHeight = Size.Height;
                return;
            }
            if (prevHeight == 0)
                return;
            double r = (double)Size.Height / prevHeight;
            foreach (ChartBox box in chartBoxes)
                box.Height = (int)(box.Height * r);
            prevHeight = Size.Height;
 
            if (hScrollBar == null)
                return;
            int count = chartBoxes[0].Count;
            if (count > 0)
            {
                if (!chartBoxes[0].NeedScrollBar)
                    hScrollBar.Enabled = false;
                else
                {
                    hScrollBar.Enabled = true;
                    hScrollBar.LargeChange = count;
                    hScrollBar.Value = Prices.Count - count;
                }
            }
        }

        private void hScrollBar_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e)
        {
            if (e.Type == ScrollEventType.EndScroll)
            {
                int index = e.NewValue + hScrollBar.LargeChange - 1;
                if (index != chartBoxes[0].RightIndex)
                    foreach (ChartBox chartBox in chartBoxes)
                        chartBox.RightIndex = index;
            }
        }

        /// <summary>
        /// ChartBox用のコンテキストメニューを生成します。
        /// </summary>
        /// <returns>ChartBox用のコンテキストメニューです。</returns>
        private ContextMenuStrip CreateContextMenuChartBox()
        {
            ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
            string dir = Global.DirChart;
            if (Directory.Exists(dir))
            {
                string[] dirlist = Directory.GetDirectories(dir);
                foreach (string s in dirlist)
                {
                    ToolStripMenuItem menuItem = CreateContextMenuItemChartBox(s);
                    contextMenuStrip.Items.Add(menuItem);
                }
                string[] filelist = Directory.GetFiles(dir, "*.pt");
                foreach (string s in filelist)
                {
                    ToolStripMenuItem menuItem = new ToolStripMenuItem();
                    menuItem.Text = Path.GetFileNameWithoutExtension(s).Replace("&", "&&");
                    menuItem.Tag = s;
                    menuItem.Click += new EventHandler(this.menuItemChartFile_Click);
                    contextMenuStrip.Items.Add(menuItem);
                }
            }
            return contextMenuStrip;
        }

        /// <summary>
        /// ChartBox用のコンテキストメニューのMenuItemを生成します。
        /// </summary>
        /// <returns>ChartBox用のコンテキストメニューのMenuItemです。</returns>
        private ToolStripMenuItem CreateContextMenuItemChartBox(string dir)
        {
            ToolStripMenuItem menuItem = new ToolStripMenuItem();
            menuItem.Text = Path.GetFileName(dir).Replace("&", "&&");
            ToolStripDropDownMenu dropDown = new ToolStripDropDownMenu();
            menuItem.DropDown = dropDown;
            if (Directory.Exists(dir))
            {
                string[] dirlist = Directory.GetDirectories(dir);
                foreach (string s in dirlist)
                {
                    ToolStripMenuItem item = CreateContextMenuItemChartBox(s);
                    dropDown.Items.Add(item);
                }
                string[] filelist = Directory.GetFiles(dir, "*.pt");
                foreach (string s in filelist)
                {
                    ToolStripMenuItem item = new ToolStripMenuItem();
                    item.Text = Path.GetFileNameWithoutExtension(s).Replace("&", "&&");
                    item.Tag = s;
                    item.Click += new EventHandler(this.menuItemChartFile_Click);
                    dropDown.Items.Add(item);
                }
            }
            return menuItem;
        }

        private void chartBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            activeChartBox = (ChartBox)sender;
            if (e.Button == MouseButtons.Right)
            {
                ContextMenuStrip contextMenu = CreateContextMenuChartBox();
                contextMenu.Show((Control)sender, new Point(e.X, e.Y));
            }
        }

        private void menuItemChartFile_Click(object sender, System.EventArgs e)
        {
            string file = (string)(((ToolStripMenuItem)sender).Tag);
            activeChartBox.ProgramFile = file;
        }

        int prevIndex = -1;

        private void  chartBox_MouseMove(Object sender, MouseEventArgs e)
        {
            var c = (ChartBox)sender;
            int index = c.CalcIndexFromX(e.X);
            if (index < 0 || Prices == null)
                return;
            if (prevIndex == index)
                return;
            prevIndex = index;
            SetPriceInfo(Prices[index]);
            for (int i = 0; i < chartBoxes.Length; i++)
                chartBoxes[i].DrawIndicatorValue(index);
        }
    }
}
