using BO;
using BO.BO.Bill;
using BO.Utils;
using BO.Utils.BillRpc;
using BWP.WinFormControl;
using BWP.WinFormControl.WeightDataFormat;
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;

namespace WeighAndGrading
{
  public partial class GradeFrom : Form, IAfterLogin
  {
    #region IAfterLogin
    public string RoleName
    {
      get { return "定级员"; }
    }

    public Form Generate()
    {
      return this;
    }
    #endregion
    private delegate void InvokeHandler();
    List<GradeAndWeight> list;
    List<GradeAndWeight_Detail> details;
    SerialPort weightPort;
    int maxIndex = 0;
    ConcurrentQueue<GradeAndWeight_Detail> noLivestockList = new ConcurrentQueue<GradeAndWeight_Detail>();

    ConcurrentQueue<GradeAndWeight_Detail> noWeightList = new ConcurrentQueue<GradeAndWeight_Detail>();
    Thread syncWork;

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

    public GradeFrom()
    {
      InitializeComponent();
      butcherTimeInput.Date = DateTime.Today;
      dataGridView.AutoGenerateColumns = false;
      dataGridView.DataSource = null;
      historyGrid.AutoGenerateColumns = false;
      AddLivestockBtn();
      BuildDiscontPanel();
      weightPort = new SerialPort();
      this.FormClosing += delegate
      {
        if (_inQueryThread != null && _inQueryThread.IsAlive)
          DisableWeight();
        if (syncWork != null && syncWork.IsAlive)
          syncWork.Abort();
      };
    }

    GradeAndWeight_Detail modifyDetail;

    void AddLivestockBtn()
    {
      var livestocks = BaseInfoRpcUtil.GetLivestockList();
      foreach (var item in livestocks)
      {
        var btn = new Button() { Name = "_" + item.Item1, Text = item.Item2, Tag = item, Size = new Size(70, 60), TextAlign = ContentAlignment.MiddleCenter, Margin = new Padding { All = 10 }, Font = new Font("宋体", 15) };
        btn.Click += (sender, e) =>
        {
          if (details == null)
          {
            MessageBox.Show("请先同步数据");
            return;
          }
          var livestockTag = btn.Tag as CTuple<long, string, short>;
          if (modifyDetail == null)
            AddDetail(livestockTag);
          else
          {
            modifyDetail.Livestock_ID = livestockTag.Item1;
            modifyDetail.Livestock_Name = livestockTag.Item2;
            modifyDetail.Technics = livestockTag.Item3;
            modifyDetail.Technics_Name = livestockTag.Item3 == 0 ? "烫褪" : "毛剥";
            GradeAndWeightRpc.UpdateLivestock(modifyDetail.ID, modifyDetail.Livestock_ID, modifyDetail.Livestock_Name, modifyDetail.Technics, modifyDetail.Technics_Name);
            historyGrid.Refresh();
            modifyDetail = null;
            modifyPanel.Hide();
          }

          //var name = livestock.Technics == 0 ? "带皮白条" : "去皮白条";
          //Print(name, entity.Index);
        };
        if (item.Item3 == 0)
          ttPanel.Controls.Add(btn);
        else
          mbPanel.Controls.Add(btn);
      }
    }

    private void closeBtn_Click(object sender, EventArgs e)
    {
      this.Close();
    }

    private void syncBtn_Click(object sender, EventArgs e)
    {
      list = GradeAndWeightRpc.GetGradeAndWeightList(butcherTimeInput.Date.Value);
      BindDataGrid();
      tangRow = FindRowSetSelected(tangEntity);
      maoRow = FindRowSetSelected(maoEntity);
      dataGridView.Refresh();
      details = GradeAndWeightRpc.GetDetails(butcherTimeInput.Date.Value, 50);
      FillQueue();
      BindDetailGrid();
      if (details.Any())
        maxIndex = details.First().Index;
      if (syncWork == null || !syncWork.IsAlive)
      {
        syncWork = new Thread(Sync);
        syncWork.Start();
        syncBtn.BackColor = Color.FromArgb(15, 215, 107);
        syncBtn.ForeColor = Color.White;
      }
      else
      {
        syncWork.Abort();
        syncBtn.BackColor = Color.FromKnownColor(KnownColor.Control);
        syncBtn.ForeColor = Color.FromKnownColor(KnownColor.ControlText);
      }
    }

    void Sync()
    {
      while (true)
      {
        Thread.Sleep(5000);
        this.Invoke(new InvokeHandler(delegate()
        {
          list = GradeAndWeightRpc.GetGradeAndWeightList(butcherTimeInput.Date.Value);
          BindDataGrid();
          tangRow = FindRowSetSelected(tangEntity);
          maoRow = FindRowSetSelected(maoEntity);
          dataGridView.Refresh();
        }));
      }
    }

