/*******************************************************************************
* Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved.
* 
* This software is protected by copyright laws of the United States and
* of foreign countries. This material may also be protected by patent laws
* and technology transfer regulations of the United States and of foreign
* countries. This software is furnished under a license agreement and/or a
* nondisclosure agreement and may only be used or reproduced in accordance
* with the terms of those agreements. Dissemination of this information to
* any party or parties not specified in the license agreement and/or
* nondisclosure agreement is expressly prohibited.
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of Maxim Integrated
* Products, Inc. shall not be used except as stated in the Maxim Integrated
* Products, Inc. Branding Policy.
*
* The mere transfer of this software does not imply any licenses
* of trade secrets, proprietary technology, copyrights, patents,
* trademarks, maskwork rights, or any other form of intellectual
* property whatsoever. Maxim Integrated Products, Inc. retains all
* ownership rights.
*******************************************************************************
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;
using RPCSupport.Pipelines;
using System.Threading;
using System.Collections;

namespace RPCSupport
{
    public class SerialPipeline : Pipeline {
	    protected SerialPort serialPort;

        public SerialPipeline() 
        {
            serialPort = new SerialPort();
	    }

        public override void Connect(String PortName)
        {
            // Set the read/write timeouts
            serialPort.ReadTimeout = 90000;
            serialPort.WriteTimeout = 90000;

            serialPort.PortName = PortName;
            serialPort.BaudRate = 9600;

            // always the same
            serialPort.DataBits = 8;
            serialPort.Parity = Parity.None;
            serialPort.StopBits = StopBits.One;
            serialPort.Handshake = Handshake.None;

            serialPort.DtrEnable = true;
            serialPort.RtsEnable = true;
            Thread.Sleep(10);
            serialPort.Open();

            //serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
            //serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(serialPort_ErrorReceived);
        }

        public override void Disconnect()
        {
            serialPort.Close();
        }

        public override bool IsConnected()
        {
            return serialPort.IsOpen;
        }

        public override String[] ScanAvailablePortNames()
        {
            return SerialPort.GetPortNames();
        }

        /*
	    public override String SendRPC(String Name, String Method, params String[] Args)
        {
		    //write to serial port and receive result
		    String Response;
		    String Arguments = "";

		    if(Args != null)
            {
			    for(int i = 0; i < Args.Length; i++)
                {
				    Arguments = Arguments + " " + Args[i];
			    }
		    }

            serialPort.DiscardInBuffer();
            String sendString = "/" + Name + "/" + Method + Arguments + "\r\n";
            String reply = RawRpcCall(sendString);

            return reply;
	    }*/

        /*
	    public override void delete()
        {
		    //Close the serial port
            if (serialPort != null) serialPort.Close();
        }
        */

        private void serialPort_DataReceived(object sender, EventArgs e)
        {
            Debug.Print("Serial Port event");
            //String Interrupt = serialPort.ReadLine();
            String str = serialPort.ReadExisting();
        }

        private void serialPort_ErrorReceived(object sender, EventArgs e)
        {
            Debug.Print("Serial Port error");
        }




        //
        // Serial Byte Collection Thread
        //
        /*private BackgroundWorker bw = new BackgroundWorker();
        private void InitThread()
        {
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        }
        private void StartThread()
        {
            if (bw.IsBusy != true)
            {
                bw.RunWorkerAsync();
            }
        }
        private void StopThread()
        {
            if (bw.WorkerSupportsCancellation == true)
            {
                bw.CancelAsync();
            }
        }
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;

            for (int i = 1; (i <= 10); i++)
            {
                if ((worker.CancellationPending == true))
                {
                    e.Cancel = true;
                    break;
                }
                else
                {
                    // Perform a time consuming operation and report progress.
                    System.Threading.Thread.Sleep(500);
                    worker.ReportProgress((i * 10));
                }
            }
        }*/

        public override string RawRpcCall(string request, bool reply)
        {
            if (rawRpcRequest != null) rawRpcRequest(request);
            //String reply = myHID.RPC_Call(request);
            serialPort.WriteLine(request);
            if (reply == false) return "";

            string replyStr;
            //replyStr = serialPort.ReadLine();
            int ch;
            int lastCh;
            bool gotCR = false;
            bool gotLF = false;
            lastCh = 0;
            ch = serialPort.ReadByte();
            StringBuilder sb = new StringBuilder();
            StringBuilder sbDebug = new StringBuilder();
            while (ch != -1)
            {
                //sbDebug.Append("0x" + ch.ToString("X2") + " ");
                if (ch != '\n') 
                    sb.Append((char)ch);
                if (lastCh == '\r' && ch == '\n') break;
                lastCh = ch;
                ch = serialPort.ReadByte();
            }
            replyStr = sb.ToString();
            if (rawRpcReply != null) rawRpcReply(sbDebug.ToString());
            if (rawRpcReply != null) rawRpcReply(replyStr);
            return replyStr;
        }

        public override string RawRpcCallBinary(string request, bool reply, out bool allOnes)
        {
            if (rawRpcRequest != null) rawRpcRequest(request);
            //String reply = myHID.RPC_Call(request);
            serialPort.WriteLine(request);
            //if (reply == false) return "";

            byte[] buffer = new byte[256];
            int bytesToRead = 256;
            while (bytesToRead != 0)
            {
                int bytesRead = serialPort.Read(buffer, 256 - bytesToRead, bytesToRead);
                bytesToRead -= bytesRead;
            }
            allOnes = true;
            for (int i = 0; i < 256; i++) {
                if (buffer[i] != 0xFF) allOnes = false;
            }
            string replyStr;
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 256; i++)
            {
                sb.Append(buffer[i].ToString("X2") + " ");
            }
            //replyStr = serialPort.ReadLine();
            replyStr = sb.ToString().Trim();
            String otherStr = serialPort.ReadLine();
            if (rawRpcReply != null) rawRpcReply(replyStr);
            return replyStr;
        }

        public override void SendSingleByte(char ch)
        {
            if (rawRpcRequest != null) rawRpcRequest("<" + ch + ">");
            char[] chArray = new char[1];
            chArray[0] = ch;
            serialPort.Write(chArray, 0, 1);
        }
        public override string ReadString()
        {
            return serialPort.ReadExisting();
        }
        public override int Read(char[] buffer, int offset, int count)
        {
            int val = 0;
            try
            {
                val = serialPort.Read(buffer, offset, count);
            }
            catch (Exception)
            {
            }
            return val;
        }
        public override void Discard()
        {
            serialPort.DiscardInBuffer();
        }
    }
}
