using System;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using DevExpress.XtraCharts;

using LFP_Manager.Forms;
using LFP_Manager.DataStructure;
using LFP_Manager.Utils;
using System.Threading;
using System.Text;

namespace LFP_Manager.Controls
{
    public delegate void paramCommand(int sId, int mode, int flag, ref DeviceParamData aParam, ref DeviceCalibration aCalib);
    public delegate void MsgPrint(object sender, string msg);

    public partial class ucShelfStatus : DevExpress.XtraEditors.XtraUserControl
    {
        #region VARIABLES
        const int STATUS_QTY = 10;

        int SystemId = 0;
        bool start = false;

        int CellDivUnit = csConstData.Unit.CELL_DIV_P3;
        string CellDisUnit = csConstData.Unit.CELL_DIS_P4;

        CommConfig Config;

        DeviceSystemData SystemData;

        DataTable[] dtVolt;
        DataTable[] dtTemp;
        Series[] seriesVolt;
        Series[] seriesTemp;

        ucStatus[] alarmTrip;

        Palette paletteV;
        Palette paletteT;

        public event paramCommand OnCommand = null;
        public event MsgPrint OnMsgPrint = null;
        #endregion

        #region CONSTRUCTORS
        public ucShelfStatus()
        {
            InitializeComponent();

            btnParam.Enabled = false;
            btnCalibration.Enabled = false;
            btnINV.Enabled = false;

            gaugeControl1.BackColor = Control.DefaultBackColor;
            gaugeControl2.BackColor = Control.DefaultBackColor;
            gaugeControl3.BackColor = Control.DefaultBackColor;
            gaugeControl4.BackColor = Control.DefaultBackColor;
            gaugeControl5.BackColor = Control.DefaultBackColor;

            gaugeControl1.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
            gaugeControl2.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
            gaugeControl3.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
            gaugeControl4.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
            gaugeControl5.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;

            gaugeControl1.LayoutPadding = new DevExpress.XtraGauges.Core.Base.Thickness(2, 2, 2, 2);
            gaugeControl2.LayoutPadding = new DevExpress.XtraGauges.Core.Base.Thickness(2, 2, 2, 2);
            gaugeControl3.LayoutPadding = new DevExpress.XtraGauges.Core.Base.Thickness(2, 2, 2, 2);
            gaugeControl4.LayoutPadding = new DevExpress.XtraGauges.Core.Base.Thickness(2, 2, 2, 2);
            gaugeControl5.LayoutPadding = new DevExpress.XtraGauges.Core.Base.Thickness(2, 2, 2, 2);
        }
        #endregion

        #region PUBLIC FUNCTIONS
        public void UpdateSystemId(int sId)
        {
            SystemId = sId;

            switch (Config.TargetModelIndex)
            {
                case 0:             // PR-57150
                    SystemData.cellQty = 18;
                    SystemData.tempQty = 6;
                    break;
                case 1:             // PR-64150
                    SystemData.cellQty = 20;
                    SystemData.tempQty = 8;
                    break;
                case 2:             // LFPM-57080
                    SystemData.cellQty = 18;
                    SystemData.tempQty = 6;
                    break;
                case 3:             // PR-102150
                    SystemData.cellQty = 32;
                    SystemData.tempQty = 8;
                    break;
                case 4:             // PR-115300
                    SystemData.cellQty = 36;
                    SystemData.tempQty = 16;
                    break;
                case 5:             // PR-67150
                    SystemData.cellQty = 21;
                    SystemData.tempQty = 8;
                    break;
                default:
                    SystemData.cellQty = 18;
                    SystemData.tempQty = 6;
                    break;
            }
        }

        public void Start(int sId, ref CommConfig aConfig, ref DeviceSystemData aSystemData)
        {
            SystemId = sId;
            Config = aConfig;
            SystemData = aSystemData;

            switch (Config.TargetModelIndex)
            {
                case 0:             // PR-57150
                    CellDivUnit = csConstData.Unit.CELL_DIV_P3;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P3;
                    break;
                case 1:             // PR-64150
                    CellDivUnit = csConstData.Unit.CELL_DIV_P4;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P4;
                    break;
                case 2:             // LFPM-57080
                    CellDivUnit = csConstData.Unit.CELL_DIV_P4;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P4;
                    break;
                case 3:             // PR-102150
                    CellDivUnit = csConstData.Unit.CELL_DIV_P4;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P4;
                    break;
                case 4:             // PR-115300
                    CellDivUnit = csConstData.Unit.CELL_DIV_P4;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P4;
                    break;
                case 5:             // PR-67150
                    CellDivUnit = csConstData.Unit.CELL_DIV_P4;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P4;
                    break;
                default:
                    CellDivUnit = csConstData.Unit.CELL_DIV_P3;
                    CellDisUnit = csConstData.Unit.CELL_DIS_P3;
                    break;
            }

            InitStatusName();
            InitDataTableVolt();
            InitDataTableTemp();
            VSeriesInit();
            tSeriesInit();

            tmrDisplay.Start();

            btnParam.Enabled = true;
            btnCalibration.Enabled = true;
            btnINV.Enabled = true;

            start = true;
        }

        public void Stop()
        {
            start = false;
            tmrDisplay.Stop();
        }

        public void SystemIdSet(int sId)
        {
            SystemId = sId;
        }

        public void UpdateData(ref DeviceSystemData aSystemData)
        {
            SystemData = aSystemData;
        }
        #endregion

        #region INIT_COMPONENT

