/*******************************************************************************
* 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.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using NUnit.Framework;
using Moq;

using RPCSupport;
using RPCSupport.Devices;

namespace RPCSupportTest
{
    //[TestFixture, RequiresThread]
    [TestFixture]
    [Property("Class", "MAX30101")]
    class MAX30101Test
    {
        RPCClient rpcClient;
        MAX30101 max30101;

        int[] avg = new int[] { 1, 2, 4, 8, 16, 32 };
        int[] sr = new int[] { 50, 100, 200, 400 };

        double minFactor = 0.75;
        double maxFactor = 1;
        int timeSleep = 10000;

        [TestFixtureSetUp]
        public void Init()
        {
            rpcClient = new RPCClient(RPCClient.ePipeline.eSerialWrap);
            rpcClient.InitPipeline();
            rpcClient.Connect(ComPort.Port);
            //rpcClient.Pipeline.Discard();
            max30101 = rpcClient.Init_MAX30101(0xAE);
            //rpcClient.streaming.Init(rpcClient.Pipeline);

            //rpcClient.Version();
        }

        [TestFixtureTearDown]
        public void Dispose()
        {
            rpcClient.Disconnect();
            rpcClient.streaming.Stop();
            Thread.Sleep(100);
        }

        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        //[TestCase(3, 0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        //[TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        //[TestCase(5, 2)]
        [TestCase(5, 3)]
        public void HRModeTest(byte sampleAverage, byte sampleRate)
        {
            HRModeTest(sampleAverage, sampleRate, 3000);
        }

        [TestCase(3, 0, 4000)]
        [TestCase(4, 0, 8000)]
        [TestCase(4, 1, 4000)]
        [TestCase(5, 0, 12000)]
        [TestCase(5, 1, 8000)]
        [TestCase(5, 2, 4000)]
        public void HRModeTest(byte sampleAverage, byte sampleRate, int sleepMilliSecond)
        {
            Mock<IPlotView> plotView;
            plotView = new Mock<IPlotView>();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView.Object);

            rpcClient.MAX30101.HRmode_init(0x0f, sampleAverage, sampleRate, 3, 0x33, (byte)(0 + 4));
            Thread.Sleep(sleepMilliSecond);
            rpcClient.MAX30101.HRmode_stop();

            Application.DoEvents();

            plotView.Verify(p => p.Display(It.IsAny<int[]>()), Times.AtLeast(1));
        }

        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        //[TestCase(3, 0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        //[TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        //[TestCase(5, 2)]
        [TestCase(5, 3)]
        public void SpO2ModeTest(byte sampleAverage, byte sampleRate)
        {
            SpO2ModeTest(sampleAverage, sampleRate, 3000);
        }

        [TestCase(3, 0, 4000)]
        [TestCase(4, 0, 8000)]
        [TestCase(4, 1, 4000)]
        [TestCase(5, 0, 12000)]
        [TestCase(5, 1, 8000)]
        [TestCase(5, 2, 4000)]
        public void SpO2ModeTest(byte sampleAverage, byte sampleRate, int sleepMillisecond)
        {
            Mock<IPlotView> plotView = new Mock<IPlotView>();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView.Object);

            rpcClient.MAX30101.SpO2mode_init(0x0f, sampleAverage, sampleRate, 3, 0x33, 0x33, (byte)(sampleRate + 4));
            Thread.Sleep(sleepMillisecond);
            rpcClient.MAX30101.SpO2mode_stop();

            Application.DoEvents();

            plotView.Verify(p => p.Display(It.IsAny<int[]>()), Times.AtLeast(1));
        }


        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        //[TestCase(3,0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        //[TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        //[TestCase(5, 2)]
        [TestCase(5, 3)]
        public void MultiModeTest(byte sampleAverage, byte sampleRate)
        {
            MultiModeTest(sampleAverage, sampleRate, 3000);
        }

        [TestCase(3, 0, 4000)]
        [TestCase(4, 0, 8000)]
        [TestCase(4, 1, 4000)]
        [TestCase(5, 0, 12000)]
        [TestCase(5, 1, 8000)]
        [TestCase(5, 2, 4000)]
        public void MultiModeTest(byte sampleAverage, byte sampleRate, int sleepMilliSecond)
        {
                        Mock<IPlotView> plotView = new Mock<IPlotView>();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView.Object);

            rpcClient.MAX30101.Multimode_init(0x0f, sampleAverage, sampleRate, 0, 0x33, 0x33, 0x33, 1, 2, 3, 0, (byte)(sampleRate + 4));
            Thread.Sleep(sleepMilliSecond);
            rpcClient.MAX30101.Multimode_stop();

            Application.DoEvents();

            plotView.Verify(p => p.Display(It.IsAny<int[]>()), Times.AtLeast(1));
        }

        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        [TestCase(3, 0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        [TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        [TestCase(5, 2)]
        [TestCase(5, 3)]
        public void HRModePointsTest(byte sampleAverage, byte sampleRate)
        {
            Stopwatch sw = new Stopwatch();
            PlotView plotView = new PlotView();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView);

            rpcClient.MAX30101.HRmode_init(0x0f, sampleAverage, sampleRate, 3, 0x33, (byte)(0 + 4));
            sw.Start();
            Thread.Sleep(timeSleep);
            rpcClient.MAX30101.HRmode_stop();
            sw.Stop();

            Application.DoEvents();

            Console.WriteLine("Points: " + plotView.Points + "Time: " + sw.ElapsedMilliseconds / 1000.0);
            Assert.That(plotView.Points, Is.GreaterThan(minFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
            Assert.That(plotView.Points, Is.LessThan(maxFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
        }

        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        [TestCase(3, 0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        [TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        [TestCase(5, 2)]
        [TestCase(5, 3)]
        public void SpO2ModePointsTest(byte sampleAverage, byte sampleRate)
        {
            //ManualResetEvent eventRasied = new ManualResetEvent(false);
            Stopwatch sw = new Stopwatch();
            PlotView plotView = new PlotView();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView);

            //rpcClient.streaming.PartialArrayIntAvailable += (sender, e) => { eventRasied.Set(); };

            rpcClient.MAX30101.SpO2mode_init(0x0f, sampleAverage, sampleRate, 3, 0x33, 0x33, (byte)(sampleRate + 4));
            sw.Start();
            Thread.Sleep(timeSleep);
            rpcClient.MAX30101.SpO2mode_stop();
            sw.Stop();

            Application.DoEvents();

            Console.WriteLine("Points: " + plotView.Points + "Time: " + sw.ElapsedMilliseconds / 1000.0);
            Assert.That(plotView.Points, Is.GreaterThan(minFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
            Assert.That(plotView.Points, Is.LessThan(maxFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
            //Assert.IsTrue(eventRasied.WaitOne(10000));
        }

        [TestCase(0, 0)]
        [TestCase(0, 1)]
        [TestCase(0, 2)]
        [TestCase(0, 3)]
        [TestCase(1, 0)]
        [TestCase(1, 1)]
        [TestCase(1, 2)]
        [TestCase(1, 3)]
        [TestCase(2, 0)]
        [TestCase(2, 1)]
        [TestCase(2, 2)]
        [TestCase(2, 3)]
        [TestCase(3, 0)]
        [TestCase(3, 1)]
        [TestCase(3, 2)]
        [TestCase(3, 3)]
        //[TestCase(4, 0)]
        [TestCase(4, 1)]
        [TestCase(4, 2)]
        [TestCase(4, 3)]
        //[TestCase(5, 0)]
        //[TestCase(5, 1)]
        [TestCase(5, 2)]
        [TestCase(5, 3)]
        public void MultiModePointsTest(byte sampleAverage, byte sampleRate)
        {
            Stopwatch sw = new Stopwatch();
            PlotView plotView = new PlotView();
            StreamHelper streamHelper = new StreamHelper(rpcClient, plotView);

            rpcClient.MAX30101.Multimode_init(0x0f, sampleAverage, sampleRate, 0, 0x33, 0x33, 0x33, 1, 2, 3, 0, (byte)(sampleRate + 4));
            sw.Start();
            Thread.Sleep(timeSleep);
            rpcClient.MAX30101.Multimode_stop();
            sw.Stop();

            Application.DoEvents();

            Console.WriteLine("Points: " + plotView.Points + "Time: " + sw.ElapsedMilliseconds / 1000.0);
            Assert.That(plotView.Points, Is.GreaterThan(minFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
            Assert.That(plotView.Points, Is.LessThan(maxFactor * sw.ElapsedMilliseconds / 1000 * sr[sampleRate] / avg[sampleAverage]));
        }
    }
}
