//-----------------------------------------------------------------------
// 
//     Copyright © 2012 Nils Hammar. All rights reserved.
// 
//-----------------------------------------------------------------------
/*
 * Software to access vehicle information via the OBD-II connector.
 * 
 * Copyright © 2012 Nils Hammar
 * 
 * This program 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 .
 * 
 * Alternative licensing is possible, see the licensing document.
 * 
 * The above text may not be removed or modified.
 */
namespace Gauges
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
    using global::Gauges.TelltalePanel;
    using global::SharedObjects.DataMgmt;
    using global::SharedObjects.Misc;
    /// 
    /// Class for editing details for a telltale.
    /// 
    public partial class TelltaleDetails : Form
    {
        /// 
        /// Gets telltale item instance.
        /// 
        public XmlClass.telltaleitem telltaleitem { get; private set; }
        /// 
        /// Gets PID name.
        /// 
        public string pidName { get; private set; }
        /// 
        /// Gets Sensor name.
        /// 
        public string sensorName { get; private set; }
        /// 
        /// Gets Sensor bit.
        /// 
        public int sensorBit { get; private set; }
        /// 
        /// Gets PID name.
        /// 
        public string digitalPidName { get; private set; }
        /// 
        /// List of PID groups.
        /// 
        private IList pidgrouplist;
        /// 
        /// List of PIDs in PID Group with bit sensors.
        /// 
        private IList pidgrouppids;
        /// 
        /// List of sensors on current PID.
        /// 
        private IList pidsensors;
        /// 
        /// Current PID group.
        /// 
        private XmlClass.pidgroup pidgroup;
        /// 
        /// Current PID.
        /// 
        private XmlClass.pidgroup.pidlist pid;
        /// 
        /// Current sensor.
        /// 
        private XmlClass.pidgroup.pidlist.sensordata sensor;
        /// 
        /// Array of used telltales, used to avoid double-booking telltales.
        /// 
        private uint[] usedItems;
        /// 
        /// Current data source instance.
        /// 
        private IDataSource iDataSource;
        /// 
        /// Data file directory path.
        /// 
        private string dataFileDir;
        /// 
        /// Current color palette.
        /// 
        private PaletteCreator palette;
        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// Data file directory.
        /// Data source instance.
        /// Telltale item.
        /// Array of used telltales, used to avoid double-booking telltales.
        /// Initial color palette.
        public TelltaleDetails(
            string dataFileDir,
            IDataSource iDataSource,
            XmlClass.telltaleitem telltaleitem,
            uint[] usedItems,
            PaletteCreator palette)
        {
            this.dataFileDir = dataFileDir;
            this.iDataSource = iDataSource;
            this.telltaleitem = telltaleitem;
            this.usedItems = usedItems;
            this.palette = palette;
            this.sensorBit = -1;
            IList providedPidGroups = this.iDataSource.restrictedPidgroups;
            this.pidgrouplist = new List();
            if (this.telltaleitem == null)
            {
                this.telltaleitem = new XmlClass.telltaleitem();
            }
            this.InitializeComponent();
            this.pidgrouppids = new List();
            for (int i1 = -99; i1 < 100; i1++)
            {
                this.priorityComboBox.Items.Add(i1.ToString());
            }
            this.priorityComboBox.SelectedIndex = 99 + this.telltaleitem.telltalePriority;
            this.telltaleGroupNumTB.Text = this.telltaleitem.telltaleGroupNumber.ToString();
            this.telltaleTextTB.Text = this.telltaleitem.telltaletext;
            this.pidGroupsCB.Items.Clear();
            this.itemCB.Items.Clear();
            this.sensorLB.Items.Clear();
            this.pidGroupsCB.SelectedIndex = -1;
            int pidGrpIx = -1;
            int i = 0;
            foreach (XmlClass.pidgroup pidGrp in providedPidGroups)
            {
                bool hasBit = false;
                if (pidGrp.pids != null)
                {
                    foreach (XmlClass.pidgroup.pidlist pid in pidGrp.pids)
                    {
                        if (pid != null)
                        {
                            foreach (XmlClass.pidgroup.pidlist.sensordata sensor in pid.sensors)
                            {
                                if (sensor.unit == "bit")
                                {
                                    hasBit = true;
                                    break;
                                }
                            }
                        }
                        if (hasBit)
                        {
                            break;
                        }
                    }
                }
                if (hasBit)
                {
                    this.pidGroupsCB.Items.Add(pidGrp.name);
                    this.pidgrouplist.Add(pidGrp);
                    if (this.telltaleitem != null
                        && this.telltaleitem.pidgroupid == pidGrp.id)
                    {
                        pidGrpIx = i;
                    }
                    i++;
                }
            }
            if (this.pidGroupsCB.Items.Count > 0)
            {
                if (pidGrpIx >= 0 && pidGrpIx < this.pidGroupsCB.Items.Count)
                {
                    this.pidGroupsCB.SelectedIndex = pidGrpIx;
                }
                else
                {
                    this.pidGroupsCB.SelectedIndex = 0;
                }
            }
            this.setIconImage(this.telltaleitem.telltaleicon);
            if (this.telltaleitem != null)
            {
                this.primaryColorBox.BackColor = string.IsNullOrEmpty(this.telltaleitem.primaryColor) ? Color.Transparent : Color.FromName(this.telltaleitem.primaryColor);
                this.secondaryColorBox.BackColor = string.IsNullOrEmpty(this.telltaleitem.secondaryColor) ? Color.Transparent : Color.FromName(this.telltaleitem.secondaryColor);
                this.flashColorBox.BackColor = string.IsNullOrEmpty(this.telltaleitem.flashColor) ? Color.Transparent : Color.FromName(this.telltaleitem.flashColor);
            }
            else
            {
                this.primaryColorBox.BackColor = Color.Transparent;
                this.secondaryColorBox.BackColor = Color.Transparent;
                this.flashColorBox.BackColor = Color.Transparent;
            }
        }
        /// 
        /// Numeric validation of input data.
        /// 
        /// Sending object.
        /// Event data.
        /// Parsed numeric value.
        private static uint numericIntValidation(object sender, CancelEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            uint scaleSteps = 0;
            try
            {
                scaleSteps = Convert.ToUInt32(tb.Text);
            }
            catch
            {
                MessageBox.Show(
                    "Field must be numeric.",
                    "Data Failure",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);
                e.Cancel = true;
            }
            return scaleSteps;
        }
        /// 
        /// Test for float value.
        /// 
        /// Sending object.
        /// Event data.
        /// Parsed float value.
        private static float numericFloatValidation(object sender, CancelEventArgs e)
        {
            TextBox tb = (TextBox)sender;
            float value = 0;
            try
            {
                value = Convert.ToSingle(tb.Text);
            }
            catch
            {
                MessageBox.Show(
                    "Field must be numeric.",
                    "Data Failure",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);
                e.Cancel = true;
            }
            return value;
        }
        /// 
        /// PidGroup checkbox change.
        /// 
        /// Current PID group.
        /// Combobox that changed.
        /// List of valid PID groups.
        /// Offset value in combo box index.
        /// New PID group or 'null' if not applicable.
        private static XmlClass.pidgroup pidGroupChange(
            XmlClass.pidgroup pidgroup,
            ComboBox cb,
            IList pidgrouplist,
            int offset)
        {
            if (cb.SelectedIndex >= offset && cb.SelectedIndex < cb.Items.Count)
            {
                pidgroup = pidgrouplist[cb.SelectedIndex - offset];
            }
            else
            {
                if (offset == 1)
                {
                    pidgroup = null;
                }
            }
            return pidgroup;
        }
        /// 
        /// Update Item Combo Box.
        /// 
        /// Current PID group.
        /// Items combobox.
        /// PID value.
        /// Actual available list of PIDs in PID group. (out data)
        private static void updateItemCB(XmlClass.pidgroup pidgroup, ComboBox itemCB, uint telltalePid_int, IList pidgrouppids)
        {
            int pidIx = -1;
            int i = 0;
            foreach (XmlClass.pidgroup.pidlist pidItem in pidgroup.pids)
            {
                bool hasBit = false;
                foreach (XmlClass.pidgroup.pidlist.sensordata sensor in pidItem.sensors)
                {
                    if (sensor.unit == "bit")
                    {
                        hasBit = true;
                        break;
                    }
                }
                if (hasBit)
                {
                    itemCB.Items.Add(pidItem.name);
                    pidgrouppids.Add(pidItem);
                    if (telltalePid_int == pidItem.pid_int)
                    {
                        pidIx = i;
                    }
                    i++;
                }
            }
            if (pidIx >= 0 && pidIx < itemCB.Items.Count)
            {
                itemCB.SelectedIndex = pidIx;
            }
            else
            {
                if (itemCB.Items.Count > 0)
                {
                    itemCB.SelectedIndex = 0;
                }
            }
        }
        /// 
        /// Change data for item combo box.
        /// 
        /// Item combo box instance.
        /// Sensor combo box instance.
        /// List of current PIDs supporting telltales.
        /// Telltale item instance.
        /// Selected PID.
        /// List of valid sensors for selected pid.
        /// PID name.
        private static string itemCbChange(
            ComboBox cb,
            ListBox sensorCB,
            IList pids,
            XmlClass.telltaleitem telltaleitem,
            ref XmlClass.pidgroup.pidlist pid,
            IList pidsensors)
        {
            string pidName = string.Empty;
            sensorCB.Items.Clear();
            pid = pids[cb.SelectedIndex];
            pidName = pid.name;
            int sensorIx = -1;
            int i = 0;
            foreach (XmlClass.pidgroup.pidlist.sensordata sensorItem in pid.sensors)
            {
                try
                {
                    if (sensorItem.unit == "bit")
                    {
                        string sensorInfo = string.Empty;
                        if (sensorItem.name != null)
                        {
                            sensorInfo += sensorItem.name + " ";
                        }
                        sensorInfo += "(" + sensorItem.unit + ")";
                        sensorCB.Items.Add(sensorInfo);
                        pidsensors.Add(sensorItem);
                        int sensorBit = Convert.ToInt32(sensorItem.startbit);
                        if (telltaleitem != null
                            && telltaleitem.sensor_unit != null
                            && telltaleitem.sensor_unit.Equals(sensorItem.unit)
                            && telltaleitem.sensor_offset == sensorItem.offset
                            && (sensorBit == -1 || telltaleitem.sensor_bit == sensorBit))
                        {
                            sensorIx = i;
                        }
                        i++;
                    }
                }
                catch
                {
                }
            }
            if (sensorIx >= 0 && sensorIx < sensorCB.Items.Count)
            {
                sensorCB.SelectedIndex = sensorIx;
            }
            else
            {
                if (sensorCB.Items.Count > 0)
                {
                    sensorCB.SelectedIndex = 0;
                }
            }
            return pidName;
        }
        /// 
        /// OK button clicked.
        /// 
        /// Sending object.
        /// Event data.
        private void okButton_Click(object sender, EventArgs e)
        {
            if (this.primaryColorBox.BackColor != Color.Transparent
                && this.secondaryColorBox.BackColor != Color.Transparent
                && this.flashColorBox.BackColor != Color.Transparent)
            {
                this.telltaleitem.pidgroupid = this.pidgroup.id;
                this.telltaleitem.pid_int = this.pid.pid_int;
                this.telltaleitem.sensor_unit = this.sensor.unit;
                this.telltaleitem.sensor_offset = this.sensor.offset;
                this.telltaleitem.sensor_bit = this.sensorBit;
                this.telltaleitem.telltaletext = this.telltaleTextTB.Text;
                this.telltaleitem.telltalePriority = this.priorityComboBox.SelectedIndex - 99;
                this.telltaleitem.primaryColor = this.primaryColorBox.BackColor.Name;
                this.telltaleitem.secondaryColor = this.secondaryColorBox.BackColor.Name;
                this.telltaleitem.flashColor = this.flashColorBox.BackColor.Name;
                this.DialogResult = DialogResult.OK;
                this.Close();
            }
            else
            {
                MessageBox.Show("Colors must be assigned.", "Incomplete Configuration.", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
        /// 
        /// Cancel button clicked.
        /// 
        /// Sending object.
        /// Event data.
        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }
        /// 
        /// PID group changed.
        /// 
        /// Sending object.
        /// Event data.
        private void pidGroupsCB_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.pidgroup = pidGroupChange(
                this.pidgroup,
                (ComboBox)sender,
                this.pidgrouplist,
                0);
            this.itemCB.Items.Clear();
            this.sensorLB.Items.Clear();
            this.pidName = string.Empty;
            this.pidgrouppids = new List();
            if (this.pidgroup != null)
            {
                updateItemCB(this.pidgroup, this.itemCB, this.telltaleitem.pid_int, this.pidgrouppids);
            }
            this.setOkButtonEnable();
        }
        /// 
        /// Check if conditions are right to enable the OK button and enable it if that's the case.
        /// 
        private void setOkButtonEnable()
        {
            this.okButton.Enabled =
                (this.pidgroup != null)
                && (this.pid != null)
                && (this.sensor != null)
                && !string.IsNullOrEmpty(this.telltaleitem.telltaleicon);
        }
        /// 
        /// Item combo box changed.
        /// 
        /// Sending object.
        /// Event data.
        private void itemCB_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            if (this.pidgroup != null
                && cb.SelectedIndex >= 0
                && cb.SelectedIndex < cb.Items.Count
                && cb.SelectedIndex < this.pidgrouppids.Count)
            {
                this.pidsensors = new List();
                this.pidName = itemCbChange(cb, this.sensorLB, this.pidgrouppids, this.telltaleitem, ref this.pid, this.pidsensors);
            }
            this.setOkButtonEnable();
        }
        /// 
        /// Sensor list box changed.
        /// 
        /// Sending object.
        /// Event data.
        private void sensorLB_SelectedIndexChanged(object sender, EventArgs e)
        {
            ListBox cb = (ListBox)sender;
            if (cb.SelectedIndex >= 0 && cb.SelectedIndex < this.sensorLB.Items.Count)
            {
                this.sensor = this.pidsensors[cb.SelectedIndex];
                this.sensorName = cb.Text;
                this.sensorBit = -1;
                try
                {
                    this.sensorBit = Convert.ToInt32(this.sensor.startbit);
                }
                catch
                {
                }
            }
            this.setOkButtonEnable();
        }
        /// 
        /// Sensor combo box changed.
        /// 
        /// Sending object.
        /// Event data.
        private void sensorCB_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            if (cb.SelectedIndex >= 0 && cb.SelectedIndex < this.itemCB.Items.Count)
            {
                this.sensor = this.pid.sensors[cb.SelectedIndex];
                this.sensorName = cb.Text;
                this.sensorBit = -1;
                try
                {
                    this.sensorBit = Convert.ToInt32(this.sensor.startbit);
                }
                catch
                {
                }
                this.telltaleitem.sensor_bit = this.sensorBit;
            }
            this.setOkButtonEnable();
        }
        /// 
        /// Select telltale.
        /// 
        /// Sending object.
        /// Event data.
        private void button1_Click(object sender, EventArgs e)
        {
            TelltaleAreaSelector gs = new TelltaleAreaSelector(this.telltaleitem.telltaleGroupNumber, this.usedItems);
            try
            {
                if (gs.ShowDialog() == System.Windows.Forms.DialogResult.OK && gs.selectedItem != null)
                {
                    this.telltaleitem.telltaleGroupNumber = (uint)gs.selectedItem;
                    this.telltaleGroupNumTB.Text = this.telltaleitem.telltaleGroupNumber.ToString();
                }
            }
            finally
            {
                gs.Dispose();
            }
        }
        /// 
        /// Update the icon.
        /// 
        /// Sending object.
        /// Event data.
        private void selectIconButton_Click(object sender, EventArgs e)
        {
            TelltaleIconSelector telltaleIconSelector = new TelltaleIconSelector(this.dataFileDir, this.iDataSource, this.telltaleitem.telltaleicon);
            try
            {
                if (telltaleIconSelector.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    string newFile = telltaleIconSelector.selectedIcon;
                    try
                    {
                        this.setIconImage(newFile);
                        this.telltaleitem.telltaleicon = newFile;
                    }
                    finally
                    {
                        this.setOkButtonEnable();
                    }
                }
            }
            finally
            {
                telltaleIconSelector.Dispose();
            }
        }
        /// 
        /// Set the image.
        /// 
        /// Icon image file name.
        private void setIconImage(string newFile)
        {
            if (newFile != null)
            {
                try
                {
                    Image img = Image.FromFile(this.dataFileDir + "Icons\\" + newFile);
                    float scale = 0.9F;
                    int height = this.iconPictureBox.Height;
                    int width = this.iconPictureBox.Width;
                    Bitmap bmp = Utils.getScaledImage(img, height, width, scale);
                    this.iconPictureBox.Image = bmp;
                }
                catch
                {
                    MessageBox.Show(
                        "Unable to open icon file '" + this.dataFileDir + "Icons\\" + newFile + "'",
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Hand);
                }
            }
        }
        /// 
        /// Color button clicked.
        /// 
        /// Sending object.
        /// Event data.
        private void primaryColorButton_Click(object sender, EventArgs e)
        {
            using (ColorSelector colorSelector = new ColorSelector(this.primaryColorBox.BackColor, this.palette))
            {
                if (colorSelector.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.primaryColorBox.BackColor = colorSelector.Color;
                }
            }
        }
        /// 
        /// Color button clicked.
        /// 
        /// Sending object.
        /// Event data.
        private void secondaryColorButton_Click(object sender, EventArgs e)
        {
            using (ColorSelector colorSelector = new ColorSelector(this.secondaryColorBox.BackColor, this.palette))
            {
                if (colorSelector.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.secondaryColorBox.BackColor = colorSelector.Color;
                }
            }
        }
        /// 
        /// Color button clicked.
        /// 
        /// Sending object.
        /// Event data.
        private void flashColorButton_Click(object sender, EventArgs e)
        {
            using (ColorSelector colorSelector = new ColorSelector(this.flashColorBox.BackColor, this.palette))
            {
                if (colorSelector.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    this.flashColorBox.BackColor = colorSelector.Color;
                }
            }
        }
    }
}