        private void InitStatusName()
        {
            ucHighTemp.SetName("High Temp");
            //ucHighTemp.SetTextWidth(80);
            ucLowTemp.SetName("Low Temp");
            //ucLowTemp.SetTextWidth(80);
            ucOverVolt.SetName("System OV");
            //ucOverVolt.SetTextWidth(80);
            ucUnderVolt.SetName("System UV");
            //ucUnderVolt.SetTextWidth(80);
            ucCellOverVolt.SetName("Cell OV");
            //ucOverVolt.SetTextWidth(80);
            ucCellUnderVolt.SetName("Cell UV");
            //ucUnderVolt.SetTextWidth(80);
            ucChaOverCurr.SetName("Cha OC");
            //ucChaOverCurr.SetTextWidth(110);
            ucDchOverCurr.SetName("Dch OC");
            //ucDchOverCurr.SetTextWidth(110);
            ucLowSOC.SetName("Low SOC");
            //ucLowSOC.SetTextWidth(80);
            ucCvDiff.SetName("Cell Voltage Dev");
            //ucMdComm.SetTextWidth(80);

            alarmTrip = new ucStatus[STATUS_QTY];

            alarmTrip[0] = ucOverVolt;
            alarmTrip[1] = ucCellOverVolt;
            alarmTrip[2] = ucUnderVolt;
            alarmTrip[3] = ucCellUnderVolt;
            alarmTrip[4] = ucChaOverCurr;
            alarmTrip[5] = ucDchOverCurr;
            alarmTrip[6] = ucHighTemp;
            alarmTrip[7] = ucLowTemp;

            //alarmTrip[0] = ucHighTemp;
            //alarmTrip[1] = ucLowTemp;
            //alarmTrip[2] = ucOverVolt;
            //alarmTrip[3] = ucUnderVolt;
            //alarmTrip[4] = ucCellOverVolt;
            //alarmTrip[5] = ucCellUnderVolt;
            //alarmTrip[6] = ucChaOverCurr;
            //alarmTrip[7] = ucDchOverCurr;
            alarmTrip[8] = ucLowSOC;
            alarmTrip[9] = ucCvDiff;
        }

        private void InitDataTableVolt()
        {
            if ((dtVolt != null) && (dtVolt.Length > 0))
            {
                for (int i = 0; i < dtVolt.Length; i++)
                    dtVolt[i].Dispose();
            }
            dtVolt = new DataTable[SystemData.cellQty];

            for (int i = 0; i < dtVolt.Length; i++)
            {
                dtVolt[i] = new DataTable();
                dtVolt[i].Columns.Add("C_No", typeof(Int32));
                dtVolt[i].Columns.Add("Alarm", typeof(Int32));
                dtVolt[i].Columns.Add("Value", typeof(double));

                // Add data rows to the table.
                DataRow row = null;
                row = dtVolt[i].NewRow();
                row["C_No"] = i + 1;
                row["Alarm"] = 0;
                row["Value"] = 3.2;

                dtVolt[i].Rows.Add(row);
            }
        }

        private void InitDataTableTemp()
        {
            if ((dtTemp != null) && (dtTemp.Length > 0))
            {
                for (int i = 0; i < dtTemp.Length; i++)
                    dtTemp[i].Dispose();
            }
            dtTemp = new DataTable[SystemData.tempQty];

            for (int i = 0; i < dtTemp.Length; i++)
            {
                dtTemp[i] = new DataTable();
                dtTemp[i].Columns.Add("T_No", typeof(Int32));
                dtTemp[i].Columns.Add("Alarm", typeof(Int32));
                dtTemp[i].Columns.Add("Value", typeof(double));

                // Add data rows to the table.
                DataRow row = null;
                row = dtTemp[i].NewRow();
                row["T_No"] = i + 1;
                row["Alarm"] = 0;
                row["Value"] = 25.4;
                dtTemp[i].Rows.Add(row);
            }
        }

        private Palette VPaletteInit(string bName)
        {
            paletteV = new Palette(bName);

            for (int i = 0; i < SystemData.cellQty; i++)
            {
                paletteV.Add(Color.Green);
            }
            return paletteV;
        }

        private void VPaletteUpdate2(uint LvValue, uint HvValue)
        {
            int nIC, nID;
            uint[] bValue = new uint[2];

            paletteV.Clear();
            
            bValue[0] = LvValue;
            bValue[1] = HvValue;
            for (int i = 0; i < SystemData.cellQty; i++)
            {
                nIC = 0; nID = 0;
                switch (Config.TargetModelIndex)
                {
                    case 0:     // PR-57150
                    case 1:
                    case 2:
                        nIC = 0;
                        nID = i;
                        break;
                    case 3:     // PR-102150
                        nIC = 0;
                        nID = i;
                        break;
                    case 4:     // PR-115300
                        nIC = i / csConstData.SystemInfo.CELL_MAX_PER_IC;
                        nID = i % csConstData.SystemInfo.CELL_MAX_PER_IC;
                        break;
                    case 5:
                        nIC = 0;
                        nID = i;
                        break;
                    default:
                        nIC = 0;
                        nID = i;
                        break;
                }

                if (((bValue[nIC] >> nID) & 0x00000001) == 0x00000001)
                    paletteV.Add(Color.Orange);
                else
                    paletteV.Add(Color.Green);
            }
        }

        private void VPaletteUpdate(uint LvValue, uint HvValue)
        {
            int nIC, nID;
            uint[] bValue = new uint[2];

            paletteV.Clear();

            bValue[0] = LvValue;
            bValue[1] = HvValue;
            for (int i = 0; i < SystemData.cellQty; i++)
            {
                nIC = 0; nID = 0;
                switch (Config.TargetModelIndex)
                {
                    case 4:     // PR-115300
                        nIC = i / csConstData.SystemInfo.CELL_MAX_PER_IC;
                        nID = i % csConstData.SystemInfo.CELL_MAX_PER_IC;
                        if (((bValue[nIC] >> nID) & 0x00000001) == 0x00000001)
                            paletteV.Add(Color.Orange);
                        else
                            paletteV.Add(Color.Green);
                        break;
                    case 0:     // PR-57150
                        nID = i;
                        if (((bValue[0] >> nID) & 0x00000001) == 0x00000001)
                        {
                            if (((bValue[1] >> nID) & 0x00000001) == 0x00000001)
                                paletteV.Add(Color.Orange);
                            else
                                paletteV.Add(Color.Blue);
                        }
                        else
                        {
                            paletteV.Add(Color.Green);
                        }
                        break;
                    case 1:
                    case 2:
                    case 3:     // PR-102150
                    case 5:
                    default:
                        nIC = 0;
                        nID = i;
                        break;
                }
            }
        }

