using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using FTD2XX_NET;

namespace UZVAS
{
    class FT2232 : IFTDI
    {
        private FTDI FtdiDevice = new FTDI();
        private string SendHelloPacket = "h";
        private string GetHelloPacket = "Hello";

        static public string[] getList()
        {
            UInt32 ftdiDeviceCount = 0;
            FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;

            // Create new instance of the FTDI device class
            FTDI myFtdiDevice = new FTDI();

            // Determine the number of FTDI devices connected to the machine
            ftStatus = myFtdiDevice.GetNumberOfDevices(ref ftdiDeviceCount);
            // Check status
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to get number of devices (error " + ftStatus.ToString() + ")");
            }

            // If no devices available, return
            if (ftdiDeviceCount == 0)
            {
               return null;
            }

           string[] result = new string[ftdiDeviceCount];
            // Allocate storage for device info list
            FTDI.FT_DEVICE_INFO_NODE[] ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];

            // Populate our device list
            ftStatus = myFtdiDevice.GetDeviceList(ftdiDeviceList);

            if (ftStatus == FTDI.FT_STATUS.FT_OK)
            {
                for (UInt32 i = 0; i < ftdiDeviceCount; i++)
                {
                    string Item = ftdiDeviceList[i].Type.ToString() + " ";
                    Item += String.Format("{0:x}", ftdiDeviceList[i].ID) + " ";
                    Item += ftdiDeviceList[i].Description.ToString();
                    result[i] = Item;
                }
            }

