#region

using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;

#endregion

namespace Lattyf.BackIt.Core.Common
{
    /// <summary>
    /// Ðàñøèðèòåëü âîçìîæíîñòåé êëàññà <see cref="SqlDataReader"/>
    /// </summary>
    public static class SqlDataReaderExtender
    {
        /// <summary>
        /// Âîçâðàùàåò ïðî÷èòàííóþ èç ðèäåðà çíà÷åíèå èëè default value, åñëè â ñòðîêå <see langword="null"/>.
        /// </summary>
        /// <param name="reader">Ðèäåð äëÿ ÷òåíèÿ.</param>
        /// <param name="fieldName">Èìÿ ïîëÿ, êîòîðîå íóæíî ïðî÷èòàòü.</param>
        /// <returns>Çíà÷åíèå ïîëÿ èëè default value.</returns>
        public static T GetValueOrDefault<T>(this IDataReader reader, string fieldName)
        {
            return GetValueOrDefault(reader, fieldName, default(T));
        }

        /// <summary>
        /// Âîçâðàùàåò ïðî÷èòàííóþ èç ðèäåðà çíà÷åíèå èëè default value, åñëè â ñòðîêå <see langword="null"/>.
        /// </summary>
        /// <param name="reader">Ðèäåð äëÿ ÷òåíèÿ.</param>
        /// <param name="fieldIndex">Èíäåêñ ïîëÿ.</param>
        /// <returns>Çíà÷åíèå ïîëÿ èëè default value.</returns>
        public static T GetValueOrDefault<T>(this IDataReader reader, int fieldIndex)
        {
            return GetValueOrDefault(reader, fieldIndex, default(T));
        }

        /// <summary>
        /// Âîçâðàùàåò ïðî÷èòàííóþ èç ðèäåðà çíà÷åíèå èëè default value, åñëè â ñòðîêå <see langword="null"/>.
        /// </summary>
        /// <param name="reader">Ðèäåð äëÿ ÷òåíèÿ.</param>
        /// <param name="fieldIndex">Èíäåêñ ïîëÿ.</param>
        /// <param name="defaultValue">Çíà÷åíèå ïî óìîë÷àíèþ. Áóäåò âîçâðàùåíî, åñëè ïîëå <see langword="null"/>.</param>
        /// <returns>Çíà÷åíèå ïîëÿ èëè default value.</returns>
        public static T GetValueOrDefault<T>(this IDataReader reader, int fieldIndex, T defaultValue)
        {
            Guard.IsNotNull(reader, "reader");

            if (reader.IsDBNull(fieldIndex))
                return defaultValue;

            object value = reader.GetValue(fieldIndex);

            if (!(value is T))
            {
                string fieldName = reader.GetName(fieldIndex);
                throw new InvalidDataException(
                    string.Format(
                                     "Value of field \"{0}\" has type {1} but readed as {2}",
                                     fieldName,
                                     value.GetType(),
                                     typeof (T)));
            }

            return (T) value;
        }

        /// <summary>
        /// Âîçâðàùàåò ïðî÷èòàííóþ èç ðèäåðà çíà÷åíèå èëè default value, åñëè â ñòðîêå <see langword="null"/>.
        /// </summary>
        /// <param name="reader">Ðèäåð äëÿ ÷òåíèÿ.</param>
        /// <param name="fieldName">Èìÿ ïîëÿ, êîòîðîå íóæíî ïðî÷èòàòü.</param>
        /// <param name="defaultValue">Çíà÷åíèå äëÿ âîçâðàùåíèÿ, åñëè â áàçå <see langword="null"/>.</param>
        /// <returns>Çíà÷åíèå ïîëÿ èëè default value.</returns>
        public static T GetValueOrDefault<T>(this IDataReader reader, string fieldName, T defaultValue)
        {
            Guard.IsNotNull(reader, "reader");

            try
            {
                int fieldIndex = reader.GetOrdinal(fieldName);
                return GetValueOrDefault(reader, fieldIndex, defaultValue);
            }
            catch (IndexOutOfRangeException)
            {
                throw new ArgumentException(
                    string.Format("Field with name \"{0}\" does not exists in reader.", fieldName));
            }
        }
    }
}