using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using CustomForms;
using OBD;
using PostWin;
using Steema.TeeChart;
using Steema.TeeChart.Styles;
using TD.SandDock;
using TD.SandDock.Rendering;
using ThreadSafe;
using XMLRoutines;

namespace OBD_PCScanner
{
	public partial class MainFormPCScanner : Form
	{
		private LogEventList EventList;
		private readonly HOBD OBD;
		private readonly string ProgramDir;
		private readonly string LogsDir;
		private readonly string AppSettingsFName;
		private readonly LogStorage Log = new LogStorage();
		private NotifyForm NF;
		private InputForm IF;
		private LampsForm FrmLamps;
		private Random r = new Random();
		private AppSettings FS = null;
		private int LastVisualUpdateTime;

		public MainFormPCScanner()
		{
			CultureInfo ci = new CultureInfo(Application.CurrentCulture.Name);
			ci.NumberFormat.NumberDecimalSeparator = ".";
			Application.CurrentCulture = ci;
			AppSettingsFName = ProgramDir + "AppSettings.xml";
			ProgramDir = Application.StartupPath + "\\";
			LogsDir = ProgramDir + "\\LogStorage\\";
			InitializeComponent();
			toolStrip.ImageList = BtnImageList;
			StatusBar.ImageList = BtnImageList;
			SeriesOxygen.Color = Color.Blue;
			SeriesRPM.Color = Color.Green;
			SeriesECT.Color = Color.FromArgb(192, 192, 255);
			SeriesIAT.Color = Color.FromArgb(192, 255, 255);
			SeriesMAP.Color = Color.Yellow;
			SeriesVSS.Color = Color.Red;
			SeriesInjTime.Color = Color.LightGreen;
			SeriesCorrCT.Color = Color.Magenta;
			SeriesCorrLT.Color = Color.LightPink;
			SeriesOxygen.IgnoreNulls = true;
			SeriesRPM.IgnoreNulls = true;
			SeriesECT.IgnoreNulls = true;
			SeriesIAT.IgnoreNulls = true;
			OBD = new HOBD(ProgramDir) { Log = Log };
			CheckDirs();
			//int res = WinTimers.timeBeginPeriod(1);
		}
		
		private void CheckDirs()
		{
			try
			{
				if (!Directory.Exists(LogsDir))
					Directory.CreateDirectory(LogsDir);
			}catch
			{
				Log.ErrorString = "Ошибка создания каталога сохранения данных";
			}
		}

		private void timer_Tick(object sender, EventArgs e)
		{
			UpdateButtons();
			CheckLog();
			UpdateSeries();
			UpdateFlags();
			UpdateErrorCodes();
			UpdateSensors();
			UpdateEngineState();
		}

		private static void AddValueToSeries(Series s, double xx, double yy, Color c)
		{
			if (s != null)
			{
				if (s.XValues.Count > 0)
				{
					double d = s.XValues[s.XValues.Count - 1];
					if (Math.Abs((xx - d)) >= 3000)
						s.Add(xx, yy, Color.Transparent);
				}
				s.Add(xx, yy, c);
			}
		}

		private void UpdateSeries()
		{
			if (OBD == null)
				return;
			if (!OBD.Params.PaintCharts)
				return;
			if (OBD.Status.CountStatItems == 0)
				return;
			bool Updated = false;
			SensorsState s = OBD.Status.SensState;
			if (OBD.Status.CountStatItems > 0)
			{
				OBDAnswerItem[] answers = OBD.Status.GetAllStatItems();
				for (int ansInd = 0; ansInd < answers.Length; ansInd++ )
					try
					{
						OBDAnswerItem ss = answers[ansInd];
						if (ss != null)
						{
							Updated = true;
							double xx = ss.AnsTime;
							double yy;
							switch (ss.AnsType)
							{
								case OBDAnswerItemType.O2:
									if (OBD.Params.O2Method == O2CalcMethod.Oxygen)
										yy = OBDHelper.FormulaO2StockLambda((byte)ss.Value);
									else
									{
										yy = OBDHelper.FormulaLAFSensor((byte)ss.Value);
										if (!OxygenAxis.AutomaticMaximum)
											OxygenAxis.AutomaticMaximum = true;
									}
									s.NewO2 = yy;
									AddValueToSeries(SeriesOxygen, xx, yy, Color.Blue);
									break;
								case OBDAnswerItemType.RPM:
									yy = OBDHelper.FormulaRPM(ss.Value, OBD.Params.RMPMethod, OBD.Params.InverseHiLoOrder);
									s.NewRPM = yy;
									if (!double.IsNaN(s.NewInjTime))
										s.NewDutyCycle = OBDHelper.FormulaDutyCycle(s.NewRPM, s.NewInjTime);
									AddValueToSeries(SeriesRPM, xx, yy, Color.Green);
									break;
								case OBDAnswerItemType.ECT:
									yy = OBDHelper.FormulaTempInCelsius((byte)ss.Value);
									s.NewECT = yy;
									AddValueToSeries(SeriesECT, xx, yy, SeriesECT.Color);
									break;
								case OBDAnswerItemType.IAT:
									yy = OBDHelper.FormulaTempInCelsius((byte)ss.Value);
									s.NewIAT = yy;
									AddValueToSeries(SeriesIAT, xx, yy, SeriesIAT.Color);
									break;
								case OBDAnswerItemType.Bat:
									yy = OBDHelper.FormulaBAT((byte)ss.Value);
									s.NewBat = yy;
									break;
								case OBDAnswerItemType.ALTF:
									yy = ss.Value;
									break;
								case OBDAnswerItemType.CorrCT:
									yy = OBDHelper.Formula_CT_LT_Correction((byte)ss.Value);
									AddValueToSeries(SeriesCorrCT, xx, yy, SeriesCorrCT.Color);
									s.NewCorrCT = yy;
									break;
								case OBDAnswerItemType.CorrLT:
									yy = OBDHelper.Formula_CT_LT_Correction((byte)ss.Value);
									AddValueToSeries(SeriesCorrLT, xx, yy, SeriesCorrLT.Color);
									s.NewCorrLT = yy;
									break;
								case OBDAnswerItemType.IAC:
									yy = ss.Value;
									s.NewIAC = yy;
									break;
								case OBDAnswerItemType.InjTime:
									yy = OBDHelper.FormulaInjTimeCalc(ss.Value, OBD.Params.InverseHiLoOrder);
									AddValueToSeries(SeriesInjTime, xx, yy, SeriesInjTime.Color);
									s.NewInjTime = yy;
									if (!double.IsNaN(s.NewRPM))
										s.NewDutyCycle = OBDHelper.FormulaDutyCycle(s.NewRPM, s.NewInjTime);
									break;
								case OBDAnswerItemType.InjAdv1_FAngle:
									yy = OBDHelper.FormulaIngAdv1FAngle((byte)ss.Value);
									s.NewIngFAngle = yy;
									break;
								case OBDAnswerItemType.InjAdv2:
									yy = ss.Value;
									s.NewIngAdv2 = yy;
									break;
								case OBDAnswerItemType.Knock:
									yy = ss.Value;
									s.NewKnock = yy;
									break;
								case OBDAnswerItemType.MAP:
									yy = OBDHelper.FormulaMAPInBar((byte)ss.Value);
									AddValueToSeries(SeriesMAP, xx, yy, SeriesMAP.Color);
									s.NewMAP = yy;
									break;
								case OBDAnswerItemType.PA:
									yy = OBDHelper.FormulaBaroAPInBar((byte)ss.Value);
									s.NewBaro = yy;
									break;
								case OBDAnswerItemType.TPS:
									yy = OBDHelper.FormulaTPS((byte)ss.Value);
									s.NewTPS = yy;
									s.NewTPSVolt = OBDHelper.volts[(byte)ss.Value];
									break;
								case OBDAnswerItemType.VSS:
									yy = ss.Value;
									AddValueToSeries(SeriesVSS, xx, yy, SeriesVSS.Color);
									//yy = r.Next(240);
									s.NewVss = yy;
									break;
								case OBDAnswerItemType.UnknownAnswer:
									//Log.ErrorString = "Получено неизвестное значение статистики: " + ss.Value;
									break;
							}
						}
					}
					catch
					{
					}
				if (Updated)
				{
					try
					{
						if (ZoomSpan > 0)
						{
							ScrollBarSeries.Maximum = (int) SensorsChart.Axes.Bottom.MaxXValue;
							if (OBD.Params.ScrollChartIfSelected)
								ScrollBarSeries.Value = (int) (ScrollBarSeries.Maximum - ZoomSpan * 0.8);
						}
					}catch
					{}
				}
			}
		}

