using System;
using SDA.DataProvider;

namespace Kreta.Framework.Entities
{
    /// <summary>
    /// A generált DataAccessor-ok által használt statikus segédosztály, 
    /// a generált kód mennyiségének csökkentésére. Az osztály kézzel írt kód számára tabu.
    /// </summary>
    /// <remarks>
    /// Az osztály metódusai teljesítménykritikusak, ezért paraméterellenőrzés nem történik bennük, 
    /// megbízunk a hívóban.
    /// </remarks>
    public sealed class DAUtil
    {
        // <<Facade>>

        /// <summary>
        /// Az osztály alapértelmezett konstruktora.
        /// </summary>
        /// <remarks>Az osztály statikus, példányosítását nem szándékozzuk.</remarks>
        private DAUtil()
        {
        }

        /// <summary>
        /// Létrehoz egy új SDA.DataProvider.SDACommand parancsobjektumot,
        /// és inicializálja a Commandtext, Connection, Transaction tulajdonságait.
        /// </summary>
        /// <param name="commandText">A parancsobjektum sql szövege</param>
        /// <returns>A létrehozott <see cref="SDA.DataProvider.SDACommand"/> parancsobjektum</returns>
        public static SDACommand CreateCommand(string commandText)
        {
            SDACommand result = new SDACommand
            {
                CommandText = commandText,
                Connection = UserContext.Instance.SDAConnection,
                Transaction = UserContext.Instance.SDATransaction
            };
            return result;

        }

        /// <summary>
        /// Az entitás felvétele után utólag lekérdezi az entitás ID-ját.
        /// </summary>
        /// <returns></returns>
        public static int? GetEntityID(SDAConnection connection, SDATransaction transaction)
        {
            using (SDACommand command = new SDACommand())
            {
                command.Connection = connection;
                command.Transaction = transaction;
                command.CommandText = "SELECT @@IDENTITY as ID";

                var id = command.ExecuteScalar();

                return id != DBNull.Value ? Convert.ToInt32(id) : (int?)null;
            }
        }

        #region BindParameter

        /// <summary>
        /// Hozzáad a parancsobjektumhoz egy új paramétert.
        /// </summary>
        /// <param name="command">A tulajdonos <see cref="SDA.DataProvider.SDACommand"/> objektum</param>
        /// <param name="parameterName">A paraméter neve</param>
        /// <param name="type">A paraméter típusa</param>
        /// <param name="length">A paraméter hossza</param>
        /// <param name="value">A paraméter értéke</param>
        /// <param name="isNull">A paraméter null-e vagy sem</param>
        public static void BindParameter(SDA.DataProvider.SDACommand command, string parameterName, SDA.DataProvider.SDADBType type, int length, object value, bool isNull)
        {
            if (isNull || value == null)
            {
                command.Parameters.Add(parameterName, type, length).Value = DBNull.Value;
            }
            else
            {
                command.Parameters.Add(parameterName, type, length).Value = value;
            }
        }

        /// <summary>
        /// Hozzáad a parancsobjektumhoz egy új paramétert.
        /// </summary>
        /// <param name="command">A tulajdonos <see cref="SDA.DataProvider.SDACommand"/> objektum</param>
        /// <param name="parameterName">A paraméter neve</param>
        /// <param name="type">A paraméter típusa</param>
        /// <param name="value">A paraméter értéke</param>
        /// <param name="isNull">A paraméter null-e vagy sem</param>
        public static void BindParameter(SDA.DataProvider.SDACommand command, string parameterName, SDA.DataProvider.SDADBType type, object value, bool isNull)
        {
            if (isNull || value == null)
            {
                command.Parameters.Add(parameterName, type).Value = DBNull.Value;
            }
            else
            {
                command.Parameters.Add(parameterName, type).Value = value;
            }
        }

        /// <summary>
        /// Hozzáad a parancsobjektumhoz egy új paramétert.
        /// </summary>
        /// <param name="command">A tulajdonos <see cref="SDA.DataProvider.SDACommand"/> objektum</param>
        /// <param name="parameterName">A paraméter neve</param>
        /// <param name="value">A paraméter értéke</param>
        public static void BindIdParameter(SDA.DataProvider.SDACommand command, string parameterName, int value)
        {
            if (value == -1)
            {
                command.Parameters.Add(parameterName, SDA.DataProvider.SDADBType.Int).Value = DBNull.Value;
            }
            else
            {
                command.Parameters.Add(parameterName, SDA.DataProvider.SDADBType.Int).Value = value;
            }
        }

        #endregion

        #region ReadAttribute

        /// <summary>
        /// Bináris típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadBinaryAttribute(SDA.DataProvider.SDADataReader reader, int index, ref byte[] target, ref bool isNull, byte[] defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = (byte[])reader.GetValue(index);
            return true;
        }