    void FillQueue()
    {
      noWeightList = new ConcurrentQueue<GradeAndWeight_Detail>();
      noLivestockList = new ConcurrentQueue<GradeAndWeight_Detail>();
      var stack = new Stack<GradeAndWeight_Detail>();
      foreach (var item in details)
      {
        if (item.Livestock_ID == 0 || item.Weight == null)
          stack.Push(item);
        else
          break;
      }
      while (stack.Count > 0)
      {
        var bottom = stack.Pop();
        if (bottom.Weight == null)
          noWeightList.Enqueue(bottom);
        else
          noLivestockList.Enqueue(bottom);
      }
    }

    void BindDataGrid()
    {
      dataGridView.DataSource = list.OrderBy(x => x.Order).OrderBy(x => x.Finish).ToList();
      foreach (DataGridViewRow row in dataGridView.Rows)
      {
        if ((bool)row.Cells["D_Finish"].Value)
          row.DefaultCellStyle.BackColor = Color.YellowGreen;
      }
      InitScrollBar1();
      dataGridView.ClearSelection();
      try
      {
        if (leftRoll != -1)
          dataGridView.FirstDisplayedScrollingRowIndex = leftRoll;
      }
      catch
      {
        leftRoll = -1;
      }
    }

    void BindDetailGrid()
    {
      historyGrid.DataSource = null;
      if (details.Any())
        historyGrid.DataSource = details;
      InitScrollBar2();
      if (lastSelectID.HasValue)
      {
        foreach (DataGridViewRow row in historyGrid.Rows)
        {
          if ((long)row.Cells["H_ID"].Value == lastSelectID)
          {
            historyGrid.CurrentCell = row.Cells[row.Cells.Count - 1];
            break;
          }
        }
      }
      try
      {
        if (rightRoll != -1)
          historyGrid.FirstDisplayedScrollingRowIndex = rightRoll;
      }
      catch
      {
        rightRoll = -1;
      }
      historyGrid.Refresh();
    }

    private void printBtn_Click(object sender, EventArgs e)
    {
      var entity = new PrintEntity();
      entity.AccountingUnit_Name = "青花瓷软件（北京）有限公司";
      entity.Goods_Name = "B2/B3 ERP";
      entity.Date = DateTime.Today;
      entity.Checker = "管理员";
      entity.StoreCondition = "0-4℃ 5日";
      entity.Place = "北京市海淀区";
      entity.TelNumber = "010-62701591";
      entity.Address = "北京市北京市海淀区知春路49号";
      entity.BarCode = string.Format("BWP{0}{1:00000}", DateTime.Today.ToString("yyyyMMdd"), new Random().Next(1, 1000));
      entity._2DQRCode = string.Format("http://www.bwpsoft.com?code={0}", entity.BarCode);
      PrintAPI.Print(entity);
    }

    private void configBtn_Click(object sender, EventArgs e)
    {
      new GradeSettingFrom().ShowDialog();
    }

    GradeAndWeight tangEntity;
    GradeAndWeight maoEntity;

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

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

