/***************************************************************************
 * Copyright (c) 2009 Digi International Inc., All Rights Reserved
 * 
 * This software contains proprietary and confidential information of Digi
 * International Inc.  By accepting transfer of this copy, Recipient agrees
 * to retain this software in confidence, to prevent disclosure to others,
 * and to make no use of this software other than that for which it was
 * delivered.  This is an unpublished copyrighted work of Digi International
 * Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 * prohibited.
 * 
 * Restricted Rights Legend
 *
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 * Technical Data and Computer Software clause at DFARS 252.227-7031 or
 * subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 * Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 ***************************************************************************
 *
 * @Descr: AuxMethods Class
 *
 * @History:
 *    10/01/09:   gsarabia      initial version.
 *
 ***************************************************************************/

#region Namespace Inclusions

using System;
using System.Text;

#endregion

namespace Digi.ZigBee
{
    /*! 
     * \class AuxMethods.
     */

    /// <summary>
    /// Class AuxMethods
    /// </summary>
    public class AuxMethods
    {
        #region Enumerations

        /*! 
         * \enum ByteOrder.
         */

        /// <summary>Byte ordering used to represent some kind of data.</summary>
        public enum ByteOrder
        {
            /*! 
             * \var Use big-endian byte order.
             */

            /// <summary>Use big-endian byte order.</summary>
            Big_Endian,

            /*! 
             * \var Use little-endian byte order.
             */

            /// <summary>Use little-endian byte order.</summary>
            Little_Endian
        }

        #endregion

        #region Variables

        private static ByteOrder InternalByteOrder = ByteOrder.Big_Endian;

        #endregion

        #region Properties

            #region Byte Order Mode

            /*! 
             * \property public ByteOrder ByteOrderMode
             */

            /// <summary>Gets or sets byte order. Default big-endian.</summary>
            public ByteOrder ByteOrderMode
            {
                get
                {
                    return InternalByteOrder;
                }
                set
                {
                    if (Enum.IsDefined(typeof(ByteOrder), value))
                        InternalByteOrder = value;
                    else
                        throw new ArgumentOutOfRangeException("ByteOrderMode", "ByteOrderMode value was out of legal range.");
                }
            }

            #endregion

        #endregion

        #region Methods

            #region ulong To byte[]

            /*! 
             * \fn public byte[] UlongToByte(ulong UlongData)
             */

            /// <summary>Converts the 8-byte unsigned integer to byte array.</summary>
            /// <param name="UlongData">The 8-byte unsigned integer.<param>
            /// <returns>Byte array.</returns>
            public byte[] UlongToByte(ulong UlongData)
            {
                int i;
                byte[] ByteArray = new byte[8];
                if (InternalByteOrder == ByteOrder.Big_Endian)
                {
                    for (i = 0; i < 8; i++)
                    {
                        ByteArray[i] = (byte)(UlongData >> (56 - i * 8));
                    }
                }
                else
                {
                    for (i = 0; i < 8; i++)
                    {
                        ByteArray[i] = (byte)(UlongData >> (i * 8));
                    }
                }
                return ByteArray;
            }

            #endregion

            #region ulong To byte string

            /*! 
             * \fn public string UlongToByteString(ulong UlongData)
             */

            /// <summary>Converts the 8-byte unsigned integer to byte string.</summary>
            /// <param name="UlongData">The 8-byte unsigned integer.<param>
            /// <returns>Byte string.</returns>
            public string UlongToByteString(ulong UlongData)
            {
                StringBuilder InternalStringBuilder = new StringBuilder(16);
                for (int i = 0; i < 8; i++)
                {
                    InternalStringBuilder.Append(Convert.ToString((byte)(UlongData >> (56 - i * 8)), 16).PadLeft(2, '0'));
                }
                return InternalStringBuilder.ToString().ToUpper();
            }

            #endregion

            #region byte[] To ulong

            /*! 
             * \fn public ulong ByteToUlong(byte[] ByteArray)
             */

            /// <summary>Converts byte array to the 8-byte unsigned integer.</summary>
            /// <param name="ByteArray">Byte array.<param>
            /// <returns>The 8-byte unsigned integer.</returns>
            public ulong ByteToUlong(byte[] ByteArray)
            {
                if (ByteArray.Length > 8)
                    throw new ArgumentOutOfRangeException("ByteArray", "ByteArray exceeds 8 bytes.");
                if (ByteArray.Length < 8)
                {
                    byte[] AuxByteArray = new byte[8];
                    Array.Copy(ByteArray, 0, AuxByteArray, (8 - ByteArray.Length), ByteArray.Length);
                    ByteArray = AuxByteArray;
                }
                if (InternalByteOrder == ByteOrder.Big_Endian)
                    return (ulong)(((ulong)(ByteArray[3] | ByteArray[2] << 8 | ByteArray[1] << 16 | ByteArray[0] << 24)) << 32 | (uint)(ByteArray[7] | ByteArray[6] << 8 | ByteArray[5] << 16 | ByteArray[4] << 24));
                else
                    return (ulong)(((ulong)(ByteArray[4] | ByteArray[5] << 8 | ByteArray[6] << 16 | ByteArray[7] << 24)) << 32 | (uint)(ByteArray[0] | ByteArray[1] << 8 | ByteArray[2] << 16 | ByteArray[3] << 24));
            }

            #endregion

            #region uint To byte[]

