using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using BO.Utils;
using BWP.WinFormControl.WeightDataFormat;
using ByProductWeight.Rpc;
using ByProductWeight.Rpc.Dto;

namespace ByProductWeight
{
  public partial class ByProductWeightForm : Form,IAfterLogin
  {

    public string RoleName { get { return "副产品计数"; } }
    public Form Generate()
    {
      return this;
    }

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



    List<ByProductWeightGoodsSet> mSetList ;


    BindingList<ByProductWeightRecord> mWeightRecords;
    public ByProductWeightForm()
    {
      InitializeComponent();
      uDataGridView1.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();
      };
    }
    #region weightNeed
    void OpenSerialPort()
    {
      if (enableWeight.Checked)
        return;
      if (ByProductWeightContext.Config.RateSet == null)
        throw new Exception("请先配置称相关信息");

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

      switch (ByProductWeightContext.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 (ByProductWeightContext.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")
                  {

                    //doInsertUnSubmit("", decimal.Parse(lblChengZhong.Text));
                    //todo 这里不需要逻辑 点击存货的时候判断是否在误差范围内
                  }
                }));
              }
              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)));
                      //todo 这里不需要逻辑 点击存货的时候判断是否在误差范围内
                    }
                  }));
                }
              }
            }
            _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 >= ByProductWeightContext.Config.MinWeight && value <= ByProductWeightContext.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

    private void ByProductWeightForm_Load(object sender, EventArgs e)
    {
      mWeightRecords = new BindingList<ByProductWeightRecord>();//以后可能取数据库中没做完的，比如做着做着突然断点
      RefreshUi();
      InitControl();
    }

    private void InitControl()
    {
      mSetList =
        XmlUtil.DeserializeFromFile<List<ByProductWeightGoodsSet>>(
          ByProductWeightGoodsSetForm.ByProductWeightGoodsSetFileName).Where(x => x.IsSelected).ToList();
      if (mSetList.Count < 1)
      {
        return;
      }

      flpClass.Controls.Clear();
      foreach (IGrouping<string, ByProductWeightGoodsSet> grouping in mSetList.GroupBy(x => x.Name))
      {
        var btnClass = CreateClassButton(grouping.Key);
        flpClass.Controls.Add(btnClass);
      }

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

    }
    private void Btn_Click(object sender, EventArgs e)
    {
      var text = (sender as Button).Text;
      foreach (Button cbutton in flpClass.Controls)
      {
        if (cbutton.Text == text)
        {
          cbutton.BackColor = Color.Aqua;
        }
        else
        {
          cbutton.BackColor = SystemColors.Control;
        }
      }

      flpGoods.Controls.Clear();
      foreach (ByProductWeightGoodsSet set in mSetList.Where(x => x.Name == text))
      {
        var btnGoods = CreateGoodsButton(set);
        flpGoods.Controls.Add(btnGoods);
      }

    }

    private Button CreateGoodsButton(ByProductWeightGoodsSet set)
    {
      var btn = new Button();
      btn.Text = set.Goods_Name;
      btn.Tag = set;
      btn.Click += BtnGoods_Click;
      btn.Width = 100;
      btn.Height = 60;
      return btn;
    }

    private void BtnGoods_Click(object sender, EventArgs e)
    {
      var btn = sender as Button;
      var set = btn.Tag as ByProductWeightGoodsSet;

      //todo 打印条码 

      var weight = 100m;
      //添加记录
      var record = GetRecordBySet(set, weight);
      var id = ByProductWeightRecordRpc.Insert(record);
      record.ID = id;
      mWeightRecords.Add(record);

      RefreshUi();

    }
    private ByProductWeightRecord GetRecordBySet(ByProductWeightGoodsSet set, decimal maoWeight)
    {
      var record = new ByProductWeightRecord();
      record.Goods_ID = set.Goods_ID;
      record.BarCode = "";//todo 条码规则
      record.Goods_Name = set.Goods_Name;
      record.Goods_Spec = set.Goods_Spec;
      record.BiaoShi = "";//todo 标识
      record.MaoWeight = maoWeight;
      record.PiWeight = 10;

      //      record.JingWeight = record.MaoWeight - record.PiWeight;

      if (set.Goods_MainUnitRatio > 0)
      {
        record.JingWeight = set.Goods_MainUnitRatio;
      }
      else
      {
        record.JingWeight = record.MaoWeight - record.PiWeight;
      }

      record.CardBarCode = "车条码"; //todo

      return record;
    }

    void RefreshUi()
    {
      if (mWeightRecords.Count < 1)
      {
        return;
      }
      lblGoodsName.Text = mWeightRecords.First().Goods_Name;
      lblNumber.Text = mWeightRecords.Count.ToString();
      lblWeight.Text = mWeightRecords.Sum(x => x.JingWeight).ToString();

      uDataGridView1.DataSource = mWeightRecords;
    }
    private void btnWeightSet_Click(object sender, EventArgs e)
    {
      var form = new WeightSettingFrom();
      form.ShowDialog();
    }

    private void btnGoodsSet_Click(object sender, EventArgs e)
    {
      var f = new ByProductWeightGoodsSetForm();
      if (f.ShowDialog() == DialogResult.OK)
      {
        InitControl();
      }
    }
  }
}
