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, ParamsReader e );

		Type OutputType { get; }

        string Description { get; }
	}

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

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

        public Contribution load(Plugin owner, ParamsReader 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 ));
		}

        public override string Description {
            get {
                string dbase = base.Description;
                if (dbase != null & dbase.Length > 0) {
                    return dbase;
                } else {
                    return base.Name;
                }
            }
        }
    }
}