		private void UpdateSensors()
		{
			if (OBD == null)
				return;
			Color c;
			string str;
			SensorsState s = OBD.Status.SensState;
			if (!double.IsNaN(s.NewBaro))
			{

			}
			if (!double.IsNaN(s.NewBat))
			{
				c = Color.Green;
				if (s.NewBat < 12)
					c = Color.Red;
				else if (s.NewBat > 12 && s.NewBat < 14)
					c = Color.Yellow;
				else if (s.NewBat > 14.8)
					c = Color.Red;
				if (LblBATValue.ForeColor != c)
					LblBATValue.ForeColor = c;
				str = s.NewBat.ToString("0.0");
				if (LblBATValue.Text != str)
					LblBATValue.Text = str;
			}
			if (!double.IsNaN(s.NewCorrCT))
			{
				str = s.NewCorrCT.ToString("0.0");
				if (SensorCorrCT.Value != (int) s.NewCorrCT)
					SensorCorrCT.Value = (int) s.NewCorrCT;
				if (SensorCorrCT.Text != str)
					SensorCorrCT.Text = str;
			}
			if (!double.IsNaN(s.NewCorrLT))
			{
				str = s.NewCorrLT.ToString("0.0");
				if (SensorCorrLT.Value != (int) s.NewCorrLT)
					SensorCorrLT.Value = (int) s.NewCorrLT;
				if (SensorCorrLT.Text != str)
					SensorCorrLT.Text = str;
			}
			if (!double.IsNaN(s.NewECT))
			{
				if (SensorECT.Value != (int) s.NewECT)
					SensorECT.Value = (int) s.NewECT;
				str = s.NewECT.ToString("0");
				if (LblSensorECTValue.Text != str)
					LblSensorECTValue.Text = str;
			}
			if (!double.IsNaN(s.NewIAT))
			{
				if (SensorIAT.Value != (int) s.NewIAT)
					SensorIAT.Value = (int) s.NewIAT;
				str = s.NewIAT.ToString("0");
				if (LblSensorIATValue.Text != str)
					LblSensorIATValue.Text = str;
			}
			if (!double.IsNaN(s.NewIAC))
			{

			}
			if (!double.IsNaN(s.NewIngAdv2))
			{

			}
			if (!double.IsNaN(s.NewIngFAngle))
			{
				str = s.NewIngFAngle.ToString("0.0") + "°";
				if (SensorIngForward.Value != s.NewIngFAngle)
					SensorIngForward.Value = (int)s.NewIngFAngle;
				if (SensorIngForward.Text != str)
					SensorIngForward.Text = str;
			}
			if (!double.IsNaN(s.NewInjTime))
			{
				str = s.NewInjTime.ToString("0.#");
				if (LblInjTimeValue.Text != str)
					LblInjTimeValue.Text = str;
			}
			if (!double.IsNaN(s.NewKnock))
			{

			}
			if (!double.IsNaN(s.NewMAP))
			{
				if (SensorMAP.Value != (int) s.NewMAP)
					SensorMAP.Value = (int) s.NewMAP;
				str = s.NewMAP.ToString("0");
				if (LblSensorMapValue.Text != str)
					LblSensorMapValue.Text = str;
			}
			if (!double.IsNaN(s.NewO2))
			{
				str = s.NewO2.ToString("0.##");
				if (LblO2Value.Text != str)
					LblO2Value.Text = str;
			}
			if (!double.IsNaN(s.NewTPS))
			{
				str = s.NewTPS.ToString("0") + "%, " + s.NewTPSVolt.ToString("0.##") + "v";
				if (SensorTPS.Value != (int)s.NewTPS)
				{
					SensorTPS.Value = s.NewTPS>0 ? (int) s.NewTPS : 0;
				}
				if (LblTPSValue.Text != str)
					LblTPSValue.Text = str;
			}
			if (!double.IsNaN(s.NewRPM))
			{
				if (SensorRPM.Value != (int) s.NewRPM / 100)
				{
					SensorRPM.Value = (int) s.NewRPM / 100;
				}
				str = s.NewRPM.ToString("0");
				if (SensorRPM.TextFooter != str)
				{
					SensorRPM.TextFooter = str;
				}
			}
			if (!double.IsNaN(s.NewVss))
			{
				if (SensorVSS.Value != s.NewVss)
				{
					SensorVSS.Value = (int) s.NewVss;
				}
				str = s.NewVss.ToString("0");
				if (SensorVSS.TextFooter != str)
				{
					SensorVSS.TextFooter = str;
				}
			}
			if(!double.IsNaN(s.NewDutyCycle))
			{
				str = s.NewDutyCycle.ToString("0.0");
				if (LblDutyCycleValue.Text != str)
					LblDutyCycleValue.Text = str;
				c = Color.Green;
				if (s.NewDutyCycle > 80)
					c = Color.Red;
				if (LblDutyCycleValue.ForeColor != c)
					LblDutyCycleValue.ForeColor = c;
			}
			s.ApplyNew();
		}
		private void UpdateEngineState()
		{
			if (OBD == null)
				return;
			bool TimeToUpdate = Math.Abs(Environment.TickCount - LastVisualUpdateTime) > 1000;
			if ((OBD.Status.ChStateFlag & ChangeStateFlag.NewEngineState) != 0 || TimeToUpdate)
			{
				LastVisualUpdateTime = Environment.TickCount;
				OBD.Status.ChStateFlag &= ~ChangeStateFlag.NewEngineState;
				double d = OBD.Status.EngineState.GetTotalLengthPath();
				if (SensorOdometr.Value != (int)(d * 10))
					SensorOdometr.Value = (int)(d * 10);
				string s;
				d = OBD.Status.EngineState.MomentumLiters100;
				s ="Литры на 100 км: " + (!double.IsNaN(d) ? d.ToString("0.##") : "- - -");
				if (LblESLitersPer100Momentum.Text != s)
					LblESLitersPer100Momentum.Text = s;
				d = OBD.Status.EngineState.MomentumLitersHour;
				s = "Литры в час: " + (!double.IsNaN(d) ? d.ToString("0.##") : "- - -");
				if (LblESLitersPerHour.Text != s)
					LblESLitersPerHour.Text = s;
				d = OBD.Status.EngineState.GetAverageLitersPer100();
				s = "Литры на 100 ср.: " + (!double.IsNaN(d) ? d.ToString("0.##") : "- - -");
				if (LblESLitersPer100Average.Text != s)
					LblESLitersPer100Average.Text = s;
				d = OBD.Status.EngineState.GetTotalLiters();
				s = "Литров всего: " + d.ToString("0.#");
				if (LblESLitersTotal.Text != s)
					LblESLitersTotal.Text = s;
				d = (OBD.Status.EngineState.CorrectionLiters*100);
				s = "Коррекция расхода: " + (d ).ToString("0.##") + " %";
				if (LblESCorrInjPercent.Text != s)
					LblESCorrInjPercent.Text = s;
				d = (OBD.Status.EngineState.CorrectionVSS * 100);
				s = "Коррекция пробега: " + (d).ToString("0.##") + " %";
				if (LblESCorrVSSPercent.Text != s)
					LblESCorrVSSPercent.Text = s;
			}
		}

