/**
 * TitleMetadataOptionProvider.java
 * Created on May 19, 2008
 * (C) Copyright TANDBERG Television Ltd.
 */
package com.tandbergtv.watchpoint.pmm.job.ui;

import java.util.ArrayList;
import java.util.List;

import com.tandbergtv.watchpoint.pmm.job.conf.ParameterReferenceGroup;
import com.tandbergtv.watchpoint.pmm.job.conf.ParameterReferenceItem;
import com.tandbergtv.watchpoint.pmm.title.conf.ComplexVariable;
import com.tandbergtv.watchpoint.pmm.title.conf.ISpecificationManager;
import com.tandbergtv.watchpoint.pmm.title.conf.SimpleVariable;
import com.tandbergtv.watchpoint.pmm.title.conf.Specification;
import com.tandbergtv.watchpoint.pmm.title.conf.TitleConf;
import com.tandbergtv.watchpoint.pmm.title.conf.Variable;
import com.tandbergtv.workflow.core.service.ServiceRegistry;

/**
 * This class simply calls SpecManager to get the list of menu options
 * and builds the group objects required to be returned back.
 * 
 * @author spuranik 
 */
public class TitleMetadataOptionProvider implements IMenuOptionProvider {

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.job.IMenuOptionProvider#getJobRuleParams()
	 */
	public List<ParameterReferenceItem> getJobRuleMenuOptions(String spec) {
		ISpecificationManager specMgr = ServiceRegistry.getDefault().lookup(
				ISpecificationManager.class);	
		Specification s = specMgr.getSpecificationByName(spec);
		return getJobRules(s);
	}

	/* (non-Javadoc)
	 * @see com.tandbergtv.watchpoint.pmm.job.IMenuOptionProvider#getJobParameterMenuOptions()
	 */
	public List<ParameterReferenceItem> getJobParameterMenuOptions(String spec) {
		ISpecificationManager specMgr = ServiceRegistry.getDefault().lookup(
				ISpecificationManager.class);
		Specification s = specMgr.getSpecificationByName(spec);
		return getJobParameters(s);
	}
	
	/**
	 * Walks thru all variables in all sections of the spec and prepares a list of groups per section type
	 * and the variables under each section which can be used as job parameters. 
	 * 
	 * @param s
	 * @return
	 */
	public List<ParameterReferenceItem> getJobRules(Specification s) {
		List<ParameterReferenceItem> items = new ArrayList<ParameterReferenceItem>();
		// go thru all root confs and collect the job variables at all levels
		for (TitleConf tc : s.getRootTitleConfs()) {
			for (ParameterReferenceGroup g : filterTitleSections(tc, null, false)) {
				items.add(g);
			}
		}		
		return items;
	}
	
	/**
	 * Walks thru all variables in all sections of the spec and prepares a list of groups per section type
	 * and the variables under each section which can be used as job parameters.
	 *  
	 * @param s
	 * @return
	 */
	public List<ParameterReferenceItem> getJobParameters(Specification s) {
		List<ParameterReferenceItem> items = new ArrayList<ParameterReferenceItem>();
		// go thru all root confs and collect the job variables at all levels
		for (TitleConf tc : s.getRootTitleConfs()) {
			for (ParameterReferenceGroup g : filterTitleSections(tc, null, true)) {
				items.add(g);
			}
		}		
		return items;
	}

	/**
	 * Recursively goes thru all sections to filter out job variables. 
	 * 
	 * @param tc
	 * @param isJobParameter
	 * @return
	 */
	private List<ParameterReferenceGroup> filterTitleSections(TitleConf tc,
			ParameterReferenceGroup parent, boolean isJobParameter) {
		List<ParameterReferenceGroup> groups = new ArrayList<ParameterReferenceGroup>();

		// filter metadata at this level
		ParameterReferenceGroup group = createGroup(tc, parent, isJobParameter);
		if (!group.getItems().isEmpty()) {
			groups.add(group);
		}
		
		// filter variables at its immediate child level
		for (TitleConf childTc : tc.getAllDescendants()) {
			List<ParameterReferenceGroup> childGroups = filterTitleSections(childTc, group, isJobParameter);
			for (ParameterReferenceGroup g : childGroups) {
				if (!g.getItems().isEmpty()) {
					groups.add(g);
				}
			}
		}
		return groups;
	}

	private ParameterReferenceGroup createGroup(TitleConf tc,
			ParameterReferenceGroup parent, boolean isJobParameter) {
		ParameterReferenceGroup group = new ParameterReferenceGroup();
		group.setName(tc.getAlias());
		group.setParent(parent);

		List<ParameterReferenceItem> items = filterJobVariable(tc.getMetadata(), group, isJobParameter);
		if (!items.isEmpty()) {
			for (ParameterReferenceItem item : items) {
				group.addItem(item);
			}
		}
		return group;
	}

	/**
	 * Recursively goes thru all variables passed in to filter out job
	 * variables. If its a job variable, the parent is set and is added to the
	 * parent group.
	 * 
	 * @param vars
	 * @param group
	 * @param isJobParameter
	 * @return
	 */
	private List<ParameterReferenceItem> filterJobVariable(
			List<Variable> vars, ParameterReferenceGroup group, boolean isJobParameter) {
		List<ParameterReferenceItem> items = new ArrayList<ParameterReferenceItem>();
		for (Variable v : vars) {
			// if its a leaf variable, and is a job variable add it to the group
			if (v instanceof SimpleVariable) {
				if (isJobParameter) {
					if (((SimpleVariable<?>) v).isJobParameter()) {
						items.add(createItem(v, group));
					}
				} else {
					if (((SimpleVariable<?>) v).isJobRuleParameter()) {
						items.add(createItem(v, group));
					}
				}
			} else if (v instanceof ComplexVariable) {
				// Create a new group for this complex type which will be added
				// later if it has any job variables at the leaf level.
				ParameterReferenceGroup variableGroup = new ParameterReferenceGroup();
				variableGroup.setName(v.getDisplayName());
				variableGroup.setParent(group);
				List<ParameterReferenceItem> variableChildItems = filterJobVariable(
						((ComplexVariable)v).getChildren(), variableGroup, isJobParameter);
				// add this group to the item list if there are any items under it for jobs.
				if (!variableChildItems.isEmpty()) {
					variableGroup.setItems(variableChildItems);
					items.add(variableGroup);
				}
			}
		}
		return items;
	}

	/**
	 * Creates an item for the variable passed in and sets its parent.
	 * 
	 * @param v
	 * @param parent
	 * @return
	 */
	private ParameterReferenceItem createItem(Variable v, ParameterReferenceGroup parent) {
		ParameterReferenceItem item = new ParameterReferenceItem();
		item.setName(v.getDisplayName());
		// value is of the form: [TitleConfName].[ttvxpath]
		item.setValue(v.getTitleConf().getName() + "." + v.getXPath());
		item.setParent(parent);
		return item;
	}
	
}