        private Palette TPaletteInit(string bName, short bValue)
        {
            paletteT = new Palette(bName);

            for (int i = 0; i < SystemData.tempQty; i++)
            {
                if (((bValue >> i) & 0x0001) == 0x0001)
                    paletteT.Add(Color.Orange);
                else
                    paletteT.Add(Color.Green);
            }

            return paletteT;
        }

        private void TPaletteUpdate(short bValue)
        {
            paletteT.Clear();
            for (int i = 0; i < SystemData.tempQty; i++)
            {
                if (((bValue >> i) & 0x0001) == 0x0001)
                    paletteT.Add(Color.Orange);
                else
                    paletteT.Add(Color.Green);
            }
        }

        private void VSeriesInit()
        {
            VChart.Series.Clear();
            VChart.Legend.Visibility = DevExpress.Utils.DefaultBoolean.False;

            seriesVolt = new Series[SystemData.cellQty];

            for (int i = 0; i < seriesVolt.Length; i++)
            {
                seriesVolt[i] = new Series(String.Format("C_{0:00}", i + 1), ViewType.Bar)
                {
                    DataSource = dtVolt[i],
                    CrosshairLabelPattern = "C_{A:00} : {V:F4}",

                    // Specify data members to bind the series.
                    ArgumentScaleType = ScaleType.Numerical,
                    ArgumentDataMember = "C_No",
                    ValueScaleType = ScaleType.Numerical,
                };
                ((SideBySideBarSeriesView)(seriesVolt[i].View)).BarWidth = 10.0;
                seriesVolt[i].ValueDataMembers.AddRange(new string[] { "Value" });
                VChart.Series.Add(seriesVolt[i]);
            }

            VChart.PaletteRepository.Clear();
            VChart.PaletteRepository.Add("V Palette", VPaletteInit("V Palette"));
            VChart.PaletteName = "V Palette";

            // Cast the chart's diagram to the XYDiagram type, to access its axes.
            XYDiagram diagram = (XYDiagram)VChart.Diagram;
            if (diagram.AxisY.ConstantLines.Count > 0)
                diagram.AxisY.ConstantLines.Clear();

            // Create a constant line.
            ConstantLine constantLineMax = new ConstantLine("Limit(Max)");
            ConstantLine constantLineMin = new ConstantLine("Limit(Min)");
            ConstantLine constantDataMax = new ConstantLine(string.Format("                                                             Max({0:#0.0000}V:{1:00}-{2:00})", 0, 0, 0));
            ConstantLine constantDataAvg = new ConstantLine(string.Format("                                   Avg({0:#0.0000}V)", 0));
            ConstantLine constantDataMin = new ConstantLine(string.Format("Min({0:#0.0000}V:{1:00}-{2:00})", 0, 0, 0));

            ConstantLine constantDataBalancing = new ConstantLine(string.Format("Balancing ({0:#0.000}", 0));
            constantDataBalancing.Title.Alignment = ConstantLineTitleAlignment.Far;
            constantDataBalancing.LineStyle.DashStyle = DashStyle.Dash;

            constantLineMax.Color = Color.Red;
            constantLineMin.Color = Color.Red;

            // Customize the behavior of the constant line.
            constantLineMax.Visible = true;
            constantLineMax.ShowInLegend = true;
            constantLineMax.LegendText = "Limit(Max)";
            constantLineMax.ShowBehind = false;

            constantLineMin.Visible = true;
            constantLineMin.ShowInLegend = true;
            constantLineMin.LegendText = "Limit(Min)";
            constantLineMin.ShowBehind = false;

            constantDataMax.Visible = true;
            constantDataMax.ShowInLegend = true;
            constantDataMax.LegendText = "Max";
            constantDataMax.ShowBehind = false;
            constantDataMax.Color = Color.MediumVioletRed;
            constantDataMax.Title.Font = new Font("Tahoma", 10F, FontStyle.Bold);

            constantDataAvg.Visible = true;
            constantDataAvg.ShowInLegend = true;
            constantDataAvg.LegendText = "Avg";
            constantDataAvg.ShowBehind = false;
            constantDataAvg.Color = Color.Green;
            constantDataAvg.Title.Font = new Font("Tahoma", 10F, FontStyle.Bold);

            constantDataMin.Visible = true;
            constantDataMin.ShowInLegend = true;
            constantDataMin.LegendText = "Min";
            constantDataMin.ShowBehind = false;
            constantDataMin.Color = Color.BlueViolet;
            constantDataMin.Title.Font = new Font("Tahoma", 10F, FontStyle.Bold);

            constantDataBalancing.Visible = true;
            constantDataBalancing.ShowInLegend = true;
            constantDataBalancing.LegendText = "Min";
            constantDataBalancing.ShowBehind = false;
            constantDataBalancing.Color = Color.BlueViolet;
            constantDataBalancing.Title.TextColor = Color.Black;
            constantDataBalancing.Title.Font = new Font("Tahoma", 10F, FontStyle.Bold);
            constantDataBalancing.Title.Alignment = ConstantLineTitleAlignment.Far;
            constantDataBalancing.LineStyle.DashStyle = DashStyle.Dash;

            // Define its axis value.
            constantLineMax.AxisValue = 3.85;
            constantLineMin.AxisValue = 2.5;
            constantDataMax.AxisValue = 0;
            constantDataAvg.AxisValue = 0;
            constantDataMin.AxisValue = 0;

            diagram.AxisY.ConstantLines.Add(constantLineMax);
            diagram.AxisY.ConstantLines.Add(constantLineMin);
            diagram.AxisY.ConstantLines.Add(constantDataMax);
            diagram.AxisY.ConstantLines.Add(constantDataAvg);
            diagram.AxisY.ConstantLines.Add(constantDataMin);
            diagram.AxisY.ConstantLines.Add(constantDataBalancing);

            // Axis Y
            diagram.AxisY.VisualRange.Auto = false;
            diagram.AxisY.VisualRange.AutoSideMargins = false;
            diagram.AxisY.VisualRange.StartSideMargin = 0;
            diagram.AxisY.VisualRange.EndSideMargin = 0;
            diagram.AxisY.VisualRange.MaxValue = 4.5;
            diagram.AxisY.VisualRange.MinValue = 2.0;
            diagram.AxisY.WholeRange.MaxValue = 4.5;
            diagram.AxisY.WholeRange.MinValue = 2.0;

            diagram.AxisY.NumericScaleOptions.AutoGrid = false;
            diagram.AxisY.NumericScaleOptions.GridAlignment = NumericGridAlignment.Ones;
            diagram.AxisY.NumericScaleOptions.GridOffset = 0;
            diagram.AxisY.NumericScaleOptions.GridSpacing = 0.1;

            //diagram.AxisY.GridSpacing = 0.1;
            diagram.AxisY.Title.Text = "Voltage(V)";
            //diagram.AxisY.Label.NumericOptions.Precision = 3;
            diagram.AxisY.Title.Visibility = DevExpress.Utils.DefaultBoolean.True;
            diagram.AxisY.Title.Font = new Font("Tahoma", 9F, FontStyle.Regular);

            // Axis X
            diagram.AxisX.WholeRange.Auto = false;
            diagram.AxisX.WholeRange.MaxValue = seriesVolt.Length;
            diagram.AxisX.WholeRange.MinValue = 0;
            diagram.AxisX.VisualRange.MaxValue = seriesVolt.Length;
            diagram.AxisX.VisualRange.MinValue = 1;
            diagram.AxisX.VisualRange.Auto = false;
            diagram.AxisX.VisualRange.AutoSideMargins = false;
            diagram.AxisX.VisualRange.SideMarginsValue = 0.5;

            diagram.AxisX.GridLines.Visible = false;

            diagram.AxisX.NumericScaleOptions.AutoGrid = false;
            diagram.AxisX.NumericScaleOptions.GridSpacing = 1D;

            diagram.AxisX.Title.Text = "Cell No";
            diagram.AxisX.Title.Visibility = DevExpress.Utils.DefaultBoolean.False;
            diagram.AxisX.Title.Font = new Font("Tahoma", 9F, FontStyle.Regular);

            diagram.DefaultPane.BackColor = Color.FromArgb(242, 242, 242);
        }

