using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceProcess;
using System.Xml.Linq;
using CFWinAppTest.Properties;
using System.IO;


namespace CFWinAppTest
{
	public partial class Form1 : Form
	{
		public string sConfigPath = "";
		public string sServiceName = "";
		public string sVideoPath = "";
		public int iFileDuration = 0;
		public string sConfigFilePath = "";
		private NotifyIcon trayIcon;
		private ContextMenu trayMenu;
		public ServiceController dxService;
		public string sServiceStatus = "";
		public int bErrorService = 0;
		public int bErrorFiles = 0;
		public bool bServiceSwitchMode = false;

		public Form1()
		{
			sConfigFilePath = System.Environment.CurrentDirectory + "\\Config.cfg";

			trayMenu = new ContextMenu();

			trayMenu.MenuItems.Add("Открыть", Tray_OnOpen);
			trayMenu.MenuItems[0].DefaultItem = true;
			trayMenu.MenuItems.Add("Выход", Tray_OnExit);
			

			trayIcon = new NotifyIcon();
			trayIcon.Text = "DxDvrCapture - Состояние сервиса";
			trayIcon.Icon = Resource1.CameraOK;

			trayIcon.Click += new System.EventHandler(this.Tray_OnOpen);

			trayIcon.ContextMenu = trayMenu;
			trayIcon.Visible = true;

			InitializeComponent();
		}

		/// <summary>
		/// Загрузка нашей формы
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Form1_Load(object sender, EventArgs e)
		{
			textBox2.Text = "";
			textBox2.BackColor = System.Drawing.SystemColors.Control;
			textBox3.Text = "";
			textBox3.BackColor = System.Drawing.SystemColors.Control;

			if (LoadAppConfigFile() != -1)
			{
				tbConfigPath.Text = sConfigPath;

				if (loadBasicParams() != -1)
				{
					groupBox2.Enabled = true;
					groupBox3.Enabled = true;
					textBox1.Text = "Имя сервиса: " + sServiceName + "\r\n" +
									"Папка с видео: " + sVideoPath + "\r\n" +
									"Длительность видео: " + iFileDuration.ToString() + " сек";
					textBox1.BackColor = System.Drawing.SystemColors.Control;

					bErrorService = UpdateServiceState();
					bErrorFiles = UpdateFilesState();
					if (bErrorService != -1 && bErrorFiles != -1)
						trayIcon.Icon = this.Icon = Resource1.CameraOK;
					else
						trayIcon.Icon = this.Icon = Resource1.CameraFail;

					timerService.Start();
					timerFiles.Interval = iFileDuration * 1000;
					timerFiles.Start();
				}
				else
				{
					textBox1.Text = "Не удалось прочитать файл настроек!";
					textBox1.BackColor = System.Drawing.Color.LightCoral;
					groupBox2.Enabled = false;
					groupBox3.Enabled = false;
				}
			}
			else
			{
				textBox1.Text = "Не удалось прочитать файл настроек!";
				textBox1.BackColor = System.Drawing.Color.LightCoral;
				groupBox2.Enabled = false;
				groupBox3.Enabled = false;
			}
		}

		/// <summary>
		/// Метод пытается прочитать свой собственный конфиг файл, в котором хранится ссылка на файл настроек сервиса.
		/// Если файл не найден - создается новый пустой конфиг файл.
		/// </summary>
		/// <returns></returns>
		private int LoadAppConfigFile()
		{
			if (File.Exists(sConfigFilePath)) // конфиг файл найден
			{
				// читаем содержимое файла
				StreamReader streamReader = new StreamReader(sConfigFilePath);
				string text = streamReader.ReadToEnd();
				streamReader.Close();
				
				// если файл пуст - выходим, путь получить не удалось
				if (string.IsNullOrEmpty(text))
					return -1;

				// сохраняем путь к файлу настроек сервиса
				sConfigPath = text;
			}
			else // конфиг файла нет
			{
				// создаем пустой конфиг файл
				var myFile = File.Create(sConfigFilePath);
				myFile.Close();
				return -1;
			}

			return 1;
		}

