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();

    const short TANG_TECH = 0;
    const short MAO_TECH = 1;
    List<GradeAndWeight> tangList;
    List<GradeAndWeight> maoList;
    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;
      tangGridView.AutoGenerateColumns = false;
      tangGridView.DataSource = null;
      maoGridView.AutoGenerateColumns = false;
      maoGridView.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(90, 75), TextAlign = ContentAlignment.MiddleCenter, Margin = new Padding { All = 15 }, Font = new Font("宋体", 18) };
        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 == TANG_TECH ? "烫褪" : "毛剥";
            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 == TANG_TECH)
          ttPanel.Controls.Add(btn);
        else
          mbPanel.Controls.Add(btn);
      }
      SetMargin(ttPanel);
      SetMargin(mbPanel);
    }

    void SetMargin(FlowLayoutPanel panel)
    {
      for (var i = 0; i < panel.Controls.Count; i++)
      {
        var c = panel.Controls[i];
        if (i % 3 == 0)//left
          c.Margin = new Padding(0, c.Margin.Top, c.Margin.Right, c.Margin.Bottom);
        if ((i + 1) % 3 == 0)//right
          c.Margin = new Padding(c.Margin.Left, c.Margin.Top, 0, c.Margin.Bottom);
        if (i <= 2)//firstRow
          c.Margin = new Padding(c.Margin.Left, 0, c.Margin.Right, c.Margin.Bottom);
      }
    }

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

    private void syncBtn_Click(object sender, EventArgs e)
    {
      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)
      {
        this.Invoke(new InvokeHandler(delegate()
        {
          BindTangGrid();
          BindMaoGrid();
        }));
        Thread.Sleep(5000);
      }
    }

    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 BindTangGrid()
    {
      tangList = GradeAndWeightRpc.GetGradeAndWeightList(butcherTimeInput.Date.Value, true);
      tangGridView.DataSource = tangList.OrderBy(x => x.Order).OrderBy(x => x.Finish).ToList();
      if (tangEntity == null && tangGridView.CurrentRow != null)
      {
        tangEntity = tangGridView.CurrentRow.DataBoundItem as GradeAndWeight;
        if (tangEntity.Finish)
          tangEntity = null;
      }
      foreach (DataGridViewRow row in tangGridView.Rows)
      {
        if ((bool)row.Cells["T_Finish"].Value)
          row.DefaultCellStyle.BackColor = Color.YellowGreen;
        if (tangEntity != null && tangEntity.OrderDetail_ID == (long)row.Cells["T_OrderDetail_ID"].Value)
        {
          tangEntity = row.DataBoundItem as GradeAndWeight;
          if (tangEntity.Finish)
            row.DefaultCellStyle.BackColor = Color.Yellow;
          else
            row.DefaultCellStyle.BackColor = tangGridView.RowsDefaultCellStyle.SelectionBackColor;
        }
      }
      InitTangScrollBar();
      tangGridView.ClearSelection();
      try
      {
        if (tangRoll != -1)
          tangGridView.FirstDisplayedScrollingRowIndex = tangRoll;
      }
      catch
      {
        tangRoll = -1;
      }
      tangGridView.Refresh();
    }

    void BindMaoGrid()
    {
      maoList = GradeAndWeightRpc.GetGradeAndWeightList(butcherTimeInput.Date.Value, false);
      maoGridView.DataSource = maoList.OrderBy(x => x.Order).OrderBy(x => x.Finish).ToList();
      if (maoEntity == null && maoGridView.CurrentRow != null)
      {
        maoEntity = maoGridView.CurrentRow.DataBoundItem as GradeAndWeight;
        if (maoEntity.Finish)
          maoEntity = null;
      }
      foreach (DataGridViewRow row in maoGridView.Rows)
      {
        if ((bool)row.Cells["M_Finish"].Value)
          row.DefaultCellStyle.BackColor = Color.YellowGreen;
        if (maoEntity != null && maoEntity.OrderDetail_ID == (long)row.Cells["M_OrderDetail_ID"].Value)
        {
          maoEntity = row.DataBoundItem as GradeAndWeight;
          if (maoEntity.Finish)
            row.DefaultCellStyle.BackColor = Color.Yellow;
          else
            row.DefaultCellStyle.BackColor = maoGridView.RowsDefaultCellStyle.SelectionBackColor;
        }
      }
      InitMaoScrollBar();
      maoGridView.ClearSelection();
      try
      {
        if (maoRoll != -1)
          maoGridView.FirstDisplayedScrollingRowIndex = maoRoll;
      }
      catch
      {
        maoRoll = -1;
      }
      maoGridView.Refresh();
    }

    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);
      WeightGradePrint.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 (GradeContext.Config.WeightType == 0)
              {
                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));
                  }
                }));
              }
              else
              {
                decimal num = 0;
                if (decimal.TryParse(str, out num))
                {
                  this.Invoke(new InvokeHandler(delegate()
                  {
                    lblChengZhong.Text = string.Format(format, num);
                  }));
                  WeighAvgControl.Add(num, isStatic);
                }
                if (WeighAvgControl.TryGetValue(out num))
                {
                  this.Invoke(new InvokeHandler(delegate()
                  {
                    //lblChengZhong.Text = string.Format(format, num);
                    if (str != "0")
                    {
                      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 >= GradeContext.Config.MinWeight && value <= GradeContext.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 (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 == TANG_TECH ? "烫褪" : "毛剥";

        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;
          if (disBtn != null)
          {
            first.Weight = (first.Weight ?? 0) - Convert.ToDecimal(disBtn.Tag);
            SetBtnUnCheck(disBtn);
            disBtn = null;
          }
          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 (disBtn != null)
          {
            entity.Weight = -Convert.ToDecimal(disBtn.Tag);
            SetBtnUnCheck(disBtn);
            disBtn = null;
          }
          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();
          tangGridView.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();
    }

    private void tangGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex == -1)
        return;
      if (e.ColumnIndex == tangGridView.Columns.Count - 1)
        return;
      var entity = tangGridView.CurrentRow.DataBoundItem as GradeAndWeight;
      if (tangEntity != null)
      {
        foreach (DataGridViewRow row in tangGridView.Rows)
        {
          if (tangEntity.OrderDetail_ID == (long)row.Cells["T_OrderDetail_ID"].Value)
          {
            row.DefaultCellStyle.BackColor = tangEntity.Finish ? Color.YellowGreen : tangGridView.RowsDefaultCellStyle.BackColor;
            break;
          }
        }
      }
      tangEntity = entity;
      tangGridView.CurrentRow.DefaultCellStyle.SelectionBackColor = tangEntity.Finish ? Color.Yellow : tangGridView.RowsDefaultCellStyle.SelectionBackColor;
      tangGridView.Refresh();
    }

    private void tangGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex == -1)
        return;
      if (e.ColumnIndex != tangGridView.ColumnCount - 1)
        return;
      var entity = tangGridView.CurrentRow.DataBoundItem as GradeAndWeight;
      if (entity.Finish)
        return;
      entity.Finish = true;
      GradeAndWeightRpc.SetGradeFinish(entity.OrderDetail_ID, TANG_TECH);
      BindTangGrid();
    }

    private void maoGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex == -1)
        return;
      if (e.ColumnIndex == maoGridView.Columns.Count - 1)
        return;
      var entity = maoGridView.CurrentRow.DataBoundItem as GradeAndWeight;
      if (maoEntity != null)
      {
        foreach (DataGridViewRow row in maoGridView.Rows)
        {
          if (maoEntity.OrderDetail_ID == (long)row.Cells["M_OrderDetail_ID"].Value)
          {
            row.DefaultCellStyle.BackColor = maoEntity.Finish ? Color.YellowGreen : maoGridView.RowsDefaultCellStyle.BackColor;
            break;
          }
        }
      }
      maoEntity = entity;
      maoGridView.CurrentRow.DefaultCellStyle.SelectionBackColor = maoEntity.Finish ? Color.Yellow : maoGridView.RowsDefaultCellStyle.SelectionBackColor;
      maoGridView.Refresh();
    }

    private void maoGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
      if (e.RowIndex == -1)
        return;
      if (e.ColumnIndex != maoGridView.ColumnCount - 1)
        return;
      var entity = maoGridView.CurrentRow.DataBoundItem as GradeAndWeight;
      if (entity.Finish)
        return;
      entity.Finish = true;
      GradeAndWeightRpc.SetGradeFinish(entity.OrderDetail_ID, MAO_TECH);
      BindMaoGrid();
    }

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

    Button disBtn = null;
    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 { Bottom = 30 }, Font = new Font("宋体", 15) };
        btn.Click += (sender, e) =>
        {
          if (modifyDetail == null)
          {
            if (disBtn != null)
              SetBtnUnCheck(disBtn);
            if (disBtn != btn)
            {
              disBtn = btn;
              SetBtnChecked(disBtn);
            }
            else
              disBtn = null;
          }
          else
          {
            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);
      }
    }

    readonly Color btnSelectForeColor = Color.FromArgb(255, 255, 255);
    readonly Color btnSelectBackColor = Color.FromArgb(66, 163, 218);
    Color btnUnSelectForeColor = SystemColors.ControlText;
    Color btnUnSelectBackColor = Color.FromArgb(225, 225, 225);
    void SetBtnChecked(Button btn)
    {
      btn.BackColor = btnSelectBackColor;
      btn.ForeColor = btnSelectForeColor;
    }

    void SetBtnUnCheck(Button btn)
    {
      btn.BackColor = btnUnSelectBackColor;
      btn.ForeColor = btnUnSelectForeColor;
    }

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

    int maoRoll = -1;
    private void InitMaoScrollBar()
    {
      maoScrollBar.Maximum = (maoGridView.RowCount - maoGridView.DisplayedRowCount(false) + 30) * maoGridView.RowTemplate.Height;
      maoScrollBar.Minimum = 0;
      maoScrollBar.SmallChange = maoGridView.RowTemplate.Height;
      maoScrollBar.LargeChange = maoGridView.RowTemplate.Height * 30;
      maoScrollBar.Scroll += (sender, e) =>
      {
        maoRoll = e.NewValue / maoGridView.RowTemplate.Height;
        maoGridView.FirstDisplayedScrollingRowIndex = maoRoll;
      };
    }

    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;
      };
    }
  }
}
