/*******************************************************************************
* 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 RPCSupport.Pipelines;
using RPCSupport.Devices;
using RPCSupport.Dialogs;

namespace RPCSupport
{
    public class RPCClient
    {
        public enum ePipeline
        {
            eHid,
            eSerial,
            eHttp,
            eSerialWrap
        }
        
        //SerialPipeline serialPipeline;
        const string SPINAME = "Spi";
        I2cDevice i2cDevice;
        SpiDevice spiDevice;
        bool rpcLogShown = false;
        public RPCSupport.Streaming.Streaming streaming;

        public Pipeline pipeline;

        public Pipeline Pipeline
        {
            get { return pipeline; }
        }

        LIS2HD lis2hd;
        public LIS2HD LIS2HD
        {
            get { return lis2hd; }
            set { lis2hd = value; }
        }

        public I2cDevice I2cDevice
        {
            get { return i2cDevice; }
            set { i2cDevice = value; }
        }
        public SpiDevice SpiDevice
        {
            get { return spiDevice; }
            set { spiDevice = value; }
        }

        MAX30101 max30101;
        public MAX30101 MAX30101
        {
            get { return max30101; }
            set { max30101 = value; }
        }

        MAX30001 max30001;
        public MAX30001 MAX30001
        {
            get { return max30001; }
            set { max30001 = value; }
        }

        MAX30205 max30205;
        public MAX30205 MAX30205
        {
            get { return max30205; }
            set { max30205 = value; }
        }

        DataLogging.DataLogging dataLogging;
        public DataLogging.DataLogging DataLogging
        {
            get { return dataLogging; }
            set { dataLogging = value; }
        }

        Devices.Led led;
        public Devices.Led Led
        {
            get { return led; }
            set { led = value; }
        }

        Devices.Testing testing;
        public Devices.Testing Testing
        {
            get { return testing; }
            set { testing = value; }
        }

        Devices.S25FS512 s25FS512;
        public Devices.S25FS512 S25FS512
        {
            get { return s25FS512; }
            set { s25FS512 = value; }
        }

        public RPCClient(ePipeline pipelineType)
        {
            switch (pipelineType)
            {
                case ePipeline.eHid:
                    pipeline = new HidPipeline();
                    break;
                case ePipeline.eSerial:
                    pipeline = new SerialPipeline();
                    break;
                case ePipeline.eHttp:
                    break;
                case ePipeline.eSerialWrap:
                    pipeline = new SerialWrapPipeline();
                    break;
            }
            ShowRpcLog(false);
            LogCallback(new RPCSupport.Pipelines.Pipeline.RawRpcRequest(LogRpcRequest), new RPCSupport.Pipelines.Pipeline.RawRpcReply(LogRpcReply), new RPCSupport.Pipelines.Pipeline.RawRpcStream(LogRpcStream));
            streaming = new Streaming.Streaming();
        }

        void LogRpcRequest(string request)
        {
            rpcLog.LogRpcRequest(request);
        }

        void LogRpcReply(string reply)
        {
            rpcLog.LogRpcReply(reply);
        }

        void LogRpcStream(string stream)
        {
            rpcLog.LogRpcStream(stream);
        }

        public void LogCallback(RPCSupport.Pipelines.Pipeline.RawRpcRequest request, RPCSupport.Pipelines.Pipeline.RawRpcReply reply, RPCSupport.Pipelines.Pipeline.RawRpcStream stream)
        {
            pipeline.LogCallback(request, reply, stream);
        }

        public void Connect(string param) {
            pipeline.Connect(param);
        }

        public void Disconnect()
        {
            pipeline.Disconnect();
        }

        public string[] ScanAvailablePortNames() {
            return pipeline.ScanAvailablePortNames();
        }

        public bool InitPipeline()
        {
            bool ret = pipeline.Init();
            return ret;
        }

        public bool IsConnected()
        {
            return pipeline.IsConnected();
        }

        public String RawRpcCall(String request, bool reply)
        {
            return pipeline.RawRpcCall(request, reply);
        }

        public Devices.MAX30101 Init_MAX30101(int slaveAddress)
        {
            MAX30101 = new RPCSupport.Devices.MAX30101(this, slaveAddress);
            return MAX30101;
        }

        public Devices.MAX30001 Init_MAX30001()
        {
            MAX30001 = new RPCSupport.Devices.MAX30001(this);
            return MAX30001;
        }

        public Devices.MAX30205 Init_MAX30205(int slaveAddress)
        {
            MAX30205 = new RPCSupport.Devices.MAX30205(this, slaveAddress);
            return MAX30205;
        }

        public Devices.LIS2HD Init_LIS2HD(int slaveAddress)
        {
            LIS2HD = new RPCSupport.Devices.LIS2HD(this, slaveAddress);
            return LIS2HD;
        }

        public Devices.I2cDevice Init_I2cDevice()
        {
            I2cDevice = new RPCSupport.Devices.I2cDevice(this);
            return I2cDevice;
        }

        public Devices.SpiDevice Init_SpiDevice()
        {
            SpiDevice = new RPCSupport.Devices.SpiDevice(this);
            return SpiDevice;
        }

        public DataLogging.DataLogging Init_Logging()
        {
            dataLogging = new RPCSupport.DataLogging.DataLogging(this);
            return dataLogging;
        }

        public RPCSupport.Devices.Led Init_Led()
        {
            led = new RPCSupport.Devices.Led(this);
            return led;
        }

        public RPCSupport.Devices.Testing Init_Testing()
        {
            testing = new RPCSupport.Devices.Testing(this);
            return testing;
        }

        public RPCSupport.Devices.S25FS512 Init_S25FS512()
        {
            s25FS512 = new RPCSupport.Devices.S25FS512(this);
            return s25FS512;
        }
        

        public void ReadRegister(DeviceSupport.DeviceDetails deviceDetails, DeviceSupport.RegisterInfo reg)
        {
            int hex;

            switch (deviceDetails.type)
            {
                case DeviceSupport.DeviceDetails.eType.eI2c:
                    i2cDevice.ReadReg(deviceDetails, reg);
                    break;
                case DeviceSupport.DeviceDetails.eType.eSpi:
                    spiDevice.ReadReg(deviceDetails, reg);
                    break;
                case DeviceSupport.DeviceDetails.eType.eMAX30001:
                    //reg.data[0] = max30001.ReadReg((byte)reg.address);
                    hex = max30001.ReadReg((byte)reg.address);
                    reg.data[0] = (hex >> 16) & 0xFF;
                    reg.data[1] = (hex >> 8) & 0xFF;
                    reg.data[2] = hex & 0xFF;
                    break;
                case DeviceSupport.DeviceDetails.eType.eMAX30205:
                    //reg.data[0] = max30001.ReadReg((byte)reg.address);
                    hex = max30205.ReadReg((byte)reg.address);
                    reg.data[0] = (hex >> 8) & 0xFF;
                    reg.data[1] = hex & 0xFF;
                    break;
            }
        }

        public void WriteRegister(DeviceSupport.DeviceDetails deviceDetails, DeviceSupport.RegisterInfo reg)
        {
            switch (deviceDetails.type)
            {
                case DeviceSupport.DeviceDetails.eType.eI2c:
                    i2cDevice.WriteReg(deviceDetails, reg);
                    break;
                case DeviceSupport.DeviceDetails.eType.eSpi:
                    spiDevice.WriteReg(deviceDetails, reg);
                    break;
                case DeviceSupport.DeviceDetails.eType.eMAX30001:
                    //max30001.WriteReg((byte)reg.address, reg.data[0]);
                    max30001.WriteReg((byte)reg.address, reg.data[2] | reg.data[1] << 8 | reg.data[0] << 16);
                    break;
                case DeviceSupport.DeviceDetails.eType.eMAX30205:
                    max30001.WriteReg((byte)reg.address, reg.data[1] | reg.data[0] << 8);
                    break;
            }
        }

        RpcLog rpcLog;
        public void ShowRpcLog(bool state)
        {
            if (rpcLog == null)
            {
                rpcLog = new RpcLog();
            }
            rpcLogShown = state;
            if (state == true)
                rpcLog.Show();
            else
                rpcLog.Hide();
        }

        public bool IsRpcLogShown()
        {
            return rpcLogShown;
        }

        public string Version()
        {
            return RawRpcCall("/System/ReadVer\r\n", true);
        }
    }
}