        private void tSeriesInit()
        {
            TChart.Series.Clear();
            TChart.Legend.Visibility = DevExpress.Utils.DefaultBoolean.False;

            seriesTemp = new Series[SystemData.tempQty];

            for (int i = 0; i < seriesTemp.Length; i++)
            {
                seriesTemp[i] = new Series(String.Format("T_{0:00}", i + 1), ViewType.Bar)
                {
                    DataSource = dtTemp[i],
                    CrosshairLabelPattern = "T_{A:00} : {V:F1}",

                    // Specify data members to bind the series.
                    ArgumentScaleType = ScaleType.Numerical,
                    ArgumentDataMember = "T_No",
                    ValueScaleType = ScaleType.Numerical
                };
                ((SideBySideBarSeriesView)(seriesTemp[i].View)).BarWidth = 2.0;
                seriesTemp[i].ValueDataMembers.AddRange(new string[] { "Value" });
                TChart.Series.Add(seriesTemp[i]);
            }

            TChart.PaletteRepository.Clear();
            TChart.PaletteRepository.Add("T Palette", TPaletteInit("T Palette", 0));
            TChart.PaletteName = "T Palette";

            // Cast the chart's diagram to the XYDiagram type, to access its axes.
            XYDiagram diagram = (XYDiagram)TChart.Diagram;
            if (diagram.AxisY.ConstantLines.Count > 0)
                diagram.AxisY.ConstantLines.Clear();

            diagram.Margins.All = 0;

            ConstantLine constantLineMax = new ConstantLine("Limit(Max)");
            ConstantLine constantLineMin = new ConstantLine("Limit(Min)");
            ConstantLine constantDataMax = new ConstantLine(String.Format("                                            Max({0:#0.0}C)", 0));
            ConstantLine constantDataAvg = new ConstantLine(String.Format("                      Avg({0:#0.0}C)", 0));
            ConstantLine constantDataMin = new ConstantLine(String.Format("Min({0:#0.0}C)", 0));

            constantLineMax.Color = Color.Red;
            constantLineMin.Color = Color.Red;

            // Customize the behavior of the constant line.
            constantLineMax.Visible = true;
            constantLineMax.ShowInLegend = true;
            constantLineMax.LegendText = "Limit(Max)";
            constantLineMax.ShowBehind = false;

            constantLineMin.Visible = true;
            constantLineMin.ShowInLegend = true;
            constantLineMin.LegendText = "Limit(Min)";
            constantLineMin.ShowBehind = false;

            constantDataMax.Visible = true;
            constantDataMax.ShowInLegend = true;
            constantDataMax.LegendText = "Max";
            constantDataMax.ShowBehind = false;
            constantDataMax.Color = Color.MediumVioletRed;
            constantDataMax.Title.Font = new Font("Tahoma", 9F, FontStyle.Bold);

            constantDataAvg.Visible = true;
            constantDataAvg.ShowInLegend = true;
            constantDataAvg.LegendText = "Avg";
            constantDataAvg.ShowBehind = false;
            constantDataAvg.Color = Color.LawnGreen;
            constantDataAvg.Title.Font = new Font("Tahoma", 9F, FontStyle.Bold);

            constantDataMin.Visible = true;
            constantDataMin.ShowInLegend = true;
            constantDataMin.LegendText = "Min";
            constantDataMin.ShowBehind = false;
            constantDataMin.Color = Color.BlueViolet;
            constantDataMin.Title.Font = new Font("Tahoma", 9F, FontStyle.Bold);

            // Define its axis value.
            constantLineMax.AxisValue = 60.0;
            constantLineMin.AxisValue = -10.0;
            constantDataMax.AxisValue = 0;
            constantDataAvg.AxisValue = 0;
            constantDataMin.AxisValue = 0;

            diagram.AxisY.ConstantLines.Add(constantLineMax);
            diagram.AxisY.ConstantLines.Add(constantLineMin);
            diagram.AxisY.ConstantLines.Add(constantDataMax);
            diagram.AxisY.ConstantLines.Add(constantDataAvg);
            diagram.AxisY.ConstantLines.Add(constantDataMin);

            // Axis Y
            diagram.AxisY.VisualRange.Auto = false;
            diagram.AxisY.VisualRange.AutoSideMargins = false;
            diagram.AxisY.VisualRange.StartSideMargin = 0;
            diagram.AxisY.VisualRange.EndSideMargin = 0;
            diagram.AxisY.VisualRange.MaxValue = 80.0;
            diagram.AxisY.VisualRange.MinValue = -30.0;
            diagram.AxisY.WholeRange.MaxValue = 80.0;
            diagram.AxisY.WholeRange.MinValue = -30.0;

            diagram.AxisY.NumericScaleOptions.AutoGrid = false;
            diagram.AxisY.NumericScaleOptions.GridAlignment = NumericGridAlignment.Ones;
            diagram.AxisY.NumericScaleOptions.GridOffset = 0;
            diagram.AxisY.NumericScaleOptions.GridSpacing = 5;

            diagram.AxisY.Title.Text = "Temperature(C)";
            diagram.AxisY.Title.Visibility = DevExpress.Utils.DefaultBoolean.True;
            diagram.AxisY.Title.Font = new Font("Tahoma", 9F, FontStyle.Regular);

            // Axis X
            diagram.AxisX.WholeRange.Auto = false;
            diagram.AxisX.WholeRange.MaxValue = seriesTemp.Length;
            diagram.AxisX.WholeRange.MinValue = 0;
            diagram.AxisX.VisualRange.MaxValue = seriesTemp.Length;
            diagram.AxisX.VisualRange.MinValue = 1;
            diagram.AxisX.VisualRange.Auto = false;
            diagram.AxisX.VisualRange.AutoSideMargins = false;
            diagram.AxisX.VisualRange.SideMarginsValue = 0.5;

            diagram.AxisX.GridLines.Visible = false;

            //diagram.AxisX.NumericScaleOptions.AutoGrid = false;
            diagram.AxisX.NumericScaleOptions.GridSpacing = 1D;

            diagram.AxisX.Title.Text = "Temperature No";
            diagram.AxisX.Title.Visibility = DevExpress.Utils.DefaultBoolean.False;
            diagram.AxisX.Title.Font = new Font("Tahoma", 9F, FontStyle.Regular);

            diagram.DefaultPane.BackColor = Color.FromArgb(242, 242, 242);
        }

