/*******************************************************************************
* 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.Windows.Forms;

//------------------------------------------------------------------------------------------
// OS24EVK-59 split into HeartRateApp EXE and MAX30101 DLL.
// Moved all MAX30101 DLL classes into namespace Maxim.MAX30101GUI
// Moved all HeartRateApp GUI classes into namespace Maxim.MAX30101
// OS24EVK-59 Create separate project that builds Maxim.MAX30101GUI DLL library

// OS24EVK-59 moved class support into namespace Maxim.MAX30101 instead of namespace HeartRateApp
namespace RPCSupport
{
    internal static class support
    {
        public const int DEFAULT_VENDOR_ID = 0x0B6A; // update USB VID PID from default Vid_16C0&Pid_0830
        public const int DEFAULT_PRODUCT_ID = 0x1366; // MAX30100EVKit USB Vid_0B6A&Pid_1364; MAX30101EVKit USB Vid_0B6A&Pid_1365
        public const byte DEFAULT_I2C_ADDRESS = 0xAE;   // 8-bit address (write address)

        public static Control getControlFromName(Control Page, string controlName)
        {
            // getControlFromName was split into two functions: 1) this function called by other subs so that "found" does not need to be declared and passed
            // and 2) getControlFromNameRecurse which uses the "found" parameter 
            Boolean found = false;

            try
            {
                return getControlFromNameRecurse(Page, controlName, ref found);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name);
            }
        }

        private static Control getControlFromNameRecurse(Control Page, string controlName, ref Boolean found)
        {
            Control returnVal = null;

            try
            {
                foreach (Control ctrl in Page.Controls)
                {
                    if (!found)
                    {// found is passed by reference; hence when a recursive call finds the control, found will always be True for all calls under the initial call
                        if (String.Compare(ctrl.Name, controlName, true) == 0)
                        {
                            found = true;
                            returnVal = ctrl;
                        }
                        else if (ctrl.Controls.Count > 0)
                        {
                            returnVal = getControlFromNameRecurse(ctrl, controlName, ref found);
                        }
                    }
                }
                return returnVal;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name);
            }
        }

        public static byte getControlIndex(Control sender)
        {
            //This function finds the 'index' of a control 'array'. Since there are no control arrays in .Net,
            //we name all the controls consistently and suffix them with an integer. This integer is the 'index' and is returned by this function.
            int iterator;
            int i = 0;
            String name = sender.Name;

            try
            {
                iterator = name.Length;
                while (char.IsNumber(name, iterator - 1))
                {
                    i+=1;
                    iterator-=1;
                    if (iterator == 0)
                        break;
                }
                if (i == 0)
                    throw new Exception("Not a control array");
                return Convert.ToByte(name.Substring(name.Length - i, i));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name);
            }
        }

        //http://www.vbforums.com/showthread.php?t=546633
        //use this to make a delay
        public static void Pause(int msDelay)
        {
            DateTime Timeout;
            DateTime PrevTimer;

            try
            {
                PrevTimer = System.DateTime.Now;
                Timeout = PrevTimer.AddMilliseconds(msDelay);
                while (PrevTimer < Timeout)
                {
                    FileIO.Sleep(4); //-- Timer is only updated every 1/64 sec = 15.625 millisecs.
                    Application.DoEvents(); //DoEvents seems to be not recommended; is there a better way to do this?
                    //DoEvents really does cause trouble. Example: pause on device change causes closeHandles and openHandles NOT to run in order!
                    if (System.DateTime.Now < PrevTimer)
                        Timeout = Timeout.AddHours(-24); //-- pass midnight
                    PrevTimer = System.DateTime.Now;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name);
            }
        }

        public const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
        /// <summary>
        /// Get text that describes the result of an API call.
        /// </summary>
        /// 
        /// <param name="functionName"> the name of the API function. </param>
        /// 
        /// <returns>
        /// The text.
        /// </returns>
        /// 
        public static string ResultOfAPICall(string functionName) 
        {
            int bytes;
            int resultCode;
            string resultString = "";
            int length = 1000;

            try
            {
                resultString = new String((char)0, length); // create space for string with all elements set to NULL

                // Returns the result code for the last API call.

                resultCode = System.Runtime.InteropServices.Marshal.GetLastWin32Error();

                // Get the result message that corresponds to the code.

                bytes = FileIO.FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, resultCode, 0, resultString, length - 1, 0);

                // Subtract all characters from the message from the CR LF and NULLs to the end
                // Important to remove all NULLs since VB doesn't use NULL to demark end of string, and thus when concatenating strings, the NULLs are troublesome

                if (bytes > 2)
                    resultString = resultString.Remove(bytes - 2, length - bytes + 2);
                
                // Create the string to return.

                resultString = functionName + Environment.NewLine + "Result = " + resultString;

                return resultString;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message + Environment.NewLine + new System.Diagnostics.StackFrame().GetMethod().Name);
            }
        }
    }
}