            return result;
        }

        public void WriteByte(char buffer)
        {
            if (FtdiDevice == null) return;
            // Perform loop back - make sure loop back connector is fitted to the device
            // Write string data to the device
            string dataToWrite = "" + buffer;
            UInt32 numBytesWritten = 0;
            // Note that the Write method is overloaded, so can write string or byte array data
            FTDI.FT_STATUS ftStatus = FtdiDevice.Write(dataToWrite, dataToWrite.Length, ref numBytesWritten);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to write to device (error " + ftStatus.ToString() + ")");
            }
        }

        public void WriteString(string buffer)
        {
            foreach (char c in buffer)
                WriteByte(c);
        }

        public FT2232(int FTDIindex)
        {
            FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OK;
            // Open first device in our list by index
            ftStatus = FtdiDevice.OpenByIndex((uint)FTDIindex);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to open device (error " + ftStatus.ToString() + ")");
            }

            // Set up device data parameters
            // Set Baud rate to 9600
            ftStatus = FtdiDevice.SetBaudRate(9600);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to set Baud rate (error " + ftStatus.ToString() + ")");
            }

            // Set data characteristics - Data bits, Stop bits, Parity
            ftStatus = FtdiDevice.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to set data characteristics (error " + ftStatus.ToString() + ")");
            }

            // Set flow control - set RTS/CTS flow control
            ftStatus = FtdiDevice.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_NONE, 0x11, 0x13);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to set flow control (error " + ftStatus.ToString() + ")");
            }

            // Set read timeout to 5 seconds, write timeout to infinite
            ftStatus = FtdiDevice.SetTimeouts(5000, 0);
            if (ftStatus != FTDI.FT_STATUS.FT_OK)
            {
                // Wait for a key press
                throw new Exception("Failed to set timeouts (error " + ftStatus.ToString() + ")");
            }

            Thread readingThread = new Thread(new ThreadStart(Reading));
            readingThread.Name = "FTDI reading";
            readingThread.IsBackground = true;
            readingThread.Priority = ThreadPriority.BelowNormal;
            readingThread.Start();

            WriteString(SendHelloPacket);
        }

        public void Close()
        {
            if (FtdiDevice == null) return;
            FtdiDevice.Close();
        }

        private void Reading()
        {
            while (true)
            {
                // Check the amount of data available to read
                // In this case we know how much data we are expecting, 
                // so wait until we have all of the bytes we have sent.
                UInt32 numBytesAvailable = 0;
                FTDI.FT_STATUS ftStatus;
              
                ftStatus = FtdiDevice.GetRxBytesAvailable(ref numBytesAvailable);
                if (numBytesAvailable != 0)
                {
                    if (ftStatus != FTDI.FT_STATUS.FT_OK)
                    {
                        // Wait for a key press
                        throw new Exception("Failed to get number of bytes available to read (error " + ftStatus.ToString() + ")");
                    }

                    // Now that we have the amount of data we want available, read it
                    string readData;
                    UInt32 numBytesRead = 0;
                    // Note that the Read method is overloaded, so can read string or byte array data
                    ftStatus = FtdiDevice.Read(out readData, (uint)numBytesAvailable, ref numBytesRead);
                    if (ftStatus != FTDI.FT_STATUS.FT_OK)
                    {
                        // Wait for a key press
                        throw new Exception("Failed to read data (error " + ftStatus.ToString() + ")");
                    }

                    if (OnRead != null)
                    {
                        if (readData == GetHelloPacket)
                            OnRead("Communication started");
                        else
                            OnRead(readData);
                    }
                }
                
            }
        }

        public event OnReadHandler OnRead;
    }
}
/*
namespace USBtoXMLReader
{
    class Program
    {
        private const byte ModAlt = 1, ModControl = 2, ModShift = 4, ModWin = 8;
        public static FTDI myFtdiDevice;
        private static byte Win32Modifiers
        {
            get
            {
                byte toReturn = 0;
                toReturn += ModShift;
                toReturn += ModControl;
                toReturn += ModAlt;
                return toReturn;
            }
        }

   
        static bool measure = false; 

        static void Main(string[] args)
        {
            Console.WriteLine("Serial commucation to cursor writting started...");
            Console.WriteLine("------------------------------------------------");

        
     
      
            string sr = sp_ReadData(GetHelloPacket.Length, myFtdiDevice);
            if (sr == GetHelloPacket )
                Console.WriteLine("Communication started");
            else
                Console.WriteLine("Communication FAILED - "+sr);

            HotKeyManager.RegisterHotKey(Keys.R, KeyModifiers.Alt | KeyModifiers.Control  );
            HotKeyManager.HotKeyPressed += new EventHandler<HotKeyEventArgs>(HotKeyManager_HotKeyPressed);
   
            Console.WriteLine("CTRL + ALT + R to start/stop reading");
            Console.WriteLine("Type q to quit");

            while (true)
            {
                string s = Console.ReadLine();
                if (s == "q")
                {
                    myFtdiDevice.Close();
                    Environment.Exit(0);
                }
            }
        }

        static void HotKeyManager_HotKeyPressed(object sender, HotKeyEventArgs e)
        {

            sp_WriteData("r", myFtdiDevice);
            measure = !measure;
            if (measure)
            {
                myFtdiDevice.ResetDevice();
                Thread t = new Thread(new ThreadStart(Measuring));
                t.IsBackground = false;
                t.Priority = ThreadPriority.BelowNormal;
                t.Start();
            }
        }

        static void Measuring()
        {
            while (measure)
            {
                string sr = sp_ReadData(1, myFtdiDevice);
                ProccessingData(sr);
            }
        }

        static void ProccessingData(string buffer)
        {
            char c = buffer[0];
            int data = (int)c;
            
            if (data == 0x55)
            {
                string sHighByte = "0";
                string sLowByte = "0";

                string sPath = sp_ReadData(1, myFtdiDevice);
                if ((int)sPath[0] == 0x55)
                    sPath = sp_ReadData(1, myFtdiDevice);
              
                if (sPath[0] == 'E')
                    Console.WriteLine("Measure mismatch");
                else
                {
                    sLowByte = sp_ReadData(1, myFtdiDevice);
                    sHighByte = sp_ReadData(1, myFtdiDevice);
                }

                string EndByte = sp_ReadData(1, myFtdiDevice);

                if ((int)EndByte[0] != 0x55)
                    Console.WriteLine("Communication mismatch");
                else
                {
                    string time = DateTime.Now.Minute.ToString()+":"+DateTime.Now.Second.ToString()+":"+DateTime.Now.Millisecond.ToString();
                    int i1 = 0;
                    int i2 = 0;

                    i2 = (int)sHighByte[0];
                    i1 = (int)sLowByte[0];

                            int value = i2 * 256 + i1;

                            Console.WriteLine(time + " " + ((int)sPath[0]).ToString() + " " + value.ToString());
                           
                            SendKeys.SendWait(time);
                            SendKeys.SendWait((char)0x09 + "");
                            SendKeys.SendWait(((int)sPath[0]).ToString());
                            SendKeys.SendWait((char)0x09 + "");
                            SendKeys.SendWait(value.ToString());
                            SendKeys.SendWait((char)13 + "");
                           
                }
            }
            else
                Console.WriteLine("Communication mismatch");
        }

    }
}

*/