        #endregion

        #region DISPLAY DATA

        private void tmrDisplay_Tick(object sender, EventArgs e)
        {
            if (start)
            {
                dgVoltage.Text = String.Format("{0:0.0}", Convert.ToDouble(SystemData.ValueData.voltageOfPack) / 10);
                dgAvgCellVoltage.Text = String.Format(CellDisUnit, Convert.ToDouble(SystemData.AvgData.avgCellVoltage) / CellDivUnit);
                dgDiffCellVoltage.Text = String.Format(CellDisUnit, Convert.ToDouble(SystemData.AvgData.diffCellVoltage) / CellDivUnit);
                dgAvgTemperature.Text = String.Format("{0:0.0}", Convert.ToDouble(SystemData.AvgData.avgTemp) / 10);
                dgDiffTemperature.Text = String.Format("{0:0.0}", Convert.ToDouble(SystemData.AvgData.diffTemp) / 10);
                //dgAvgTemperature.Text = String.Format("{0:0.0}", ((XYDiagram)VChart.Diagram).AxisX.VisualRange.MinValueInternal);
                //dgDiffTemperature.Text = String.Format("{0:0.0}", ((XYDiagram)VChart.Diagram).AxisX.WholeRange.MaxValueInternal);

                DisplayCellVoltage();
                DisplayCellTemperature();
                DisplayStatusAndAlarm();
                DisplayAlarm();

                lbHeatbeat.Text = String.Format("HB({0}): {1}", (SystemData.CalibriationData.ForcedBalancing.AutoB) ? 1 : 0, SystemData.heatbeat);

                //lbOneBuffTime.Text = string.Format("  OBT: {0}", SystemData.OneBuffTime);
                //lbAllBuffTime.Text = string.Format("  DCP: {0:X4}", SystemData.StatusData.batteryStatusA);

                lbOneBuffTime.Text = string.Format("  ENAB: {0:X8}", SystemData.StatusData.BalanceEnable);
                lbAllBuffTime.Text = string.Format("  MODE: {0:X8}", SystemData.StatusData.BalanceMode);
            }
        }

