using System;
using System.Xml;
using nft.util;
using System.Diagnostics;

namespace nft.framework.plugin
{
	/// <summary>
	/// Responsible for loading a contribution from an XML element.
	/// </summary>
	public interface IContributionFactory
	{
		/// <summary>
		/// Loads a contribution from an XML Element "e",
		/// which belongs to the plugin "owner".
		/// 
		/// In case of an error, this method must throw an exception
		/// instead of silently returning null.
		/// </summary>
		Contribution load( Plugin owner, XmlElement e );

		Type OutputType { get; }
	}

    public class DefaultContributionFactory : Contribution, IContributionFactory
    {
        internal protected DefaultContributionFactory(Plugin p, XmlElement elm )
            : base(p, elm)
        {
            XmlNode nd = elm.SelectSingleNode("basetype");
            if (nd == null) {
                nd = elm.SelectSingleNode("implementation");
                if (nd == null)
                {
                    throw new PluginXmlException(p, elm, "<basetype> is required for ContributionFactory.");
                }
            }
            this.baseType = PluginUtil.loadTypeFromManifest((XmlElement)nd);
        }

		private readonly Type baseType;
		public Type OutputType { get{ return baseType; } }

		public Contribution load( Plugin owner, XmlElement e ) 
		{
            Contribution contrib = (Contribution)Activator.CreateInstance(baseType, new object[] { owner, e });
			if( baseType.IsInstanceOfType(contrib) )
				return contrib;
			else
				throw new PluginXmlException(owner, e, string.Format(
					"{0} is incorrect for this contribution (expected:{1})",
					contrib.GetType().FullName, baseType.FullName ));
		}
    }
}
