class AddXMLSplitterEdit implements Edit<Dataflow> {

	@Override
	public Dataflow doEdit() throws EditException {
		if (applied) throw new EditException("Edit has already been applied!");
		List<Edit<?>> editList = new ArrayList<Edit<?>>();

		Activity<JsonNode> splitter = null;
		String sourcePortName = "";
		Processor sourceProcessor = null;
		Activity<?> sourceActivity = null;

		String sinkPortName = "";
		Processor sinkProcessor = null;
		Activity<?> sinkActivity = null;


		Processor activityProcessor = findProcessorForActivity(dataflow,
				activity);
		if (activityProcessor == null) {
			throw new EditException(
					"Cannot find the processor that the activity belongs to");
		}


		String displayName = portName;
		if (portName.equals("parameters")) {
			displayName = isInput ? "input" : "output";
		}
		String processorName = activityProcessor.getLocalName();
		String candidateName;
		if (displayName.startsWith(processorName)) {
			// No need to make GetRequest_GetRequestResponse
			candidateName = displayName;
		} else {
			// Combine with processor name
			String displayProcessorName;
			if (activity instanceof XMLOutputSplitterActivity || activity instanceof XMLInputSplitterActivity) {
				// For splitters on splitters - avoid adding up blah_bluh_blih_more_stuff
				String[] processorNameSplit = processorName.replace("_input", "").replace("_output", "").split("_");
				displayProcessorName = processorNameSplit[processorNameSplit.length-1];
			} else {
				displayProcessorName = activityProcessor.getLocalName();
			}
			candidateName = displayProcessorName + "_" + displayName;
		}
		String name = Tools.uniqueProcessorName(candidateName, dataflow);
		Processor splitterProcessor = edits.createProcessor(name);

		try {
			if (activity instanceof XMLInputSplitterActivity) {
				if (!isInput) {
					throw new EditException(
							"Can only add an input splitter to another input splitter");
				}
				TypeDescriptor descriptor = ((XMLInputSplitterActivity) activity)
						.getTypeDescriptorForInputPort(portName);
				if (descriptor instanceof ArrayTypeDescriptor && !((ArrayTypeDescriptor)descriptor).isWrapped()) {
					descriptor=((ArrayTypeDescriptor)descriptor).getElementType();
				}

				JsonNode bean = XMLSplitterConfigurationBeanBuilder
						.buildBeanForInput(descriptor);
				splitter = new XMLInputSplitterActivity();
				editList.add(edits.getConfigureActivityEdit(splitter, bean));

			} else if (activity instanceof XMLOutputSplitterActivity) {
				if (isInput) {
					throw new EditException(
							"Can only add an output splitter to another output splitter");
				}
				TypeDescriptor descriptor = ((XMLOutputSplitterActivity) activity)
						.getTypeDescriptorForOutputPort(portName);

				if (descriptor instanceof ArrayTypeDescriptor && !((ArrayTypeDescriptor)descriptor).isWrapped()) {
					descriptor=((ArrayTypeDescriptor)descriptor).getElementType();
				}

				JsonNode bean = XMLSplitterConfigurationBeanBuilder
						.buildBeanForOutput(descriptor);
				splitter = new XMLOutputSplitterActivity();
				editList.add(edits.getConfigureActivityEdit(splitter, bean));

			} else if (activity instanceof WSDLActivity) {
				if (isInput) {
					TypeDescriptor descriptor = ((WSDLActivity) activity)
							.getTypeDescriptorForInputPort(portName);
					JsonNode bean = XMLSplitterConfigurationBeanBuilder
							.buildBeanForInput(descriptor);
					splitter = new XMLInputSplitterActivity();
					editList
							.add(edits.getConfigureActivityEdit(splitter, bean));
				} else {
					TypeDescriptor descriptor = ((WSDLActivity) activity)
							.getTypeDescriptorForOutputPort(portName);
					JsonNode bean = XMLSplitterConfigurationBeanBuilder
							.buildBeanForOutput(descriptor);
					splitter = new XMLOutputSplitterActivity();
					editList
							.add(edits.getConfigureActivityEdit(splitter, bean));
				}
			} else {
				throw new EditException(
						"The activity type is not suitable for adding xml processing processors");
			}
		} catch (Exception e) {
			throw new EditException(
					"An error occured whilst tyring to add an XMLSplitter to the activity:"
							+ activity, e);
		}

		if (isInput) {
			sourcePortName = "output";
			sinkPortName = portName;
			sinkProcessor = activityProcessor;
			sinkActivity = activity;
			sourceProcessor = splitterProcessor;
			sourceActivity = splitter;
		}
		else {
			sourcePortName = portName;
			sinkPortName = "input";
			sinkProcessor = splitterProcessor;
			sinkActivity = splitter;
			sourceProcessor = activityProcessor;
			sourceActivity = activity;
		}

		editList.add(edits.getDefaultDispatchStackEdit(splitterProcessor));
		editList.add(edits.getAddActivityEdit(splitterProcessor, splitter));
//		editList.add(edits
//				.getMapProcessorPortsForActivityEdit(splitterProcessor));
		editList.add(edits.getAddProcessorEdit(dataflow, splitterProcessor));

		compoundEdit1 = new CompoundEdit(editList);
		compoundEdit1.doEdit();

		List<Edit<?>> linkUpEditList = new ArrayList<Edit<?>>();

		EventForwardingOutputPort source = getSourcePort(sourceProcessor, sourceActivity,
				sourcePortName, linkUpEditList);
		EventHandlingInputPort sink = getSinkPort(sinkProcessor, sinkActivity, sinkPortName, linkUpEditList);

		if (source == null)
			throw new EditException(
					"Unable to find the source port when linking up "
							+ sourcePortName + " to " + sinkPortName);
		if (sink == null)
			throw new EditException(
					"Unable to find the sink port when linking up "
							+ sourcePortName + " to " + sinkPortName);

		linkUpEditList.add(org.apache.taverna.workflowmodel.utils.Tools.getCreateAndConnectDatalinkEdit(dataflow, source, sink, edits));

		linkUpEdit = new CompoundEdit(linkUpEditList);
		linkUpEdit.doEdit();
		applied = true;
		return dataflow;
	}

	public  AddXMLSplitterEdit(Dataflow dataflow, Activity<?> activity,
			String portName, boolean isInput, Edits edits);

}