package org.handwerkszeug.riak.op.mapreduce;

import java.util.ArrayList;
import java.util.List;

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.ObjectNode;
import org.handwerkszeug.riak.JsonAppender;
import org.handwerkszeug.riak.util.StringUtil;

public abstract class AbstractMapReduceQuery implements MapReduceQuery {

	protected String bucket;

	protected List<MapReduceInput> inputs = new ArrayList<MapReduceInput>();

	protected MapReduceSearchInput search;

	protected List<MapReducePhase> queries = new ArrayList<MapReducePhase>();

	protected long timeout;

	protected AbstractMapReduceQuery() {
	}

	@Override
	public void setInputs(String bucket) {
		if (this.inputs.isEmpty() == false || this.search != null) {
			throw new IllegalStateException();
		}
		this.bucket = bucket;
	}

	@Override
	public void addInputs(MapReduceInput... inputs) {
		if (StringUtil.isEmpty(this.bucket) == false || this.search != null) {
			throw new IllegalStateException();
		}
		for (MapReduceInput in : inputs) {
			this.inputs.add(in);
		}
	}

	@Override
	public void setInputs(MapReduceSearchInput search) {
		if (StringUtil.isEmpty(this.bucket) == false
				|| this.inputs.isEmpty() == false) {
			throw new IllegalStateException();
		}
		this.search = search;
	}

	@Override
	public void addQueries(MapReducePhase... mapReducePhases) {
		for (MapReducePhase ph : mapReducePhases) {
			this.queries.add(ph);
		}
	}

	@Override
	public void setTimeout(long timeout) {
		this.timeout = timeout;
	}

	@Override
	public void clear() {
		this.bucket = null;
		this.inputs.clear();
		this.search = null;
		this.queries.clear();
		this.timeout = 0L;
	}

	protected ObjectNode prepare() {
		ObjectMapper om = new ObjectMapper();
		ObjectNode root = om.createObjectNode();
		if (this.bucket != null && this.bucket.isEmpty() == false) {
			root.put("inputs", this.bucket);
		} else if (this.search != null) {
			ObjectNode node = root.putObject("inputs");
			this.search.appendTo(node);
		} else {
			add(root.putArray("inputs"), this.inputs);
		}

		add(root.putArray("query"), this.queries);

		if (0 < this.timeout) {
			root.put("timeout", this.timeout);
		}
		return root;
	}

	protected void add(ArrayNode node,
			List<? extends JsonAppender<ArrayNode>> list) {
		for (JsonAppender<ArrayNode> ja : list) {
			ja.appendTo(node);
		}
	}
}

@@ -1780,32 +1780,175 @@
 ut = 0L;%0D%0A%09%7D%0D%0A%0D%0A
+%09static final String FIELD_INPUTS = %22inputs%22;%0D%0A%09static final String FIELD_QUERY = %22query%22;%0D%0A%09static final String FIELD_TIMEOUT = %22timeout%22;%0D%0A%0D%0A
 %09protected Objec
@@ -2127,24 +2127,28 @@
 oot.put(
-%22inputs%22
+FIELD_INPUTS
 , this.b
@@ -2229,24 +2229,28 @@
 tObject(
-%22inputs%22
+FIELD_INPUTS
 );%0D%0A%09%09%09t
@@ -2310,24 +2310,28 @@
 utArray(
-%22inputs%22
+FIELD_INPUTS
 ), this.
@@ -2367,23 +2367,27 @@
 utArray(
-%22query%22
+FIELD_QUERY
 ), this.
@@ -2438,25 +2438,29 @@
 oot.put(
-%22timeout%22
+FIELD_TIMEOUT
 , this.t

use local constants.