using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NewsCrawler
{
	public partial class NewsForm : Form
	{
		class NEWS_ITEM
		{
			public NEWS_ITEM(int iID, string strTitle, string strCode, CodeList.CODE_VALUE Code,
				DateTime NewsTime, DateTime ResTime, string strRef, string strURL, float fElapseT)
			{
				m_iID = iID;
				m_strCode = strCode;
				m_Code = Code;
				m_NewsTime = NewsTime;
				m_ResTime = ResTime;
				m_strRef = strRef;
				m_strTitle = strTitle;
				m_strURL = strURL;
				m_fElapseT = fElapseT;
			}

			public int m_iID;

			public string m_strCode;
			public CodeList.CODE_VALUE m_Code = null;

			public DateTime m_NewsTime;
			public DateTime m_ResTime;

			public string m_strRef;
			public string m_strTitle;
			public string m_strURL;

			public float m_fElapseT;
		}

		class PRICE_CHECK_DATA
		{
			public int m_iID;
			public CodeList.CODE_VALUE m_Code;
			public int m_iPriceStart = 0;
			public int m_iPriceLow = 0;
			public int m_iPriceHigh = 0;
			public DateTime m_StartTime;
			public int m_iTryCnt = 0;
			public bool m_bLog = false;

			public NEWS_ITEM m_NewsItem;
		}

		CybosHelper m_CybosHelper = null;
		CodeList m_CodeList = null;
		TextCondition m_Condition = null;
		ConfigForm m_ConfigForm = null;

		DateTime m_StartTime;
		DateTime m_EndTime;

		System.Timers.Timer m_CrawlTimer = new System.Timers.Timer();
		int m_iCrawlInterval = 500;
		bool m_bBuy = false;

		List<string> m_URLs = new List<string>();

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

		ConcurrentQueue<PRICE_CHECK_DATA> m_PriceCheckList = new ConcurrentQueue<PRICE_CHECK_DATA>();
		System.Timers.Timer m_PriceCheckTimer = new System.Timers.Timer();

		delegate void InsertListView(string strTitle, string strName, string strCode, DateTime time, DateTime ResTime, string strURL, string strRef, double responseT, bool bInitial);
		InsertListView m_InsertListViewDelegate = null;

		Crawler m_Crawler = null;

		ExcelHandler m_Excel = null;

		object m_lvListLock = new object();

		


		public NewsForm()
		{
			InitializeComponent();

			m_StartTime = DateTime.ParseExact("09:00", "HH:mm", CultureInfo.CurrentCulture);
			m_EndTime = DateTime.ParseExact("15:30", "HH:mm", CultureInfo.CurrentCulture);

			Config.Init();
			Util.SetLogView(tbLog);
			m_CodeList = new CodeList();
			m_Condition = new TextCondition();
			m_CybosHelper = new CybosHelper(this);
			m_Crawler = new Crawler(this);

			Util.Log(Util.LOG_TYPE.VERVOSE, "========== NewsCrawler 실행 ==========");

			//MessageBox.Show("Keywords : \n\n" + m_Condition.GetKeywordsCnt());

			m_InsertListViewDelegate = new InsertListView(this.InsertItem);

			m_Crawler.ReadKIND(true);
			m_Crawler.ReadDart(true);
			m_Crawler.ReadEtoday(true);
			//m_Crawler.ReadEtoday2(true);
			m_Crawler.ReadAsiaE(true);
			m_Crawler.ReadEdaily(true);
			m_Crawler.ReadMoneyToday(true);
			m_Crawler.ReadFinancialNews(true);


			lvList.Columns[chTime.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chResponseT.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chResT.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chId.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chPriceS.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chPriceLow.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chPriceLowP.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chPriceHigh.Index].TextAlign = HorizontalAlignment.Right;
			lvList.Columns[chPriceHighP.Index].TextAlign = HorizontalAlignment.Right;

			lvList.ListViewItemSorter = new ListViewItemComparer(chId.Index, SortOrder.Ascending);
			lvList.Sorting = SortOrder.Ascending;
			lvList.Sort();

			if(lvList.Items.Count > 0)
			{
				lvList.Items[lvList.Items.Count - 1].Selected = true;
				lvList.Select();
				if(lvList.SelectedItems.Count > 0)
					lvList.SelectedItems[0].EnsureVisible();
			}

			//foreach(ColumnHeader col in lvList.Columns)
			//{
			//	if(!(col == chPriceS || col == chPriceLow || col == chPriceHigh))
			//		col.Width = -2;
			//}

			m_Excel = new ExcelHandler(Util.GetLogPath()+"/PriceCheck"+DateTime.Now.ToString("yyyy-MM-dd")+".csv");

			m_CrawlTimer.Elapsed+=CrawlTimer_Tick;
			m_CrawlTimer.Interval = m_iCrawlInterval;
			m_CrawlTimer.Start();

			m_SystemTimer.Elapsed+=SystemTimer_Elapsed;
			m_SystemTimer.Interval=1000;
			m_SystemTimer.Start();

			m_PriceCheckTimer.Interval = 5000;
			m_PriceCheckTimer.Elapsed += PriceCheckTimer_Elapsed;
			m_PriceCheckTimer.Start();

			m_bBuy = true;

			Test();
		}

		void Test()
		{
			if(Util.IsDebugging() == false)
				return;

			InsertItem("[test] 덕산하이메탈, 덕산네오룩스 66만여주 취득14:38", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914371817318", "asiae", 0, false);
			InsertItem("[test] 자연과환경, 12월15일~22일 주주명부폐쇄14:19", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914193170301", "asiae", 0, false);
			InsertItem("[test] 이엠코리아, 한국항공우주산업과 3억원 규모 공급계약14:06", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.asiae.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914055964082", "asiae", 0, false);
			InsertItem("[test] [특징주]	진원생명과학, 국외 AI 인체감염증...", "", "", new DateTime(2016, 11, 30, 00, 00, 00), DateTime.Now, "http://www.etoday.co.kr/news/sokbo/sokbo_view.htm?idxno=2016112914055964082", "이투데이", 0, false);
		}

		private void BuyItem(CodeList.CODE_VALUE Code)
		{
			if(m_bBuy == false)
				return;

			if((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
			{
				Util.Log(Util.LOG_TYPE.DENIAL, string.Format("거부종목 ({0})", Code));
				return;
			}

			if((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
			{
				Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("중복종목 ({0})", Code));
				return;
			}

			m_CybosHelper.Buy(Code, Config.GetBuyPrice());
			m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName);
		}

		public void OnManualItemBuy(CodeList.CODE_VALUE Code)
		{
			BuyItem(Code);
		}

		void CheckPrice(NEWS_ITEM NewsItem)
		{
			if(DateTime.Now < m_StartTime || DateTime.Now >= m_EndTime)
				return;

			PRICE_CHECK_DATA CheckData = new PRICE_CHECK_DATA();
			CheckData.m_iID = NewsItem.m_iID;
			CheckData.m_Code = NewsItem.m_Code;
			CheckData.m_StartTime = DateTime.Now;
			CheckData.m_NewsItem = NewsItem;
			m_PriceCheckList.Enqueue(CheckData);
		}

		void ProcessSearchAndBuy(NEWS_ITEM NewsItem)
		{
			TextCondition.RESULT MatchResult = m_Condition.Match(NewsItem.m_strTitle);
			switch(MatchResult.m_enType)
			{
				case TextCondition.TYPE.NEGATIVE:
					Util.Log(Util.LOG_TYPE.NEGATIVE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));
					break;

				case TextCondition.TYPE.POSITIVE:
					if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
						Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));
					else if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
						Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));
					else if((NewsItem.m_Code.m_enType&CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL)
					{
						Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));

						if(m_bBuy == true)
						{
							ModelessPopup ManualPopup = new ModelessPopup(this);
							ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n(keyword:{3}, code:{4})\n\n매수하시겠습니까?",
								DateTime.Now.ToString("[hh:mm:ss]"),
								NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code), NewsItem.m_Code);
							ManualPopup.TopMost = true;
							ManualPopup.Show();
						}
					}
					else
					{
						BuyItem(NewsItem.m_Code);
						Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));
					}

					m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName);
					break;

				case TextCondition.TYPE.MANUAL:
					Util.Log(Util.LOG_TYPE.MANUAL_KEYWORD, string.Format("[{0}] {1} (keyword:{2}, code:{3})", NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code.ToString()));

					if(m_bBuy == true)
					{
						ModelessPopup ManualPopup = new ModelessPopup(this);
						ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n(keyword:{3}, code:{4})\n\n매수하시겠습니까?",
							DateTime.Now.ToString("[hh:mm:ss]"),
							NewsItem.m_strRef, NewsItem.m_strTitle, MatchResult.m_strKeyword, NewsItem.m_Code), NewsItem.m_Code);
						ManualPopup.TopMost = true;
						ManualPopup.Show();
					}

					m_CodeList.AddDuplicatedList(NewsItem.m_Code.m_strCode, NewsItem.m_Code.m_strName);
					break;

				case TextCondition.TYPE.NOT_MATCHED:
					Util.Log(Util.LOG_TYPE.DEBUG, string.Format("[NOT_MATCHED] [{0}] {1}({2})", NewsItem.m_strRef, NewsItem.m_strTitle, NewsItem.m_Code.ToString()));
					break;
			}

			CheckPrice(NewsItem);
		}

		public void OnReceivedSupplyContract(string strCodeName, float fRate)
		{
			CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName);
			if(Code == null)
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][공급계약체결] 종목을 찾을 수 없음({0}, {1}%", strCodeName, fRate));
				return;
			}

			if(fRate < Config.GetSupplyContractRate())
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][공급계약체결] 매출액 대비율 낮음({0}, {1}% / {2}%)", strCodeName, fRate, Config.GetSupplyContractRate()));
				return;
			}

			string strRef = "DartAPI";
			string strTitle = string.Format("공급계약체결 - {0} {1:n2}%", strCodeName, fRate);

			if((Code.m_enType&CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
				Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle));
			else if((Code.m_enType&CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
				Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle));
			else if((Code.m_enType&CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL)
			{
				Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle));

				if(m_bBuy == true)
				{
					ModelessPopup ManualPopup = new ModelessPopup(this);
					ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?",
						DateTime.Now.ToString("[hh:mm:ss]"),
						strRef, strTitle), Code);
					ManualPopup.TopMost = true;
					ManualPopup.Show();
				}
			}
			else
			{
				BuyItem(Code);
				Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle));
			}

			m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName);
		}

		public void OnReceivedRevenue(string strCodeName, float fRate)
		{
			CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName);
			if (Code == null)
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][영업실적] 종목을 찾을 수 없음({0}, {1}%", strCodeName, fRate));
				return;
			}

			if (fRate < Config.GetRevenueRate())
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][영업실적] 당기순이익률 낮음({0}, {1}% / {2}%)", strCodeName, fRate, Config.GetRevenueRate()));
				return;
			}

			string strRef = "DartAPI";
			string strTitle = string.Format("영업실적 - {0} {1:n2}%", strCodeName, fRate);

			if ((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
				Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle));
			else if ((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
				Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle));
			else if ((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL)
			{
				Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle));

				if (m_bBuy == true)
				{
					ModelessPopup ManualPopup = new ModelessPopup(this);
					ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?",
						DateTime.Now.ToString("[hh:mm:ss]"),
						strRef, strTitle), Code);
					ManualPopup.TopMost = true;
					ManualPopup.Show();
				}
			}
			else
			{
				BuyItem(Code);
				Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle));
			}

			m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName);
		}

		public void OnReceivedRightsIssue(string strCodeName)
		{
			CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName);
			if (Code == null)
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][제3자배정증자] 종목을 찾을 수 없음({0})", strCodeName));
				return;
			}

			string strRef = "DartAPI";
			string strTitle = string.Format("제3자배정증자 - {0}", strCodeName);

			if ((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
				Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle));
			else if ((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
				Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle));
			else if ((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL)
			{
				Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle));

				if (m_bBuy == true)
				{
					ModelessPopup ManualPopup = new ModelessPopup(this);
					ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?",
						DateTime.Now.ToString("[hh:mm:ss]"),
						strRef, strTitle), Code);
					ManualPopup.TopMost = true;
					ManualPopup.Show();
				}
			}
			else
			{
				BuyItem(Code);
				Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle));
			}

			m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName);
		}

		public void OnReceivedPatent(string strCodeName)
		{
			CodeList.CODE_VALUE Code = m_CodeList.GetCodeByName(strCodeName);
			if(Code == null)
			{
				Util.Log(Util.LOG_TYPE.VERVOSE, string.Format("[DartAPI][특허권취득] 종목을 찾을 수 없음({0})", strCodeName));
				return;
			}

			string strRef = "DartAPI";
			string strTitle = string.Format("특허권취득 - {0}", strCodeName);

			if((Code.m_enType & CodeList.CODE_TYPE.DENIAL) == CodeList.CODE_TYPE.DENIAL)
				Util.Log(Util.LOG_TYPE.DENIAL, string.Format("[{0}] {1}", strRef, strTitle));
			else if((Code.m_enType & CodeList.CODE_TYPE.DUPLICATED) == CodeList.CODE_TYPE.DUPLICATED)
				Util.Log(Util.LOG_TYPE.DUPLICATED, string.Format("[{0}] {1}", strRef, strTitle));
			else if((Code.m_enType & CodeList.CODE_TYPE.MANUAL) == CodeList.CODE_TYPE.MANUAL)
			{
				Util.Log(Util.LOG_TYPE.MANUAL_CODE, string.Format("[{0}] {1}", strRef, strTitle));

				if(m_bBuy == true)
				{
					ModelessPopup ManualPopup = new ModelessPopup(this);
					ManualPopup.SetMessage(string.Format("{0}\n[{1}] {2}\n\n매수하시겠습니까?",
						DateTime.Now.ToString("[hh:mm:ss]"),
						strRef, strTitle), Code);
					ManualPopup.TopMost = true;
					ManualPopup.Show();
				}
			}
			else
			{
				BuyItem(Code);
				Util.Log(Util.LOG_TYPE.POSITIVE, string.Format("[{0}] {1}", strRef, strTitle));
			}

			m_CodeList.AddDuplicatedList(Code.m_strCode, Code.m_strName);
		}

		public bool IsDuplicatedURL(string strURL)
		{
			if(strURL == "")
				return false;

			lock(m_URLs)
				return m_URLs.Any(s => s == strURL);
		}

		public void InsertItem(string strTitle, string strName, string strCode, DateTime time, DateTime ResTime, string strURL, string strRef, double dElapseT, bool bInitial)
		{
			try
			{
				if(this.InvokeRequired)
				{
					this.Invoke(m_InsertListViewDelegate, strTitle, strName, strCode, time, ResTime, strURL, strRef, dElapseT, bInitial);
				}
				else
				{
					if(IsDuplicatedURL(strURL) == true)
						return;

					int iID = lvList.Items.Count+1;

					CodeList.CODE_VALUE Code = null;
					if(bInitial == false)
					{
						if(strCode == "")
							Code = m_CodeList.SearchCode(strTitle);
						else
							Code = m_CodeList.GetCode(strCode);

						if(Code != null)
							ProcessSearchAndBuy(new NEWS_ITEM(iID, strTitle, strCode, Code, time, ResTime, strRef, strURL, (float)dElapseT));
					}
						

					lvList.Items.Add(new ListViewItem(new string[] {
						iID.ToString(),
						time.ToString("HH:mm:ss"),
						ResTime.ToString("HH:mm:ss:fff"),
						string.Format("{0:n3} ms", dElapseT),
						strRef,
						strTitle,
						(Code != null) ? Code.m_strName : "",
						"",
						"",
						"",
						"",
						"",
						strURL }));

					if(lvList.Items.Count == 0)
					{
						foreach (ColumnHeader col in lvList.Columns)
						{
							if (!(col == chPriceS || col == chPriceLow || col == chPriceHigh))
								col.Width = -2;
						}
					}

					lock(m_URLs)
						m_URLs.Add(strURL);

					if(bInitial == false)
						lvList.Sort();
				}
			}
			catch(Exception ex)
			{
				Util.Log(Util.LOG_TYPE.ERROR, ex.Message + Environment.NewLine + ex.StackTrace);
			}
		}


		private void SystemTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			if(statusBar.InvokeRequired)
			{
				statusBar.BeginInvoke((MethodInvoker)delegate ()
				{
					statusBar.Items[3].Text = DateTime.Now.ToString("HH:mm:ss");
					statusBar.Items[2].Text = m_CybosHelper.GetLimitRemainCountRQ().ToString();
					statusBar.Items[0].Text = m_CybosHelper.IsConnected() ? "연결됨" : "연결끊김";
				});
			}
			else
			{
				statusBar.Items[3].Text = DateTime.Now.ToString("HH:mm:ss");
				statusBar.Items[2].Text = m_CybosHelper.GetLimitRemainCountRQ().ToString();
				statusBar.Items[0].Text = m_CybosHelper.IsConnected() ? "연결됨" : "연결끊김";
			}
		}


		private void CrawlTimer_Tick(object sender, EventArgs e)
		{
			m_CrawlTimer.Stop();

			if(chAutoReload.Checked == true)
			{
				m_Crawler.ReadKIND();
				m_Crawler.ReadDart();
				if(Config.CheckDartAPI())
					m_Crawler.ReadDartAPI();
				m_Crawler.ReadEtoday();
				//m_Crawler.ReadEtoday2();
				m_Crawler.ReadAsiaE();
				m_Crawler.ReadEdaily();
				m_Crawler.ReadMoneyToday();
				m_Crawler.ReadFinancialNews();
				
			}

			m_CrawlTimer.Interval = m_iCrawlInterval;
			m_CrawlTimer.Start();
		}

		private void UpdateStartPrice(int iID, int iPrice)
		{
			if(lvList.InvokeRequired)
			{
				lvList.BeginInvoke((MethodInvoker)delegate ()
			   {
				   ListViewItem item = lvList.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chId.Index].Text == iID.ToString());
				   item.SubItems[chPriceS.Index].Text = iPrice.ToString("n0");
				   lvList.Columns[chPriceS.Index].Width = -1;
			   });
			}
			else
			{
				ListViewItem item = lvList.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chId.Index].Text == iID.ToString());
				item.SubItems[chPriceS.Index].Text = iPrice.ToString("n0");
				lvList.Columns[chPriceS.Index].Width = -1;
			}
		}

		private void UpdateLowHighPrice(PRICE_CHECK_DATA Data)
		{
			if(lvList.InvokeRequired)
			{
				lvList.BeginInvoke((MethodInvoker)delegate ()
				{
					ListViewItem item = lvList.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chId.Index].Text == Data.m_iID.ToString());
					item.SubItems[chPriceLow.Index].Text = string.Format("{0:n0}", Data.m_iPriceLow);
					float fLowRate = (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart;
					item.UseItemStyleForSubItems = false;
					item.SubItems[chPriceLowP.Index].Text = string.Format("{0:n}", fLowRate);
					if(fLowRate > 0)
						item.SubItems[chPriceLowP.Index].ForeColor = Color.Red;
					else if(fLowRate < 0)
						item.SubItems[chPriceLowP.Index].ForeColor = Color.Blue;
					item.SubItems[chPriceHigh.Index].Text = string.Format("{0:n0}", Data.m_iPriceHigh);
					float fLowHigh = (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart;
					item.SubItems[chPriceHighP.Index].Text = string.Format("{0:n}", fLowHigh);
					if(fLowHigh > 0)
						item.SubItems[chPriceHighP.Index].ForeColor = Color.Red;
					else if(fLowHigh < 0)
						item.SubItems[chPriceHighP.Index].ForeColor = Color.Blue;

					lvList.Columns[chPriceHighP.Index].Width = -1;
					lvList.Columns[chPriceLowP.Index].Width = -1;
				});
			}
			else
			{
				ListViewItem item = lvList.Items.Cast<ListViewItem>().FirstOrDefault(s => s.SubItems[chId.Index].Text == Data.m_iID.ToString());
				item.SubItems[chPriceLow.Index].Text = string.Format("{0:n0}", Data.m_iPriceLow);
				float fLowRate = (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart;
				item.SubItems[chPriceLowP.Index].Text = string.Format("{0:n}", fLowRate);
				item.UseItemStyleForSubItems = false;
				if(fLowRate > 0)
					item.SubItems[chPriceLowP.Index].ForeColor = Color.Red;
				else if(fLowRate < 0)
					item.SubItems[chPriceLowP.Index].ForeColor = Color.Blue;
				item.SubItems[chPriceHigh.Index].Text = string.Format("{0:n0}", Data.m_iPriceHigh);
				float fLowHigh = (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart;
				item.SubItems[chPriceHighP.Index].Text = string.Format("{0:n}", fLowHigh);
				if(fLowHigh > 0)
					item.SubItems[chPriceHighP.Index].ForeColor = Color.Red;
				else if(fLowHigh < 0)
					item.SubItems[chPriceHighP.Index].ForeColor = Color.Blue;

				lvList.Columns[chPriceHighP.Index].Width = -1;
				lvList.Columns[chPriceLowP.Index].Width = -1;
			}
		}

		private void PriceCheckTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			if(cbPriceCheck.Checked == false)
				return;

			m_PriceCheckTimer.Enabled = false;

			DateTime CurTime = DateTime.Now;
			foreach(PRICE_CHECK_DATA data in m_PriceCheckList)
			{
				if(data.m_iPriceStart == 0)
				{
					data.m_iPriceStart = m_CybosHelper.GetCurPrice(data.m_Code);
					UpdateStartPrice(data.m_iID, data.m_iPriceStart);
				}
				else if(data.m_iPriceHigh == 0 && (CurTime - data.m_StartTime).Minutes >= 5)
				{
					m_CybosHelper.GetLowHighPrice(data.m_Code, data.m_StartTime, 5, out data.m_iPriceLow, out data.m_iPriceHigh);
					data.m_iTryCnt++;
					if(data.m_iPriceHigh > 0)
						UpdateLowHighPrice(data);
				}
			}

			while(m_PriceCheckList.Count > 0)
			{
				PRICE_CHECK_DATA Data;
				if(m_PriceCheckList.TryPeek(out Data) == false)
					break;

				if(Data.m_iTryCnt < 3 && Data.m_iPriceHigh == 0)
					break;

				if(Data.m_bLog == false)
				{
					Data.m_bLog = m_Excel.AddRow(Data.m_NewsItem.m_NewsTime.ToString("HH:mm:ss:fff"), Data.m_NewsItem.m_ResTime.ToString("HH:mm:ss:fff"), Data.m_NewsItem.m_fElapseT,
						Data.m_NewsItem.m_strRef, Data.m_NewsItem.m_strTitle, Data.m_NewsItem.m_Code.m_strName,
						Data.m_iPriceStart,
						Data.m_iPriceLow, (Data.m_iPriceLow-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart,
						Data.m_iPriceHigh, (Data.m_iPriceHigh-Data.m_iPriceStart)*100/(float)Data.m_iPriceStart,
						Data.m_NewsItem.m_strURL);
				}

				if(Data.m_bLog == false)
					break;

				m_PriceCheckList.TryDequeue(out Data);
			}
			

			m_PriceCheckTimer.Enabled = true;
		}

		private void tbInterval_KeyPress(object sender, KeyPressEventArgs e)
		{
			if(e.KeyChar == Convert.ToChar(Keys.Enter))
			{
				m_iCrawlInterval = (int)(float.Parse(Regex.Replace(tbInterval.Text, @"\D\.", "")) * 1000);
				if(m_iCrawlInterval < 1)
					m_iCrawlInterval = 500;

				tbInterval.Text = (m_iCrawlInterval / (float)1000).ToString("##0.0") + "초";
			}
		}

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

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

		private void lvList_DoubleClick(object sender, EventArgs e)
		{
			if(lvList.SelectedItems.Count < 1)
				return;

			string strLink = lvList.SelectedItems[0].SubItems[chLink.Index].Text;
			try
			{
				System.Diagnostics.Process.Start(strLink);
			} catch
			{

			}
		}

		private void btnConfig_Click(object sender, EventArgs e)
		{
			if(m_ConfigForm == null)
				m_ConfigForm = new ConfigForm(this);

			FormCollection OpenForms = Application.OpenForms;
			bool bOpen = false;
			foreach(Form form in OpenForms)
			{
				if(form == m_ConfigForm)
				{
					bOpen = true;
					break;
				}
			}

			if(bOpen == false)
			{
				m_ConfigForm.Show();
			}
			else
			{
				m_ConfigForm.BringToFront();
			}
		}

		public void OnConfigFormClosing()
		{
			m_ConfigForm = null;
		}

		public void OnManualCodeClick(int iPrice)
		{
			m_CodeList.MakeManualList(iPrice);
		}

		public void ApplyDenialCode()
		{
			m_CodeList.LoadDenialList();
		}
		public void ApplyDuplicatedCode()
		{
			m_CodeList.LoadDuplicatedList();
		}

		public void ApplyPositive()
		{
			m_Condition.LoadPositive();
		}

		public void ApplyManual()
		{
			m_Condition.LoadManual();
		}

		public void ApplyNegative()
		{
			m_Condition.LoadNegative();
		}

		public void ApplySynonym()
		{
			m_CodeList.LoadSynonym();
		}

		private void NewsForm_FormClosing(object sender, FormClosingEventArgs e)
		{
			Util.Clear();
		}

		private void chBuy_CheckedChanged(object sender, EventArgs e)
		{
			m_bBuy = chBuy.Checked;

			if(m_bBuy == true && Config.GetAccount() == "")
			{
				chBuy.Checked = false;
				MessageBox.Show("계좌를 선택해주시기 바랍니다");
				return;
			}

			if(m_bBuy == true)
				Util.Log(Util.LOG_TYPE.VERVOSE, "매수 시작");
			else
				Util.Log(Util.LOG_TYPE.VERVOSE, "매수 취소");
		}

		public string[] GetAccounts()
		{
			return m_CybosHelper.GetAccounts();
		}

		public void ApplyAccount(string strAccount, string strAccountSub)
		{
			Config.SetAccount(strAccount, strAccountSub);
		}
	}


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

		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))
			{
				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);
			}
		}
	}

}
