using Emgu.CV;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WatsonWebsocket;
using AR;

namespace Project
{
	public partial class FMain
	{
		//DateTime lastRecvWSL = new DateTime(1982, 11, 23);
		//DateTime lastRecvWSR = new DateTime(1982, 11, 23);
		string lastBarcodeRawL = string.Empty;
		string lastBarcodeRawR = string.Empty;


		void AttachCameraEventL()
		{
			//크레비스오픈 - 210203
			//PUB.log.Add("카메라 이벤트 생성");
			PUB.wsL.MessageReceived += Ws_DataArrivalL;
			PUB.wsL.ServerConnected += Ws_ConnectedL;
			PUB.wsL.ServerDisconnected += Ws_DisconnectedL;
		}
		void DetachCameraEventL()
		{
			//크레비스오픈 - 210203
			//PUB.log.Add("카메라 이벤트 해제");
			PUB.wsL.MessageReceived -= Ws_DataArrivalL;
			PUB.wsL.ServerConnected -= Ws_ConnectedL;
			PUB.wsL.ServerDisconnected -= Ws_DisconnectedL;

		}
		void AttachCameraEventR()
		{
			//크레비스오픈 - 210203
			//if (COMM.SETTING.Data.Log_CameraConn) PUB.log.Add("카메라 이벤트 생성");
			PUB.wsR.MessageReceived += Ws_DataArrivalR;
			PUB.wsR.ServerConnected += Ws_ConnectedR;
			PUB.wsR.ServerDisconnected += Ws_DisconnectedR;
		}
		void DetachCameraEventR()
		{
			//크레비스오픈 - 210203
			//if (COMM.SETTING.Data.Log_CameraConn) PUB.log.Add("카메라 이벤트 해제");
			PUB.wsR.MessageReceived -= Ws_DataArrivalR;
			PUB.wsR.ServerConnected -= Ws_ConnectedR;
			PUB.wsR.ServerDisconnected -= Ws_DisconnectedR;
		}
		private void Ws_DisconnectedL(object sender, EventArgs e)
		{
			var ws = sender as WatsonWebsocket.WatsonWsClient;
			PUB.log.AddAT("Camera L connection terminated");
			//_isCrevisOpen[0] = false;
			PUB.flag.set(eVarBool.FG_RDY_CAMERA_L, false, "DISC");
		}

		private void Ws_ConnectedL(object sender, EventArgs e)
		{
			PUB.log.AddAT("Camera L connection successful");
			//_isCrevisOpen[0] = true;
		}
		private void Ws_DisconnectedR(object sender, EventArgs e)
		{
			var ws = sender as WatsonWebsocket.WatsonWsClient;
			PUB.log.AddAT("Camera R connection terminated");
			//_isCrevisOpen[2] = false;
			PUB.flag.set(eVarBool.FG_RDY_CAMERA_R, false, "DISC");
		}

		private void Ws_ConnectedR(object sender, EventArgs e)
		{
			PUB.log.AddAT("Camera R connection successful");
			//_isCrevisOpen[2] = true;
		}

		private void Ws_DataArrivalL(object sender, MessageReceivedEventArgs e)
		{
			Ws_DataArrival(0, sender as WatsonWsClient, e);
		}
		private void Ws_DataArrivalR(object sender, MessageReceivedEventArgs e)
		{
			Ws_DataArrival(1, sender as WatsonWsClient, e);
		}

