using System;
using System.Windows.Forms;
using System.ComponentModel;

namespace Mix.Tool.ModelEditor
{
    /// <summary>
    /// ダイナミクスマネージャーフォームクラス
    /// </summary>
    public partial class PhysicsManagerForm : Mix.Tool.Docking.DockContent
    {
        #region const value

        const string GROUP_NAME_COLUMN_NAME = "columnGroupName";
        const string GROUP_VALUE_COLUMN_NAME = "columnGroupValue";
        const int GROUP_MIN = 1;
        const int GROUP_MAX = 16;

        const string IDENT_NAME_COLUMN_NAME = "columnIdentName";
        const string IDENT_VALUE_COLUMN_NAME = "columnIdentValue";
        const int IDENT_MIN = 1;
        const int IDENT_MAX = 32767;

        const string ATTR_NAME_COLUMN_NAME = "columnAttrName";
        const string ATTR_VALUE_COLUMN_NAME = "columnAttrValue";
        const int ATTR_MIN = 1;
        const int ATTR_MAX = 32;

        #endregion

        #region private member

        Project.Dynamics dynamics = null;

        #endregion

        #region public method

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="_dynamics">ダイナミクス</param>
        public PhysicsManagerForm(Project.Dynamics _dynamics)
        {
            InitializeComponent();

            ////////////////////////////////////////////////////////////////////////////////////////////////////
            // 初期設定
            ////////////////////////////////////////////////////////////////////////////////////////////////////

            this.dynamics = _dynamics;
            this.dynamics.ChangedState += new Project.Dynamics.ChangedStateEventHandler(this.Physics_ChangedState);

            this.tbDSFilePath.Text = this.dynamics.FilePath;
        }

        #endregion

        #region Private method