        private void DisplayCellVoltage()
        {
            try
            {
                for (int i = 0; i < dtVolt.Length; i++)
                {
                    dtVolt[i].Rows[0]["Value"] = Convert.ToDouble(SystemData.ValueData.CellVoltage[i]) / CellDivUnit;
                }

                //for (int i = 0; i < cellQty; i++)
                //{
                //    dtVolt[i].Rows[0]["Value"] = Convert.ToDouble(SystemData.ValueData.CellVoltage[i]) / CellDivUnit;
                //    //((SideBySideBarSeriesView)seriesVolt[i].View).BarWidth = 10.0;
                //}

                //if (SystemData.StatusData.cellBalanceFlag == 0x0001)
                //{
                    VPaletteUpdate(SystemData.StatusData.BalanceEnable, SystemData.StatusData.BalanceMode);
                //}
                //else
                //{
                //    VPaletteUpdate(0, 0);
                //}

                double maxValue = Convert.ToDouble(SystemData.AvgData.maxCellVoltage) / CellDivUnit;
                double avgValue = Convert.ToDouble(SystemData.AvgData.avgCellVoltage) / CellDivUnit;
                double minValue = Convert.ToDouble(SystemData.AvgData.minCellVoltage) / CellDivUnit;

                double balanceValue = Convert.ToDouble(SystemData.StatusData.cellBalanceValue) / CellDivUnit;

                int maxCno = Convert.ToInt32(SystemData.AvgData.maxCellNum);
                int minCno = Convert.ToInt32(SystemData.AvgData.minCellNum);

                // Cast the chart's diagram to the XYDiagram type, to access its axes.
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[2].Name =
                    String.Format("                                                             Max({0:#0.0000}V:{1:00})", maxValue, maxCno);
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[3].Name =
                    String.Format("                                  Avg({0:#0.0000}V)", avgValue);
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[4].Name =
                    String.Format("Min({0:#0.0000}V:{1:00})", minValue, minCno);

                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[5].Name =
                    String.Format("Cell Balancing ({0:#0.000}V: EndGap[{1}])"
                                    , balanceValue, SystemData.StatusData.cellBalanceEndGap);

                // Define its axis value.
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[2].AxisValue = maxValue;
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[3].AxisValue = avgValue;
                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[4].AxisValue = minValue;

                ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[5].AxisValue = balanceValue;
                if (SystemData.StatusData.cellBalanceFlag == 1)
                    ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[5].Title.TextColor = Color.Red;
                else
                    ((XYDiagram)VChart.Diagram).AxisY.ConstantLines[5].Title.TextColor = Color.Blue;

                //((XYDiagram)VChart.Diagram).AxisX.WholeRange.MinValue = 0.5;
                //((XYDiagram)VChart.Diagram).AxisX.VisualRange.MinValue = 0.5;

                //VChart.Legend.Visible = true;

                //VChart.Titles[0].Text =
                //    String.Format("Voltage Status");

                //VChart.Invalidate();
            }
            catch (Exception)
            {
                //MsgBox.ErrorShow(ex);
            }

        }
        private void DisplayCellTemperature()
        {
            try
            {
                for (int i = 0; i < seriesTemp.Length; i++)
                    seriesTemp[i].DataSource = null;

                for (int i = 0; i < dtTemp.Length; i++)
                {
                    dtTemp[i].Rows[0]["Value"] = Convert.ToDouble(SystemData.ValueData.CellTemperature[i]) / 10;
                }
                for (int i = 0; i < seriesTemp.Length; i++)
                    seriesTemp[i].DataSource = dtTemp[i];

                //for (int i = 0; i < tempQty; i++)
                //{
                //    dtTemp[i].Rows[0]["Value"] = Convert.ToDouble(SystemData.ValueData.CellTemperature[i]) / 10;
                //}

                double maxValue = Convert.ToDouble(SystemData.AvgData.maxTemp) / 10;
                double avgValue = Convert.ToDouble(SystemData.AvgData.avgTemp) / 10;
                double minValue = Convert.ToDouble(SystemData.AvgData.minTemp) / 10;
                int maxCno = Convert.ToInt32(SystemData.AvgData.maxTempNum);
                int minCno = Convert.ToInt32(SystemData.AvgData.minTempNum);

                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[2].Name = String.Format("                                                       Max({0:#0.0}C:{1:00})", maxValue, maxCno);
                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[3].Name = String.Format("                               Avg({0:#0.0}C)", avgValue);
                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[4].Name = String.Format("Min({0:#0.0}C:{1:00})", minValue, minCno);

                // Define its axis value.
                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[2].AxisValue = maxValue;
                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[3].AxisValue = avgValue;
                ((XYDiagram)TChart.Diagram).AxisY.ConstantLines[4].AxisValue = minValue;

                //TChart.Legend.Visible = true;

                //TChart.Titles[0].Text =
                //    String.Format("Temperature Status");
            }
            catch (Exception)
            {
                //MsgBox.ErrorShow(ex);
            }

        }

        private void DisplayStatusAndAlarm()
        {
            if (SystemData.CommFail == false)
            {
                if (SystemData.ShelfCommFail == false)
                {
                    switch (SystemData.StatusData.status)
                    {
                        case 0x0000:                // Stand by
                            lbStatus.Text = "STANDBY";
                            lbStatus.ForeColor = System.Drawing.Color.Black;
                            break;
                        case 0x0001:                // Charging
                            lbStatus.Text = "CHARGING";
                            lbStatus.ForeColor = System.Drawing.Color.Blue;
                            break;
                        case 0x0002:                // Discharging
                            lbStatus.Text = "DISCHARGING";
                            lbStatus.ForeColor = System.Drawing.Color.Magenta;
                            break;
                        case 0x0003:                // Float Charging
                            lbStatus.Text = "FLOATING";
                            lbStatus.ForeColor = System.Drawing.Color.Black;
                            break;
                        case 0x0004:                // Warming Up
                            lbStatus.Text = "WARMING UP";
                            lbStatus.ForeColor = System.Drawing.Color.Black;
                            break;
                        default:
                            lbStatus.Text = "UNKNOWN";
                            lbStatus.ForeColor = System.Drawing.Color.Black;
                            break;
                    }
                    // Alarm Display
                    if (SystemData.StatusData.alarm == 0)
                    {
                        lbAlarm.Text = "NORMAL";
                        lbAlarm.ForeColor = System.Drawing.Color.Green;
                    }
                    else if (SystemData.StatusData.alarm == 1)
                    {
                        lbAlarm.Text = "WARNING";
                        lbAlarm.ForeColor = System.Drawing.Color.Orange;
                    }
                    else if (SystemData.StatusData.alarm == 2)
                    {
                        lbAlarm.Text = "FAULT";
                        lbAlarm.ForeColor = System.Drawing.Color.Red;
                    }
                    else if (SystemData.StatusData.alarm == 3)
                    {
                        lbAlarm.Text = "WARMING UP";
                        lbAlarm.ForeColor = System.Drawing.Color.Green;
                    }
                    else
                    {
                        lbAlarm.Text = "UNKNOWN";
                        lbAlarm.ForeColor = System.Drawing.Color.Red;
                    }
                }
                else
                {
                    lbStatus.Text = "COMM FAIL";
                    lbStatus.ForeColor = System.Drawing.Color.Red;
                    lbAlarm.Text = "COMM FAIL";
                    lbAlarm.ForeColor = System.Drawing.Color.Red;
                }
            }
            else
            {
                lbStatus.Text = "OFF LINE";
                lbStatus.ForeColor = System.Drawing.Color.Red;
                lbAlarm.Text = "OFF LINE";
                lbAlarm.ForeColor = System.Drawing.Color.Red;
            }

            // Charge Relay Status Display
        }

