// (c) Copyright 2014 by PTC Inc. All rights reserved.

/**
 * Example Integration Command Extension demonstrating how to return
 * an API Response object containing WorkItems
 */

package ptc.integrationcommandextensions.example;

import java.util.*;
import java.util.Map.Entry;

import com.mks.api.*;
import com.mks.api.ext.*;
import com.mks.api.response.*;
import com.mks.api.response.impl.SimpleResponseFactory;
import com.mks.api.response.modifiable.*;
import com.mks.api.util.APIVersion;

public class ResponseExampleIntegrationCommand extends SimpleIntegrationCommand
{
    private static final String MODEL_TYPE = "abc.cp";

    public ResponseExampleIntegrationCommand()
    {
	super(APIVersion.API_4_13.getMajor(), APIVersion.API_4_13.getMinor());
    }

    @Override
    protected void execute(ResponseWriter apiout, CommandOptions options,
	    CommandSelection selection) throws APIException
    {
	String project = options.getOptionValue("project");
	String devpath = options.getOptionValue("devpath");
	
	List<ChangePackage> cps = getFilteredCPs(project, devpath);
	
	//write the response to the API
	for (ChangePackage cp : cps) {
	    apiout.startWorkItem(cp.getId(), cp.getContext(),
		    cp.getModelType());
	    Iterator fields = cp.getFields();
	    if (fields != null) {
		while (fields.hasNext()) {
			apiout.writeAPIObj((Field) fields.next());
	    	}
	    }
	    apiout.endWorkItem();
	}
    }

    /**
     * Retrieve a list of all change packages for a specific project, including
     * the change package entries
     * 
     * @param siProject The flat path of the project to use in the CP filter
     * @param devPath The name of the variant (if null, assumed to be mainline) 
     * @return
     * @throws APIException
     */
    public List<ChangePackage> getFilteredCPs(String siProject, String devPath)
	    throws APIException
    {
	//get the list of CPs
	OptionList options = new OptionList();
	options.add(new Option("filter", "project:" + siProject));
	if (devPath != null && !devPath.isEmpty()) {
	    options.add(new Option("filter", "variant:" + devPath));
	}
	else {
	    options.add(new Option("filter", "mainline"));
	}
	Command viewCPsCommand = new Command(Command.SI, "viewcps");
	viewCPsCommand.setOptionList(options);
	Response response = runLocalCommand(viewCPsCommand);
	WorkItemIterator wii = response.getWorkItems();
	SelectionList cpIds = new SelectionList();
	while (wii.hasNext()) {
	    WorkItem wi = wii.next();
	    cpIds.add(wi.getId());
	}
	
	//get the entries
	OptionList viewCpOptions = new OptionList();
	List<ChangePackage> cps = new ArrayList<ChangePackage>();
	if (cpIds.size() > 0) {
	    Command viewCPCommand = new Command(Command.SI, "viewcp");
	    viewCPCommand.setOptionList(viewCpOptions);
	    viewCPCommand.setSelectionList(cpIds);
	    response = runLocalCommand(viewCPCommand);
	    wii = response.getWorkItems();
	    while (wii.hasNext()) {
		WorkItem wi = wii.next();
		cps.add(new ChangePackage(wi));
	    }
	}
	return cps;
    }

    public class ChangePackage implements Item
    {
	private static final String CP_ENTRIES = "entries";
	private static final String CLOSED_DATE = "closeddate";
	private static final String CREATION_DATE = "creationdate";
	private static final String USER = "user";
	private String itemId;
	private Field user;
	private Date created, closed;
	private List<ChangePackageEntry> entries = new ArrayList<ChangePackageEntry>();
	private Map<String, Object> fields = new HashMap<String, Object>();

	public ChangePackage(WorkItem wi)
	{
	    itemId = wi.getId();
	    user = wi.getField(USER);
	    created = wi.getField(CREATION_DATE).getDateTime();
	    closed = wi.getField(CLOSED_DATE).getDateTime();
	    Field cpEntries = wi.getField("MKSEntries");
	    List<?> wiEntries = new ArrayList<>();
	    if (cpEntries != null)
		wiEntries = cpEntries.getList();
	    for (Object wiEntry : wiEntries) {
		entries.add(new ChangePackageEntry((Item) wiEntry));
	    }
	    fields.put(USER, user);
	    fields.put(CREATION_DATE, created);
	    fields.put(CLOSED_DATE, closed);
	    fields.put(CP_ENTRIES, entries);
	}

	public String getId()
	{
	    return itemId;
	}

	public Field getUserField()
	{
	    return user;
	}

	public Date getCreated()
	{
	    return created;
	}

	public Date getClosed()
	{
	    return closed;
	}

	public List<ChangePackageEntry> getEntries()
	{
	    return entries;
	}

