using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using BO;
using BO.BarCodeScan;
using BO.BO.Dtos;
using BO.Utils;
using BO.Utils.BillRpc;
using BWP.WinFormControl.WeightDataFormat;
using TrunksIousOutInStore.LocalSyncBO;
using TrunksIousOutInStore.Rpc;

namespace TrunksIousOutInStore
{
  public partial class TrunksIousOutInStoreForm : Form, IAfterLogin
  {

    private readonly string ClientGoodsSetApplyClient = "白条出入库";
    public const string DATA_PATH = "LocalData/TrunksIousOutInStore";

    //        BardCodeHooK BarCode = new BardCodeHooK();

    #region weightNeed
    SerialPort weightPort;
    private IDataFormat _dataFormat;
    private Thread _inQueryThread;
    private bool _mainProcessIsRun;
    readonly StringBuilder _dataStrBuilder = new StringBuilder();
    #endregion


    public TrunksIousOutInStoreForm()
    {
      InitializeComponent();

      gridUnCheck.AutoGenerateColumns = false;
      gridChecked.AutoGenerateColumns = false;

      weightPort = new SerialPort();
      this.FormClosing += delegate
      {
        if (_inQueryThread != null && _inQueryThread.IsAlive)
          DisableWeight();
        //        if (syncWork != null && syncWork.IsAlive)
        //          syncWork.Abort();
        //        if (syncToServer != null && syncToServer.IsAlive)
        //          syncToServer.Abort();
      };

      //            BarCode.BarCodeEvent += new BardCodeHooK.BardCodeDeletegate(BarCode_BarCodeEvent);

      if (!Directory.Exists(DATA_PATH))
      {
        Directory.CreateDirectory(DATA_PATH);
      }
    }
    void BarCode_BarCodeEvent(BardCodeHooK.BarCodes barCode)
    {
      ShowInfo(barCode);
    }
    private delegate void ShowInfoDelegate(BardCodeHooK.BarCodes barCode);

    private void ShowInfo(BardCodeHooK.BarCodes barCode)
    {
      if (this.InvokeRequired)
      {
        this.BeginInvoke(new ShowInfoDelegate(ShowInfo), new object[] { barCode });
      }
      else
      {
        if (barCode.IsValid)
        {
          //          var code = UrlUtil.GetBarCode(barCode.BarCode.Trim());
          //          var goodsName = UrlUtil.GetGoodsName(barCode.BarCode);
          var code = barCode.BarCode.Trim();
          doInsertUnSubmit(code, "", null);
        }
      }
    }

    #region weightNeed
    void OpenSerialPort()
    {
      if (enableWeight.Checked)
        return;
      if (TrunksIousOutInStoreContext.Config.RateSet == null)
        throw new Exception("请先配置称相关信息");

      weightPort.PortName = TrunksIousOutInStoreContext.Config.ComSet;
      weightPort.BaudRate = TrunksIousOutInStoreContext.Config.RateSet.Value;
      weightPort.DataBits = TrunksIousOutInStoreContext.Config.BitSet.Value;
      weightPort.ReadBufferSize = 4096 * 100;
      if (!string.IsNullOrEmpty(TrunksIousOutInStoreContext.Config.Format))
        format = "{0:{format}}".Replace("{format}", TrunksIousOutInStoreContext.Config.Format);

      switch (TrunksIousOutInStoreContext.Config.WeightSet)
      {
        case "IND560":
          _dataFormat = new IND560DataFormat();
          break;
        case "Xk3124":
          _dataFormat = new Xk3124DataFormat();
          break;
        case "Xk3190A9":
          _dataFormat = new Xk3190A9DataFormat();
          break;
        default:
          _dataFormat = new Xk3190D10DataFormat();
          break;
      }
      if (!weightPort.IsOpen)
      {
        try
        {
          weightPort.Open();
        }
        catch (InvalidOperationException)
        {
          MessageBox.Show(@"指定的端口已打开");
        }
        catch (UnauthorizedAccessException)
        {
          MessageBox.Show(@"对端口的访问被拒绝");
        }
      }
    }

    void ReadData()
    {
      _inQueryThread = new Thread(InQuery);
      _inQueryThread.Start();
    }

    string format = "{0:0.00}";