            /*! 
             * \fn public byte[] UintToByte(uint UintData)
             */

            /// <summary>Converts the 4-byte unsigned integer to byte array.</summary>
            /// <param name="UintData">The 4-byte unsigned integer.<param>
            /// <returns>Byte array.</returns>
            public byte[] UintToByte(uint UintData)
            {
                int i;
                byte[] ByteArray = new byte[4];
                if (InternalByteOrder == ByteOrder.Big_Endian)
                {
                    for (i = 0; i < 4; i++)
                    {
                        ByteArray[i] = (byte)(UintData >> (24 - i * 8));
                    }
                }
                else
                {
                    for (i = 0; i < 4; i++)
                    {
                        ByteArray[i] = (byte)(UintData >> (i * 8));
                    }
                }
                return ByteArray;
            }

            #endregion

            #region uint To byte string

            /*! 
             * \fn public string UintToByteString(uint UintData)
             */

            /// <summary>Converts the 4-byte unsigned integer to byte string.</summary>
            /// <param name="UintData">The 4-byte unsigned integer.<param>
            /// <returns>Byte string.</returns>
            public string UintToByteString(uint UintData)
            {
                StringBuilder InternalStringBuilder = new StringBuilder(8);
                for (int i = 0; i < 4; i++)
                {
                    InternalStringBuilder.Append(Convert.ToString((byte)(UintData >> (24 - i * 8)), 16).PadLeft(2, '0'));
                }
                return InternalStringBuilder.ToString().ToUpper();
            }

            #endregion

            #region byte[] To uint

            /*! 
             * \fn public uint ByteToUint(byte[] ByteArray)
             */

            /// <summary>Converts byte array to the 4-byte unsigned integer.</summary>
            /// <param name="ByteArray">Byte array.<param>
            /// <returns>The 4-byte unsigned integer.</returns>
            public uint ByteToUint(byte[] ByteArray)
            {
                if (ByteArray.Length > 4)
                    throw new ArgumentOutOfRangeException("ByteArray", "ByteArray exceeds 4 bytes.");
                if (ByteArray.Length < 4)
                {
                    byte[] AuxByteArray = new byte[4];
                    Array.Copy(ByteArray, 0, AuxByteArray, (4 - ByteArray.Length), ByteArray.Length);
                    ByteArray = AuxByteArray;
                }
                if (InternalByteOrder == ByteOrder.Big_Endian)
                    return (uint)(ByteArray[3] | ByteArray[2] << 8 | ByteArray[1] << 16 | ByteArray[0] << 24);
                else
                    return (uint)(ByteArray[0] | ByteArray[1] << 8 | ByteArray[2] << 16 | ByteArray[3] << 24);
            }

            #endregion

            #region ushort To byte[]

            /*! 
             * \fn public byte[] UshortToByte(ushort UshortData)
             */

            /// <summary>Converts the 2-byte unsigned integer to byte array.</summary>
            /// <param name="UshortData">The 2-byte unsigned integer.<param>
            /// <returns>Byte array.</returns>
            public byte[] UshortToByte(ushort UshortData)
            {
                int i;
                byte[] ByteArray = new byte[2];
                if (InternalByteOrder == ByteOrder.Big_Endian)
                {
                    for (i = 0; i < 2; i++)
                    {
                        ByteArray[i] = (byte)(UshortData >> (8 - i * 8));
                    }
                }
                else
                {
                    for (i = 0; i < 2; i++)
                    {
                        ByteArray[i] = (byte)(UshortData >> (i * 8));
                    }
                }
                return ByteArray;
            }

            #endregion

            #region ushort To byte string

            /*! 
             * \fn public string UshortToByteString(ushort UshortData)
             */

            /// <summary>Converts the 2-byte unsigned integer to byte string.</summary>
            /// <param name="UshortData">The 2-byte unsigned integer.<param>
            /// <returns>Byte string.</returns>
            public string UshortToByteString(ushort UshortData)
            {
                StringBuilder InternalStringBuilder = new StringBuilder(4);
                for (int i = 0; i < 2; i++)
                {
                    InternalStringBuilder.Append(Convert.ToString((byte)(UshortData >> (8 - i * 8)), 16).PadLeft(2, '0'));
                }
                return InternalStringBuilder.ToString().ToUpper();
            }

            #endregion

            #region byte[] To ushort

            /*! 
             * \fn public ushort ByteToUshort(byte[] ByteArray)
             */

            /// <summary>Converts byte array to the 2-byte unsigned integer.</summary>
            /// <param name="ByteArray">Byte array.<param>
            /// <returns>The 2-byte unsigned integer.</returns>
            public ushort ByteToUshort(byte[] ByteArray)
            {
                if (ByteArray.Length > 2)
                    throw new ArgumentOutOfRangeException("ByteArray", "ByteArray exceeds 2 bytes.");
                if (ByteArray.Length < 2)
                {
                    byte[] AuxByteArray = new byte[2];
                    Array.Copy(ByteArray, 0, AuxByteArray, (2 - ByteArray.Length), ByteArray.Length);
                    ByteArray = AuxByteArray;
                }
                if (InternalByteOrder == ByteOrder.Big_Endian)
                    return (ushort)(ByteArray[1] | ByteArray[0] << 8);
                else
                    return (ushort)(ByteArray[0] | ByteArray[1] << 8);
            }

            #endregion

        #endregion
    }
}