        private void btDSFilePath_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dlg = new OpenFileDialog())
            {
                if (this.dynamics.FilePath.Length > 0)
                {
                    try
                    {
                        dlg.InitialDirectory = System.IO.Path.GetDirectoryName(this.dynamics.FilePath);
                    }
                    catch
                    {
                        dlg.InitialDirectory = System.IO.Path.GetPathRoot(this.dynamics.FilePath);
                    }

                    dlg.FileName = System.IO.Path.GetFileName(this.dynamics.FilePath);
                }
                else
                {
                    dlg.InitialDirectory = "";
                    dlg.FileName = "";
                }

                dlg.Title = Properties.Resources.SPECIFIED_DATASRC;
                dlg.CheckFileExists = false;
                dlg.Filter = Properties.Resources.FILE_FILTER_PDD;
                dlg.FilterIndex = 1;

                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    this.dynamics.FilePath = dlg.FileName;

                    try
                    {
                        this.dynamics.Load();
                        this.tbDSFilePath.Text = this.dynamics.FilePath;
                    }
                    catch (System.Exception excep)
                    {
                        Mix.Tool.MessageDialog.ShowOK(Properties.Resources.PROJECT_DYNAMICS_LOAD_ERROR + excep.Message,
                            Properties.Resources.TITLE,
                            MessageDialogIcon.Error);
                    }
                }
            }

        }

        private void btDSSave_Click(object sender, EventArgs e)
        {
            try
            {
                this.dynamics.Save();
            }
            catch (System.Exception excep)
            {
                Mix.Tool.MessageDialog.ShowOK(Properties.Resources.PROJECT_DYNAMICS_SAVE_ERROR + excep.Message,
                    Properties.Resources.TITLE,
                    MessageDialogIcon.Error);
            }
        }

        #endregion

        #region dgv MIdent

        private void dgvIdents_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            this.dgvEditingControlShowing(sender, e, IDENT_VALUE_COLUMN_NAME);
        }

        private void dgvIdents_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (this.dgvCellCheckable(sender, e) == true)
            {
                DataGridView dgv = (DataGridView)sender;

                switch (dgv.Columns[e.ColumnIndex].Name)
                {
                    case IDENT_NAME_COLUMN_NAME:
                        this.dgvCheckName(sender, e);
                        break;
                    case IDENT_VALUE_COLUMN_NAME:
                        this.dgvCheckValue(sender, e, IDENT_MIN, IDENT_MAX);
                        break;
                }
            }
        }

        private void dgvIdents_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {
            this.dgvRowValidating(sender, e, IDENT_NAME_COLUMN_NAME, IDENT_VALUE_COLUMN_NAME);
        }

        private void dgvIdents_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            this.dgvCellEndEdit(sender, e);
        }

        private void dgvIdents_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            this.dgvUserDeletingRow(sender, e, Properties.Resources.IDENT_COLLECTION);
        }

        private void dgvIdents_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            this.dgvDataError(sender, e, Properties.Resources.IDENT_COLLECTION);
        }

        #endregion

        #region dgv MAttr

        private void dgvAttrs_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            this.dgvEditingControlShowing(sender, e, ATTR_VALUE_COLUMN_NAME);
        }

        private void dgvAttrs_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            if (this.dgvCellCheckable(sender, e) == true)
            {
                DataGridView dgv = (DataGridView)sender;

                switch (dgv.Columns[e.ColumnIndex].Name)
                {
                    case ATTR_NAME_COLUMN_NAME:
                        this.dgvCheckName(sender, e);
                        break;
                    case ATTR_VALUE_COLUMN_NAME:
                        this.dgvCheckValue(sender, e, IDENT_MIN, IDENT_MAX);
                        break;
                }
            }
        }

        private void dgvAttrs_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {
            this.dgvRowValidating(sender, e, ATTR_NAME_COLUMN_NAME, ATTR_VALUE_COLUMN_NAME);
        }

        private void dgvAttrs_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            this.dgvCellEndEdit(sender, e);
        }

        private void dgvAttrs_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            this.dgvUserDeletingRow(sender, e, Properties.Resources.ATTR_COLLECTION);
        }

        private void dgvAttrs_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            this.dgvDataError(sender, e, Properties.Resources.ATTR_COLLECTION);
        }

        #endregion

        #region dgv Common

        private void dgvEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e, string columnName)
        {
            if (e.Control is DataGridViewTextBoxEditingControl)
            {
                DataGridView dgv = sender as DataGridView;
                DataGridViewTextBoxEditingControl tbEditCtrl = e.Control as DataGridViewTextBoxEditingControl;

                tbEditCtrl.KeyPress -= new KeyPressEventHandler(this.dgvTextBoxEditCtrl_KeyPress);

                if (dgv.CurrentCell.OwningColumn.Name.Equals(columnName) == true)
                {
                    //入力は数値とバックスペースのみにするためにイベントを追加
                    tbEditCtrl.KeyPress += new KeyPressEventHandler(this.dgvTextBoxEditCtrl_KeyPress);
                }
            }
        }

        private bool dgvCellCheckable(object sender, DataGridViewCellValidatingEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;

            if (((this.CausesValidation == false) && (this.ActiveControl == this)) ||
                (this.ActiveControl == null) ||
                (this.ActiveControl.CausesValidation == false))
            {
                //エラーが発生してる際にフォームが閉じられなくなる対策
                return false;
            }

            if (e.RowIndex == dgv.NewRowIndex)
            {
                //新しい行
                return false;
            }

            if (e.FormattedValue == null)
            {
                //入力値が不明
                return false;
            }

            return true;
        }

        private void dgvCheckName(object sender, DataGridViewCellValidatingEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;
            DataGridViewRow row = dgv.Rows[e.RowIndex];
            DataGridViewCell cell = row.Cells[e.ColumnIndex];

            //重複チェック
            foreach (DataGridViewRow checkRow in dgv.Rows)
            {
                if (checkRow == row)
                {
                    continue;
                }

                object checkCellValue = checkRow.Cells[e.ColumnIndex].Value;

                if ((checkCellValue != null) &&
                    (checkCellValue.Equals(e.FormattedValue) == true))
                {
                    row.ErrorText = string.Format(Properties.Resources.ERROR_OVERLAP_NAME, e.FormattedValue.ToString());
                    dgv.CancelEdit();
                    e.Cancel = true;
                    break;
                }
            }
        }

        private void dgvCheckValue(object sender, DataGridViewCellValidatingEventArgs e, int minValue, int maxValue)
        {
            DataGridView dgv = (DataGridView)sender;
            DataGridViewRow row = dgv.Rows[e.RowIndex];
            DataGridViewCell cell = row.Cells[e.ColumnIndex];

            int value;

            //数値チェック
            if (int.TryParse(e.FormattedValue.ToString(), out value) == true)
            {
                //範囲チェック
                if ((value < minValue) ||
                    (value > maxValue))
                {
                    dgv.Rows[e.RowIndex].ErrorText = "値は " + minValue + "～" + maxValue + " の間である必要があります";
                    dgv.CancelEdit();
                    e.Cancel = true;
                }
                else
                {
                    //重複チェック
                    foreach (DataGridViewRow checkRow in dgv.Rows)
                    {
                        if (checkRow == row)
                        {
                            continue;
                        }

                        object checkCellValue = checkRow.Cells[e.ColumnIndex].Value;

                        if ((checkCellValue != null) &&
                            (checkCellValue.Equals(e.FormattedValue) == true))
                        {
                            row.ErrorText = string.Format(Properties.Resources.ERROR_OVERLAP_NUMBER, e.FormattedValue.ToString());
                            dgv.CancelEdit();
                            e.Cancel = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                dgv.Rows[e.RowIndex].ErrorText = "入力は数値( " + minValue + "～" + maxValue + " )のみになります";
                dgv.CancelEdit();
                e.Cancel = true;
            }
        }

        private void dgvRowValidating(object sender, DataGridViewCellCancelEventArgs e, string nameColumnName, string valueColumnName)
        {
            DataGridView dgv = (DataGridView)sender;

            if (((this.CausesValidation == false) && (this.ActiveControl == this)) ||
                (this.ActiveControl == null) ||
                (this.ActiveControl.CausesValidation == false))
            {
                //エラーが発生してる際にフォームが閉じられなくなる対策
                return;
            }

            if (e.RowIndex == dgv.NewRowIndex)
            {
                return;
            }

            for (int i = 0; i < dgv.Columns.Count; i++)
            {
                DataGridViewColumn column = dgv.Columns[i];
                DataGridViewRow row = dgv.Rows[e.RowIndex];
                DataGridViewCell cell = row.Cells[i];
                string cellValue = (cell.Value != null) ? cell.Value.ToString() : "";

                if (column.Name == nameColumnName)
                {
                    if (cellValue.Length == 0)
                    {
                        row.ErrorText = Properties.Resources.ERROR_OVERLAP_NAME;
                        e.Cancel = true;
                    }
                }
                else if (column.Name == valueColumnName)
                {
                    if (cellValue.Length == 0)
                    {
                        row.ErrorText = Properties.Resources.ERROR_OVERLAP_NUMBER;
                        e.Cancel = true;
                    }
                }
            }
        }

        private void dgvCellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;

            dgv.Rows[e.RowIndex].ErrorText = string.Empty;
        }

        private void dgvUserDeletingRow(object sender, DataGridViewRowCancelEventArgs e, string title)
        {
            object objName = e.Row.Cells[0].Value;
            string name = (objName != null) ? objName.ToString() : "";

            if (Mix.Tool.MessageDialog.ShowYN(string.Format(Properties.Resources.WARNING_DGV_USER_DEL_ROW, title, name), Properties.Resources.TITLE, MessageDialogIcon.Warning) == DialogResult.No)
            {
                e.Cancel = true;
            }
        }

        private void dgvDataError(object sender, DataGridViewDataErrorEventArgs e, string title)
        {
            Mix.Tool.Logger.Print(Logger.Type.Error, string.Format(Properties.Resources.ERROR_DGV_DATA_ERROR, title, e.Exception.Message));

            e.ThrowException = false;
        }

        private void dgvTextBoxEditCtrl_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (((e.KeyChar < '0') || (e.KeyChar > '9')) && (e.KeyChar != '\b'))
            {
                e.Handled = true;
            }
        }

        #endregion

        #region Misc

        private void Physics_ChangedState(object sender, Project.Dynamics.ChangedStateEventArgs e)
        {
            this.EnabledControlles(e.State);
        }

        private void EnabledControlles(bool state)
        {
            if (state == true)
            {
                this.btDSSave.Enabled = true;
                this.lbIdent.Enabled = true;
                this.dgvIdents.Enabled = true;
                this.lbIdent.Enabled = true;
                this.dgvAttrs.Enabled = true;

                this.dgvIdents.DataSource = this.dynamics.Identities;
                this.dgvAttrs.DataSource = this.dynamics.Attributes;
            }
            else
            {
                this.btDSSave.Enabled = false;
                this.lbIdent.Enabled = false;
                this.dgvIdents.Enabled = false;
                this.lbAttr.Enabled = false;
                this.dgvAttrs.Enabled = false;

                this.dgvIdents.DataSource = null;
                this.dgvAttrs.DataSource = null;
            }
        }

        #endregion
    }
}