    private void InQuery()
    {
      while (_mainProcessIsRun)
      {
        int availableCount = weightPort.BytesToRead;
        if (availableCount == 0)
        {
          Thread.Sleep(1);
        }
        char[] buffer = new char[availableCount];
        if (!weightPort.IsOpen)
        {
          continue;
        }
        weightPort.Read(buffer, 0, availableCount);
        foreach (var c in buffer)
        {
          if (c == _dataFormat.Beginchar)
          {
            _dataStrBuilder.Clear();
            _dataStrBuilder.Append(c);
          }
          else if (c == _dataFormat.Endchar && _dataStrBuilder.Length == _dataFormat.DataLength - 1)
          {
            _dataStrBuilder.Append(c);
            bool isStatic;
            string str;
            if (_dataFormat.ParseAscii(_dataStrBuilder.ToString(), out str, out isStatic))
            {
              if (TrunksIousOutInStoreContext.Config.WeightType == 0)
              {
                if (string.IsNullOrEmpty(str))
                  str = "0";
                this.Invoke(new Action(delegate ()
                {
                  lblChengZhong.Text = string.Format(format, decimal.Parse(str));
                  if (str != "0")
                  {
                    //AddWeightDetail(decimal.Parse(lblChengZhong.Text));
                    doInsertUnSubmit("", "", decimal.Parse(lblChengZhong.Text));
                  }
                }));
              }
              else
              {
                decimal num = 0;
                if (decimal.TryParse(str, out num))
                {
                  this.Invoke(new Action(delegate ()
                  {
                    lblChengZhong.Text = string.Format(format, num);
                  }));
                  //                  LocalGradeAndWeightBL.SaveWeightData(num);
                  WeighAvgControl.Add(num, isStatic);
                }
                if (WeighAvgControl.TryGetValue(out num))
                {
                  this.Invoke(new Action(delegate ()
                  {
                    //lblChengZhong.Text = string.Format(format, num);
                    if (str != "0")
                    {
                      doInsertUnSubmit("", "", decimal.Parse(string.Format(format, num)));
                      //AddWeightDetail(decimal.Parse(string.Format(format, num)));
                    }
                  }));
                }
              }
            }
            _dataStrBuilder.Clear();
          }
          else if (_dataStrBuilder.Length != 0)
          {
            _dataStrBuilder.Append(c);
          }
        }
      }
    }

    private class WeighAvgControl
    {
      public static bool TryGetValue(out decimal result)
      {
        List<Tuple<decimal, bool>> list;
        if (mWeighList.TryDequeue(out list))
        {
          var r = list.Where(x => x.Item2).Select(x => x.Item1).GroupBy(x => x);
          var firstOrDefault = r.OrderByDescending(x => x.Count()).FirstOrDefault();
          if (firstOrDefault != null)
          {
            result = firstOrDefault.Key;
            return true;
          }
          result = 0;
          return false;
        }
        result = 0;
        return false;
      }

      static ConcurrentQueue<List<Tuple<decimal, bool>>> mWeighList = new ConcurrentQueue<List<Tuple<decimal, bool>>>();

      static List<Tuple<decimal, bool>> _list = new List<Tuple<decimal, bool>>();

      public static void Add(decimal value, bool isStatic)
      {
        if (value >= TrunksIousOutInStoreContext.Config.MinWeight && value <= TrunksIousOutInStoreContext.Config.MaxWeight)
        {
          _list.Add(new Tuple<decimal, bool>(value, isStatic));
        }
        else
        {
          if (_list.Count > 0)
          {
            mWeighList.Enqueue(_list);
            _list = new List<Tuple<decimal, bool>>();
          }
        }
      }
    }

    void DisableWeight()
    {
      _mainProcessIsRun = false;
      lblChengZhong.Text = string.Format(format, 0);
      format = "{0:0.00}";
      Thread.Sleep(10);
      if (_inQueryThread.IsAlive)
      {
        _inQueryThread.Abort();
      }
      if (weightPort.IsOpen)
        weightPort.Close();
    }

    public void enableWeight_Click(object sender, EventArgs e)
    {
      if (!enableWeight.Checked)
      {
        OpenSerialPort();
        _mainProcessIsRun = true;
        ReadData();
      }
      else
      {
        DisableWeight();
      }
      enableWeight.CheckState = enableWeight.Checked ? CheckState.Unchecked : CheckState.Checked;
    }
    #endregion



