using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NewsCrawler
{
	public class CybosHelper
	{
		CPUTILLib.CpCybos m_CPCybos = new CPUTILLib.CpCybos();
		CPFORETRADELib.CpForeTdUtil m_CPUtil = new CPFORETRADELib.CpForeTdUtil();
		DSCBO1Lib.StockMst m_CPStockMst = new DSCBO1Lib.StockMst();
		CPTRADELib.CpTd0311 m_CP0311 = new CPTRADELib.CpTd0311();
		CPSYSDIBLib.StockChart m_StockChart = new CPSYSDIBLib.StockChart();
		bool m_bInitialized = false;

		System.Timers.Timer m_timer = new System.Timers.Timer();
		ushort m_uiLastReqT = 0;

		DSCBO1Lib.CpSvr8092S m_Cp8092S = new DSCBO1Lib.CpSvr8092S();

		NewsForm m_Listener = null;

		public CybosHelper(NewsForm Listener)
		{
			m_Listener = Listener;

			short iResult = m_CPUtil.TradeInit();
			switch(iResult)
			{
				case -1:
					Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 오류");
					break;

				case 0:
					m_bInitialized = true;
					Util.Log(Util.LOG_TYPE.VERVOSE, "[TradeInit] 로그인 되었습니다");
					break;

				case 1:
					Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 업무 키 입력 잘못됨");
					break;

				case 2:
					Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 계좌 비밀번호가 잘못되었습니다");
					break;

				case 3:
					Util.Log(Util.LOG_TYPE.ERROR, "[TradeInit] 취소되었습니다");
					break;
			}

			m_timer.Interval = 1000;
			m_timer.Elapsed += M_timer_Elapsed;
			//m_timer.Start();

			m_Cp8092S.SetInputValue(0, "*");
			m_Cp8092S.Received += Cp8092S_Received;
			m_Cp8092S.Subscribe();
		}

		private void Cp8092S_Received()
		{
			byte cType = m_Cp8092S.GetHeaderValue(0);
			string strCode = m_Cp8092S.GetHeaderValue(1);
			short iTime = m_Cp8092S.GetHeaderValue(2);
			string strName = m_Cp8092S.GetHeaderValue(3);
			short iType = m_Cp8092S.GetHeaderValue(4);
			string strContents = m_Cp8092S.GetHeaderValue(5);

			if(iType == 1 || iType == 2)
			{
				m_Listener.InsertItem(strContents, "", strCode,
					DateTime.ParseExact(iTime.ToString("0000"), "HHmm", CultureInfo.CurrentCulture),
					DateTime.Now,
					"", "CYBOS", 0, false);
			}

			//Console.WriteLine(string.Format("[8092S] {0} ({1}:{2})", strContents, strName, strCode));
		}

		private void M_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
		{
			m_timer.Enabled = false;

			if(GetLimitRemainCountRQ() < 5)
				return;

			CPSYSDIBLib.CpMarketWatch Watch = new CPSYSDIBLib.CpMarketWatch();
			Watch.SetInputValue(0, "*");
			Watch.SetInputValue(1, "1,2");
			Watch.SetInputValue(2, 0);

			Watch.BlockRequest2(0);

			ushort uiLatestT = 0;
			int iCount = Watch.GetHeaderValue(2);
			if(iCount > 0)
				uiLatestT = Watch.GetDataValue(0, 0);

			for(int i = 0; i<iCount; i++)
			{
				ushort uiTime = Watch.GetDataValue(0, i);
				string strCode = Watch.GetDataValue(1, i);
				string strName = Watch.GetDataValue(2, i);
				ushort uiType = Watch.GetDataValue(3, i);
				string strContents = Watch.GetDataValue(4, i);

				if(uiTime <= m_uiLastReqT)
					break;

				if(m_uiLastReqT > 0)
				{
					m_Listener.InsertItem(strContents, "", strCode,
						DateTime.ParseExact(uiTime.ToString("0000"), "HHmm", CultureInfo.CurrentCulture),
						DateTime.Now,
						"", "CYBOS", 0, m_uiLastReqT>0);
				}

				//Console.WriteLine(string.Format("[{0}][{1}] {2} ({3}:{4})", uiTime, uiType, strContents, strName, strCode));
			}

			m_uiLastReqT = uiLatestT;

			m_timer.Enabled = true;
		}

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

		public int GetLimitRemainCountTrade()
		{
			return m_CPCybos.GetLimitRemainCount(CPUTILLib.LIMIT_TYPE.LT_TRADE_REQUEST);
		}

		public int GetLimitRemainCountRQ()
		{
			return m_CPCybos.GetLimitRemainCount(CPUTILLib.LIMIT_TYPE.LT_NONTRADE_REQUEST);
		}

		public int GetLimitRemainCountSB()
		{
			return m_CPCybos.GetLimitRemainCount(CPUTILLib.LIMIT_TYPE.LT_SUBSCRIBE);
		}

		public bool IsConnected()
		{
			return (m_CPCybos.IsConnect==1);
		}

		public int GetCurPrice(CodeList.CODE_VALUE Code)
		{
			m_CPStockMst.SetInputValue(0, Code.m_strCode);
			m_CPStockMst.BlockRequest2(0);
			int iCurPrice = m_CPStockMst.GetHeaderValue(13);
			return iCurPrice;
		}

		public void GetLowHighPrice(CodeList.CODE_VALUE Code, DateTime StartTime, int iAfterMin, out int iPriceLow, out int iPriceHigh)
		{
			iPriceLow = 1000000;
			iPriceHigh = 0;

			if(GetLimitRemainCountRQ() < 5)
				return;

			string strTime = StartTime.ToString("yyyyMMdd");

			m_StockChart.SetInputValue(0, Code.m_strCode);
			m_StockChart.SetInputValue(1, '1');
			m_StockChart.SetInputValue(2, strTime);
			m_StockChart.SetInputValue(3, strTime);
			m_StockChart.SetInputValue(4, 20);
			m_StockChart.SetInputValue(5, new int[] { 0, 1, 2, 3, 4, 5, });
			m_StockChart.SetInputValue(6, 'm');
			m_StockChart.SetInputValue(7, 1);
			m_StockChart.BlockRequest2(0);

			int iTimeStart;
			int.TryParse(StartTime.ToString("HHmm"), out iTimeStart);

			int iCheckCnt = 0;

			int iCount = m_StockChart.GetHeaderValue(3);
			for(int i=0; i<iCount; i++)
			{
				uint uiDate = m_StockChart.GetDataValue(0, i);
				long iTime = m_StockChart.GetDataValue(1, i);

				if(iTime >= iTimeStart && iTime <= iTimeStart+iAfterMin)
				{
					long iPriceStartLocal = m_StockChart.GetDataValue(2, i);
					long iPriceHighLocal = m_StockChart.GetDataValue(3, i);
					long iPriceLowLocal = m_StockChart.GetDataValue(4, i);
					long iPriceEndLocal = m_StockChart.GetDataValue(5, i);

					iPriceLow = Math.Min(iPriceLow, (int)iPriceLowLocal);
					iPriceHigh = Math.Max(iPriceLow, (int)iPriceHighLocal);

					iCheckCnt++;
				}

				if(iCheckCnt >= 5)
					break;
			}
		}

		public void Buy(CodeList.CODE_VALUE Code, int iMaxPrice)
		{
			if(m_bInitialized == false)
			{
				Util.Log(Util.LOG_TYPE.ERROR, "[Buy] 매수 준비가 되지 않았습니다");
				return;
			}

			int iCurPrice = GetCurPrice(Code);
			int iCount = iMaxPrice/iCurPrice;

			m_CP0311.SetInputValue(0, 2);
			m_CP0311.SetInputValue(1, Config.GetAccount());
			m_CP0311.SetInputValue(2, Config.GetSubAccount());
			m_CP0311.SetInputValue(3, Code.m_strCode);
			m_CP0311.SetInputValue(4, iCount);
			m_CP0311.SetInputValue(5, 0);
			m_CP0311.SetInputValue(7, "0");
			m_CP0311.SetInputValue(8, "03");
			m_CP0311.BlockRequest2(0);

			Util.Log(Util.LOG_TYPE.BUY, string.Format("code:{0} {1}주 현재가 {2}원, 시장가 매수", Code.ToString(), iCount, iCurPrice));
		}
	}
}
