//RShare
//Copyright (C) 2009-2010 Lars Regensburger, T.Norad

//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Regensburger.RCollections.ArrayBased;

namespace Regensburger.RShare
{
    public sealed class Logger
    {
        // singelton instance and lock object
        // Added on 2007-05-05 by T.Norad
        private static Logger instance = null;
        private static readonly object padlock = new object();

        // list of all observers
        private List<ILogObserver> m_Observers = new List<ILogObserver>();

        /*
         * private constructor to prevent creating manually an instance of this class.
         * 
         * Added on 2007-05-05 by T.Norad
         */
        private Logger()
        {
            // do nothing
        }

        /*
         * singelton implementation
         * 
         * Added on 2007-05-05 by T.Norad
         */
        public static Logger Instance
        {
            get
            {
                lock (padlock)
                {
                    if (instance == null)
                    {
                        instance = new Logger();
                    }
                    return instance;
                }
            }
        }

        /// <summary>
        /// Logs the passed message. The message can contain composite format strings like {0}.
        /// 
        /// Added on 2007-05-05 by T.Norad
        /// </summary>
        /// <param name="format">logmessage</param>
        /// <param name="args">array ob arguments replaced in the logmessage</param>
        public void Log(string format, params object[] args)
        {
            if (format == null)
                throw new ArgumentNullException("format");
            if (args == null)
                throw new ArgumentNullException("args");

            this.Log(null, format, args);
        }

        /// <summary>
        /// Logs the passed message. The message can contain composite format strings like {0}.
        /// The passed exception is used to extend the log entry with the exception message.
        /// 
        /// Added on 2007-05-05 by T.Norad
        /// </summary>
        /// <param name="thrownException">exception to extend the log entry with the exception message</param>
        /// <param name="format">logmessage</param>
        /// <param name="args">array ob arguments replaced in the logmessage</param>
        public void Log(Exception thrownException, string format, params object[] args)
        {
            if (format == null)
                throw new ArgumentNullException("format");
            if (args == null)
                throw new ArgumentNullException("args");

            this.Log(new LogEntry(string.Format(format, args), thrownException));
        }

        /// <summary>
        /// private method to write the log entry to a logfile. The LogEntry is only write to file if this class is initialized.
        /// 
        /// Added on 2007-05-05 by T.Norad
        /// </summary>
        /// <param name="logEntry">LogEntry contains all necessary informations to log</param>
        private void Log(LogEntry logEntry)
        {
            if (logEntry == null)
            {
                throw new ArgumentNullException("logEntry");
            }

            // notify all registered observer
            Notify(logEntry);
        }

        public void Attach(ILogObserver observer)
        {
            m_Observers.Add(observer);
        }

        public void Detach(ILogObserver investor)
        {
            m_Observers.Remove(investor);
        }

        public void Notify(LogEntry logEntry)
        {
            foreach (ILogObserver observer in m_Observers)
            {
                observer.NewLogEntry(logEntry);
            }
        }
    }
}