		private void Ws_DataArrival(int idx, WatsonWsClient ws, MessageReceivedEventArgs e)
		{
			//throw new NotImplementedException();
			var data = Encoding.UTF8.GetString(e.Data);// Pub.ws.Get<String>();
			if (idx == 0) VAR.TIME[eVarTime.lastRecvWSL] = DateTime.Now;
			else VAR.TIME[eVarTime.lastRecvWSR] = DateTime.Now;



			if (data.Contains("\"command\":\"status"))
			{
				//PUB.logVision.Add($"[{idx}]상태메세지수신");
				//PUB.logVision.Flush();
				try
				{
					var jsondata = JObject.Parse(data);
					var msgdata = new
					{
						command = jsondata.Value<String>("command"),
						camera = jsondata.Value<String>("camera"),
						live = jsondata.Value<String>("live"),
						stream = jsondata.Value<String>("stream"),
						listen = jsondata.Value<String>("listen"),
						trig = jsondata.Value<String>("trig"),
						license = jsondata.Value<String>("license"),
                        reel = jsondata.Value<String>("reel"),
                        conv = jsondata.Value<String>("conv"),
                    };

                    if (idx == 0)
                    {
                        PUB.flag.set(eVarBool.VS_DETECT_REEL_L, (msgdata.reel == "1"), "WS");
                        PUB.flag.set(eVarBool.VS_DETECT_CONV_L, (msgdata.conv == "1"), "WS");
                    }   
                    else
                    {
                        PUB.flag.set(eVarBool.VS_DETECT_REEL_R, (msgdata.reel == "1"), "WS");
                        PUB.flag.set(eVarBool.VS_DETECT_CONV_R, (msgdata.conv == "1"), "WS");
                    }
                    

                    if (msgdata.license == "1" && msgdata.camera == "1")
					{
						if (idx == 0)
						{
                            if(PUB.flag.get(eVarBool.FG_RDY_CAMERA_L)==false)
                            {
                                PUB.flag.set(eVarBool.FG_RDY_CAMERA_L, true, "WEBSOCKET");
                                PUB.log.Add("Left camera ready");
                            }
						}
						else
						{
                            if (PUB.flag.get(eVarBool.FG_RDY_CAMERA_R) == false)
                            {
                                PUB.flag.set(eVarBool.FG_RDY_CAMERA_R, true, "WEBSOCKET");
                                PUB.log.Add("Right camera ready");
                            }
                                
						}
					}
					else
					{
						if (idx == 0) PUB.flag.set(eVarBool.FG_RDY_CAMERA_L, false, "WEBSOCKET");
						else PUB.flag.set(eVarBool.FG_RDY_CAMERA_R, false, "WEBSOCKET");
					}
				}
				catch (Exception ex)
				{
					PUB.log.AddE("Status message analysis failed: " + ex.Message);
				}
			}
			else
			{
				//처리가능한 상황에서만 큐에 데이터를 넣는다
				if (idx == 0 && PUB.flag.get(eVarBool.FG_PRC_VISIONL) == false)
				{
					PUB.log.AddAT("Left side vision not in verification state, deleting barcode data\n" + data);
					return;
				}
				if (idx != 0 && PUB.flag.get(eVarBool.FG_PRC_VISIONR) == false)
				{
					PUB.log.AddAT("Right side vision not in verification state, deleting barcode data\n" + data);
					return;
				}

				PUB.log.Add($"QR verification ({(idx == 0 ? "L" : "R")}) received: " + data);
				var guid = idx == 0 ? PUB.Result.ItemDataL.guid : PUB.Result.ItemDataR.guid;

				//BarcodeParsing(idx, guid, data, "WS");
				var qrDataList = ProcessRecvBarcodeData(idx, data);
				if (qrDataList.Count > 0)  //바코드데이터가 존재 했다
				{
					//처리가 완료되지 않은경우엠ㄴ 사용한다.
					if (idx == 0)
					{
						if (PUB.flag.get(eVarBool.FG_END_VISIONL) == false)
						{
							var Complete = RecvQRProcess(qrDataList, eWorkPort.Left);
							if (Complete) PUB.flag.set(eVarBool.FG_END_VISIONL, true, "DATA_ARRIVAL");
						}
						else PUB.log.AddAT("Vision (L) previous task completed, not processing");
					}
					else
					{
						if (PUB.flag.get(eVarBool.FG_END_VISIONR) == false)
						{
							var Complete = RecvQRProcess(qrDataList, eWorkPort.Right);
							if (Complete) PUB.flag.set(eVarBool.FG_END_VISIONR, true, "DATA_ARRIVAL");
						}
						else PUB.log.AddAT("Vision (R) previous task completed, not processing");
					}
				}

			}

		}




        //바코드 원본의 데이터큐
        //ConcurrentQueue<string> BarcodeQueL = new ConcurrentQueue<string>();
        //ConcurrentQueue<string> BarcodeQueR = new ConcurrentQueue<string>();

        //bool BarcodeParsing(int idx, string guid, string jsonstr, string source, Boolean force = false)
        //{

        //	//값이있다면 바코드 큐에 집어 넣는다.
        //	if (idx == 0)
        //	{
        //		lastBarcodeRawL = jsonstr;
        //		lock (BarcodeQueL)
        //			BarcodeQueL.Enqueue(jsonstr);
        //	}
        //	else
        //	{
        //		lastBarcodeRawR = jsonstr;
        //		lock (BarcodeQueR)
        //			BarcodeQueR.Enqueue(jsonstr);
        //	}

        //	return true;
        //}

