using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace Mercury.Mobile.Logging
{
    /// <summary>
    /// Represents a message entry to a log.
    /// </summary>
    public sealed class LogEntry
    {
        internal LogEntry(LogSeverity severity, int eventId, long timestamp, DateTime loggedDateTime, 
            string callstack, Func<string> messageFunc, string rawMessage, object[] args)
        {
            this.Severity = severity;
            this.EventId = eventId;
            this.Timestamp = timestamp;
            this.LoggedDateTime = loggedDateTime;
            this.Callstack = callstack;
            this._messageFunction = messageFunc;
            this.RawMessage = rawMessage;
            this.Args = args;
            this.ProcessId = Process.GetCurrentProcess().Id;
            this.ThreadId = Thread.CurrentThread.ManagedThreadId;
        }

        private string _cachedMessage;
        private Func<string> _messageFunction;

        /// <summary>
        /// Gets the name of the logger that created this entry.
        /// </summary>
        public string LoggerName { get; internal set; }

        /// <summary>
        /// Gets the severity of this entry.
        /// </summary>
        public LogSeverity Severity { get; private set; }
        
        /// <summary>
        /// Gets the event identifier of this entry.
        /// </summary>
        public int EventId { get; private set; }

        /// <summary>
        /// Gets the identifier of the thread on which this entry was logged.
        /// </summary>
        public int ThreadId { get; private set; }

        /// <summary>
        /// Gets the identifier of the process on which this entry was logged.
        /// </summary>
        public int ProcessId { get; private set; }

        /// <summary>
        /// Gets the date and time at which this entry was logged.
        /// </summary>
        public DateTime LoggedDateTime { get; private set; }

        /// <summary>
        /// Gets the timestamp at which this entry was logged.
        /// </summary>
        public long Timestamp { get; private set; }

        /// <summary>
        /// Gets the call stack at which this entry was logged.
        /// </summary>
        public string Callstack { get; private set; }

        /// <summary>
        /// Gets the message to log.
        /// </summary>
        public string Message
        {
            get
            {
                this.EnsureMessage();
                return this._cachedMessage;
            }
        }

        /// <summary>
        /// Gets the filter data to apply to this entry.
        /// </summary>
        internal object FilterData { get; set; }

        /// <summary>
        /// Gets the unformatted, raw message string.
        /// </summary>
        internal string RawMessage { get; private set; }

        /// <summary>
        /// Gets any arguments that should be 
        /// </summary>
        internal object[] Args { get; private set; }

        internal void EnsureMessage()
        {
            if (string.IsNullOrEmpty(this._cachedMessage))
            {
                if (this._messageFunction != null)
                    this.RawMessage = this._messageFunction.Invoke();
                this._cachedMessage = this.RawMessage;
                if (this.Args != null && this.Args.Length > 0)
                    this._cachedMessage = string.Format(this.RawMessage, this.Args);
            }
        }
    }
}
