package org.treesched.ant;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicConfigurator;
import org.treesched.CompoundSchedule;
import org.treesched.RefineableSchedule;
import org.treesched.Schedule;
import org.treesched.ScheduleFactory;

/**
 * Represents a nested scheudle element of an Ant build file.
 */
public class NestedScheduleElement implements DynamicConfigurator {

	/** The element this schedule wraps. This is null for the topmost
	 * elemnt, which only contains a schedule list. */
	private final Schedule schedule;

	/**
	 * Constructor.
	 * 
	 * @param schedule The schedule this wraps.
	 */
	public NestedScheduleElement(Schedule schedule) {
		this.schedule = schedule;
	}
	
	/* (non-Javadoc)
	 * @see org.apache.ant.DynamicConfigurator#setDynamicAttribute(java.lang.String, java.lang.Object)
	 */
	public void setDynamicAttribute(String name, String value)
		throws BuildException {

	    String mName = "set" + capitalize(name);
	    try {
		    Method setter= schedule.getClass().getMethod(mName, new Class[] {String.class} );
            setter.invoke(schedule, new Object[] {value});
        } catch (IllegalArgumentException e) {
			throw new BuildException("Failed to set attribute " + name, e);
        } catch (NoSuchMethodException e) {
			throw new BuildException("No such attribute " + name, e);
        } catch (IllegalAccessException e) {
			throw new BuildException("Failed to set attribute " + name, e);
        } catch (InvocationTargetException e) {
			throw new BuildException("Failed to set attribute " + name, e);
        }
	}

	/* (non-Javadoc)
	 * @see org.oddjob.arooa.DynamicConfigurator#createDynamicElement(java.lang.String)
	 */
	public Object createDynamicElement(String name) throws BuildException {

		if (schedule instanceof RefineableSchedule) {
			ScheduleFactory factory = ScheduleFactory.getInstance();
			Schedule newChild = factory.createSchedule(name);
		
			((RefineableSchedule)schedule).addChildSchedule(newChild);
			NestedScheduleElement se = new NestedScheduleElement(newChild);
			return se;
		}
		else if (schedule instanceof CompoundSchedule) {
		    return new CompoundScheduleProxy(schedule, name);
		}
		else {
		    throw new BuildException("Unsupported elelement " + name);
		}
	}

	/**
	 * Helper function for getting property name.
	 * 
	 * @param s PropertyName.
	 * @return Uppercase first letter of property.
	 */
	static String capitalize(String s) {
        if (s.length() == 0) {
            return s;
        }
        char chars[] = s.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return new String(chars);
    }	
}