    static object _obj = new object();
    private void doInsertUnSubmit(string barCode, string goodsName, decimal? weight)
    {
      lock (_obj)
      {
        var record = new TrunksIousOutInStoreRecord();
        record.Goods_Name = goodsName;
        var set = GetSelectedClientGoodsSet();
        if (set != null)
        {
          record.Goods_Name = set.Goods_Name;
          record.Goods_ID = set.Goods_ID;
        }
        record.Number = 1;
        record.CarcassStatus = cbxBaiTiaoStatus.Text;
        if (!string.IsNullOrWhiteSpace(barCode))
        {//扫码
          record.BarCode = barCode;
          //找到条码为空但是重量不为空的
          var fd = unSumbitList.FirstOrDefault(x => string.IsNullOrWhiteSpace(x.BarCode) && x.Weight.HasValue);
          if (fd == null)
          {
            //            record.ID = unSumbitList.Max(x => x.ID) + 1;
            unSumbitList.Add(record);
          }
          else
          {
            //给条码赋值
            fd.BarCode = barCode;
          }
        }
        if (weight.HasValue)
        {//称重
          record.Weight = weight;
          //找到称重为空条码不为空的
          var fd = unSumbitList.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.BarCode) && x.Weight == null);
          if (fd == null)
          {
            //            record.ID = unSumbitList.Max(x => x.ID) + 1;
            unSumbitList.Add(record);
          }
          else
          {
            //给条码赋值
            fd.Weight = weight;
          }
        }
        gridUnCheck.Refresh();
        Application.DoEvents();
        //        BindUnCheckGrid();
      }