		/// <summary>
		/// Открыть файл настроек сервиса
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void button1_Click(object sender, EventArgs e)
		{
			if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) // если выбран файл
			{
				tbConfigPath.Text = sConfigPath = openFileDialog1.FileName;
				timerService.Stop();

				textBox2.Text = "";
				textBox2.BackColor = System.Drawing.SystemColors.Control;
				textBox3.Text = "";
				textBox3.BackColor = System.Drawing.SystemColors.Control;

				// сохранить новый путь в конфиг файл
				System.IO.StreamWriter myFile = new System.IO.StreamWriter(sConfigFilePath);
				myFile.Write(openFileDialog1.FileName);
				myFile.Close();


				if (LoadAppConfigFile() != -1)
				{
					if (loadBasicParams() != -1)
					{
						groupBox2.Enabled = true;
						groupBox3.Enabled = true;
						textBox1.Text = "Имя сервиса: " + sServiceName + "\r\n" +
										"Папка с видео: " + sVideoPath + "\r\n" +
										"Длительность видео: " + iFileDuration.ToString() + " сек";
						textBox1.BackColor = System.Drawing.SystemColors.Control;

						bErrorService = UpdateServiceState();
						bErrorFiles = UpdateFilesState();
						if (bErrorService != -1 && bErrorFiles != -1)
							trayIcon.Icon = this.Icon = Resource1.CameraOK;
						else
							trayIcon.Icon = this.Icon = Resource1.CameraFail;

						timerService.Start();
						timerFiles.Interval = iFileDuration * 1000;
						timerFiles.Start();
					}
					else
					{
						textBox1.Text = "Не удалось прочитать файл настроек!";
						textBox1.BackColor = System.Drawing.Color.LightCoral;
						groupBox2.Enabled = false;
						groupBox3.Enabled = false;
					}
				}
				else
				{
					textBox1.Text = "Не удалось прочитать файл настроек!";
					textBox1.BackColor = System.Drawing.Color.LightCoral;
					groupBox2.Enabled = false;
					groupBox3.Enabled = false;
				}
			}
		}

		/// <summary>
		/// Загрузка базовых параметров из файла настроек сервиса
		/// </summary>
		/// <returns></returns>
		private int loadBasicParams()
		{
			XDocument xDocument = XDocument.Load(tbConfigPath.Text);

			try // пытаемся прочитать всё необходимое по предполагаемой структуре файла настроек
			{
				List<XElement> elements = xDocument.Element("configuration").Element("appSettings").Elements().ToList();
				if (elements.Count > 0)
				{
					foreach (XElement xe in elements)
					{
						if (xe.Attribute("key").Value == "ServiceInstall_ServiceName")
						{
							sServiceName = xe.Attribute("value").Value;
							break;
						}
					}
				}

				XElement element = xDocument.Element("configuration").Element("StreamDevices").Element("Cameras").Element("add");
				sVideoPath = element.Attribute("filePath").Value;
				iFileDuration = int.Parse(element.Attribute("recordingDurationPerFileInSec").Value);
			}
			catch (Exception ex)
			{
				return -1;
			}

			return 1;
		}

		/// <summary>
		/// Метод контроля сервиса (наличие, текущее состояние)
		/// </summary>
		/// <returns></returns>
		private int UpdateServiceState()
		{
			textBox2.Text = "";
			textBox2.BackColor = System.Drawing.SystemColors.Control;

			bool bServiceFound = false;
			bool bServiceError = false;
			ServiceController[] services = ServiceController.GetServices();
			foreach (ServiceController service in services)
			{
				if (service.ServiceName == sServiceName)
				{
					bServiceFound = true;
					dxService = service;
					switch (service.Status.ToString().ToLower())
					{
						case "":
						case "stopped": sServiceStatus = "остановлен";
										button2.Image = Resource1.Start;
										button2.Enabled = true;
										break;
						case "running": sServiceStatus = "работает";
										button2.Image = Resource1.Stop;
										button2.Enabled = true;
										break;
						default: sServiceStatus = service.Status.ToString().ToLower();
										button2.Image = Resource1.Start;
										button2.Enabled = false;
										break;
					}
					break;
				}
			}

			if (!bServiceFound)
			{
				textBox2.Text = "Сервис не найден в системе!" + "\r\n" +
								DateTime.Now.ToString("HH:mm:ss");
				button2.Enabled = false;
				bServiceError = true;
			}
			else
			{
				button2.Enabled = true;
				if (sServiceStatus != "работает")
					bServiceError = true;

				textBox2.Text = "Сервис обнаружен: ок" + "\r\n" +
					"Текущий статус: " + sServiceStatus + "\r\n" +
					DateTime.Now.ToString("HH:mm:ss");
			}

			if (bServiceError)
			{
				textBox2.BackColor = System.Drawing.Color.LightCoral;
				return -1;
			}
			else
			{
				textBox2.BackColor = System.Drawing.Color.LightGreen;
			}

			return 1;
		}