      switch (GradeContext.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 (string.IsNullOrEmpty(str))
                str = "0";
              this.Invoke(new InvokeHandler(delegate()
              {
                lblChengZhong.Text = string.Format(format, decimal.Parse(str));
                if (str != "0")
                {
                  AddWeightDetail(decimal.Parse(lblChengZhong.Text));
                }
              }));
            }
            _dataStrBuilder.Clear();
          }
          else if (_dataStrBuilder.Length != 0)
          {
            _dataStrBuilder.Append(c);
          }
        }
      }
    }

    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 (details == null)
      {
        MessageBox.Show("请先同步数据");
        return;
      }
      if (!enableWeight.Checked)
      {
        OpenSerialPort();
        _mainProcessIsRun = true;
        ReadData();
      }
      else
        DisableWeight();
      enableWeight.CheckState = enableWeight.Checked ? CheckState.Unchecked : CheckState.Checked;
    }
    #endregion

    static object _obj = new object();

    void AddDetail(CTuple<long, string, short> livestock)
    {
      lock (_obj)
      {
        var currentRow = livestock.Item3 == 0 ? tangEntity : maoEntity;
        var tech = livestock.Item3 == 0 ? "烫褪" : "毛剥";

        GradeAndWeight_Detail first;
        if (noLivestockList.TryPeek(out first) && first.Livestock_ID == 0)
        {
          noLivestockList.TryDequeue(out first);
          if (currentRow != null)
            first.OrderDetail_ID = currentRow.OrderDetail_ID;
          first.Date = butcherTimeInput.Date.Value;
          first.Livestock_ID = livestock.Item1;
          first.Livestock_Name = livestock.Item2;
          first.Technics = livestock.Item3;
          first.Technics_Name = tech;
          GradeAndWeightRpc.UpdateOrInsertDetail(first, true);
          historyGrid.Refresh();
        }
        else//add
        {
          maxIndex++;
          var entity = new GradeAndWeight_Detail();
          entity.Index = maxIndex;
          if (currentRow != null)
            entity.OrderDetail_ID = currentRow.OrderDetail_ID;
          entity.Date = butcherTimeInput.Date.Value;
          entity.Livestock_ID = livestock.Item1;
          entity.Livestock_Name = livestock.Item2;
          entity.Technics = livestock.Item3;
          entity.Technics_Name = tech;
          entity.Time = DateTime.Now;
          entity.Date = butcherTimeInput.Date.Value;
          if (details.Count == 50)
            details.RemoveAt(49);
          details.Insert(0, entity);
          GradeAndWeightRpc.UpdateOrInsertDetail(entity, true);
          noWeightList.Enqueue(entity);
          BindDetailGrid();
        }
        if (currentRow != null)
        {
          currentRow.Already = currentRow.Already + 1;
          orderLabel.Text = currentRow.Order.ToString();
          alreadyLabel.Text = currentRow.Already.ToString();
          dataGridView.Refresh();
        }
        else
        {
          orderLabel.Text = string.Empty;
          alreadyLabel.Text = string.Empty;
        }
      }
    }

    void AddWeightDetail(decimal weight)
    {
      lock (_obj)
      {
        weight -= (GradeContext.Config.Discont ?? 0);
        GradeAndWeight_Detail first;
        if (noWeightList.TryPeek(out first))
        {
          noWeightList.TryDequeue(out first);
          if (first.Weight < 0)
            first.Weight = (first.Weight ?? 0) + weight;
          else
            first.Weight = weight;
          GradeAndWeightRpc.UpdateOrInsertDetail(first);
          historyGrid.Refresh();
        }
        else//add
        {
          maxIndex++;
          var entity = new GradeAndWeight_Detail();
          entity.Index = maxIndex;
          entity.Weight = (entity.Weight ?? 0) + weight;
          entity.Time = DateTime.Now;
          entity.Date = butcherTimeInput.Date.Value;
          if (details.Count == 50)
            details.RemoveAt(49);
          details.Insert(0, entity);
          GradeAndWeightRpc.UpdateOrInsertDetail(entity);
          noLivestockList.Enqueue(entity);
          BindDetailGrid();
        }
      }
    }

    private void cancelBtn_Click(object sender, EventArgs e)
    {
      modifyDetail = null;
      modifyPanel.Hide();
    }

    GradeAndWeight_Detail lastCheckItem;
    long? lastSelectID = null;
    private void historyGrid_CellClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex < 0)
        return;
      var currentRow = historyGrid.CurrentRow.DataBoundItem as GradeAndWeight_Detail;
      lastSelectID = currentRow.ID;
      if (e.ColumnIndex == 2)
      {
        if (lastCheckItem != null && lastCheckItem.ID != currentRow.ID)
          lastCheckItem.ReadWeight = false;
        lastCheckItem = currentRow;
        lastCheckItem.ReadWeight = !lastCheckItem.ReadWeight;

        modifyDetail = null;
        if (modifyPanel.Visible)
          modifyPanel.Hide();
        historyGrid.Refresh();
        if (lastCheckItem.ReadWeight)
        {
          noWeightList = new ConcurrentQueue<GradeAndWeight_Detail>();
          var stack = new Stack<GradeAndWeight_Detail>();
          foreach (var item in details)
          {
            stack.Push(item);
            if (item.ID == lastCheckItem.ID)
              break;
          }
          while (stack.Count > 0)
            noWeightList.Enqueue(stack.Pop());
        }
        else
        {
          FillQueue();
          lastCheckItem = null;
        }
        return;
      }
      modifyDetail = currentRow;
      stateLabel.Text = string.Format("您正在修改序号为 {0} 的信息", modifyDetail.Index);
      modifyPanel.Show();
    }

    DataGridViewRow tangRow;
    DataGridViewRow maoRow;
    private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex == -1)
        return;
      var entity = dataGridView.CurrentRow.DataBoundItem as GradeAndWeight;
      if (entity.Technics_Name == "烫褪")
      {
        if (tangRow != null)
        {
          if (tangEntity.Finish)
            tangRow.DefaultCellStyle.BackColor = Color.YellowGreen;
          else
            tangRow.DefaultCellStyle.BackColor = dataGridView.RowsDefaultCellStyle.BackColor;
        }
        tangRow = dataGridView.CurrentRow;
        tangRow.DefaultCellStyle.BackColor = tangRow.DefaultCellStyle.SelectionBackColor = entity.Finish ? Color.YellowGreen : dataGridView.RowsDefaultCellStyle.SelectionBackColor;
        tangEntity = entity;
      }
      else
      {
        if (maoRow != null)
        {
          if (maoEntity.Finish)
            maoRow.DefaultCellStyle.BackColor = Color.YellowGreen;
          else
            maoRow.DefaultCellStyle.BackColor = dataGridView.RowsDefaultCellStyle.BackColor;
        }
        maoRow = dataGridView.CurrentRow;
        maoRow.DefaultCellStyle.BackColor = maoRow.DefaultCellStyle.SelectionBackColor = entity.Finish ? Color.YellowGreen : Color.Yellow;
        maoEntity = entity;
      }

      if (e.ColumnIndex == dataGridView.ColumnCount - 1 && !entity.Finish)
      {
        entity.Finish = true;
        GradeAndWeightRpc.SetGradeFinish(entity.OrderDetail_ID, entity.Technics);
        BindDataGrid();
        if (entity.Technics == 0)
        {
          maoRow = FindRowSetSelected(maoEntity);
          tangEntity = null;
          tangRow = null;
        }
        else
        {
          tangRow = FindRowSetSelected(tangEntity);
          maoEntity = null;
          maoRow = null;
        }
      }
      dataGridView.Refresh();
    }

    DataGridViewRow FindRowSetSelected(GradeAndWeight tag)
    {
      if (tag == null)
        return null;
      foreach (DataGridViewRow row in dataGridView.Rows)
      {
        if ((long)row.Cells["D_OrderDetail_ID"].Value == tag.OrderDetail_ID && (string)row.Cells["D_Technics_Name"].Value == tag.Technics_Name)
        {
          if (tag.Finish)
            row.DefaultCellStyle.BackColor = Color.YellowGreen;
          else
            row.DefaultCellStyle.BackColor = tag.Technics == 1 ? Color.Yellow : dataGridView.RowsDefaultCellStyle.SelectionBackColor;

          if (tag.Technics == 0)
            tangEntity = row.DataBoundItem as GradeAndWeight;
          else
            maoEntity = row.DataBoundItem as GradeAndWeight;
          return row;
        }
      }
      return null;
    }

    private void discontBtn_Click(object sender, EventArgs e)
    {
      if (new BodyDiscontSetting().ShowDialog() == DialogResult.OK)
        BuildDiscontPanel();
    }

    void BuildDiscontPanel()
    {
      var disconts = GradeAndWeightRpc.GetBodyDiscontItem().Where(x => x.Discont > 0).OrderBy(x => x.ID);
      discontPanel.Controls.Clear();
      foreach (var item in disconts)
      {
        var btn = new Button() { Name = "_D" + item.ID, Text = item.Name, Tag = item.Discont, Size = new Size(70, 60), TextAlign = ContentAlignment.MiddleCenter, Margin = new Padding { Left = 0, Right = 0, Top = 10, Bottom = 10 }, Font = new Font("宋体", 15) };
        btn.Click += (sender, e) =>
        {
          if (modifyDetail == null)
            throw new Exception("请先选择要扣重的记录");
          modifyDetail.Weight = (modifyDetail.Weight ?? 0) - Convert.ToDecimal(btn.Tag);
          GradeAndWeightRpc.UpdateWeight(modifyDetail.ID, modifyDetail.Weight);
          historyGrid.Refresh();
          modifyDetail = null;
          modifyPanel.Hide();
        };
        discontPanel.Controls.Add(btn);
      }
    }

    int leftRoll = -1;
    private void InitScrollBar1()
    {
      vScrollBar1.Maximum = (dataGridView.RowCount - dataGridView.DisplayedRowCount(false) + 30) * dataGridView.RowTemplate.Height;
      vScrollBar1.Minimum = 0;
      vScrollBar1.SmallChange = dataGridView.RowTemplate.Height;
      vScrollBar1.LargeChange = dataGridView.RowTemplate.Height * 30;
      this.vScrollBar1.Scroll += (sender, e) =>
      {
        leftRoll = e.NewValue / dataGridView.RowTemplate.Height;
        dataGridView.FirstDisplayedScrollingRowIndex = leftRoll;
      };
    }

    int rightRoll = -1;
    private void InitScrollBar2()
    {
      vScrollBar2.Maximum = (historyGrid.RowCount - historyGrid.DisplayedRowCount(false) + 30) * historyGrid.RowTemplate.Height;
      vScrollBar2.Minimum = 0;
      vScrollBar2.SmallChange = historyGrid.RowTemplate.Height;
      vScrollBar2.LargeChange = historyGrid.RowTemplate.Height * 30;
      this.vScrollBar2.Scroll += (sender, e) =>
      {
        rightRoll = e.NewValue / historyGrid.RowTemplate.Height;
        historyGrid.FirstDisplayedScrollingRowIndex = rightRoll;
      };
    }
  }
}
