using System;
using System.Reflection;
using AopAlliance.Intercept;
using Spring.Aop.Framework;

namespace Spring.AopQuickStart
{
    public class ModificationAdvice : IMethodInterceptor
    {
        public virtual Object Invoke(IMethodInvocation invocation)
        {
            MethodInfo method = invocation.Method;
            object proxy = invocation.Proxy;

            if (proxy is IIsModified)
            {
                IIsModified obj = (IIsModified) proxy;
                if (IsSetter(method))
                {
                    obj.IsModified = HasModificationOccured(method, invocation.This, invocation.Arguments);
                }
            }
            return invocation.Proceed();
        }

        private bool HasModificationOccured(MethodInfo setter, Object target, Object[] args)
        {
            PropertyInfo property = target.GetType().GetProperty(setter.Name.Substring(4));

            if (property != null)
            {
                // modification check is unimportant
                // for write only methods
                Object newVal = args[0];
                Object oldVal = property.GetValue(target, null);

                if ((newVal == null) && (oldVal == null))
                {
                    return false;
                }
                else if ((newVal == null) && (oldVal != null))
                {
                    return true;
                }
                else if ((newVal != null) && (oldVal == null))
                {
                    return true;
                }
                else
                {
                    return (!newVal.Equals(oldVal));
                }
            }

            return false;
        }

        private bool IsSetter(MethodInfo method)
        {
            return (method.Name.StartsWith("set_")) && (method.GetParameters().Length == 1);
        }
        
    }
}
