/**
 * $$\\ToureNPlaner\\$$
 */
package computecore;

import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import server.Responder;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * This class is used to represent a request for computation
 * 
 * @author Niklas Schnelle, Peter Vollmer, Sascha Meusel
 * 
 */
public class ComputeRequest {

	private final RequestPoints points;
	private final List<Way> resultWays;
	private final Map<String, Object> constraints;
	private Map<String, Object> misc;
	private final String algName;
	private final Responder responder;
	private int requestID;
    private final boolean acceptsSmile;

	/**
	 * Constructs a new ComputeRequest using the given Responder, Points and
	 * Constraints. The requestID of the constructed ComputeRequest object is
	 * -1, must be set with {@link #setRequestID(int)} if server is private. If
	 * server is not private the requestID must remain -1.
	 *
     * @param responder The to this compute request corresponding Responder
     * @param algName The algorithm name
     * @param points
     * @param constraints
     * @param acceptsSmile Flag if client accepts Smile
     */
	public ComputeRequest(Responder responder, String algName,
                          RequestPoints points, Map<String, Object> constraints, boolean acceptsSmile) {
		this.algName = algName;
		this.points = points;
		this.resultWays = new ArrayList<Way> (1);
		this.constraints = constraints;
		this.responder = responder;
		this.misc = null;
		this.requestID = -1;
        this.acceptsSmile = acceptsSmile;
	}

	/**
	 * Gets the responder object which is used to send the result to the correct
	 * client connection
	 * 
	 * @return Returns the Responder object
	 */
	public Responder getResponder() {
		return responder;
	}

	/**
	 * Gets the URLSuffix for the requested algorithm e.g. "sp" for a shortest
	 * path algorithm
	 * 
	 * @return Returns the URLSuffix
	 */
	public String getAlgorithmURLSuffix() {
		return algName;
	}

	/**
	 * Returns the Points associated with this request
	 * 
	 * @return
	 */
	public RequestPoints getPoints() {
		return points;
	}

    // TODO rewrite not good readable javadoc. newline must be written with <br />
	/**
	 * Returns the list of Ways making up the result of the computation <br />
     * it's an Algorithms job that after it's computation it contains all <br />
     * the ways connection the Points
	 * 
	 * @return A List with the result ways
	 */
	public List<Way> getResultWays() {
		return resultWays;
	}

	/**
	 * Returns the constraints associated with this request
	 * 
	 * @return A Map representing the constraints
	 */
	public Map<String, Object> getConstraints() {
		return constraints;
	}

	/**
	 * Returns the misc field used to store results, initially this is null
	 * 
	 * @return A Map representing the misc field
	 */
	public Map<String, Object> getMisc() {
		return misc;
	}

    /**
     * Sets the misc field used to store results, initially this is null
     *
     * @param misc A Map representing the misc field
     */
	public void setMisc(Map<String, Object> misc) {
		this.misc = misc;
	}

	/**
	 * Sets the requestID. The requestID must be -1 if server is not in private
	 * mode. If the requestID is not explicitly set, it is -1. <br /> This
	 * attribute should cointain the requestID of the corresponding
	 * RequestDataset within the database. Must be set after construction of the
	 * ComputeRequest object if server is in private mode.
	 *
     * @param requestID The requestID to set
     */
	public void setRequestID(int requestID) {
		this.requestID = requestID;
	}

	/**
	 * Gets the requestID, should be -1 if server is not in private mode. This
	 * attribute should contain the requestID of the corresponding
	 * RequestDataset within the database.
	 * 
	 * @return Returns the requestID
	 */
	public int getRequestID() {
		return this.requestID;
	}

    /**
     * Returns if request was constructed in private or public mode
     * @return true if request was constructed in private mode
     */
    public boolean isPrivate() {
        return requestID != -1;
    }

    /**
     * Returns if request comes from a client accepting "application/x-jackson-smile"
     * @return Returns if client is accepting smile
     */
    public boolean isAcceptsSmile() {
        return acceptsSmile;
    }

	/**
	 * Writes a json representation of the result of this request to the given
	 * stream
	 * 
	 * @param mapper Jackson ObjectMapper
	 * @param stream OutputStream
	 * @throws JsonGenerationException Thrown if generating json fails
     * @throws JsonProcessingException Thrown if json generation processing fails
     * @throws IOException Thrown if writing json onto the stream fails
	 */
	public void writeToStream(ObjectMapper mapper, OutputStream stream) throws IOException {

		JsonGenerator gen = mapper.getJsonFactory().createJsonGenerator(stream);
		Map<String, Object> pconsts;

		gen.setCodec(mapper);
		gen.writeStartObject();

        gen.writeObjectField("constraints", this.getConstraints());

		gen.writeArrayFieldStart("points");
		RequestPoints points = this.getPoints();
		for (int i = 0; i < points.size(); i++) {
			pconsts = points.getConstraints(i);
			gen.writeStartObject();
			gen.writeNumberField("lt", points.getPointLat(i));
			gen.writeNumberField("ln", points.getPointLon(i));
			if (pconsts != null) {
				for (Entry<String, Object> entry : pconsts.entrySet()) {
					gen.writeObjectField(entry.getKey(), entry.getValue());
				}
			}
			gen.writeEndObject();
		}
		gen.writeEndArray();

		gen.writeArrayFieldStart("way");
        for(Way way : this.getResultWays()){
            gen.writeStartArray();
            for (int i = 0; i < way.size(); i++) {
                gen.writeStartObject();
                gen.writeNumberField("lt", way.getPointLat(i));
                gen.writeNumberField("ln", way.getPointLon(i));
                gen.writeEndObject();
            }
            gen.writeEndArray();
        }
		gen.writeEndArray();
		gen.writeObjectField("misc", this.getMisc());
		gen.writeEndObject();
		gen.close();
	}
}

@@ -5234,16 +5234,88 @@
 ject();%0A
+        gen.writeNumberField(%22requestid%22, this.getRequestID());%0A        
 %0A       

Write RequestId to Responses