        public static byte[] ReadBinaryAttribute(SDA.DataProvider.SDADataReader reader, int index, byte[] defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return (byte[])reader.GetValue(index);
        }

        public static byte[] ReadBinaryAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return (byte[])reader.GetValue(index);
        }

        /// <summary>
        /// Logikai típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadBooleanAttribute(SDA.DataProvider.SDADataReader reader, int index, ref bool target, ref bool isNull, bool defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            char tmp = reader.GetString(index)[0];
            target = (tmp == 'T' || tmp == 'I');
            return true;
        }

        public static bool ReadBooleanAttribute(SDA.DataProvider.SDADataReader reader, int index, bool defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            char tmp = reader.GetString(index)[0];
            return (tmp == 'T' || tmp == 'I');
        }

        public static bool? ReadBooleanAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            char tmp = reader.GetString(index)[0];
            return (tmp == 'T' || tmp == 'I');
        }

        /// <summary>
        /// Dátum típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadDateTimeAttribute(SDA.DataProvider.SDADataReader reader, int index, ref DateTime target, ref bool isNull, DateTime defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = reader.GetDateTime(index);
            return true;
        }

        public static DateTime ReadDateTimeAttribute(SDA.DataProvider.SDADataReader reader, int index, DateTime defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return reader.GetDateTime(index);
        }

        public static DateTime? ReadDateTimeAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return reader.GetDateTime(index);
        }

        /// <summary>
        /// Lebegőpontos típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadDoubleAttribute(SDA.DataProvider.SDADataReader reader, int index, ref double target, ref bool isNull, double defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = Convert.ToDouble(reader.GetValue(index));
            return true;
        }

        public static double ReadDoubleAttribute(SDA.DataProvider.SDADataReader reader, int index, double defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return Convert.ToDouble(reader.GetValue(index));
        }

        public static double? ReadDoubleAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return Convert.ToDouble(reader.GetValue(index));
        }

        /// <summary>
        /// ID típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="target">A cél</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadIDAttribute(SDA.DataProvider.SDADataReader reader, int index, ref int target, int defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                target = defaultValue;
                return false;
            }

            target = Convert.ToInt32(reader.GetValue(index));
            return true;
        }

        /// <summary>
        /// Egész típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadIntegerAttribute(SDA.DataProvider.SDADataReader reader, int index, ref int target, ref bool isNull, int defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = Convert.ToInt32(reader.GetValue(index));
            return true;
        }

        public static int ReadIntegerAttribute(SDA.DataProvider.SDADataReader reader, int index, int defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return Convert.ToInt32(reader.GetValue(index));
        }

        public static int? ReadIntegerAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return Convert.ToInt32(reader.GetValue(index));
        }

        /// <summary>
        /// Karakterlánc típusú attribútum értékét olvassa be.
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <param name="target">A cél</param>
        /// <param name="isNull">Null-t olvasott vagy nem null-t</param>
        /// <param name="defaultValue">Alapértelmezett érték null olvasása esetén</param>
        /// <returns>True, ha nem null lett olvasva; egyébként false</returns>
        public static bool ReadStringAttribute(SDA.DataProvider.SDADataReader reader, int index, ref string target, ref bool isNull, string defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = reader.GetString(index);
            return true;
        }

        public static string ReadStringAttribute(SDA.DataProvider.SDADataReader reader, int index, string defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return reader.GetString(index);
        }

        public static string ReadStringAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return reader.GetString(index);
        }

        public static bool ReadGuidAttribute(SDA.DataProvider.SDADataReader reader, int index, ref Guid target, ref bool isNull, Guid defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                isNull = true;
                target = defaultValue;
                return false;
            }

            isNull = false;
            target = Guid.Parse(reader.GetString(index));
            return true;
        }

        public static Guid ReadGuidAttribute(SDA.DataProvider.SDADataReader reader, int index, Guid defaultValue)
        {
            if (reader.IsDBNull(index))
            {
                return defaultValue;
            }

            return reader.GetGuid(index);
        }

        public static Guid? ReadGuidAttribute(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return reader.GetGuid(index);
        }

        #endregion

        #region Read methods for framework
        /// <summary>
        /// DateTime? típusú értékét olvas be
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <returns>A beolvasott dátum, vagy null</returns>
        internal static DateTime? ReadDateTime(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return reader.GetDateTime(index);
        }

        /// <summary>
        /// Karakterlánc típusú attribútum értékét olvas be
        /// </summary>
        /// <param name="reader">A forrás <see cref="SDA.DataProvider.SDADataReader"/> objektum</param>
        /// <param name="index">Az attribútum indexe</param>
        /// <returns>A beolvasott string vagy null</returns>
        internal static string ReadString(SDA.DataProvider.SDADataReader reader, int index)
        {
            if (reader.IsDBNull(index))
            {
                return null;
            }

            return reader.GetString(index);
        }
        #endregion
    }
}