//-----------------------------------------------------------------------
// 
//     Copyright (c) Microsoft Corporation.
// 
//-----------------------------------------------------------------------
namespace Microsoft.Isam.Esent.Interop
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.InteropServices;
    using Microsoft.Isam.Esent.Interop.Vista;
    /// 
    /// The native version of the JET_INDEXCREATE3 structure.
    /// 
    [StructLayout(LayoutKind.Sequential)]
    [SuppressMessage("Microsoft.StyleCop.CSharp.NamingRules",
        "SA1305:FieldNamesMustNotUseHungarianNotation",
        Justification = "This should match the unmanaged API, which isn't capitalized.")]
    [SuppressMessage(
        "Microsoft.StyleCop.CSharp.NamingRules",
        "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter",
        Justification = "This should match the unmanaged API, which isn't capitalized.")]
    internal unsafe struct NATIVE_INDEXCREATE3
    {
        /// 
        /// Size of the structure.
        /// 
        public uint cbStruct;
        /// 
        /// Name of the index.
        /// 
        public IntPtr szIndexName;
        /// 
        /// Index key description.
        /// 
        public IntPtr szKey;
        /// 
        /// Size of index key description.
        /// 
        public uint cbKey;
        /// 
        /// Index options.
        /// 
        public uint grbit;
        /// 
        /// Index density.
        /// 
        public uint ulDensity;
        /// 
        /// Pointer to unicode sort options.
        /// 
        public NATIVE_UNICODEINDEX2* pidxUnicode;
        /// 
        /// Maximum size of column data to index. This can also be
        /// a pointer to a JET_TUPLELIMITS structure.
        /// 
        public IntPtr cbVarSegMac;
        /// 
        /// Pointer to array of conditional columns.
        /// 
        public IntPtr rgconditionalcolumn;
        /// 
        /// Count of conditional columns.
        /// 
        public uint cConditionalColumn;
        /// 
        /// Returned error from index creation.
        /// 
        public int err;
        /// 
        /// Maximum size of the key.
        /// 
        public uint cbKeyMost;
        /// 
        /// A  pointer.
        /// 
        public IntPtr pSpaceHints;
    }
    /// 
    /// Contains the information needed to create an index over data in an ESE database.
    /// 
    public sealed partial class JET_INDEXCREATE : IContentEquatable, IDeepCloneable
    {
        /// 
        /// Gets the native (interop) version of this object, except for
        ///  and .
        /// 
        /// The cbKey holds the length of the key in bytes, and does not need to be adjusted.
        /// The native (interop) version of this object.
        internal NATIVE_INDEXCREATE3 GetNativeIndexcreate3()
        {
            this.CheckMembersAreValid();
            var native = new NATIVE_INDEXCREATE3();
            native.cbStruct = checked((uint)Marshal.SizeOf(typeof(NATIVE_INDEXCREATE3)));
            // szIndexName and szKey are converted at pinvoke time.
            //
            // native.szIndexName = this.szIndexName;
            // native.szKey = this.szKey;
            native.cbKey = checked((uint)this.cbKey * sizeof(char));
            native.grbit = unchecked((uint)this.grbit);
            native.ulDensity = checked((uint)this.ulDensity);
            native.cbVarSegMac = new IntPtr(this.cbVarSegMac);
            native.cConditionalColumn = checked((uint)this.cConditionalColumn);
            if (0 != this.cbKeyMost)
            {
                native.cbKeyMost = checked((uint)this.cbKeyMost);
                native.grbit |= unchecked((uint)VistaGrbits.IndexKeyMost);
            }
            return native;
        }
        /// 
        /// Sets only the output fields of the object from a  struct,
        /// specifically .
        /// 
        /// 
        /// The native indexcreate to set the values from.
        /// 
        internal void SetFromNativeIndexCreate(ref NATIVE_INDEXCREATE3 value)
        {
            this.err = (JET_err)value.err;
        }
        /// 
        /// Sets all of the fields (not just output fields) of the object from a  struct,
        /// specifically .
        /// 
        /// 
        /// The native indexcreate to set the values from.
        /// 
        internal void SetAllFromNativeIndexCreate(ref NATIVE_INDEXCREATE3 value)
        {
            this.szIndexName = Marshal.PtrToStringUni(value.szIndexName);
            this.cbKey = unchecked((int)value.cbKey / sizeof(char));
            this.szKey = Marshal.PtrToStringUni(value.szKey, this.cbKey);
            if (this.cbKey != this.szKey.Length)
            {
                throw new ArgumentException(string.Format("cbKey {0} != szKey.Length {1}", this.cbKey, this.szKey.Length));
            }
            this.grbit = unchecked((CreateIndexGrbit)value.grbit);
            this.ulDensity = unchecked((int)value.ulDensity);
            unsafe
            {
                this.pidxUnicode = new JET_UNICODEINDEX(ref *value.pidxUnicode);
            }
            this.cbVarSegMac = (int)value.cbVarSegMac;
            this.cConditionalColumn = unchecked((int)value.cConditionalColumn);
            this.rgconditionalcolumn = new JET_CONDITIONALCOLUMN[this.cConditionalColumn];
            int sizeofConditionalColumn = Marshal.SizeOf(typeof(NATIVE_CONDITIONALCOLUMN));
            for (int i = 0; i < this.cConditionalColumn; ++i)
            {
                IntPtr addressOfElement = value.rgconditionalcolumn + i * sizeofConditionalColumn;
                NATIVE_CONDITIONALCOLUMN nativeConditionalColumn =
                    (NATIVE_CONDITIONALCOLUMN)Marshal.PtrToStructure(addressOfElement, typeof(NATIVE_CONDITIONALCOLUMN));
                this.rgconditionalcolumn[i] = new JET_CONDITIONALCOLUMN(ref nativeConditionalColumn);
            }
            this.err = (JET_err)value.err;
            this.cbKeyMost = unchecked((int)value.cbKeyMost);
            var nativeSpaceHints = (NATIVE_SPACEHINTS)Marshal.PtrToStructure(value.pSpaceHints, typeof(NATIVE_SPACEHINTS));
            this.pSpaceHints = new JET_SPACEHINTS();
            this.pSpaceHints.SetFromNativeSpaceHints(nativeSpaceHints);
        }
    }
}