        private void DisplayAlarm()
        {
            bool[] aFault = csUtils.Int16ToBitArray(SystemData.StatusData.protect);
            bool[] aWarining = csUtils.Int16ToBitArray(SystemData.StatusData.warning);
            bool aCommfail;

            if (Config.CommType == 0)
            {
                aCommfail = SystemData.ShelfCommFail;
            }
            else
            {
                aCommfail = SystemData.CommFail;
            }

            for (int i = 0; i < 6; i++)
            {
                if (aFault[i] == true)
                    alarmTrip[i].SetValue(2);
                else if (aWarining[i] == true)
                    alarmTrip[i].SetValue(1);
                else
                    alarmTrip[i].SetValue(0);
            }

            // High Temp
            if (aFault[8] || aFault[9])
                alarmTrip[6].SetValue(2);
            else if (aWarining[8] || aWarining[9])
                alarmTrip[6].SetValue(1);
            else
                alarmTrip[6].SetValue(0);

            // Low Temp
            if (aFault[10] || aFault[11])
                alarmTrip[7].SetValue(2);
            else if (aWarining[10] || aWarining[11])
                alarmTrip[7].SetValue(1);
            else
                alarmTrip[7].SetValue(0);

            // Low SOC
            if (aWarining[12] == true)
                alarmTrip[8].SetValue(1);
            else
                alarmTrip[8].SetValue(0);

            // Cell Voltage Difference
            if (aFault[14] == true)
                alarmTrip[9].SetValue(2);
            else if (aWarining[14] == true)
                alarmTrip[9].SetValue(1);
            else
                alarmTrip[9].SetValue(0);
        }

        #endregion

        #region BUTTON EVENT

        private void btnParam_Click(object sender, EventArgs e)
        {
            foreach (Form frm in Application.OpenForms)
            {
                if (frm.Name == "fmxParamConfig")
                {
                    frm.Activate();
                    return;
                }
            }
            fmxParamConfig ParamConfigForm = new fmxParamConfig(SystemId, SystemData.ParamData);

            ParamConfigForm.OnUpdate += UpdateParam;
            ParamConfigForm.OnCommand += ParamSetCmd;
            ParamConfigForm.Show();
        }

        private void btnCalibration_Click(object sender, EventArgs e)
        {
            foreach (Form frm in Application.OpenForms)
            {
                if (frm.Name == "fmxCalibration")
                {
                    frm.Activate();
                    return;
                }
            }
            fmxCalibration CalibrationForm = new fmxCalibration(SystemId, SystemData.CalibriationData);

            CalibrationForm.OnUpdate += UpdateCalibration;
            CalibrationForm.OnCommand += ParamSetCmd;
            CalibrationForm.Show();

            //VChart.ShowPrintPreview();
        }
        private void btnINV_Click(object sender, EventArgs e)
        {
            foreach (Form frm in Application.OpenForms)
            {
                if (frm.Name == "fmxInventoryConfig")
                {
                    frm.Activate();
                    return;
                }
            }
            fmxInventoryConfig InventoryConfigForm = new fmxInventoryConfig(Config, SystemId, ref SystemData);

            InventoryConfigForm.OnUpdate += UpdateInformation;
            InventoryConfigForm.OnCommand += InvDataSetCmd;
            InventoryConfigForm.Show();

            //VChart.ShowPrintPreview();
        }

        private void btnINV2_Click(object sender, EventArgs e)
        {
            foreach (Form frm in Application.OpenForms)
            {
                if (frm.Name == "fmxInventoryConfig2")
                {
                    frm.Activate();
                    return;
                }
            }
            fmxInventoryConfig2 InventoryConfig2Form = new fmxInventoryConfig2(Config, SystemId, ref SystemData, CellDivUnit);

            InventoryConfig2Form.OnUpdate += UpdateInformation2;
            InventoryConfig2Form.OnCommand += InvDataSetCmd2;
            InventoryConfig2Form.ShowDialog();

            //VChart.ShowPrintPreview();
        }

        int CbTestFlag = 0;

