using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OfficeOpenXml;
using System.IO;
using System.Data;

namespace friction
{
	public class DataHandler
	{
		public struct CalcResult
		{
			public int m_iCnt;
			public float m_fAvgRPN;
			public float m_fStdRPN;
			public float m_fDiffByForce;
			public float m_fDiffByTemp;
			public float m_fDiffByHumid;
			public float m_fDiffByVel;
		}

		public struct RADAR_CHART
		{
			public string m_strTable;
			public float m_fMin;
			public float m_fMax;
			public float m_fAvg;
			public int m_iCnt;

			override public string ToString()
			{
				return string.Format("{0}: {1}-{2}-{3}", m_strTable, m_fMin, m_fAvg, m_fMax);
			}
		}

		public struct TREND_CHART
		{
			public float HUMIDITY;
			public float TEMPERATURE;
			public float FORCE;
			public float VELOCITY;
			public float RPN;

			override public string ToString()
			{
				return string.Format("Humi({0}) Temp({1}) RPN({2})", HUMIDITY, TEMPERATURE, RPN);
			}
		}


		DataTable m_Data = new DataTable();

		string m_strFileName = "";
		string m_strFilePath = "";

		string m_strCurSpring = "";
		string m_strCurTable = "";

		List<string> m_ColumnsNames = new List<string>();
		List<string> m_ActiveColumns = new List<string>();
		List<string> m_NonactiveColumns = new List<string>();
		List<string> m_SpringList = new List<string>();
		List<string> m_TableList = new List<string>();

		public DataHandler()
		{
		}

		bool IsNumberColumn(string strColumn)
		{
			return (strColumn == Config.COLUMN_NAME.RPN ||
				strColumn == Config.COLUMN_NAME.FORCE ||
				strColumn == Config.COLUMN_NAME.TEMP ||
				strColumn == Config.COLUMN_NAME.HUMIDITY ||
				strColumn == Config.COLUMN_NAME.VELOCITY);
		}