        //DateTime WSLLastRecv = DateTime.Now;
        //DateTime WSRLastRecv = DateTime.Now;
		bool WS_Send(eWorkPort idx, WatsonWebsocket.WatsonWsClient ws, string guid, string cmd,string data)
		{
            if (ws == null) return false;

			//데이터 생성
			var msg = new
			{
				guid = guid,
				command = cmd,
                data = data
			};

			var json = Newtonsoft.Json.JsonConvert.SerializeObject(msg);
			Boolean sendok = false;
			try
			{
				//PUB.log.Add($"전송({idx}),ID:{guid},명령:{cmd}");
				ws.SendAsync(json);
				sendok = true;
			}
			catch (Exception ex)
			{
				PUB.log.AddE($"Transmission {idx} failed {ex.Message}");
				sendok = false;
			}

			if (sendok == false)
			{
				try
				{
					if (idx == 0) CameraConTimeL = DateTime.Now;
					else CameraConTimeR = DateTime.Now;

                    if(ws != null)
                    {
                        PUB.log.AddAT($"Closing socket due to transmission {idx} failure");
                        ws.Stop();
                    }
				}
				catch (Exception ex)
				{
					PUB.log.AddE($"Socket {idx} termination failed: {ex.Message}");
				}
			}
            return sendok;
		}

		//System.Diagnostics.Stopwatch wat = new System.Diagnostics.Stopwatch();
		//System.Diagnostics.Stopwatch wat0 = new System.Diagnostics.Stopwatch();
		//System.Diagnostics.Stopwatch wat1 = new System.Diagnostics.Stopwatch();
		//System.Diagnostics.Stopwatch wat2 = new System.Diagnostics.Stopwatch();


		/// <summary>
		/// 바코드큐에있는 데이터를 분석하고 시작한다.
		/// </summary>
		/// <param name="Idx"></param>
		/// <param name="Process"></param>
		/// <returns></returns>
		List<string> ProcessRecvBarcodeData(int vIdx, string JsonStr)
		{
			//PUB.logVision.Add($"[{vIdx}]ProcessBarcodeQue");
			//PUB.logVision.Flush();
			List<string> retval = new List<string>();

			if (JsonStr.isEmpty())
			{
				PUB.log.AddE("Cannot proceed due to missing barcode receive value (JSON)");
				return retval;
			}

			if (vIdx == 0)
				lastBarcodeRawL = JsonStr;
			else
				lastBarcodeRawR = JsonStr;

			try
			{
				//모델에서 고정값을 입력한게 있다면 그것을 사용한다
				var itemC = PUB.Result.ItemDataC;
				if (itemC.VisionData.VNAME.isEmpty() && PUB.Result.vModel.Def_Vname.isEmpty() == false)
				{
					itemC.VisionData.VNAME = PUB.Result.vModel.Def_Vname;
					itemC.VisionData.VNAME_Trust = true;
					PUB.log.Add($"Defaul V.Name Set to {PUB.Result.vModel.Def_Vname}");
				}
				if (itemC.VisionData.MFGDATE.isEmpty() && PUB.Result.vModel.Def_MFG.isEmpty() == false)
				{
					itemC.VisionData.MFGDATE = PUB.Result.vModel.Def_MFG;
					itemC.VisionData.MFGDATE_Trust = true;
					PUB.log.Add($"Defaul MFGDATE Set to {PUB.Result.vModel.Def_MFG}");
				}

				var jsondata = JObject.Parse(JsonStr);
				var msgdata = new
				{
					guid = jsondata.Value<String>("guid"),
					command = jsondata.Value<String>("command"),
					data = jsondata.Value<String>("data[]"),
					time = jsondata.Value<String>("time"),
					file = jsondata.Value<String>("file")
				};

				var datas = jsondata.GetValue("data");
				if (datas.Type == JTokenType.String)
				{
					var bcdstr = datas.ToString();

					//새로운 바코드라면 추가한다
					if (retval.Contains(bcdstr) == false)
						retval.Add(bcdstr);
				}
				else
				{
					//데이터가 배열로 들어있는 경우이다
					foreach (var data in datas)
					{
						var dataarr = new
						{
							barcode = data.ToString()
						};
						if (dataarr.barcode.isEmpty()) continue;
						if (retval.Contains(dataarr.barcode) == false)
							retval.Add(dataarr.barcode);
					}
				}

				//입력된 바코드 데이터를 확인한다.
				//각 데이터는 아래처럼 변수에 추가를 해줘야ㅏ한ㄷ.ㅏ
				//ImageProcessResult[vIdx].Add(item.data);


			}
			catch (Exception ex)
			{
				PUB.logVision.Add($"Camera ({vIdx}) ProcessBarcodeQue failed {ex.Message}"); PUB.logVision.Flush();
			}

			return retval;
		}


	}
}
