// Copyright(C) 2003 Daisuke Arai <darai@users.sourceforge.jp>
// Copyright(C) 2004-2008, 2010, 2013 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: MainForm.cs 486 2013-07-18 01:57:49Z panacoran $

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Protra.Dialogs;
using Protra.Lib;
using Protra.Lib.Config;
using Protra.Lib.Data;
using Protra.Lib.Dialogs;

namespace Protra
{
    /// <summary>
    /// メインフォーム
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// メインエントリポイント
        /// </summary>
        [STAThread]
        public static void Main()
        {
            if (Win32API.ProcessAlreadyExists())
                return;
            Application.EnableVisualStyles();
            Application.Run(new MainForm());
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainForm()
        {
            InitializeComponent();

            //設定ファイルの読み込み。
            (GlobalEnv.ProtraConfig = new ProtraConfig()).Load();
            (GlobalEnv.UpdateConfig = new UpdateConfig()).Load();
            (GlobalEnv.BrandData = new BrandData()).Load();
            (GlobalEnv.BrandListConfig = new BrandListConfig()).Load();

            if (GlobalEnv.ProtraConfig.TimeFrame == TimeFrame.Weekly)
                weeklyChartToolStripMenuItem.PerformClick();
            foreach (var bl in GlobalEnv.BrandListConfig.List)
                if (GlobalEnv.ProtraConfig.BrandListName == bl.Name)
                {
                    comboBoxBrandList.Items.Add(bl); // Add a dummy to select it.
                    comboBoxBrandList.SelectedItem = bl;
                    var code = GlobalEnv.ProtraConfig.SelectedCode;
                    if (bl.List.Contains(code))
                    {
                        var brand = GlobalEnv.BrandData[code];
                        listBoxBrandList.Items.Add(brand); // Add a dummy to select it.
                        listBoxBrandList.SelectedItem = brand;
                    }
                    break;
                }
            BrandListInit();
            GlobalEnv.BrandData.BrandListInit = BrandListInit;
            GlobalEnv.BrandListConfig.BrandListInit = BrandListInit;
        }

        private void BrandListInit()
        {
            SuspendLayout();
            var selectedList = (BrandList)comboBoxBrandList.SelectedItem;
            comboBoxBrandList.Items.Clear();
            foreach (var bl in GlobalEnv.BrandListConfig.List)
            {
                comboBoxBrandList.Items.Add(bl);
                if (selectedList == null || bl.Name != selectedList.Name)
                    continue;
                comboBoxBrandList.SelectedItem = bl;
                selectedList = bl;
            }
            if (selectedList == null && comboBoxBrandList.Items.Count > 0)
            {
                comboBoxBrandList.SelectedIndex = 0;
                selectedList = (BrandList)comboBoxBrandList.SelectedItem;
            }
            if (selectedList != null)
            {
                var selectedBrand = (Brand)listBoxBrandList.SelectedItem;
                listBoxBrandList.Items.Clear();
                foreach (var code in selectedList.List)
                {
                    var brand = GlobalEnv.BrandData[code];
                    listBoxBrandList.Items.Add(brand);
                    if (selectedBrand != null && code == selectedBrand.Code)
                        listBoxBrandList.SelectedItem = brand;
                }
            }
            ResumeLayout();
        }

        /// <summary>
        /// 設定ファイルを書き込む。
        /// </summary>
        private void ConfigWrite()
        {
            var config = GlobalEnv.ProtraConfig;
            var maximized = WindowState == FormWindowState.Maximized;
            var bounds = (WindowState == FormWindowState.Normal) ? Bounds : RestoreBounds;
            config.Maximized = maximized;
            config.Size = bounds.Size;
            config.Location = bounds.Location;
            config.PanelLeftWidth = splitContainerMain.SplitterDistance;
            var brandList = (BrandList)comboBoxBrandList.SelectedItem;
            config.BrandListName = brandList == null ? null : brandList.Name;
            chartPanel.GetConfig(config);
            config.Save();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            var config = GlobalEnv.ProtraConfig;
            if (config.Size.Height != 0) // 設定ファイルが存在するか？
            {
                Size = config.Size;
                if (config.Location.X != int.MinValue && // 古い設定ファイルはLocationがない。
                    Utils.IsShowOnScreen(new Rectangle(config.Location, Size))) // 表示可能範囲か？
                    Location = config.Location;
                if (config.Maximized)
                    WindowState = FormWindowState.Maximized;
                splitContainerMain.SplitterDistance = config.PanelLeftWidth;
            }
            ChartPanelInit();
            if (config.SelectedCode != null)
                SetBrandInfo(GlobalEnv.BrandData[config.SelectedCode]);
        }

        private void ChartPanelInit()
        {
            chartPanel.SetPriceInfo = SetPriceInfo;
            chartPanel.HScrollBar = hScrollBarChart;
            chartPanel.SetConfig(GlobalEnv.ProtraConfig);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            ConfigWrite();
        }

        private void dailyChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            weeklyChartToolStripMenuItem.Checked = false;
            dailyChartToolStripButton.Checked = true;
            weeklyChartToolStripButton.Checked = false;
            chartPanel.TimeFrame = TimeFrame.Daily;
        }