        private void BtnCbTest_Click(object sender, EventArgs e)
        {
            if (CbTestFlag == 0)
            {
                CbTestFlag = 1;
            }
            else if (CbTestFlag == 1)
            {
                CbTestFlag = 2;
                return;
            }
            else if (CbTestFlag == 2)
            {
                return;
            }

            BtnCbTest.Text = "Cancel";

            Config.AppPath = Application.ExecutablePath;
            Config.mSN = Encoding.Default.GetString(SystemData.Information.pcb_sn).Trim('\0');

            string alog = string.Format("\r\nCB Data Start [{0}]: {1}", Application.ProductVersion, Config.mSN);
            csLog.MakeCosoleStrLog(Config, alog);
            OnMsgPrint?.Invoke(this, alog);

            int CbTestGap = 0;
            int CbTestGapMax = 0;
            DeviceParamData aParam = SystemData.ParamData;
            DeviceCalibration wCalib = SystemData.CalibriationData.DeepCopy();

            // Auto Cell Balancing Disable
            wCalib.ForcedBalancing.AutoB = false;
            ParamSetCmd(SystemId, 1, 1, ref aParam, ref wCalib);

            int CellNo = 0;
            int CellVoltageBefore = 0;
            int CellVoltageAfter = 0;
            for (int i = 0; i < SystemData.cellQty; i++)
            {
                CellNo = i;
                CellVoltageBefore = SystemData.ValueData.CellVoltage[i];

                wCalib.ForcedBalancing.Control = 0;
                wCalib.ForcedBalancing.CellNo = (short)0;
                ParamSetCmd(SystemId, 12, 1, ref aParam, ref wCalib);

                Application.DoEvents();
                Thread.Sleep(100);

                wCalib.ForcedBalancing.Control = 2;
                wCalib.ForcedBalancing.CellNo = (short)(CellNo + 1);
                ParamSetCmd(SystemId, 12, 1, ref aParam, ref wCalib);

                CbTestGap = 0;
                for (int j = 0; j < (Config.CbTestTime / 100); j++)
                {
                    Application.DoEvents();
                    Thread.Sleep(100);
                    if (CbTestFlag == 2)
                    {
                        break;
                    }
                    if (CbTestGap < SystemData.AvgData.diffCellVoltage)
                    {
                        CbTestGap = SystemData.AvgData.diffCellVoltage;
                    }
                    if (CbTestGapMax < SystemData.AvgData.diffCellVoltage)
                    {
                        CbTestGapMax = SystemData.AvgData.diffCellVoltage;
                    }
                }
                CellVoltageAfter = SystemData.ValueData.CellVoltage[i];

                alog = string.Format("CB Test [{0:00}]: {1:0.0000} - {2:0.0000}/{3:0.0000} - {4:0.0000}"
                    , CellNo
                    , Convert.ToDouble(CbTestGap) / CellDivUnit
                    , Convert.ToDouble(CellVoltageBefore) / CellDivUnit
                    , Convert.ToDouble(CellVoltageAfter) / CellDivUnit
                    , Convert.ToDouble(CellVoltageBefore - CellVoltageAfter) / CellDivUnit
                    );
                csLog.MakeCosoleStrLog(Config, alog);
                OnMsgPrint?.Invoke(this, alog);

                int testGap;
                if (Config.TargetModelIndex == 0)
                {
                    testGap = Config.CbTestGap / 10;
                }
                else
                {
                    testGap = Config.CbTestGap;
                }
                if (CbTestGap > testGap)
                {
                    alog = string.Format("CB Test Fail - Cell No: {0}, V: {1:0.0000}", CellNo, Convert.ToDouble(CbTestGap) / CellDivUnit);
                    csLog.MakeCosoleStrLog(Config, alog);
                    OnMsgPrint?.Invoke(this, alog);
                    MessageBox.Show(string.Format("CB Test Fail - Cell No: {0}, V: {1:0.0000}", CellNo, Convert.ToDouble(CbTestGap) / CellDivUnit)
                        , "Exception"
                        , MessageBoxButtons.OK
                        , MessageBoxIcon.Error);
                    CbTestFlag = 2;
                }
                if (CbTestFlag == 2)
                {
                    alog = string.Format("CB Test Cancel");
                    csLog.MakeCosoleStrLog(Config, alog);
                    OnMsgPrint?.Invoke(this, alog);
                    break;
                }
            }
            wCalib.ForcedBalancing.Control = 0;
            wCalib.ForcedBalancing.CellNo = (short)SystemData.cellQty;
            ParamSetCmd(SystemId, 12, 1, ref aParam, ref wCalib);

            // Auto Cell Balancing Enable
            wCalib.ForcedBalancing.AutoB = true;
            wCalib.ForcedBalancing.DCP = false;
            ParamSetCmd(SystemId, 1, 1, ref aParam, ref wCalib);

            if (CbTestFlag == 1)
            {
                alog = string.Format("CB Test Pass - V: {0:0.0000}", Convert.ToDouble(CbTestGapMax) / CellDivUnit);
                csLog.MakeCosoleStrLog(Config, alog);
                OnMsgPrint?.Invoke(this, alog);
                MessageBox.Show(string.Format("CB Test Pass - Max. V: {0:0.0000}", Convert.ToDouble(CbTestGapMax) / CellDivUnit)
                    , "Exception"
                    , MessageBoxButtons.OK
                    , MessageBoxIcon.Information);
            }
            BtnCbTest.Text = "CB Test";

            CbTestFlag = 0;
        }
        #endregion

        #region COMPONENT EVENT FUNCTION
        private void UpdateParam(object sendor)
        {
            ((fmxParamConfig)sendor).UpdateData(SystemData.ParamData, SystemData.CalibriationData);
        }

        private void UpdateCalibration(object sendor)
        {
            ((fmxCalibration)sendor).UpdateData(SystemData.ParamData, SystemData.CalibriationData, SystemData);
        }

        private void UpdateInformation(object sendor)
        {
            ((fmxInventoryConfig)sendor).UpdateData(ref SystemData);
        }

        private void UpdateInformation2(object sendor)
        {
            ((fmxInventoryConfig2)sendor).UpdateData(ref SystemData);
        }

        private void ParamSetCmd(int sId, int mode, int flag, ref DeviceParamData aParam, ref DeviceCalibration aCalib)
        {
            OnCommand?.Invoke(sId, mode, flag, ref aParam, ref aCalib);
        }
        private void InvDataSetCmd(int sId, int mode, int flag, ref DeviceInforation aInvData)
        {
            SystemData.CalibriationData.InvData = aInvData;
            OnCommand?.Invoke(sId, mode, flag, ref SystemData.ParamData, ref SystemData.CalibriationData);
        }
        private void InvDataSetCmd2(int sId, int mode, int flag, ref DeviceInforation aInvData)
        {
            SystemData.CalibriationData.InvData = aInvData;
            OnCommand?.Invoke(sId, mode, flag, ref SystemData.ParamData, ref SystemData.CalibriationData);
        }
        #endregion
    }
}