		public void LoadData(string strFilePath)
		{
			using (ExcelPackage package = new ExcelPackage())
			{
				using (var stream = new FileStream(strFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
					package.Load(stream);
				ExcelWorksheet Sheet = package.Workbook.Worksheets[1];

				m_Data.Columns.Clear();
				m_Data.Rows.Clear();

				// read column
				for (int iCol = Sheet.Dimension.Start.Column; iCol <= Sheet.Dimension.End.Column; iCol++)
				{
					string strCol = (string)Sheet.Cells[Sheet.Dimension.Start.Row, iCol].Value;
					m_Data.Columns.Add(new DataColumn(strCol, IsNumberColumn(strCol) ? typeof(float) : typeof(string)));
				}

				// read data
				for (int iRow = Sheet.Dimension.Start.Row + 1; iRow <= Sheet.Dimension.End.Row; iRow++)
				{
					DataRow newRow = m_Data.NewRow();

					for (int iCol = Sheet.Dimension.Start.Column; iCol <= Sheet.Dimension.End.Column; iCol++)
					{
						var value = Sheet.Cells[iRow, iCol].Value;
						if (m_Data.Columns[iCol-1].DataType == typeof(float))
						{
							float fData = 0;
							if (value != null)
							{
								if (value is string)
									float.TryParse((string)value, out fData);
								else
									fData = (float)(double)value;
							}

							newRow[iCol - 1] = fData;
						}
						else
						{
							string strData = "";
							if (value != null)
							{
								strData = value.ToString();
								strData = strData.Trim();
							}

							newRow[iCol - 1] = strData;
						}
					}

					m_Data.Rows.Add(newRow);
				}

				m_strFilePath = strFilePath;
				int iSeperate = strFilePath.LastIndexOf('\\');
				m_strFileName = strFilePath.Substring(iSeperate+1);
			}


			m_SpringList = (from r in m_Data.AsEnumerable()
						   select r[Config.COLUMN_NAME.SPRING]).Distinct().Cast<string>().ToList();

			m_TableList = (from r in m_Data.AsEnumerable()
						   select r[Config.COLUMN_NAME.TABLE]).Distinct().Cast<string>().ToList();

			m_ColumnsNames = (from c in m_Data.Columns.Cast<DataColumn>()
						 select c.ColumnName).ToList<string>();


			m_ActiveColumns.Clear();
			m_NonactiveColumns.Clear();
			for (int i=0; i< m_ColumnsNames.Count; i++)
			{
				if(m_Data.Columns[i].DataType == typeof(string))
				{
					if(m_Data.AsEnumerable().Any(r => (string)r[i] != ""))
						m_ActiveColumns.Add(m_ColumnsNames[i]);
					else
						m_NonactiveColumns.Add(m_ColumnsNames[i]);
				}
				else
				{
					m_ActiveColumns.Add(m_ColumnsNames[i]);
				}
			}

			SetSelectedMaterial("", "");
		}

		public void SetSelectedMaterial(string strSpring, string strTable)
		{
			m_strCurSpring = strSpring;
			m_strCurTable = strTable;
		}

		public string GetCurSpring()
		{
			return m_strCurSpring;
		}

		public string GetCurTable()
		{
			return m_strCurTable;
		}

		public List<RADAR_CHART> GetAvgAll(string strSpring)
		{
			string strQuery = string.Format("[{0}]='{1}'", Config.COLUMN_NAME.SPRING, strSpring);
			DataRow[] rows = m_Data.Select(strQuery);

			var group = rows
							.GroupBy(r => r[Config.COLUMN_NAME.TABLE]);


			List<RADAR_CHART> result = rows
										.GroupBy(r => r[Config.COLUMN_NAME.TABLE])
										.Select(t => new RADAR_CHART
										{
											m_strTable = t.Key.ToString(),
											m_iCnt = t.Count(),
											m_fMin = t.Min(k => (float)k[Config.COLUMN_NAME.RPN]),
											m_fMax = t.Max(k => (float)k[Config.COLUMN_NAME.RPN]),
											m_fAvg = t.Average(k => (float)k[Config.COLUMN_NAME.RPN])
										})
										.ToList<RADAR_CHART>();

			return result;
		}

		public List<TREND_CHART> GetTrendChart(string strSpring, string strTable)
		{
			string strQuery = string.Format("[{0}]='{1}' and [{2}]='{3}'", Config.COLUMN_NAME.SPRING, strSpring, Config.COLUMN_NAME.TABLE, strTable);
			DataRow[] rows = m_Data.Select(strQuery);

			List<TREND_CHART> result = new List<TREND_CHART>();
			foreach(DataRow r in rows)
			{
				result.Add(new TREND_CHART
				{
					HUMIDITY = (float)r[Config.COLUMN_NAME.HUMIDITY],
					TEMPERATURE = (float)r[Config.COLUMN_NAME.TEMP],
					FORCE = (float)r[Config.COLUMN_NAME.FORCE],
					VELOCITY = (float)r[Config.COLUMN_NAME.VELOCITY],
					RPN = (float)r[Config.COLUMN_NAME.RPN],
				});
			}

			return result;
		}

		#region calculation
		float CalcDependency(DataRow[] rows, string strColumn)
		{
			// 각 그룹의 평균들의 표준편차
			var AvgOfGroup = rows
							.GroupBy(r => r[Config.COLUMN_NAME.FORCE])
							.Select(t => t.Average(k => (float)k[Config.COLUMN_NAME.RPN]));
			var Avg = AvgOfGroup.Average();
			var Squares = AvgOfGroup.Select(r => (r - Avg) * (r - Avg));
			var result = (float)Math.Sqrt(Squares.Average());
			return result;
		}

		public CalcResult GetCalc(string strSpring, string strTable)
		{
			CalcResult result = new CalcResult();

			string strQuery = string.Format("[{0}]='{1}' and [{2}]='{3}'", Config.COLUMN_NAME.SPRING, strSpring, Config.COLUMN_NAME.TABLE, strTable);
			DataRow[] rows = m_Data.Select(strQuery);

			if(rows.Length > 0)
			{
				result.m_iCnt = rows.Length;
				result.m_fAvgRPN = rows.Average(r => (float)r[Config.COLUMN_NAME.RPN]);
				result.m_fStdRPN = rows.Average(r => (float)Math.Pow((float)r[Config.COLUMN_NAME.RPN] - result.m_fAvgRPN, 2));
				result.m_fStdRPN = (float)Math.Sqrt(result.m_fStdRPN);

				result.m_fDiffByForce = CalcDependency(rows, "force");
				result.m_fDiffByTemp = CalcDependency(rows, "temp");
				result.m_fDiffByHumid = CalcDependency(rows, "humidity");
				result.m_fDiffByVel = CalcDependency(rows, "velocity");
			}
			else
			{

			}

			

			return result;
		}
		#endregion


		#region get
		public DataTable GetData()
		{
			return m_Data;
		}

		public string GetFilePath()
		{
			return m_strFilePath;
		}

		public string GetFileName()
		{
			return m_strFileName;
		}

		public List<string> GetSpringList()
		{
			return m_SpringList;
		}

		public List<string> GetTableList()
		{
			return m_TableList;
		}

		public List<string> GetColumns()
		{
			return m_ColumnsNames;
		}

		public List<string> GetActiveColumns()
		{
			return m_ActiveColumns;
		}

		public List<string> GetNonactiveColumns()
		{
			return m_NonactiveColumns;
		}
		#endregion
	}
}
