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

namespace BWP.WinFormControl
{
  public enum WeightType
  {
    IND560,
    Xk3124,
    Xk3190A9,
    Xk3190D10
  }
  public partial class WeightControl : UserControl
  {
    public event EventHandler InitWeightInfo;

    #region weight Need

    private IDataFormat _dataFormat;
    private Thread _inQueryThread;
    //, _outQueryThread;
    readonly StringBuilder _dataStrBuilder = new StringBuilder();
    //readonly ConcurrentQueue<string> _dataQueue = new ConcurrentQueue<string>();
    Form mainForm;
    #endregion

    bool inited = false;
    public void InitSerialPort(string comPort, int baudRate, int dataBits)
    {
      weightSerialPort.PortName = comPort;
      weightSerialPort.BaudRate = baudRate;
      weightSerialPort.DataBits = dataBits;
      weightSerialPort.ReadBufferSize = 4096 * 100;
      inited = true;
    }

    //public SerialPort WeightSerialPort { get { return this.weightSerialPort; } }

    private string _valueFormat = @"0.00";
    public string ValueFormat { get { return _valueFormat; } set { _valueFormat = value; } }

    private WeightType _weightType = WeightType.Xk3190A9;
    /// <summary>
    /// 称类型
    /// </summary>
    public WeightType TypeOfWeight
    {
      get { return _weightType; }
      set { _weightType = value; }
    }
    string format
    {
      get
      {
        if (string.IsNullOrEmpty(_valueFormat))
          _valueFormat = @"0.00";
        return "{0:" + _valueFormat + "}";
      }
    }
    public decimal? Value
    {
      get
      {
        if (string.IsNullOrEmpty(weightLabel.Text)) return null;
        return decimal.Parse(string.Format(format, weightLabel.Text));
      }
      private set { weightLabel.Text = string.Format(format, value); }
    }

    public void Clear()
    {
      Value = 0;
    }

    public CheckBox EnableCheckBox { get { return enableWeightBox; } }

    public WeightControl()
    {
      InitializeComponent();
      Control.CheckForIllegalCrossThreadCalls = false;
    }

    private void OpenSerialPort()
    {
      if (!inited)
        throw new Exception("Com口没有实例化，请先调用InitSerialPort");
      Thread.Sleep(10);
      // 打开串口
      if (!weightSerialPort.IsOpen)
      {
        try
        {
          weightSerialPort.Open();
          if (mainForm == null)
            mainForm = ComponentUtil.GetParentFormm(this);
          mainForm.FormClosed += MainFrom_FormClosed;
        }
        catch (InvalidOperationException)
        {
          MessageBox.Show(@"指定的端口已打开");
        }
        catch (UnauthorizedAccessException)
        {
          MessageBox.Show(@"对端口的访问被拒绝");
        }
      }
    }

    void ReadData()
    {
      _inQueryThread = new Thread(InQuery);
      //_inQueryThread.IsBackground = true;
      _inQueryThread.Start();

      //_outQueryThread = new Thread(OutQuery);
      //_outQueryThread.IsBackground = true;
      //_outQueryThread.Start();
    }

    private void InQuery()
    {
      while (enableWeightBox.CheckState == CheckState.Checked)
      {
        int availableCount = weightSerialPort.BytesToRead;
        if (availableCount == 0)
        {
          Thread.Sleep(1);
        }
        char[] buffer = new char[availableCount];
        if (!weightSerialPort.IsOpen)
        {
          continue;
        }
        weightSerialPort.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))
            {
              Value = decimal.Parse(str);
              break;
            }
            _dataStrBuilder.Clear();
          }
          else if (_dataStrBuilder.Length != 0)
          {
            _dataStrBuilder.Append(c);
          }
        }
      }
    }

    void InitWeightType()
    {
      switch (_weightType)
      {
        case WeightType.IND560:
          _dataFormat = new IND560DataFormat();
          break;
        case WeightType.Xk3124:
          _dataFormat = new Xk3124DataFormat();
          break;
        case WeightType.Xk3190A9:
          _dataFormat = new Xk3190A9DataFormat();
          break;
        case WeightType.Xk3190D10:
          _dataFormat = new Xk3190D10DataFormat();
          break;
        default:
          throw new Exception("未知称类型");
      }
    }

    void DisableWeight()
    {
      mainForm.FormClosed -= MainFrom_FormClosed;
      Thread.Sleep(10);
      if (_inQueryThread.IsAlive)
      {
        _inQueryThread.Abort();
      }
      weightSerialPort.Close();
      Value = 0;
    }

    private void MainFrom_FormClosed(object sender, FormClosedEventArgs e)
    {
      if (enableWeightBox.CheckState == CheckState.Checked)
        return;
      DisableWeight();
    }

    public void enableWeightBox_Click(object sender, EventArgs e)
    {
      if (InitWeightInfo == null)
        throw new Exception("InitWeightInfo是用来实例化称参数的，请给此委托赋值并在其中实例化称参数");
      InitWeightInfo(this, EventArgs.Empty);
      if (!inited)
        throw new Exception("Com口没有实例化，请先调用InitSerialPort");
      if (!enableWeightBox.Checked)
      {
        InitWeightType();
        OpenSerialPort();
        ReadData();
      }
      else
        DisableWeight();
      enableWeightBox.CheckState = enableWeightBox.Checked ? CheckState.Unchecked : CheckState.Checked;
    }
  }
}