		private void UpdateButtons()
		{
			if (OBD == null)
				return;
			string s = OBD.Status.StateStr;
			if (LblStatus.Text != s)
				LblStatus.Text = s;
			bool b = OBD.Status.State != HOBDState.Connecting && !OBD.Status.FileOperationActive;
			if (ConnectBtn.Enabled != b)
				ConnectBtn.Enabled = b;
			b = OBD.Status.State == HOBDState.Disconnected && !OBD.Status.FileOperationActive;
			if (MenuItemLoadLog.Enabled != b)
				MenuItemLoadLog.Enabled = b;
			if (MenuItemSaveLog.Enabled != b)
				MenuItemSaveLog.Enabled = b;
			if (BtnLoadSave.Enabled != b)
				BtnLoadSave.Enabled = b;
			b = OBD.Status.State == HOBDState.Disconnected;
			if (LblComPort.Enabled != b)
				LblComPort.Enabled = b;
			if (ComboCOMPort.Enabled != b)
				ComboCOMPort.Enabled = b;
			bool pressed = !(OBD.Status.State == HOBDState.Disconnected);

			if (ConnectBtn.Checked != pressed)
			{
				if (pressed)
				{
					ConnectBtn.Text = "Отключиться от устройства";
					ConnectBtn.Image = BtnImageList.Images[2];
				}
				else
				{
					ConnectBtn.Text = "Подключиться к устройству";
					ConnectBtn.Image = BtnImageList.Images[3];
				}
				ConnectBtn.Checked = pressed;
			}
			if (BtnClearStat.ImageIndex != 1)
				BtnClearStat.ImageIndex = 1;
			b = OBD != null && OBD.CommandsAnswersHistory != null && OBD.CommandsAnswersHistory.list.Count > 0;
			if (BtnClearStat.Enabled != b)
				BtnClearStat.Enabled = b;
			int activity = OBD != null && OBD.ActivityVisible ? 7 : 8;
			if (LblStatus.ImageIndex != activity)
				LblStatus.ImageIndex = activity;
			if (OBD != null)
			{
				switch (OBD.Params.ReadMode)
				{
					case ReadMode.All:
						if (!RBtnLogAllData.Checked)
							RBtnLogAllData.Checked = true;
						break;
					case ReadMode.Fast_60h:
						if (!RBtnLogFast.Checked)
							RBtnLogFast.Checked = true;
						break;
					case ReadMode.Custom:
						if (!RBtnLogCustom.Checked)
							RBtnLogCustom.Checked = true;
						break;
				}
				b = OBD.Params.ReadMode == ReadMode.Custom;
			}
			if (TBoxOBDCustomModeText.Visible != b)
				TBoxOBDCustomModeText.Visible = b;
			if (b)
			{
				b = OBD.Status.State == HOBDState.Disconnected;
				if (TBoxOBDCustomModeText.Enabled != b)
					TBoxOBDCustomModeText.Enabled = b;
			}
			s = OBD.Status.IdECU;
			if (!String.IsNullOrEmpty(s))
			{
				if (!string.IsNullOrEmpty(OBD.Status.StringAPPTitle))
					s = string.Format("H OBD Id:[{0}] Log file: {1}", s, OBD.Status.StringAPPTitle);
				else
					s = string.Format("H OBD Id:[{0}]", s);
				
				if (Text != s)
					Text = s;
			}
			b = OBD.Status.State == HOBDState.Connected;
			if (BtnClearErrors.Enabled != b)
				BtnClearErrors.Enabled = b;
			if (BtnReadErrors.Enabled != b)
				BtnReadErrors.Enabled = b;
			b = ZoomSpan != 0;
			if (ScrollBarSeries.Visible != b)
				ScrollBarSeries.Visible = b;

			#region File Operations Buttons
			b = OBD.Status.FileOperationActive;
			if (StripProgressBarLoadHistory.Visible != b)
				StripProgressBarLoadHistory.Visible = b;
			if (BtnFileOperationCancel.Visible != b)
				BtnFileOperationCancel.Visible = b;
			if (LblLoadHistory.Visible != b)
				LblLoadHistory.Visible = b;
			if (BtnFileOperationPlay.Visible != b)
				BtnFileOperationPlay.Visible = b;
			if (BtnFileOperationStop.Visible != b)
				BtnFileOperationStop.Visible = b;
			if (BtnFileOperationPause.Visible != b)
				BtnFileOperationPause.Visible = b;
			if (b)
			{
				if (StripProgressBarLoadHistory.Value != OBD.Status.FileOperationPercent)
					StripProgressBarLoadHistory.Value = OBD.Status.FileOperationPercent;
				b = OBD.Status.FileOprationNeedPause;
				if (BtnFileOperationPause.Enabled == b)
					BtnFileOperationPause.Enabled = !b;
				if (BtnFileOperationPlay.Enabled != b)
					BtnFileOperationPlay.Enabled = b;
			}

			#endregion

			b = OBD.Status.EngineState.GetTotalLengthPath() > 5 && OBD.Status.EngineState.GetTotalLiters()>0.01;
			if (BtnESCorrCoeffEdit.Enabled != b)
				BtnESCorrCoeffEdit.Enabled = b;
			b = OBD.Status.EngineState.GetTotalLengthPath() > 0 || OBD.Status.EngineState.GetTotalLiters()>0;
			if(BtnClearEngineState.Enabled != b)
			{
				BtnClearEngineState.Enabled = b;
				if (BtnClearEngineState.Grayed == b)
					BtnClearEngineState.Grayed = !b; 
			}
			s = "Временные графики";
			if (ZoomSpan != 0)
			{
				TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int) ZoomSpan);
				s += string.Format("   {0}{1}{2}.{3}   ",
				                   ts.Hours > 0 ? ts.Hours.ToString("00")+":" : "",
				                   ts.Minutes > 0 ? ts.Minutes.ToString("00")+":" : "",
				                   ts.Seconds > 0 ? ts.Seconds.ToString("00") : "",
				                   ts.Milliseconds.ToString("0"));
			}
			if(GBoxSensors.Text != s)
				GBoxSensors.Text = s;
			b = FrmLamps == null || (FrmLamps != null && !FrmLamps.Visible);
			if (ChBoxLampsFormVisible.Checked && b)
				ChBoxLampsFormVisible.Checked = false;
		}

		private void UpdateFlags()
		{
			if (OBD == null)
				return;
			if ((OBD.Status.ChStateFlag & ChangeStateFlag.NewFlags) > 0)
			{
				if (FrmLamps != null)
					FrmLamps.NeedUpdate = true;
				OBD.Status.ChStateFlag &= ~ChangeStateFlag.NewFlags;
				HOBDFlags F = OBD.Status.Flags;
				bool Grayed = (F & HOBDFlags.AirCondition) == 0;
				if (IndicatorAirCondition.Grayed != Grayed)
					IndicatorAirCondition.Grayed = Grayed;
				Grayed = (F & HOBDFlags.Brake) == 0;
				if (IndicatorBrake.Grayed != Grayed)
					IndicatorBrake.Grayed = Grayed;
				Grayed = (F & HOBDFlags.CEL) == 0;
				if (IndicatorCEL.Grayed != Grayed)
					IndicatorCEL.Grayed = Grayed;
				Grayed = (F & HOBDFlags.Econo) == 0;
				if (IndicatorEcono.Grayed != Grayed)
					IndicatorEcono.Grayed = Grayed;
				Grayed = (F & HOBDFlags.Engine) == 0;
				if (IndicatorEngine.Grayed != Grayed)
					IndicatorEngine.Grayed = Grayed;
				Grayed = (F & HOBDFlags.MainRelay) == 0;
				if (IndicatorMainRelay.Grayed != Grayed)
					IndicatorMainRelay.Grayed = Grayed;
				Grayed = (F & HOBDFlags.O2Heater) == 0 && (F & HOBDFlags.O2Heater2) == 0;
				if (IndicatorO2Heater.Grayed != Grayed)
					IndicatorO2Heater.Grayed = Grayed;
				Grayed = (F & HOBDFlags.PASPressure) == 0;
				if (IndicatorPASPressure.Grayed != Grayed)
					IndicatorPASPressure.Grayed = Grayed;
				Grayed = (F & HOBDFlags.SCS) == 0;
				if (IndicatorSCS.Grayed != Grayed)
					IndicatorSCS.Grayed = Grayed;
				Grayed = (F & HOBDFlags.Starter) == 0;
				if (IndicatorStarter.Grayed != Grayed)
					IndicatorStarter.Grayed = Grayed;
				Grayed = (F & HOBDFlags.VTEC_E) == 0;
				if (IndicatorEVTEC.Grayed != Grayed)
					IndicatorEVTEC.Grayed = Grayed;
				Grayed = (F & HOBDFlags.VTECPressure) == 0;
				if (IndicatorVtecPressure.Grayed != Grayed)
					IndicatorVtecPressure.Grayed = Grayed;
				Grayed = (F & HOBDFlags.VTSControl) == 0;
				if (IndicatorVTEC.Grayed != Grayed)
					IndicatorVTEC.Grayed = Grayed;
				Grayed = (F & HOBDFlags.ACClutch) == 0;
				if (IndicatorACClutch.Grayed != Grayed)
					IndicatorACClutch.Grayed = Grayed;
				Grayed = (F & HOBDFlags.FAN) == 0;
				if (IndicatorFAN.Grayed != Grayed)
					IndicatorFAN.Grayed = Grayed;
			}
		}
		private void UpdateErrorCodes()
		{
			if (OBD == null)
				return;
			if((OBD.Status.ChStateFlag & ChangeStateFlag.NewErrors)>0)
			{
				OBD.Status.ChStateFlag &= ~ChangeStateFlag.NewErrors;
				LVErrorCodes.Items.Clear();
				for(int i=0; i<OBD.Status.ErrorCodes.Count; i++)
				{
					string desc = OBDHelper.Errors.ErrorCodesDescription[OBD.Status.ErrorCodes[i]];
					bool exist = false;
					for(int j=0; j<LVErrorCodes.Items.Count; j++)
					{
						if(LVErrorCodes.Items[j].Text == desc)
						{
							exist = true;
							break;
						}
					}
					if (!exist)
					{
						ListViewItem lvi = new ListViewItem(desc);
						LVErrorCodes.Items.Add(lvi);
					}
				}
			}
		}

		private void Connect()
		{
			OBD.Connect();
		}
		private void Disconnect()
		{
			OBD.Disconnect();
		}
		private void ClearHistory()
		{
			SeriesOxygen.Clear();
			SeriesRPM.Clear();
			SeriesCorrCT.Clear();
			SeriesCorrLT.Clear();
			SeriesECT.Clear();
			SeriesIAT.Clear();
			SeriesInjTime.Clear();
			SeriesMAP.Clear();
			SeriesVSS.Clear();
			SensorsChart.Axes.Bottom.Minimum = 0;
			SensorsChart.Axes.Bottom.Maximum = 0;
			OBD.ClearHistory();
			OBD.Status.Flags = 0;
			OBD.Status.SensState.ResetToZero();
			OBD.Status.ChStateFlag |= ChangeStateFlag.NewFlags;

		}

		#region Log Routines
		private void CheckLog()
		{
			if (Log == null)
				return;
			bool Updated = false;
			if (Log.LogCount > 0)
			{
				FillLog(Log);
				Updated = true;
			}
			if (Updated)
				LogGrid.UpdateGrid();
		}

		private void FillLog(LogStorage LS)
		{
			if (LS == null)
				return;
			LogItem[] liArr = LS.GetAllItems;
			FillScrollPage(LogPage, liArr);
		}

		private static void FillScrollPage(tScrollPage p, LogItem[] li)
		{
			if (p != null && (li != null && li.Length > 0))
			{
				tScrollRow row;
				for (int i = 0; i < li.Length; i++)
				{
					row = new tScrollRow { Columns = new string[p.Columns.Count], ForeColor = li[i].Color };
					row.Columns[0] = li[i].DateStr;
					row.Columns[1] = li[i].LogMessage;
					p.AddRow(row);
				}
			}
			return;
		}
		#endregion

		#region Chart & Series Events
		private void SensorsChart_GetAxisLabel(object sender, Steema.TeeChart.GetAxisLabelEventArgs e)
		{
			if (e.ValueIndex > -1)
			{
				if (sender == SensorsChart.Axes.Bottom)
				{
					Axis a = (Axis) sender;
					double value = e.Series.XValues[e.ValueIndex];
					TimeSpan ts = TimeSpan.FromMilliseconds(value);
					DateTime dt = DateTime.MinValue;
					dt = dt + ts;
					e.LabelText = dt.ToString("mm:ss:fff");
				}
			}
		}
		private void UpdateVisibleAxis()
		{
			bool b = SeriesOxygen.Visible;
			if (OxygenAxis.Visible != b)
				OxygenAxis.Visible = b;
			b = SeriesRPM.Visible;
			if (RPMAxis.Visible != b)
				RPMAxis.Visible = b;
			b = SeriesECT.Visible || SeriesIAT.Visible;
			if (TemperatureAxis.Visible != b)
				TemperatureAxis.Visible = b;
			b = SeriesMAP.Visible;
			if (AbsPressureAxis.Visible != b)
				AbsPressureAxis.Visible = b;
			b = SeriesInjTime.Visible;
			if (InjTimeAxis.Visible != b)
				InjTimeAxis.Visible = b;
			b = SeriesCorrLT.Visible || SeriesCorrCT.Visible;
			if (CorrLT_CTAxis.Visible != b)
				CorrLT_CTAxis.Visible = b;
			b = SeriesVSS.Visible;
			if (VSSAxis.Visible != b)
				VSSAxis.Visible = b;
		}

		private void SensorsChart_ClickLegend(object sender, MouseEventArgs e)
		{
			UpdateVisibleAxis();
		}
		#endregion

		#region Controls Click Routines
		private void ComboCOMPort_DropDown(object sender, EventArgs e)
		{
			ComboCOMPort.Items.Clear();
			ComboCOMPort.Items.AddRange(SerialPort.GetPortNames());
		}

		private void ComboCOMPort_TextUpdate(object sender, EventArgs e)
		{
			if (OBD != null)
			{
				string s = ComboCOMPort.Text;
				string tmpres = "";
				for (int i = 0; i < s.Length; i++)
				{
					if ("0123456789".IndexOf(s[i]) > -1)
						tmpres += s[i];
				}
				if (tmpres != "")
					int.TryParse(tmpres, out OBD.Params.PortNumber);

			}
		}

		private void ExitBtn_Click(object sender, EventArgs e)
		{
			Close();
		}

		private void ConnectBtn_Click(object sender, EventArgs e)
		{
			if (OBD.Status.State == HOBDState.Disconnected)
				Connect();
			else
				Disconnect();
		}

		private void BtnClearStat_Click(object sender, EventArgs e)
		{
			if (MessageBox.Show(this, "ОЧИСТИТЬ ВСЕ ПОЛУЧЕННЫЕ ДАННЫЕ?","ВНИМАНИЕ",  MessageBoxButtons.YesNo,
				MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
			{
				ClearHistory();
			}
		}

		private void ChBoxChartSettings_CheckedChanged(object sender, EventArgs e)
		{
			if (sender == ChBoxScrollIfZoomed)
			{
				OBD.Params.ScrollChartIfSelected = ChBoxScrollIfZoomed.Checked;
			}
			if (sender == ChBoxPaintCharts)
			{
				OBD.Params.PaintCharts = ChBoxPaintCharts.Checked;
			}
		}

		private void RBtnLogDataMode_CheckedChanged(object sender, EventArgs e)
		{
			if (OBD == null)
				return;
			if (RBtnLogAllData.Checked)
				OBD.Params.ReadMode = ReadMode.All;
			if (RBtnLogFast.Checked)
				OBD.Params.ReadMode = ReadMode.Fast_60h;
			if (RBtnLogCustom.Checked)
				OBD.Params.ReadMode = ReadMode.Custom;
		}

		private void TBoxOBDCustomModeText_KeyPress(object sender, KeyPressEventArgs e)
		{
			if (OBD == null)
				return;
			string Patt = "0123456789ABCDEF \b";
			if (Patt.IndexOf(e.KeyChar.ToString().ToUpper()) < 0)
				e.Handled = true;
		}

		private void TBoxOBDCustomModeText_TextChanged(object sender, EventArgs e)
		{
			string[] sarr = TBoxOBDCustomModeText.Text.Split(' ');
			bool good = false;
			if (sarr.Length > 0)
			{
				for (int i = 0; i < sarr.Length; i++)
				{
					if (!string.IsNullOrEmpty(sarr[i]))
					{
						if (sarr[i].Length == 4)
							good = true;
						else
						{
							good = false;
							break;
						}
					}
				}
			}
			if (good)
				OBD.Params.CustomReqests = TBoxOBDCustomModeText.Text;
			Color c = good ? Color.Green : Color.Red;
			if (TBoxOBDCustomModeText.ForeColor != c)
				TBoxOBDCustomModeText.ForeColor = c;
		}

		private void ComboECUSettings_SelectedIndexChanged(object sender, EventArgs e)
		{
			if(sender == ComboECUSettingsRPM)
				if (OBD != null && ComboECUSettingsRPM.SelectedIndex > -1)
				{
					OBD.Params.RMPMethod = (RPMCalcMethod)ComboECUSettingsRPM.SelectedIndex;
				}
			if(sender == ComboECUSettingsO2)
				if (OBD != null && ComboECUSettingsRPM.SelectedIndex > -1)
				{
					OBD.Params.O2Method = (O2CalcMethod)ComboECUSettingsO2.SelectedIndex;
				}
		}

		private void ChBoxECUSettingsHILOBytesOrder_CheckedChanged(object sender, EventArgs e)
		{
			if(OBD != null)
			{
				OBD.Params.InverseHiLoOrder = ChBoxECUSettingsHILOBytesOrder.Checked;
			}
		}

		private void BtnErrors_Click(object sender, EventArgs e)
		{
			if (sender == BtnClearErrors)
			{
				OBD.SendClearECUReq();
			}
			if (sender == BtnReadErrors)
			{
				OBD.SendErrorCodesReq();
			}
		}

		private void TrackBarReadHistorySpeed_ValueChanged(object sender, EventArgs e)
		{
			if(OBD != null)
			{
				OBD.Params.SpeedLoadingHistory = TrackBarReadHistorySpeed.Value;
			}
		}
		private void BtnFileOperationCancel_Click(object sender, EventArgs e)
		{
			if(OBD != null)
			{
				if (MessageBox.Show(this, "ОТМЕНА ОПЕРАЦИИ МОЖЕТ ПРИВЕСТИ К ЧАСТИЧНОЙ ПОТЕРЕ ДАННЫХ!\r\n ПРОДОЛЖИТЬ?",
					"ВНИМАНИЕ", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) ==
					DialogResult.Yes)
				{
					OBD.Status.FileOperationNeedCancel = true;
				}
			}
		}
		private void BtnFileOperation_Click(object sender, EventArgs e)
		{
			if (OBD == null)
				return;
			if(sender == BtnFileOperationPlay)
			{
				OBD.Status.FileOprationNeedPause = false;
			}
			if(sender == BtnFileOperationStop)
			{
				BtnFileOperationCancel_Click(sender, e);
			}
			if(sender == BtnFileOperationPause)
			{
				OBD.Status.FileOprationNeedPause = true;
			}
		}


		private void ChBoxAutoSaveLoad_CheckedChanged(object sender, EventArgs e)
		{
			if (OBD == null)
				return;
			if(sender == ChBoxAutoSaveOnExit)
			{
				OBD.Params.AutoSaveLogDataOnExit = ChBoxAutoSaveOnExit.Checked;
			}
			if(sender == ChBoxAutoLoadOnEnter)
			{
				OBD.Params.AutoLoadLogDataOnStartApp = ChBoxAutoLoadOnEnter.Checked;
			}
		}

		private void BtnESCorrCoeffEdit_Click(object sender, EventArgs e)
		{
			if (IF == null)
			{
				IF = new InputForm(this);
			}
			string path = OBD.Status.EngineState.GetTotalLengthPath().ToString("0.###");
			string fuel = OBD.Status.EngineState.GetTotalLiters().ToString("0.###");
			if (IF.Show("ВВОД ПОПРАВОК", "РЕАЛЬНОЕ РАССТОЯНИЕ", ref path, "РЕАЛЬНЫЙ РАСХОД", ref fuel))
			{
				try
				{
					double dpath = double.Parse(path.Replace(",", "."));
					double dfuel = double.Parse(fuel.Replace(",", "."));
					OBD.Status.EngineState.CorrectionVSS = 0;
					OBD.Status.EngineState.CorrectionLiters = 0;
					double rpath = OBD.Status.EngineState.GetTotalLengthPath();
					double rfuel = OBD.Status.EngineState.GetTotalLiters();
					OBD.Status.EngineState.CorrectionLiters = (dfuel - rfuel)/rfuel;
					OBD.Status.EngineState.CorrectionVSS = (dpath - rpath)/rpath;
					
					OBD.Status.ChStateFlag |= ChangeStateFlag.NewEngineState;
				}
				catch
				{
					MessageBox.Show(this, "ОШИБКА ВВОДА ЧИСЛОВОГО ЗНАЧЕНИЯ", "ОШИБКА", MessageBoxButtons.OK,
					                MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
				}
			}
		}

		private void ComboInjFlowRate_SelectedIndexChanged(object sender, EventArgs e)
		{
			if(OBD == null)
				return;
			int value = ComboInjFlowRate.SelectedItem != null ? (int) ComboInjFlowRate.SelectedItem : -1;
			if(value > 0)
			{
				OBD.Status.EngineState.InjectorFlowRate = (FuelInjFlowRate) value;
				OBD.Params.InjectorFlowRate = OBD.Status.EngineState.InjectorFlowRate;
				OBD.Status.ChStateFlag |= ChangeStateFlag.NewEngineState;
			}
		}

		private void LblESCorr_Click(object sender, EventArgs e)
		{
			if (OBD == null)
				return;
			if (IF == null)
			{
				IF = new InputForm(this);
			}
			string s;
			double d;
			if (sender == LblESCorrInjPercent)
			{
				s = (OBD.Status.EngineState.CorrectionLiters * 100).ToString("0.##");
				if (IF.Show("УСТАНОВКА КОРРЕКЦИИ", "КОРРЕКЦИЯ РАСХОДА %", ref s))
				{
					try
					{
						s = s.Replace(",", ".");
						d = double.Parse(s)/100;
						OBD.Status.EngineState.CorrectionLiters = d;
						OBD.Status.ChStateFlag |= ChangeStateFlag.NewEngineState;
					}
					catch
					{
						MessageBox.Show(this, "ОШИБКА ВВОДА ЧИСЛОВОГО ЗНАЧЕНИЯ", "ОШИБКА", MessageBoxButtons.OK,
						                MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
					}
				}
			}
			if (sender == LblESCorrVSSPercent)
			{
				s = (OBD.Status.EngineState.CorrectionVSS * 100).ToString("0.##");
				if (IF.Show("УСТАНОВКА КОРРЕКЦИИ", "КОРРЕКЦИЯ ПРОБЕГА %", ref s))
				{
					try
					{
						s = s.Replace(",", ".");
						d = double.Parse(s) / 100;
						OBD.Status.EngineState.CorrectionVSS = d;
						OBD.Status.ChStateFlag |= ChangeStateFlag.NewEngineState;
					}
					catch
					{
						MessageBox.Show(this, "ОШИБКА ВВОДА ЧИСЛОВОГО ЗНАЧЕНИЯ", "ОШИБКА", MessageBoxButtons.OK,
														MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
					}

				}
			}
		}

		private void BtnClearEngineState_Click(object sender, EventArgs e)
		{
			if (OBD != null)
			{
				if (MessageBox.Show(this, "ПОЛНАЯ ОЧИСТКА ДАННЫХ О ПРОБЕГЕ И РАСХОДЕ!\r\n ПРОДОЛЖИТЬ?",
					"ВНИМАНИЕ", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) ==
					DialogResult.Yes)
				{
					OBD.Status.EngineState.ClearTotalState();
					OBD.Status.ChStateFlag |= ChangeStateFlag.NewEngineState;
				}
			}

		}

		private void ChBoxLampsFormVisible_CheckedChanged(object sender, EventArgs e)
		{
			bool v = ChBoxLampsFormVisible.Checked;
			if(v)
			{
				if(FrmLamps == null)
				{
					FrmLamps = new LampsForm {OBD = OBD};
				}
				FrmLamps.Show(this);
			}
			else
			{
				if (FrmLamps != null)
					FrmLamps.Hide();
			}
		}

		#endregion

		#region ScrollBar Routines 

		private double ZoomSpan = 0;
		private void SensorsChart_Zoomed(object sender, EventArgs e)
		{
			ZoomSpan = SensorsChart.Axes.Bottom.Maximum - SensorsChart.Axes.Bottom.Minimum;
			double  FullSpan = SensorsChart.Axes.Bottom.MaxXValue - SensorsChart.Axes.Bottom.MinXValue;
			ScrollBarSeries.Maximum = (int)SensorsChart.Axes.Bottom.MaxXValue;
			ScrollBarSeries.LargeChange = (int) ((double)ZoomSpan*0.8);
			ScrollBarSeries.Value = (int) SensorsChart.Axes.Bottom.Minimum;
		}

		private void SensorsChart_UndoneZoom(object sender, EventArgs e)
		{
			double oldZoomSpan = SensorsChart.Axes.Bottom.Maximum - SensorsChart.Axes.Bottom.Minimum;
			ZoomSpan = 0;
			double FullSpan = SensorsChart.Axes.Bottom.MaxXValue - SensorsChart.Axes.Bottom.MinXValue;
			ScrollBarSeries.Maximum = (int)SensorsChart.Axes.Bottom.MaxXValue;
			ScrollBarSeries.LargeChange = (int)FullSpan;
		}

		private void ScrollBarSeries_Scroll(object sender, ScrollEventArgs e)
		{
		//	int i = e.NewValue;
		//	SensorsChart.Axes.Bottom.Minimum = e.NewValue;
		//	SensorsChart.Axes.Bottom.Maximum = e.NewValue + ZoomSpan;
		}
		private void ScrollBarSeries_ValueChanged(object sender, EventArgs e)
		{
			int i = ScrollBarSeries.Value;
			SensorsChart.Axes.Bottom.Minimum = i;
			SensorsChart.Axes.Bottom.Maximum = i + ZoomSpan;
		}
		#endregion

		#region Load Save
		private void MainForm_Load(object sender, EventArgs e)
		{
			int res = WinTimers.timeBeginPeriod(1);
			OBD.Load();
			NF = new NotifyForm("", this, 10);
			SandDockLanguage.ActiveFilesText = "Активные файлы";
			SandDockLanguage.AutoHideText = "Автоматически скрывать";
			SandDockLanguage.CloseText = "Закрыть";
			SandDockLanguage.ScrollLeftText = "Прокрутка влево";
			SandDockLanguage.ScrollRightText = "Прокрутка вправо";
			SandDockLanguage.WindowPositionText = "Положение окна";
			DockManager.Renderer = new WhidbeyRenderer(WindowsColorScheme.LunaOlive);
			ComboCOMPort.Text = "COM" + OBD.Params.PortNumber.ToString();
			ComboECUSettingsRPM.SelectedIndex = (int)OBD.Params.RMPMethod;
			ComboECUSettingsO2.SelectedIndex = (int)OBD.Params.O2Method;
			ChBoxScrollIfZoomed.Checked = OBD.Params.ScrollChartIfSelected;
			ChBoxPaintCharts.Checked = OBD.Params.PaintCharts;
			ChBoxECUSettingsHILOBytesOrder.Checked = OBD.Params.InverseHiLoOrder;
			TBoxOBDCustomModeText.Text = OBD.Params.CustomReqests;
			ChBoxAutoSaveOnExit.Checked = OBD.Params.AutoSaveLogDataOnExit;
			ChBoxAutoLoadOnEnter.Checked = OBD.Params.AutoLoadLogDataOnStartApp;

			if (OBD.Params.SpeedLoadingHistory < 1)
				OBD.Params.SpeedLoadingHistory = 1;
			if (OBD.Params.SpeedLoadingHistory > 11)
				OBD.Params.SpeedLoadingHistory = 1;
			TrackBarReadHistorySpeed.Value = OBD.Params.SpeedLoadingHistory;
			ComboInjFlowRate.Items.Clear();
			Array a = Enum.GetValues(typeof (FuelInjFlowRate));
			for (int i = 0; i < a.Length; i++ )
			{
				object o = a.GetValue(i);
				ComboInjFlowRate.Items.Add(o);
				if ((int)o == (int)OBD.Status.EngineState.InjectorFlowRate)
					ComboInjFlowRate.SelectedIndex = i;
			}

			FS = AppSettings.Load(AppSettingsFName);
			if (FS != null)
			{
				FS.SetToForm(this);
				SeriesOxygen.Visible = FS.SeriesOxygenVisible;
				SeriesRPM.Visible = FS.SeriesRPMVisible;
				SeriesECT.Visible = FS.SeriesECTVisible;
				SeriesIAT.Visible = FS.SeriesIATVisible;
				SeriesMAP.Visible = FS.SeriesMAPVisible;
				SeriesInjTime.Visible = FS.SeriesInjTimeVisible;
				SeriesCorrCT.Visible = FS.SeriesCorrCTVisible;
				SeriesCorrLT.Visible = FS.SeriesCorrLTVisible;
				SeriesVSS.Visible = FS.SeriesVSSVisible;
				UpdateVisibleAxis();
				if (!string.IsNullOrEmpty(FS.DockLayout))
					DockManager.SetLayout(FS.DockLayout);
			}
			else
				FS = new AppSettings();
		}
		private void MainFormPCScanner_FormClosing(object sender, FormClosingEventArgs e)
		{
			int res = WinTimers.timeEndPeriod(1);
			OBD.Save();
			if (FS != null)
			{
				string s = DockManager.GetLayout();
				FS.DockLayout = s;
				FS.GetFromForm(this);
				FS.SeriesOxygenVisible= SeriesOxygen.Visible;
				FS.SeriesRPMVisible = SeriesRPM.Visible;
				FS.SeriesECTVisible = SeriesECT.Visible;
				FS.SeriesIATVisible = SeriesIAT.Visible;
				FS.SeriesMAPVisible = SeriesMAP.Visible;
				FS.SeriesInjTimeVisible = SeriesInjTime.Visible; 
				FS.SeriesCorrCTVisible = SeriesCorrCT.Visible;
				FS.SeriesCorrLTVisible = SeriesCorrLT.Visible;
				FS.SeriesVSSVisible = SeriesVSS.Visible;
				FS.Save(AppSettingsFName);
			}
		}
		private void MenuItemSaveLoadLog_Click(object sender, EventArgs e)
		{
			if (sender == MenuItemLoadLog)
			{
				OpenFileDialog ofd = new OpenFileDialog
				                     	{
				                     		InitialDirectory = LogsDir,
				                     		CheckFileExists = true,
				                     		CheckPathExists = true,
				                     		RestoreDirectory = true,
				                     		Filter = "Лог файлы  (*.log)|*.log|Все файлы (*.*)|*.*",
				                     		FilterIndex = 1
				                     	};
				if (ofd.ShowDialog() == DialogResult.OK)
				{
					ClearHistory();
					OBD.LoadHistory(ofd.FileName);
				}
			}
			if (sender == MenuItemSaveLog)
			{
				SaveFileDialog sfd = new SaveFileDialog
				                     	{
				                     		InitialDirectory = LogsDir,
				                     		RestoreDirectory = true,
				                     		Filter = "Лог файлы  (*.log)|*.log|Все файлы (*.*)|*.*",
				                     		FilterIndex = 1
				                     	};
				string FName = "Log " + DateTime.Now.ToString("dd.MM.yyyy HH.mm.ss") + ".log";
				sfd.FileName = FName;
				if (sfd.ShowDialog() == DialogResult.OK)
				{
					OBD.SaveHistory(sfd.FileName);
				}
			}
		}


		#endregion

		private void SensorsChart_Click(object sender, EventArgs e)
		{
			try
			{
				Point p = SensorsChart.PointToClient(Control.MousePosition);
				double d = SensorsChart.Axes.Bottom.CalcPosPoint(p.X);
				ColorLineCursor.Value = d;
				if (OBD != null)
				{
					SensorsState s = OBD.Status.SensState;
					if (s != null)
					{
						s.NewO2 = GetValueForTime(SeriesOxygen, d);
						s.NewRPM = GetValueForTime(SeriesRPM, d);
						s.NewMAP = GetValueForTime(SeriesMAP, d);
						s.NewCorrCT = GetValueForTime(SeriesCorrCT, d);
						s.NewCorrLT = GetValueForTime(SeriesCorrLT, d);
						s.NewInjTime = GetValueForTime(SeriesInjTime, d);
						s.NewVss = GetValueForTime(SeriesVSS, d);
						s.NewIAT = GetValueForTime(SeriesIAT, d);
						s.NewECT = GetValueForTime(SeriesECT, d);
					}
				}
			}catch(Exception ex)
			{
				Log.ErrorString = ex.Message;
			}
		}
		private static double GetValueForTime(Series s ,double Time)
		{
			double res = double.NaN;
			if(s != null && s.XValues != null && s.XValues.Count > 1)
			{
				int ind = -1;
				for(int i=1; i<s.XValues.Count; i++)
				if(s.XValues[i-1]<=Time && s.XValues[i]>=Time)
				{
					ind = i;
					break;
				}
				if (ind != -1)
					res = s.YValues[ind];
			}
			return res;
		}

	}
	public class AppSettings : UniversalFormSettings
	{
		public bool SeriesOxygenVisible = true;
		public bool SeriesRPMVisible = true;
		public bool SeriesECTVisible = true;
		public bool SeriesIATVisible = true;
		public bool SeriesMAPVisible = true;
		public bool SeriesInjTimeVisible = true;
		public bool SeriesCorrCTVisible = true;
		public bool SeriesCorrLTVisible = true;
		public bool SeriesVSSVisible = true;

		public new void Save(string FName)
		{
			SaveSettings(FName);
		}
		public new static AppSettings Load(string FName)
		{
			return (AppSettings)LoadSettings(FName, typeof(AppSettings));
		}
		
	}
	internal class WinTimers
	{
		[DllImport("Winmm.dll")]
		internal static extern int timeBeginPeriod(int Quantum);

		[DllImport("Winmm.dll")]
		internal static extern int timeEndPeriod(int Quantum);
	}
}
