using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace RS_WF62_terminal_CS
{
    public partial class Terminal : Form
    {
        private bool fReceive = true;
        public int connectType;
        System.IO.Ports.SerialPort SerialPort;
        public string PortName;
        private NetworkStream mStream = null;
        private TcpClient mClient = null;
        private Thread ReceiveThread;
        public string IPAdrs;

        delegate void SetTxtCallback(TextBox Txt, string str1);
        private void SetTxt(TextBox Txt, string str1)
        {
            // 呼び出し元のコントロールのスレッドが異なるか確認をする
            if (Txt.InvokeRequired)
            {
                // 同一メソッドへのコールバックを作成する
                SetTxtCallback delegateMethod = new SetTxtCallback(SetTxt);

                // コントロールの親のInvoke()メソッドを呼び出すことで、呼び出し元の
                // コントロールのスレッドでこのメソッドを実行する
                this.BeginInvoke(delegateMethod, new object[] { Txt, str1 });
            }
            else
            {
                // コントロールを直接呼び出す
                Txt.Text = str1;
            }
        }


        public Terminal()
        {
            InitializeComponent();
        }

        private void Terminal_Load(object sender, EventArgs e)
        {
            // TCP/IP モード
            if ( connectType == 0 )
            {
                int timeout = 3000;

                IPAddress ip = IPAddress.Parse(IPAdrs);
                int port = 5074;

                // IPアドレスとポート番号からソケット・アドレスを作成
                mClient = new TcpClient();
                mClient.ReceiveTimeout = mClient.SendTimeout = timeout;

                var result = mClient.BeginConnect(ip, port, null, null);
                var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(timeout));

                if (!success)
                {
                    // 失敗、例外を投げる
                    return;
                }

                // ソケットへの接続
                // ソケットへ接続中
                if (mClient.Connected)
                {
                    //return;
                }

                // 出力ストリーム取得
                if (mStream == null)
                {
                    mStream = mClient.GetStream();
                }

                // 受信スレッド
                ReceiveThread = new Thread(ReceiveProc);
                ReceiveThread.Start();
            }
            // COM モード
            else if (connectType == 1)
            {
                SerialPort = new System.IO.Ports.SerialPort();
                // ポート番号
                SerialPort.PortName = PortName;
                // 転送速度
                SerialPort.BaudRate = 9600;
                // データビット
                SerialPort.DataBits = 8;
                // パリティ
                SerialPort.Parity = System.IO.Ports.Parity.None;
                // ストップビット
                SerialPort.StopBits = System.IO.Ports.StopBits.One;
                // フロー制御
                SerialPort.Handshake = System.IO.Ports.Handshake.None;
                // タイムアウト
                SerialPort.ReadTimeout = 5000;
                SerialPort.WriteTimeout = 5000;
                // RTS
                SerialPort.RtsEnable = true;
                // 受信処理
                SerialPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.SerialPort_DataReceived);

                // ポートオープン
                SerialPort.Open();
                SerialPort.DiscardInBuffer();
                SerialPort.DiscardOutBuffer();
            }
        }

        private void BtnSend_Click(object sender, EventArgs e)
        {
            // TCP/IP モード
            if (connectType == 0)
            {
                writeCommand(mStream, Encoding.ASCII.GetBytes(TxtSendData.Text));
            }
            // COM モード
            else if (connectType == 1)
            {
                // データ送信
                SerialPort.Write( Encoding.ASCII.GetBytes(TxtSendData.Text), 0, TxtSendData.Text.Length);
            }

            // 送信データクリア
            TxtSendData.Text = string.Empty;
        }

        private void BtnRecvClear_Click(object sender, EventArgs e)
        {
            // 受信データクリア
            TxtRecvData.Text = string.Empty;
        }

        private void BtnDisconnect_Click(object sender, EventArgs e)
        {
            fReceive = false;
            // TCP/IP モード
            if (connectType == 0)
            {
                // ストリームクローズ
                if (mStream != null)
                {
                    mStream.Dispose();
                    mStream = null;
                }
                // ソケットクローズ
                if (mClient != null)
                {
                    mClient.Dispose();
                    mClient = null;
                }

                ReceiveThread.Interrupt();
                ReceiveThread.Join();
            }
            // COM モード
            else if (connectType == 1)
            {
                // ポートクローズ
                SerialPort.Close();
            }

            // クローズ
            this.Close();
        }

        // シリアル受信
        private void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            byte Offset;
            byte result;
            int RetryCount;
            byte[] readbuf = new byte[1024];

            Offset = 0;
            result = 0;
            RetryCount = 0;

            while (fReceive)
            {
                result = (Byte)SerialPort.BytesToRead;
                // 受信データ取得
                SerialPort.Read(readbuf, Offset, result);

                Offset = (byte)(Offset + result);
                // 50msウェイト
                System.Threading.Thread.Sleep(50);

                if (result > 0)
                {
                    RetryCount = 0;
                }
                else
                {
                    RetryCount++;
                    //                        if (RetryCount == 20)
                    break;
                }
            }

            // データがあれば追加して表示更新
            if (Offset > 0)
            {
                // 表示
                SetTxt(TxtRecvData, TxtRecvData.Text + Encoding.ASCII.GetString(readbuf));
            }
        }

        // TCP/IP送信
        public static bool writeCommand(Stream mOutputStream, byte[] writeBuf)
        {
            // バッファが空でない
            if (writeBuf != null)
            {
                try
                {
                    if (mOutputStream != null)
                    {
                        // 指定されたバイト配列を出力ストリームに書き込む
                        mOutputStream.Write(writeBuf, 0, writeBuf.Length);
                        // 出力ストリームを書き込む
                        //mOutputStream.Flush();
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
            return false;
        }

        // TCP/IP受信
        private void ReceiveProc()
        {
            int TotalCount = 0;
            byte[] resultBuf;

            while (fReceive) 
            {
                using (var memStream = new MemoryStream())
                {
                    try
                    {
                        TotalCount = 0;
                        resultBuf = null;
                        if (mStream != null)
                        {
                            byte[] rcvBuf = new byte[256];
                            int readCount;
                            mStream.ReadTimeout = 10;
                            while ((readCount = mStream.Read(rcvBuf, 0, rcvBuf.Length)) > 0)
                            {
                                //受信したデータを蓄積する
                                memStream.Write(rcvBuf, TotalCount, rcvBuf.Length);
                                TotalCount += readCount;
                            }
                        }
                    }
                    catch (IOException ioe)
                    {
                        Debug.WriteLine(ioe.Message);
                    }
                    catch (SocketException se)
                    {
                        Debug.WriteLine(se.Message);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }

                    // データがあれば
                    if (TotalCount > 0)
                    {
                        resultBuf = memStream.ToArray();

                        // 表示
                        SetTxt(TxtRecvData, TxtRecvData.Text + Encoding.ASCII.GetString(resultBuf));
                    }
                }
            }
        }
    }
}