	@Override
	public String toString()
	{
	    return "CP " + itemId + " created by " + user.getName() + " on " + created
		    + " with " + entries.toString() + " was closed on "
		    + closed;
	}

	@Override
	public Field getField(String id)
	{
	    ResponseFactory factory = SimpleResponseFactory
		    .getResponseFactory();
	    if (!fields.containsKey(id)) {
		return null;
	    }
	    ModifiableField field = factory.createField(id);
	    switch (id) {
		case USER :
		    return user;
		case CREATION_DATE :
		case CLOSED_DATE :
		    field.setValue(fields.get(id));
		    return field;
		case CP_ENTRIES :
		    if (entries.size() > 0) {
			ModifiableItemList entryItemList = factory
				.createItemList();
			entryItemList.addAll(entries);
			field.setValue(entryItemList);
		    }
		    return field;
	    }
	    return null;
	}

	@Override
	public Iterator getFields()
	{
	    List<Field> fieldList = new ArrayList<Field>();
	    for (Entry<String, Object> field : fields.entrySet()) {
		fieldList.add(getField(field.getKey()));
	    }
	    return fieldList.iterator();
	}

	@Override
	public int getFieldListSize()
	{
	    return fields.size();
	}

	@Override
	public boolean contains(String id)
	{
	    return fields.containsKey(id);
	}

	@Override
	public String getModelType()
	{
	    return MODEL_TYPE;
	}

	@Override
	public String getContext()
	{
	    return null;
	}

	@Override
	public String getDisplayId()
	{
	    return getId();
	}

	@Override
	public String getContext(String key)
	{
	    return null;
	}

	@Override
	public Enumeration getContextKeys()
	{
	    return Collections.emptyEnumeration();
	}
    }

    public class ChangePackageEntry implements Item
    {
	private static final String TYPE = "type";
	private static final String REVISION = "revision";
	private static final String VARIANT = "variant";
	private static final String PROJECT = "project";
	private static final String MEMBER = "member";
	private static final String ABC_CPENTRY = "abc.cpentry";
	private String member, project, revision, variant, action;
	private Map<String, String> fields = new HashMap<String, String>();

	public ChangePackageEntry(Item wiEntry)
	{
	    member = ResponseExampleIntegrationCommand.getId(MEMBER, wiEntry);
	    project = ResponseExampleIntegrationCommand.getId(PROJECT, wiEntry);
	    variant = ResponseExampleIntegrationCommand.getId(VARIANT, wiEntry);
	    revision = ResponseExampleIntegrationCommand.getId(REVISION,
		    wiEntry);
	    action = ResponseExampleIntegrationCommand.getId(TYPE, wiEntry);
	    fields.put(TYPE, action);
	    fields.put(REVISION, revision);
	    fields.put(PROJECT, project);
	    fields.put(VARIANT, variant);
	}

	public String getMember()
	{
	    return member;
	}

	public String getProject()
	{
	    return project;
	}

	public String getRevision()
	{
	    return revision;
	}

	public String getVariant()
	{
	    return variant;
	}

	public String getAction()
	{
	    return action;
	}

	@Override
	public String toString()
	{
	    return "ChangePackageEntry [member=" + member + ", project="
		    + project + ", revision=" + revision + ", variant="
		    + variant + ", action=" + action + "]";
	}

	@Override
	public Field getField(String id)
	{
	    ResponseFactory factory = SimpleResponseFactory
		    .getResponseFactory();
	    if (!fields.containsKey(id)) {
		return null;
	    }
	    ModifiableField field = factory.createField(id);
	    field.setValue(fields.get(id));
	    return field;
	}

	@Override
	public Iterator getFields()
	{
	    List<Field> fieldList = new ArrayList<Field>();
	    for (Map.Entry<String, String> field : fields.entrySet()) {
		fieldList.add(getField(field.getKey()));
	    }
	    return fieldList.iterator();
	}

	@Override
	public int getFieldListSize()
	{
	    return fields.size();
	}

	@Override
	public boolean contains(String id)
	{
	    return fields.containsKey(id);
	}

	@Override
	public String getId()
	{
	    return member;
	}

	@Override
	public String getModelType()
	{
	    return ABC_CPENTRY;
	}

	@Override
	public String getContext()
	{
	    return project;
	}

	@Override
	public String getDisplayId()
	{
	    return getId();
	}

	@Override
	public String getContext(String key)
	{
	    return null;
	}

	@Override
	public Enumeration getContextKeys()
	{
	    return Collections.emptyEnumeration();
	}
    }

    /**
     * Convenience method to retrieve the id value from a Field on an Item.
     * 
     * @param field
     * @param item
     * @return
     */
    public static String getId(String field, Item item)
    {
	Field itemField = item.getField(field);
	if (itemField != null && itemField.getItem() != null) {
	    return itemField.getItem().getId();
	}
	return "";
    }
}
