using MaterialSkin;
using MaterialSkin.Controls;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace AutoSellerNS
{
	public partial class AutoSeller : MaterialForm
	{
		public class ITEM
		{
			public string m_strCodeName;
			public string m_strCode;
			public int m_iItemCnt;
			public long m_iAssessedValue;
			public long m_iValuationGains;
			public double m_dYield;
			public int m_iAvailableQuantity;
			public double m_dBookUnitPrice;
			public long m_iProfitUnitPrice;

			public int m_iCurPrice;

			public override string ToString()
			{
				return $"[{m_strCodeName}:{m_strCode}] {m_iCurPrice}";
			}
		}

		public class NCITEM
		{
			public string m_strCodeName;
			public string m_strCode;
			public int m_iRemainCnt;
			public int m_iOrderPrice;
			public string m_strDesc;
			public bool m_bAsk;
			public int m_iOrderNo;
			public int m_iOrgOrderNo;
			public DateTime m_Time;

			public override string ToString()
			{
				return $"[{m_strCodeName}:{m_strCode}] {m_iOrderNo}";
			}
		}


		int m_iCurPricePanelWith;
		CybosHelper m_CybosHelper = null;
		List<ITEM> m_Items = new List<ITEM>();
		List<NCITEM> m_NCItems = new List<NCITEM>();
		string m_strSelectedCode = "";
		bool m_bSell = false;

		System.Timers.Timer m_Timer = new System.Timers.Timer();

		public AutoSeller()
		{
			InitializeComponent();
			cbSMMethod.SelectedIndex = 0;

			Util.SetLogView(tbLog);
			Config.Init();

			btUpdate.Enabled = false;
			btSell.Enabled = false;
			
			for (int i = 0; i < 21; i++)
			{
				lvCurPrice.Items.Add(new ListViewItem(new string[] { "", "", "", "" }));
				lvCurPrice.Items[i].UseItemStyleForSubItems = false;
				if (i < 10)
				{
					lvCurPrice.Items[i].SubItems[chAskCount.Index].BackColor = Color.FromArgb(215, 233, 255);
					lvCurPrice.Items[i].SubItems[chCallPrice.Index].BackColor = Color.FromArgb(215, 233, 255);
				}
				else if (i > 10)
				{
					lvCurPrice.Items[i].SubItems[chBidCount.Index].BackColor = Color.FromArgb(255, 227, 227);
					lvCurPrice.Items[i].SubItems[chCallPrice.Index].BackColor = Color.FromArgb(255, 227, 227);
				}
			}
			lvCurPrice.Items[10].SubItems[chAskCount.Index].Text = "현재가";
			lvCurPrice.Items[10].SubItems[chCallPrice.Index].Font = new Font(lvCurPrice.Items[0].SubItems[0].Font, FontStyle.Bold);

			cbAccount.Text = Config.GetAccount();
			tbSubAccount.Text = Config.GetSubAccount();
			tbBidCount.Text = Config.GetBidCount().ToString();
			tbTrailingP.Text = Config.GetTrailingRate().ToString();
			tbTrailingCnt.Text = Config.GetTrailingCnt().ToString();

			tbCFListSize.Text = Config.GetListSize().ToString();
			tbCFFastSD.Text = Config.GetFastSD().ToString();
			tbCFFastUp.Text = Config.GetFastUp().ToString();
			tbCFFastDown.Text = Config.GetFastDown().ToString();
			tbCFSlowSD.Text = Config.GetSlowSD().ToString();
			tbCFSlowUp.Text = Config.GetSlowUp().ToString();
			tbCFSlowDown.Text = Config.GetSlowDown().ToString();
			tbCFTimeLimit.Text = Config.GetTimeLimit().ToString();
			tbCFTimeDown.Text = Config.GetTimeDown().ToString();
			tbCFIgnorePrice.Text = Config.GetIgnorePrice().ToString();

			cbMockTrading.Checked = Config.GetMockTrading();

			m_CybosHelper = new CybosHelper(this);

			m_iCurPricePanelWith = 240;

			var materialSkinManager = MaterialSkinManager.Instance;
			materialSkinManager.AddFormToManage(this);
			materialSkinManager.Theme = MaterialSkinManager.Themes.DARK;
			materialSkinManager.ColorScheme = new ColorScheme(Primary.BlueGrey800, Primary.BlueGrey900, Primary.BlueGrey500, Accent.LightBlue200, TextShade.WHITE);

			m_Timer.Interval = 500;
			m_Timer.Elapsed += Timer_Elapsed;
			m_Timer.Start();
		}

		public void SetAccountList(string[] aAccountList)
		{
			Action update = new Action(delegate {
				cbAccount.Items.Clear();
				cbAccount.Items.AddRange(aAccountList);
				foreach (var account in aAccountList)
				{
					if (account == Config.GetAccount())
					{
						cbAccount.SelectedItem = account;
						break;
					}
				}
			});

			if (cbAccount.InvokeRequired)
				cbAccount.Invoke(update);
			else
				update();
		}

		private void splitContainer2_SizeChanged(object sender, EventArgs e)
		{
			int iDist = Math.Min(Math.Max(splitContainer2.Width-m_iCurPricePanelWith, splitContainer2.Panel1MinSize), splitContainer2.Width-splitContainer2.Panel2MinSize);
			if(iDist >= splitContainer2.Panel1MinSize && iDist <= splitContainer2.Width - splitContainer2.Panel2MinSize)
				splitContainer2.SplitterDistance = iDist;
		}

		private async void btCybos_Click(object sender, EventArgs e)
		{
			await m_CybosHelper.InitCybosAsync();

			btCybos.Primary = false;
			btCybos.Enabled = false;

			btUpdate.Enabled = true;
			btSell.Enabled = true;
		}

		void SyncItems(List<ITEM> OldItems, List<ITEM> NewItems)
		{
			foreach(ITEM newItem in NewItems)
			{
				ITEM oldItem = OldItems.FirstOrDefault(s => s.m_strCode == newItem.m_strCode);
				if (oldItem != null)
				{
					// update
					oldItem.m_iItemCnt = newItem.m_iItemCnt;
					oldItem.m_iAssessedValue = newItem.m_iAssessedValue;
					oldItem.m_iValuationGains = newItem.m_iValuationGains;
					oldItem.m_dYield = newItem.m_dYield;
					oldItem.m_iAvailableQuantity = newItem.m_iAvailableQuantity;
					oldItem.m_dBookUnitPrice = newItem.m_dBookUnitPrice;
					oldItem.m_iProfitUnitPrice = newItem.m_iProfitUnitPrice;
					oldItem.m_iCurPrice = newItem.m_iCurPrice;
				}
				else
				{
					// add
					m_Items.Add(newItem);
					m_CybosHelper.Subscribe(newItem);
				}
			}

			// remove
			OldItems.RemoveAll(s => (NewItems.Any(k => k.m_strCode == s.m_strCode) == false));
		}

		void SyncListViewItems(List<ITEM> Items)
		{
			foreach (ListViewItem item in lvItems.Items)
			{
				if (Items.Any(t => t.m_strCode == item.SubItems[chCode.Index].Text) == false)
					item.Remove();
			}

			//lvItems.Items.Cast<ListViewItem>().ToList().RemoveAll(s => (Items.Any(t => t.m_strCode == s.SubItems[chCode.Index].Text) == false));

			foreach(ITEM item in Items)
			{
				ListViewItem row = lvItems.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chCode.Index].Text == item.m_strCode);
				if(row == null)
				{
					// insert
					row = lvItems.Items.Add(new ListViewItem(new string[12]));
					row.SubItems[chCode.Index].Text = item.m_strCode;
					row.SubItems[chCodeName.Index].Text = item.m_strCodeName;

					row.UseItemStyleForSubItems = false;
				}

				// update
				STOCK_CUR_ITEM ItemCur = m_CybosHelper.GetItem(item.m_strCode);

				row.SubItems[chCurPrice.Index].Text = string.Format("{0:n0}", item.m_iCurPrice);
				row.SubItems[chCount.Index].Text = string.Format("{0:n0}", item.m_iItemCnt);
				row.SubItems[chBookValue.Index].Text = string.Format("{0:n2}", item.m_dBookUnitPrice);
				row.SubItems[chCapitalGains.Index].Text = string.Format("{0:n0}", item.m_iProfitUnitPrice);
				row.SubItems[chAssessedValue.Index].Text = string.Format("{0:n0}", item.m_iAssessedValue / 1000);
				row.SubItems[chValuation.Index].Text = string.Format("{0:n0}", item.m_iValuationGains / 1000);
				row.SubItems[chYield.Index].Text = string.Format("{0:n2}", item.m_dYield);
				row.SubItems[chMaxPrice.Index].Text = ItemCur != null ? string.Format("{0:n0}", ItemCur.m_iMaxPrice) : "";
				row.SubItems[chCheckCountLimit.Index].Text = ItemCur != null ? string.Format("{0:n2}", ItemCur.m_dCheckCountLimit) : "";
				row.SubItems[chCheckCount.Index].Text = ItemCur != null ? string.Format("{0:n0}", ItemCur.m_iCheckCount) : "";

				row.SubItems[chValuation.Index].ForeColor = (item.m_iValuationGains > 0) ? Color.Red : (item.m_iValuationGains < 0) ? Color.Blue : Color.Black;
				row.SubItems[chYield.Index].ForeColor = (item.m_dYield > 0) ? Color.Red : (item.m_dYield < 0) ? Color.Blue : Color.Black;
			}
		}

		public void UpdateItem()
		{
			m_CybosHelper.UpdateItems();
		}

		public void UpdateItemCallback(List<ITEM> Items)
		{
			SyncItems(m_Items, Items);
			SyncListViewItems(m_Items);
		}

		void SyncNCItems(List<NCITEM> oldList, List<NCITEM> newList)
		{
			oldList.RemoveAll(s => newList.Any(t => t.m_iOrgOrderNo == s.m_iOrgOrderNo) == false);
			foreach (var NCItem in newList)
			{
				if (oldList.Any(s => s.m_iOrgOrderNo == NCItem.m_iOrgOrderNo) == false)
				{
					NCItem.m_Time = DateTime.Now;
					oldList.Add(NCItem);
				}
			}
		}

		void SyncNCListVIewItems(List<NCITEM> NCItems)
		{
			foreach(ListViewItem item in lvNCItem.Items)
			{
				if (NCItems.Any(t => t.m_iOrgOrderNo.ToString() == item.SubItems[chNCOrgOrderNo.Index].Text) == false)
					item.Remove();
			}
			//lvNCItem.Items.Cast<ListViewItem>().ToList().RemoveAll(r => 
			//	NCItems.Any(t => (t.m_iOrgOrderNo.ToString() == r.SubItems[chNCOrgOrderNo.Index].Text) == false));

			foreach (var NCItem in NCItems)
			{
				ListViewItem row = lvNCItem.Items.Cast<ListViewItem>().FirstOrDefault(r => r.SubItems[chNCOrgOrderNo.Index].Text == NCItem.m_iOrgOrderNo.ToString());
				if(row == null)
				{
					// insert
					row = new ListViewItem(new string[7]);
					row.SubItems[chNCOrderNo.Index].Text = NCItem.m_iOrderNo.ToString();
					row.SubItems[chNCOrgOrderNo.Index].Text = NCItem.m_iOrgOrderNo.ToString();
					row.SubItems[chNCCode.Index].Text = NCItem.m_strCode;
					row.SubItems[chNCCodeName.Index].Text = NCItem.m_strCodeName;
					row.SubItems[chNCType.Index].Text = NCItem.m_strDesc;

					row.UseItemStyleForSubItems = false;
					lvNCItem.Items.Add(row);
				}

				// update
				row.SubItems[chNCPrice.Index].Text = NCItem.m_iOrderPrice.ToString("n0");
				row.SubItems[chNCCount.Index].Text = NCItem.m_iRemainCnt.ToString("n0");
				row.SubItems[chNCType.Index].ForeColor = NCItem.m_bAsk ? Color.Blue : Color.Red;
			}
		}

		public void UpdateNCItem()
		{
			m_CybosHelper.UpdateNC();
		}

		public void UpdateNCItemCallback(List<AutoSeller.NCITEM> NCItems)
		{
			SyncNCItems(m_NCItems, NCItems);
			SyncNCListVIewItems(m_NCItems);
		}

		async Task CorrectItems()
		{
			if (m_bSell == false)
				return;

			List<NCITEM> cloned;
			lock (m_NCItems)
				cloned = m_NCItems.ConvertAll(s => s);

			foreach (var NCItem in cloned)
			{
				if (NCItem.m_bAsk == true && DateTime.Now - NCItem.m_Time >= TimeSpan.FromSeconds(5))
				{
					var CurItem = m_CybosHelper.GetItem(NCItem.m_strCode);
					if (CurItem == null)
						continue;

					int iPrice = CurItem.m_aiBidPrice[0];
					if (iPrice == NCItem.m_iOrderPrice)
						continue;

					await m_CybosHelper.CorrectionItem(NCItem.m_strCode, NCItem.m_iOrderNo, NCItem.m_iRemainCnt, iPrice);
					NCItem.m_Time = DateTime.Now;
					Util.Log(Util.LOG_TYPE.SELL, string.Format("[{0}] 정정 주문 (주문번호: {1})", NCItem.m_strCodeName, NCItem.m_iOrgOrderNo));
				}
			}
		}

		private async void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			await CorrectItems();

			lbRQCnt.Invoke(new Action(delegate {
				lbRQCnt.Text = $"{m_CybosHelper.GetLimitRemainCountRQ(), 3}";
			}));
			lbTRCnt.Invoke(new Action(delegate {
				lbTRCnt.Text = $"{m_CybosHelper.GetLimitRemainCountTrade(), 3}";
			}));
			lbSBCnt.Invoke(new Action(delegate {
				lbSBCnt.Text = $"{m_CybosHelper.GetLimitRemainCountSB(), 3}";
			}));
		}

		private void btUpdate_Click(object sender, EventArgs e)
		{
			UpdateItem();
		}

		public class HttpResult
		{
			public HttpStatusCode StatusCode;
			public string strData;
		};

		async Task<HttpResult> Request(string url, HttpMethod method,
			string data = null,
			Dictionary<string, string> headers = null)
		{
			HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
			req.Method = method.ToString();
			req.ContentType = "application/json";
			if (headers != null)
			{
				foreach (var kv in headers)
					req.Headers[kv.Key] = kv.Value;
			}

			if (data != null)
			{
				Stream writeStream = req.GetRequestStream();
				byte[] buffer = Encoding.UTF8.GetBytes(data);
				await writeStream.WriteAsync(buffer, 0, buffer.Length);
			}

			HttpWebResponse resp = null;
			HttpResult result = null;
			try
			{
				resp = await req.GetResponseAsync() as HttpWebResponse;
			}
			catch (WebException ex)
			{
				if (ex.Status == WebExceptionStatus.ProtocolError)
					resp = ex.Response as HttpWebResponse;
			}
			finally
			{
				Stream readStream = resp.GetResponseStream();
				StreamReader sr = new StreamReader(readStream);
				result = new HttpResult()
				{
					StatusCode = resp.StatusCode,
					strData = await sr.ReadToEndAsync()
				};
			}

			return result;
		}

		async void SendConfiguration()
		{
			var oData = new
			{
				Mac = NetworkInterface.GetAllNetworkInterfaces()[0].GetPhysicalAddress().ToString(),
				Date = DateTime.Now.ToString("yyyy-MM-dd"),
				Config = Config.GetAllConfig(),
			};

			string serverURL = "http://mjjo53.us.to:9200";
			string index = "trading-autoseller";
			string doc = "default";
			string id = $"{oData.Mac}-{oData.Date}";
			JObject data = JObject.FromObject(oData);
			string json = data.ToString(Newtonsoft.Json.Formatting.Indented);

			Dictionary<string, string> headers = new Dictionary<string, string>();
			headers["Authorization"] = "Basic dHJhZGVyOnNidG1hb2Fv";

			var result = await Request($"{serverURL}/{index}/{doc}/{id}?pretty", HttpMethod.Post, json, headers);
		}

		private void btSell_Click(object sender, EventArgs e)
		{
			btSell.Primary = !btSell.Primary;
			m_bSell = (btSell.Primary == false);

			if(m_bSell == true)
			{
				//FileTransfer ft = new FileTransfer();
				//string today = DateTime.Now.ToString("yyyy-MM-dd");
				//string macAddr = NetworkInterface.GetAllNetworkInterfaces()[0].GetPhysicalAddress().ToString();
				//ft.SendDir("/configure", macAddr + "/AutoSeller/" + today);
				//ft.SendDir("/log", macAddr + "/AutoSeller");
				//ft.SendDir("/simulation", macAddr + "/AutoSeller");

				SendConfiguration();
			}
		}

		public bool IsSelling()
		{
			return m_bSell;
		}

		public void OnReceivedCurPrice(string strCode, int iPrice, int iMaxPrice, double dCheckCountLimit, int iCheckCount, bool bReal)
		{
			ITEM Item = m_Items.FirstOrDefault(s => s.m_strCode == strCode);
			if (Item == default(ITEM))
				return;

			Item.m_iCurPrice = iPrice;
			Item.m_iAssessedValue = iPrice * Item.m_iItemCnt;
			Item.m_iValuationGains = (iPrice-Item.m_iProfitUnitPrice)*Item.m_iItemCnt;
			Item.m_dYield = (iPrice-Item.m_iProfitUnitPrice)*100 / (double)Item.m_iProfitUnitPrice;

			Action update = delegate {
				ListViewItem row = lvItems.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chCode.Index].Text == strCode);
				if (row == default(ListViewItem))
					return;

				row.SubItems[chCurPrice.Index].Text = string.Format("{0}{1:n0}", bReal ? "" : "*", Item.m_iCurPrice);
				row.SubItems[chAssessedValue.Index].Text = string.Format("{0:n0}", Item.m_iAssessedValue / 1000);
				row.SubItems[chValuation.Index].Text = string.Format("{0:n0}", Item.m_iValuationGains / 1000);
				row.SubItems[chYield.Index].Text = string.Format("{0:n2}", Item.m_dYield);
				row.SubItems[chMaxPrice.Index].Text = string.Format("{0:n0}", iMaxPrice);
				row.SubItems[chCheckCountLimit.Index].Text = string.Format("{0:n2}", dCheckCountLimit);
				row.SubItems[chCheckCount.Index].Text = string.Format("{0:n0}", iCheckCount);
			};

			if (lvItems.InvokeRequired)
				lvItems.BeginInvoke(update);
			else
				update();

			if(strCode == m_strSelectedCode)
			{
				lvCurPrice.BeginInvoke((MethodInvoker)(() => {
					lvCurPrice.Items[10].SubItems[chCallPrice.Index].Text = string.Format("{0:n0}", Item.m_iCurPrice);
				}));
			}
		}

		public void OnReceivedCall(string strCode, int iCurPrice, int[] aiBidPrice, int[] aiBidCount, int[] aiAskPrice, int[] aiAskCount)
		{
			if (strCode != m_strSelectedCode)
				return;

			ITEM Item = m_Items.FirstOrDefault(s => s.m_strCode == strCode);
			if (Item == default(ITEM))
				return;

			Action update = delegate {
				if (iCurPrice > 0)
					lvCurPrice.Items[10].SubItems[chCallPrice.Index].Text = string.Format("{0:n0}", iCurPrice);

				for (int i = 0; i < 10; i++)
				{
					lvCurPrice.Items[i].SubItems[chAskCount.Index].Text = string.Format("{0:n0}", aiAskCount[9 - i]);
					lvCurPrice.Items[i].SubItems[chCallPrice.Index].Text = string.Format("{0:n0}", aiAskPrice[9 - i]);
				}

				for (int i = 0; i < 10; i++)
				{
					lvCurPrice.Items[11 + i].SubItems[chBidCount.Index].Text = string.Format("{0:n0}", aiBidCount[i]);
					lvCurPrice.Items[11 + i].SubItems[chCallPrice.Index].Text = string.Format("{0:n0}", aiBidPrice[i]);
				}
			};

			if (lvCurPrice.InvokeRequired)
				lvCurPrice.BeginInvoke(update);
			else
				update();
		}

		public int GetSellableCount(string strCode)
		{
			ITEM Item = m_Items.FirstOrDefault(s => s.m_strCode == strCode);
			if(Item == default(ITEM))
				return 0;

			return Item.m_iAvailableQuantity;
		}

		private void lvList_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (lvItems.SelectedItems.Count <= 0)
				return;

			string strCode = lvItems.SelectedItems[0].SubItems[chCode.Index].Text;
			STOCK_CUR_ITEM Item = m_CybosHelper.GetItem(strCode);
			if (Item == null)
				return;

			m_strSelectedCode = strCode;
			OnReceivedCall(strCode, Item.m_iCurPrice, Item.m_aiBidPrice, Item.m_aiBidCount, Item.m_aiAskPrice, Item.m_aiAskCount);
			//OnReceivedCurPrice(strCode, Item.m_iCurPrice);
		}

		private void btApply_Click(object sender, EventArgs e)
		{
			string strAccount = (string)cbAccount.SelectedItem;
			string strSubAccount = tbSubAccount.Text;
			Config.SetAccount(strAccount, strSubAccount);

			int iBidCount = 0;
			int.TryParse(tbBidCount.Text, out iBidCount);
			Config.SetBidCount(iBidCount);

			float fTrailingPercent = 0;
			float.TryParse(tbTrailingP.Text, out fTrailingPercent);
			int iTrailingCnt = 0;
			int.TryParse(tbTrailingCnt.Text, out iTrailingCnt);
			Config.SetTrailing(fTrailingPercent, iTrailingCnt);

			int iListSize;
			double dFastSD;
			double dFastUp;
			double dFastDown;
			double dSlowSD;
			double dSlowUp;
			double dSlowDown;
			int iTimeLimit;
			double dTimeDown;
			int iIgnorePrice;

			int.TryParse(tbCFListSize.Text, out iListSize);
			double.TryParse(tbCFFastSD.Text, out dFastSD);
			double.TryParse(tbCFFastUp.Text, out dFastUp);
			double.TryParse(tbCFFastDown.Text, out dFastDown);
			double.TryParse(tbCFSlowSD.Text, out dSlowSD);
			double.TryParse(tbCFSlowUp.Text, out dSlowUp);
			double.TryParse(tbCFSlowDown.Text, out dSlowDown);
			int.TryParse(tbCFTimeLimit.Text, out iTimeLimit);
			double.TryParse(tbCFTimeDown.Text, out dTimeDown);
			int.TryParse(tbCFIgnorePrice.Text, out iIgnorePrice);
			Config.SetVolatility(iListSize, dFastSD, dFastUp, dFastDown, dSlowSD, dSlowUp, dSlowDown, iTimeLimit, dTimeDown, iIgnorePrice);

			Config.SetMockTrading(cbMockTrading.Checked);
		}

		class ListViewItemComparer : IComparer
		{
			int m_iColumn = 0;
			SortOrder m_Order = SortOrder.Descending;

			public ListViewItemComparer(int column, SortOrder Order)
			{
				m_iColumn = column;
				m_Order = Order;
			}

			public int Compare(object x, object y)
			{
				ListViewItem item1 = (ListViewItem)x;
				ListViewItem item2 = (ListViewItem)y;

				double num1;
				double num2;
				if (double.TryParse(item1.SubItems[m_iColumn].Text, out num1) &&
					double.TryParse(item2.SubItems[m_iColumn].Text, out num2))
				{
					if (m_Order == SortOrder.Ascending)
						return (num1 > num2) ? 1 : -1;
					else
						return (num1 > num2) ? -1 : 1;
				}
				else
				{
					if (m_Order == SortOrder.Ascending)
						return string.Compare(item1.SubItems[m_iColumn].Text, item2.SubItems[m_iColumn].Text);
					else
						return string.Compare(item2.SubItems[m_iColumn].Text, item1.SubItems[m_iColumn].Text);
				}
			}
		}

		#region Simulation
		private void btLoad_Click(object sender, EventArgs e)
		{
			SimulationHelper helper = new SimulationHelper(this, m_CybosHelper, tbSimulationLog);
			helper.LoadExcel2();
		}

		private void btSimulate_Click(object sender, EventArgs e)
		{
			SimulationHelper helper = new SimulationHelper(this, m_CybosHelper, tbSimulationLog);
			helper.StartSimuation2();
		}

		private void btUpdateNC_Click(object sender, EventArgs e)
		{
			UpdateNCItem();
		}
		#endregion

		private void lvItems_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			SortOrder Order = (lvItems.Sorting == SortOrder.Ascending || lvItems.Sorting == SortOrder.None) ? SortOrder.Descending : SortOrder.Ascending;

			lvItems.ListViewItemSorter = new ListViewItemComparer(e.Column, Order);
			lvItems.Sorting = Order;
			lvItems.Sort();
		}

		private void lvNCItem_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			SortOrder Order = (lvNCItem.Sorting == SortOrder.Ascending || lvNCItem.Sorting == SortOrder.None) ? SortOrder.Descending : SortOrder.Ascending;

			lvNCItem.ListViewItemSorter = new ListViewItemComparer(e.Column, Order);
			lvNCItem.Sorting = Order;
			lvNCItem.Sort();
		}

		private async void btClearAll_Click(object sender, EventArgs e)
		{
			List<ITEM> cloned;
			lock (m_Items)
				cloned = m_Items.ConvertAll(s => s);
			foreach(var item in cloned)
			{
				await m_CybosHelper.SellItem(item.m_strCode, item.m_iItemCnt);
			}
		}

		private void btUpdateConclusion_Click(object sender, EventArgs e)
		{
			m_CybosHelper.GetConclusion();
		}

		public void UpdateConclusionCallback(List<CybosHelper.CONCLUSION> data)
		{
			List<ListViewItem> items = new List<ListViewItem>();
			string lastItemCode = "";
			foreach(var conclusion in data)
			{
				bool bSameItem = (conclusion.strCode == lastItemCode);

				var listItem = new ListViewItem(new string[] {
					bSameItem ? "" : conclusion.strCode,
					bSameItem ? "" : conclusion.strCodeName,
					conclusion.strSellBuy,
					conclusion.iCommitedAmount.ToString("n0"),
					conclusion.iSettlementAmount.ToString("n0"),
					conclusion.iFee.ToString("n0"),
					conclusion.iTransactionTax.ToString("n0"),
					conclusion.iSpecialTax.ToString("n0"),
					conclusion.strDate
				});

				if (conclusion.strSellBuy == "매수")
					listItem.SubItems[2].ForeColor = Color.Red;
				else
					listItem.SubItems[2].ForeColor = Color.Blue;
				listItem.UseItemStyleForSubItems = false;

				items.Add(listItem);
			}

			lvConclusion.Invoke(new Action(() => {
				lvConclusion.BeginUpdate();
				lvConclusion.Items.Clear();
				lvConclusion.Items.AddRange(items.ToArray());
				foreach (ColumnHeader col in lvConclusion.Columns)
					col.Width = -2;
				lvConclusion.EndUpdate();
			}));
		}
	}
}