        private void weeklyChartToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dailyChartToolStripMenuItem.Checked = false;
            weeklyChartToolStripButton.Checked = true;
            dailyChartToolStripButton.Checked = false;
            chartPanel.TimeFrame = TimeFrame.Weekly;
        }

        private void dailyChartToolStripButton_Click(object sender, EventArgs e)
        {
            dailyChartToolStripMenuItem.PerformClick();
        }

        private void weeklyChartToolStripButton_Click(object sender, EventArgs e)
        {
            weeklyChartToolStripMenuItem.PerformClick();
        }

        private void comboBoxBrandList_SelectionChangeCommited(object sender, EventArgs e)
        {
            SuspendLayout();
            listBoxBrandList.Items.Clear();
            var brandList = (BrandList)comboBoxBrandList.SelectedItem;
            foreach (var code in brandList.List)
                listBoxBrandList.Items.Add(GlobalEnv.BrandData[code]);
            ResumeLayout();
        }

        private void listBoxBrandList_SelectedIndexChanged(object sender, EventArgs e)
        {
            var brand = (Brand)((ListBox)sender).SelectedItem;
            if (brand == null)
                return;
            chartPanel.Code = brand.Code;
            SetBrandInfo(brand);
        }

        /// <summary>
        /// 銘柄情報を表示する。
        /// </summary>
        /// <param name="brand">銘柄オブジェクト</param>
        private void SetBrandInfo(Brand brand)
        {
            labelCode.Text = brand.Code + " " + brand.MarketName;
            labelBrandName.Text = brand.Name;
        }

        /// <summary>
        /// 価格情報を表示する。
        /// </summary>
        /// <param name="price">価格オブジェクト</param>
        private void SetPriceInfo(Price price)
        {
            labelDate.Text = price.Date.ToString("yyyy/MM/dd");
            labelOpenValue.Text = price.Open.ToString("#,#");
            labelHighValue.Text = price.High.ToString("#,#");
            labelLowValue.Text = price.Low.ToString("#,#");
            labelCloseValue.Text = price.Close.ToString("#,#");
            labelVolumeValue.Text = price.Volume.ToString("#,#.#");
        }

        private void manualToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Process.Start(Global.PathMan);
        }

        private void versionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (var dialog = new VersionDialog())
                dialog.ShowDialog(this);
        }

        private void searchToolStripButton_Click(object sender, EventArgs e)
        {
            if (toolStripTextBox.Text == "")
                return;
            var b = GlobalEnv.BrandData[toolStripTextBox.Text];
            var brands = b.Unit > 0 ? new List<Brand> {b} : GlobalEnv.BrandData.Search(toolStripTextBox.Text);
            var contextMenu = new ContextMenu();
            foreach (var brand in brands)
            {
                var menuItem = new MenuItem {Text = brand.ToString(), Tag = brand};
                menuItem.Click += menuItemSearchedBrand_Click;
                contextMenu.MenuItems.Add(menuItem);
            }
            contextMenu.Show(mainToolStrip,
                             new Point(searchToolStripButton.Bounds.Left,
                                       searchToolStripButton.Bounds.Bottom));
        }

        private void menuItemSearchedBrand_Click(object sender, EventArgs e)
        {
            listBoxBrandList.SelectedItem = null;
            var brand = (Brand)((MenuItem)sender).Tag;
            chartPanel.Code = brand.Code;
            SetBrandInfo(brand);
        }

        private void toolStripTextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                e.Handled = true;
                searchToolStripButton.PerformClick();
            }
        }

        private void priceUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (var updateDialog = new PriceUpdateDialog())
                updateDialog.ShowDialog();
            chartPanel.InvalidatePrices();
        }

        private void priceUpdateToolStripButton_Click(object sender, EventArgs e)
        {
            priceUpdateToolStripMenuItem.PerformClick();
        }

        private InputDateDialog _inputDateDialog;

        private void priceDeleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_inputDateDialog == null)
                _inputDateDialog = new InputDateDialog();
            var dialog = _inputDateDialog;
            dialog.Message = "指定した日付以降のデータを削除します。";
            dialog.Value = PriceData.MaxDate;
            dialog.ShowDialog();
            if (dialog.DialogResult != DialogResult.OK)
                return;
            Cursor = Cursors.WaitCursor;
            Application.DoEvents();
            PriceData.Delete(dialog.Value);
            Cursor = Cursors.Default;
            chartPanel.InvalidatePrices();
        }

        private DataConvertDialog _dataConvertDialog;

        private void priceConvertToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_dataConvertDialog == null)
                _dataConvertDialog = new DataConvertDialog();
            var dialog = _dataConvertDialog;
            dialog.ShowDialog();
            if (dialog.DialogResult != DialogResult.OK)
                return;
            Cursor = Cursors.WaitCursor;
            Application.DoEvents();
            bool result;
            if (_dataConvertDialog.ToCSV)
                result = PriceData.ConvertToCSV(dialog.StartCode, dialog.EndCode);
            else
            {
                result = PriceData.ConvertFromCSV(dialog.StartCode, dialog.EndCode);
                chartPanel.InvalidatePrices();
            }
            Cursor = Cursors.Default;
            MessageBox.Show(result ? "変換が終了しました。" : "変換を中断しました。", "株価データの変換", MessageBoxButtons.OK);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void ptSimToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var path = Path.Combine(Global.DirApp, "PtSim.exe");
            Process.Start(path);
        }

        private void ptSimToolStripButton_Click(object sender, EventArgs e)
        {
            ptSimToolStripMenuItem.PerformClick();
        }

        private void OptionToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (var dialog = new OptionDialog())
            {
                if (dialog.ShowDialog(this) != DialogResult.OK)
                    return;
                // 設定を描画に反映させる。
                var config = GlobalEnv.ProtraConfig;
                chartPanel.ChartNum = config.ChartNum;
                chartPanel.ChartForeColor = Color.FromArgb(config.ChartForeColor);
                chartPanel.ChartBackColor = Color.FromArgb(config.ChartBackColor);
                chartPanel.DrawLastWeek = config.DrawLastWeek;
                chartPanel.UseDifferentChart = config.UseDifferentChart;
            }
        }

        private void listEditToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (var dialog = new EditBrandListDialog())
                dialog.ShowDialog(this);
            BrandListInit();
        }

        private void listAddtoolStripMenuItem_Click(object sender, EventArgs e)
        {
            var index = comboBoxBrandList.SelectedIndex;
            var code = chartPanel.Code;
            if (index == -1 || code == null)
                return;
            if (index < 3)
            {
                MessageBox.Show("この銘柄リストには追加できません。", "エラー", MessageBoxButtons.OK);
                return;
            }
            var bl = (BrandList)comboBoxBrandList.Items[index];
            if (bl.List.Contains(code))
                return;
            listBoxBrandList.Items.Add(GlobalEnv.BrandData[code]);
            bl.List.Add(code);
            GlobalEnv.BrandListConfig.Save();
        }

        private void listDelToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var brandListIndex = comboBoxBrandList.SelectedIndex;
            var brandIndex = listBoxBrandList.SelectedIndex;
            if (brandListIndex == -1 || brandIndex == -1)
                return;
            if (brandListIndex < 3)
            {
                MessageBox.Show("この銘柄リストからは削除できません。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            ((BrandList)comboBoxBrandList.SelectedItem).List.Remove(((Brand)listBoxBrandList.SelectedItem).Code);
            listBoxBrandList.Items.RemoveAt(brandIndex);
            listBoxBrandList.SelectedIndex = brandIndex == listBoxBrandList.Items.Count ? brandIndex - 1 : brandIndex;
            GlobalEnv.BrandListConfig.Save();
        }
    }
}