		/// <summary>
		/// Метод контроля файлов записей (наличие файлов, время создания)
		/// </summary>
		/// <returns></returns>
		private int UpdateFilesState()
		{
			textBox3.Text = "";
			textBox3.BackColor = System.Drawing.SystemColors.Control;

			bool bFilesError = false;
			DateTime? dtMin = null;
			DateTime? dtMax = null;

			// есть ли папка вообще
			if (!Directory.Exists(sVideoPath))
			{
				textBox3.Text = "Папка с видео не найдена!" + "\r\n" + 
								DateTime.Now.ToString("HH:mm:ss"); ;
				button3.Enabled = false;
				bFilesError = true;
				return -1;
			}
			else // папка найден
			{
				button3.Enabled = true;

				// получим список файлов
				string[] filePaths = Directory.GetFiles(sVideoPath, "*.*", SearchOption.AllDirectories);
				
				// если список пуст
				if (filePaths.Length == 0)
				{
					textBox3.Text = "Файлов с видео нет!" + "\r\n" +
									DateTime.Now.ToString("HH:mm:ss");
					bFilesError = true;
				}
				else
				{
					// пройдем по всем файлам
					foreach (string filePath in filePaths)
					{
						// найдем самый старый и самый новый - запомним эти даты/времена
						DateTime dt = File.GetCreationTime(filePath);
						if (dtMin == null || dtMin > dt)
							dtMin = dt;

						if (dtMax == null || dtMax < dt)
							dtMax = dt;
					}

					// получим
					TimeSpan diffResult = DateTime.Now.Subtract((DateTime)dtMax); // сколько времени прошло с момента создания самого нового файла
					TimeSpan ts = new TimeSpan(iFileDuration * 10000000 * 2); // удвоенное (множим на 2) время видеофайла - из установок сервиса

					DateTime dtLimit = DateTime.Now.AddSeconds(-(iFileDuration + 15)); // вычисляем крайнее время, когда должен был появиться последний файл (+15 сек на погрешность)
						// Принцип: время одного файла - 30сек; значит примерно каждые 30 сек должен появляться новый файл, если сервис работает исправно; 
						// на всякий случай накидываем ещё 15сек - если что-то немного подвиснет/затормозит.
						// Итого: от текущего времени отнимается Nсек длительности файл и ещё 15сек; если время самого свежего файла меньше - значит что-то сломалось

					if (dtLimit > dtMax)
						bFilesError = true;
					
					textBox3.Text = "Самый старый файл: " + dtMin.ToString() + "\r\n" +
									"Самый новый файл: " + dtMax.ToString() + "\r\n" +
									"Прошло от последней записи: " + timeSpanToString(diffResult) + "\r\n" +
									DateTime.Now.ToString("HH:mm:ss");
				}
			}

			if (bFilesError)
			{
				textBox3.BackColor = System.Drawing.Color.LightCoral;
				return -1;
			}
			else
			{
				textBox3.BackColor = System.Drawing.Color.LightGreen;
			}

			return 1;
		}

		/// <summary>
		/// Форматирует TimeSpan в строку
		/// </summary>
		/// <param name="diffResult"></param>
		/// <returns></returns>
		private string timeSpanToString(TimeSpan diffResult)
		{
			string result = "";

			result += diffResult.Seconds.ToString() + "с";

			if (diffResult.Minutes > 0)
				result = diffResult.Minutes.ToString() + "м " + result;

			if (diffResult.Hours > 0)
				result = diffResult.Hours.ToString() + "ч " + result;

			if (diffResult.Days > 0)
				result = diffResult.Days.ToString() + "д " + result;

			return result;			
		}

		private void timer1_Tick(object sender, EventArgs e)
		{
			bErrorService = UpdateServiceState();

			if (bErrorService != -1 && bErrorFiles != -1)
				trayIcon.Icon = this.Icon = Resource1.CameraOK;
			else
				trayIcon.Icon = this.Icon = Resource1.CameraFail;

			if (bServiceSwitchMode)
			{
				bServiceSwitchMode = false;
				button2.Enabled = true;
				timerService.Stop();
				timerService.Interval = 15 * 1000;
				timerService.Start();
			}
		}

		private void timerFiles_Tick(object sender, EventArgs e)
		{
			bErrorFiles = UpdateFilesState();

			if (bErrorService != -1 && bErrorFiles != -1)
				trayIcon.Icon = this.Icon = Resource1.CameraOK;
			else
				trayIcon.Icon = this.Icon = Resource1.CameraFail;
		}


		private void button3_Click(object sender, EventArgs e)
		{
			System.Diagnostics.Process process = new System.Diagnostics.Process();
			process.StartInfo.UseShellExecute = true;
			process.StartInfo.FileName = @"explorer";
			process.StartInfo.Arguments = sVideoPath;
			process.Start();
		}

		private void button2_Click(object sender, EventArgs e)
		{
			if (dxService != null)
			{
				bServiceSwitchMode = true;
				button2.Enabled = false;
				timerService.Stop();
				timerService.Interval = 3 * 1000;

				if (dxService.Status == ServiceControllerStatus.Running)
					try
					{
						dxService.Stop();
					}
					catch
					{

					}
				else
					try
					{
						dxService.Start();
					}
					catch
					{
					}

				timerService.Start();
			}
		}

		#region Поведение формы
		private void Tray_OnExit(object sender, EventArgs e)
		{
			Application.Exit();
		}

		private void Tray_OnOpen(object sender, EventArgs e)
		{
			this.Show();
			this.WindowState = FormWindowState.Normal;
		}

		private void Form1_Resize(object sender, EventArgs e)
		{
			if (WindowState == FormWindowState.Minimized)
				this.Hide();
		} 
		#endregion

	}
}
