//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Reflection;

namespace CommunityServer.Components
{
	/// <summary>
	/// Enables to objects of the same type to be combined
	/// </summary>
	public class Merger
	{
		private Merger(){}

        /// <summary>
        /// Merges to objects
        /// </summary>
        /// <param name="baseObject">Object with default data. This object will be returned</param>
        /// <param name="objectToMerge">Object which will be merged</param>
        /// <returns></returns>
        public static void Merge(object baseObject, object objectToMerge)
        {
            if(baseObject == null)
                throw new Exception("Base Object to merge is null");

            if(objectToMerge != null)
            {
                if(baseObject.GetType() != objectToMerge.GetType())
                    throw new Exception("Objects to merge must be of the same type");

                ProcessFields(baseObject,objectToMerge);
                ProcessProperties(baseObject,objectToMerge);
            
            }

           // return baseObject;
        }

        private static void ProcessProperties(object baseObject, object objectToMerge)
        {
            PropertyInfo[] properties = baseObject.GetType().GetProperties(BindingFlags.Instance|BindingFlags.Public);

            foreach(PropertyInfo pi in properties)
            {
                if(pi.CanWrite && pi.CanRead && !IsReadOnly(pi))
                {
                    pi.SetValue(baseObject,pi.GetValue(objectToMerge,null),null);
                }
            }
            
        }

        private static void ProcessFields(object baseObject, object objectToMerge)
        {
            FieldInfo[] fields = baseObject.GetType().GetFields(BindingFlags.Instance|BindingFlags.Public);

            foreach(FieldInfo fi in fields)
            {
                if(fi.IsPublic && !IsReadOnly(fi))
                {
                    fi.SetValue(baseObject,fi.GetValue(objectToMerge));
                }
            }
        }

        private static bool IsReadOnly(MemberInfo mi)
        {
            return mi.IsDefined(typeof(ReadFromConfigurationFileOnlyAttribute),true);
        }
	}
}