      //      barCodequeue.Enqueue(barCode);
    }



    public string RoleName
    {
      get { return "胴体白条出入库"; }
    }
    public Form Generate()
    {
      return this;
    }





    string goodsSetFileName = Path.Combine(DATA_PATH, "TrunksIousOutInStoreClientGoodsSet.xml");

    private List<TrunksIousOutInStoreClientGoodsSet> mLocaList;

    void InitLocalList()
    {
      if (LoginRpcUtil.TestConnection())
      {
        mLocaList = ClientGoodsSetRpc.GetListByApplyClient(ClientGoodsSetApplyClient).Select(x => x.CreateChild<TrunksIousOutInStoreClientGoodsSet>()).ToList();
        XmlUtil.SerializerObjToFile(mLocaList, goodsSetFileName);
      }
      else
      {
        mLocaList = XmlUtil.DeserializeFromFile<List<TrunksIousOutInStoreClientGoodsSet>>(goodsSetFileName);
      }

    }

    private void TrunksIousOutInStoreForm_Load(object sender, EventArgs e)
    {
      //            BarCode.Start();

      InitLocalList();

      InitGoodsControl();

      GridUnCheckFocus();
    }

    private void InitGoodsControl()
    {
      flpClass.Controls.Clear();
      foreach (IGrouping<string, TrunksIousOutInStoreClientGoodsSet> grouping in mLocaList.Where(x => !string.IsNullOrWhiteSpace(x.Name)).GroupBy(x => x.Name))
      {
        var btn = CreateClassButton(grouping.Key);
        flpClass.Controls.Add(btn);
      }
    }

    private Button CreateClassButton(string text)
    {
      var btn = new Button() { Text = text };
      btn.Width = 100;
      btn.Height = 60;
      btn.Click += BtnClass_Click;
      return btn;
    }

    private void BtnClass_Click(object sender, EventArgs e)
    {
      var btnClass = sender as Button;
      flpGoods.Controls.Clear();
      foreach (TrunksIousOutInStoreClientGoodsSet set in mLocaList.Where(x => x.Name == btnClass.Text))
      {
        var btn = CreateGoodsSetButton(set);
        flpGoods.Controls.Add(btn);
      }
      GridUnCheckFocus();
      Application.DoEvents();
    }

    private Button CreateGoodsSetButton(TrunksIousOutInStoreClientGoodsSet set)
    {
      var btn = new Button();
      btn.Text = set.Goods_Name;
      btn.Tag = set;
      btn.Width = 100;
      btn.Height = 60;
      btn.Click += BtnSet_Click;
      return btn;
    }

    private void BtnSet_Click(object sender, EventArgs e)
    {
      var btn = sender as Button;
      foreach (Button button in flpGoods.Controls)
      {
        if (button.Text == btn.Text)
        {
          if (button.BackColor == Color.Aqua)
          {
            button.BackColor = SystemColors.Control;
          }
          else
          {
            button.BackColor = Color.Aqua;
          }
        }
        else
        {
          button.BackColor = SystemColors.Control;
        }
      }
      gridUnCheck.Focus();
      Application.DoEvents();
    }

    TrunksIousOutInStoreClientGoodsSet GetSelectedClientGoodsSet()
    {
      foreach (Button button in flpGoods.Controls)
      {
        if (button.BackColor == Color.Aqua)
        {
          return button.Tag as TrunksIousOutInStoreClientGoodsSet;
        }
      }
      return null;
    }

    private void TrunksIousOutInStoreForm_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (unSumbitList.Count > 0)
      {
        if (MessageBox.Show("待提交区域不为空，确定关闭？", "确定关闭", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) ==
            DialogResult.OK)
        {
          e.Cancel = false;
        }
        else
        {
          e.Cancel = true;

        }
      }
    }

    BindingList<TrunksIousOutInStoreRecord> unSumbitList = new BindingList<TrunksIousOutInStoreRecord>();
    BindingList<TrunksIousOutInStoreRecord> sumbitedList = new BindingList<TrunksIousOutInStoreRecord>();
    //    ConcurrentQueue<string> barCodequeue=new ConcurrentQueue<string>();
    private void timer1_Tick(object sender, EventArgs e)
    {
      timer1.Stop();
      if (unSumbitList == null)
      {
        return;
      }

      var canSubmitList = unSumbitList.Where(x => !string.IsNullOrWhiteSpace(x.BarCode) && x.Weight != null).ToList();
      foreach (TrunksIousOutInStoreRecord record in canSubmitList)
      {

        LocalDmoSession.Insert(record);
        unSumbitList.Remove(record);
        sumbitedList.Insert(0, record);
      }

      BindUnCheckGrid();
      BindCheckedGrid();

      timer1.Start();
    }

    void BindUnCheckGrid()
    {
      gridUnCheck.DataSource = unSumbitList;
    }
    void BindCheckedGrid()
    {
      gridChecked.DataSource = sumbitedList;
    }


    private void btnWeightSet_Click(object sender, EventArgs e)
    {
      var f = new WeightSettingFrom();

      if (f.ShowDialog() == DialogResult.OK)
      {
        enableWeight_Click(sender, e);
        GridUnCheckFocus();
      }
    }

    void GridUnCheckFocus()
    {
      gridUnCheck.Focus();
    }

    private void TrunksIousOutInStoreForm_FormClosed(object sender, FormClosedEventArgs e)
    {
      //            BarCode.Stop();
    }


    #region 检查网络畅通
    private void timerChectNetStatus_Tick(object sender, EventArgs e)
    {
      timerChectNetStatus.Stop();
      ChectConnectionStatus();
      timerChectNetStatus.Start();
    }
    void ChectConnectionStatus()
    {
      if (LoginRpcUtil.TestConnection())
      {
        btnNetStatus.Text = "网络畅通";
        btnNetStatus.BackColor = Color.Green;
      }
      else
      {
        btnNetStatus.Text = "网络不通";
        btnNetStatus.BackColor = Color.Red;
      }
    }

    #endregion

    #region  同步到中间服务器
    //同步到
    private void timerSyncToService_Tick(object sender, EventArgs e)
    {
      timerSyncToService.Stop();
      if (LoginRpcUtil.TestConnection())
      {
        TrunksIousOutInStoreRecordRpc.GetInstance().SyncToServer();
      }
      timerSyncToService.Start();
    }

    #endregion

    #region 检查是否同步完成

    //检查是否同步完成
    private void timerCheckSyncSucessed_Tick(object sender, EventArgs e)
    {
      timerCheckSyncSucessed.Stop();
      if (LoginRpcUtil.TestConnection())
      {
        if (TrunksIousOutInStoreRecordRpc.GetInstance().IsSyncSucessed())
        {
          btnSycnStatus.Text = "同步完成";
          btnSycnStatus.BackColor = Color.Green;
        }
        else
        {
          btnSycnStatus.Text = "正在同步";
          btnSycnStatus.BackColor = Color.Red;
        }
      }
      timerCheckSyncSucessed.Start();
    }
    #endregion

    private void btnCreateBill_Click(object sender, EventArgs e)
    {
      GridUnCheckFocus();
    }

    BwpBarCodes barCodes = new BwpBarCodes();

    private void TrunksIousOutInStoreForm_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyData == (Keys.ShiftKey | Keys.Shift))
      {
        return;
      }
      TimeSpan ts = DateTime.Now.Subtract(barCodes.Time);
      var str = BwpBarCodeUtil.GetStringByKeyKeyEventArgs(e);
      barCodes.StringBuilder.Append(str);

      if (ts.TotalMilliseconds < 50)
      {
        if (e.KeyData == Keys.Enter && barCodes.BarCode.Length > 0)
        {
          //回车
          barCodes.IsValid = true;
          barCodes.StringBuilder.Remove(barCodes.StringBuilder.Length - 1, 1);
        }
      }
      try
      {
        if (barCodes.IsValid)
        {


          //          MessageBox.Show(barCodes.BarCode);
          var code = UrlUtil.GetBarCode(barCodes.BarCode.ToLower().Trim());
          var goodsName = UrlUtil.GetGoodsName(barCodes.BarCode.ToLower());

          doInsertUnSubmit(code, goodsName, null);
          barCodes.StringBuilder = new StringBuilder();
        }
      }
      catch
      {
      }
      finally
      {

        barCodes.IsValid = false; //最后一定要 设置barCode无效
        barCodes.Time = DateTime.Now;
      }

    }
  }
}
