/**
 * 
 */
package com.amazonaws.lambda.pentahoreporting;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectResult;

/**
 * @author Jaret
 *
 */
public class PentahoReportHandlerBase {
	protected static final String PARM_REPORT = "prpt_file";
	protected static final String PARM_OUTPUT_TYPE = "output_type";
	protected static final String PARM_OUTPUT_BUCKET = "output_s3_bucket";
	protected static final String PARM_OUTPUT_KEY = "output_file";
	protected static final String PARM_S3_BUCKET = "prpt_s3_bucket";
	protected static final String PROP_PRPT = "prpt";
	protected static final String PROP_DATA_DRIVER = "dataDriver";
	protected static final String PROP_DATA_URL = "dataUrl";
	protected static final String PROP_DATA_USER = "dataUser";
	protected static final String PROP_DATA_PASSWORD = "dataPassword";
	protected static final String PROP_DATA_QUERY = "dataQuery";
	protected static final String PARM_OUTPUT_TYPE_PDF = "pdf";
	protected static final String PARM_OUTPUT_TYPE_EXCEL = "excel";
	protected static final String PARM_OUTPUT_TYPE_HTML = "html";
	protected static final String RESPONSE_TEMPLATE = "{\n"
		    + "    \"isBase64Encoded\": false,\n"
		    + "    \"statusCode\": %d,\n"
		    + "    \"headers\": { \"Content-Type\": \"application/json\" },\n"
		    + "    \"body\": \"%s\"\n"
		    + "}";
	
	protected PutObjectResult putS3Object(String bucketName, String key, InputStream inputStream) {
		// Read out the stream to get the content length which is required by S3
		// WARNING: This could cause OOM errors if not enough memory is allocated to the lambda
		// function
		try {
			byte[] inputBytes = IOUtils.toByteArray(inputStream);
			return putS3Object(bucketName, key, new ByteArrayInputStream(inputBytes), inputBytes.length);
		} catch (IOException e) {
			System.out.println("Caught an Exception while determining the size of the file to upload to S3.");
			System.out.println("Error Message: " + e.getMessage());
		}
		return null;
	}
	
	protected PutObjectResult putS3Object(String bucketName, String key, InputStream inputStream, long contentLength) {
		AmazonS3 s3Client = AmazonS3Client.builder().build();
		try {
			System.out.println("Uploading an object");
			ObjectMetadata omd = new ObjectMetadata();
			return s3Client.putObject(bucketName, key, inputStream, omd);
		} catch (AmazonServiceException ase) {
			System.out.println("Caught an AmazonServiceException, which" + " means your request made it "
					+ "to Amazon S3, but was rejected with an error response" + " for some reason.");
			System.out.println("Error Message:    " + ase.getMessage());
			System.out.println("HTTP Status Code: " + ase.getStatusCode());
			System.out.println("AWS Error Code:   " + ase.getErrorCode());
			System.out.println("Error Type:       " + ase.getErrorType());
			System.out.println("Request ID:       " + ase.getRequestId());
		} catch (AmazonClientException ace) {
			System.out.println("Caught an AmazonClientException, which means" + " the client encountered "
					+ "an internal error while trying to " + "communicate with S3, "
					+ "such as not being able to access the network.");
			System.out.println("Error Message: " + ace.getMessage());
		}
		return null;
	}

    protected Map<String, Object> parseParameters(String input) throws IOException, ParseException {
    	Map<String, Object> out = new HashMap<String, Object>();

    	JSONParser parser = new JSONParser();

        JSONObject event = (JSONObject)parser.parse(input);
        if (event.get("queryStringParameters") != null) {
            JSONObject qps = (JSONObject)event.get("queryStringParameters");
            for (Object key : qps.keySet()) {
        		out.put((String) key, (String)qps.get(key));
            }
        }

        if (event.get("pathParameters") != null) {
            JSONObject pps = (JSONObject)event.get("pathParameters");
            for (Object key : pps.keySet()) {
            	out.put((String) key, (String)pps.get(key));
            }
        }

        // TODO raw json request
    	return out;
    }
}

@@ -3846,16 +3846,96 @@
 ption %7B%0A
+    %09System.out.println(String.format(%22parseParameters: input = '%25s'%22, input));%0A
     %09Map
@@ -3994,16 +3994,22 @@
 ;%0A%0A    %09
+final 
 JSONPars
@@ -4038,24 +4038,26 @@
 rser();%0A
-%0A   
     
+%09final
  JSONObj
@@ -4101,16 +4101,17 @@
 input);%0A
+%0A
         
@@ -4627,13 +4627,8 @@
   //
- TODO
  raw
@@ -4640,16 +4640,388 @@
  request
+ from body - trumps others%0A        final Object bodyObject = event.get(%22body%22);%0A        if(bodyObject != null) %7B%0A        %09final String bodyString = (String) bodyObject;%0A        %09final JSONObject bodyJO = (JSONObject)parser.parse(bodyString);%0A        %09for(final Object key : bodyJO.keySet()) %7B%0A        %09%09out.put((String) key, (String)bodyJO.get(key));%0A        %09%7D%0A        %7D%0A
 %0A    %09re

Add support for raw JSON request body