using System;
using System.Diagnostics;
using iiie.Logs.DBO;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace iiie.Logs.DataAccess
{
    /// <summary>
    /// Logger for OpResult
    /// </summary>
    public static class Logger
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        public static TraceEventType ResultStatusToSeverity(ResultStatus status)
        {
            if (status == ResultStatus.DBError)
                return TraceEventType.Critical;
            if (status == ResultStatus.LoginError)
                return TraceEventType.Error;
            if (status == ResultStatus.PermissionError)
                return TraceEventType.Error;
            if (status == ResultStatus.InternalError)
                return TraceEventType.Error;
            if (status == ResultStatus.InputError)
                return TraceEventType.Warning;
            if (status == ResultStatus.NotFound)
                return TraceEventType.Information;
            return TraceEventType.Verbose;
        }

        /// <summary>
        /// Config the logger for database and default settings provider
        /// </summary>
        public static void Config()
        {
            DatabaseFactory.SetDatabaseProviderFactory(new DatabaseProviderFactory());
            IConfigurationSource configurationSource = ConfigurationSourceFactory.Create();
            LogWriterFactory logWriterFactory = new LogWriterFactory(configurationSource);
            Microsoft.Practices.EnterpriseLibrary.Logging.Logger.SetLogWriter(logWriterFactory.Create());
        }

        /// <summary>
        /// Log provided informations
        /// </summary>
        /// <param name="status">The status to be logged</param>
        /// <param name="title">The log title</param>
        /// <param name="message">The log message</param>
        public static void Log(ResultStatus status, string title, string message)
        {
            try
            {
                Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(new LogEntry()
                {
                    Title = title,
                    Severity = ResultStatusToSeverity(status),
                    Message = message
                });
            }
            catch (Exception e)
            {
            }
        }

        /// <summary>
        /// Log an exception
        /// </summary>
        /// <param name="e">The exception to be logged</param>
        public static void Log(Exception e)
        {
            LogOpResult(OpResult<int>.Error(ResultStatus.InternalError, e));
        }

        /// <summary>
        /// Log an OpResult
        /// </summary>
        /// <typeparam name="T">User data type</typeparam>
        /// <param name="result">The result to be logged</param>
        /// <returns>The OpResult</returns>
        public static OpResult<T> LogOpResult<T>(OpResult<T> result)
        {
            string message = "Location:\n";
            for (int i = 0; i < result.StackFrames.Length && i < 10; ++i)
            {
                var frame = result.StackFrames[i];
                var method = frame.GetMethod();
                if (method.DeclaringType != null)
                    message += method.DeclaringType.Name + "." + frame.GetMethod().Name + "\n";
            }
            if (result.PrivateDetails != null)
                message += "\nPrivate details:\n" + result.PrivateDetails + "\n";
            if (result.PublicDetails != null)
                message += "\nPublic details:\n" + result.PublicDetails;
            Log(result.Status, result.Status.ToString(), message);
            return result;
        }

        /// <summary>
        /// Create and returns a new OpResult with
        /// PrivateDetails = privateDetails, Data = null, Status = status
        /// If publicDetails == "", privateDetails will be used
        /// Used for all errors (invalid input, ...)
        /// </summary>
        public static OpResult<T> Error<T>(ResultStatus status, string privateDetails, string publicDetails = null)
        {
            return LogOpResult(OpResult<T>.Error(status, privateDetails, publicDetails));
        }

        /// <summary>
        /// Create and returns a new OpResult with
        /// PrivateDetails = e to string, Data = null, Status = status
        /// If publicDetails == "", privateDetails will be used
        /// Used for all errors (invalid input, ...)
        /// </summary>
        public static OpResult<T> Error<T>(ResultStatus status, Exception e, string userDetails = null)
        {
            return LogOpResult(OpResult<T>.Error(status, e, userDetails));
        }
    }
}
