package edu.ucla.cens.awserver.service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;
import org.json.JSONArray;

import edu.ucla.cens.awserver.datatransfer.AwRequest;
import edu.ucla.cens.awserver.util.JsonUtils;

/**
 * Service for logging details about data uploads.
 * 
 * @author selsky
 */
public class MessageLoggerService implements Service {
	private static Logger _uploadLogger = Logger.getLogger("uploadLogger");
	private static Logger _logger = Logger.getLogger(MessageLoggerService.class);
	
	/**
	 * Performs the following tasks: logs the user's upload to the filesystem, logs the failed response message to the filesystem
	 * (if the request failed), and logs a statistic message to the upload logger. 
	 */
	public void execute(AwRequest awRequest) {
		_logger.info("beginning to log files and stats about a device upload");
		logUploadToFilesystem(awRequest);
		logUploadStats(awRequest);
		_logger.info("finished with logging files and stats about a device upload");
	}
	
	private void logUploadStats(AwRequest awRequest) {
		JSONArray jsonArray = (JSONArray) awRequest.getAttribute("jsonData");
		List<Integer> duplicateIndexList = (List<Integer>) awRequest.getAttribute("duplicateIndexList");
		
		int totalNumberOfMessages = jsonArray.length();
		int numberOfDuplicates = 0;
		if(null != duplicateIndexList && duplicateIndexList.size() > 0) {
			numberOfDuplicates = duplicateIndexList.size(); 
		}
				
		long processingTime = System.currentTimeMillis() - (Long) awRequest.getAttribute("startTime");
		
		StringBuilder builder = new StringBuilder();
		
		if( awRequest.isFailedRequest()) {
			builder.append("failed_upload");
		} else {
			builder.append("successful_upload");
		}
		
		builder.append(" user=" + awRequest.getUser().getUserName());
		builder.append(" requestType=" + (String) awRequest.getAttribute("requestType"));
		builder.append(" numberOfRecords=" + totalNumberOfMessages);
		builder.append(" numberOfDuplicates=" + numberOfDuplicates);
		builder.append(" proccessingTimeMillis=" + processingTime);
		
		_uploadLogger.info(builder.toString());
	}

	private void logUploadToFilesystem(AwRequest awRequest) {
		// Persist the devices's upload to the filesystem 		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		String fileName = awRequest.getUser().getUserName() + "-" + sdf.format(new Date());
		String catalinaBase = System.getProperty("catalina.base"); // need a system prop called upload-logging-directory or something like that

		JSONArray jsonArray = (JSONArray) awRequest.getAttribute("jsonData");
		
		try {
			PrintWriter printWriter = new PrintWriter(new BufferedWriter(new FileWriter(new File(catalinaBase + "/uploads/" + fileName  + "-upload.json")))); 
			printWriter.write(jsonArray.toString());
			close(printWriter);
		
			if(awRequest.isFailedRequest()) {
				
				printWriter = new PrintWriter(new BufferedWriter(new FileWriter(new File(catalinaBase + "/uploads/" + fileName  + "-upload-response.json")))); 
				printWriter.write(awRequest.getFailedRequestErrorMessage());
				close(printWriter);
			}
			
			List<Integer> duplicateIndexList = (List<Integer>) awRequest.getAttribute("duplicateIndexList");
			if(null != duplicateIndexList && duplicateIndexList.size() > 0) {
				
				printWriter = new PrintWriter(new BufferedWriter(new FileWriter(new File(catalinaBase + "/uploads/" + fileName  + "-upload-duplicates.json"))));
				
				for(Integer index : duplicateIndexList) {
					printWriter.write(JsonUtils.getJsonObjectFromJsonArray(jsonArray, index).toString());
				}
				
				close(printWriter);
			}
		}
		catch(IOException ioe) {
	
			_logger.warn("caught IOException when logger upload data to the filesystem. " + ioe.getMessage());
			throw new ServiceException(ioe);
		}
	}

	private void close(PrintWriter writer) throws IOException {
		writer.flush();
		writer.close();
		writer = null;	
	}
}

@@ -1245,78 +1245,257 @@
 %7B%0A%09%09
-JSONArray jsonArray = (JSONArray) awRequest.getAttribute(%22jsonData%22);%0A
+Object data = awRequest.getAttribute(%22jsonData%22);%0A%09%09String totalNumberOfMessages = %22unknown%22;%0A%09%09String numberOfDuplicates = %22unknown%22;%0A%09%09%0A%09%09if(data instanceof JSONArray) %7B%0A%09%09%09totalNumberOfMessages = String.valueOf(((JSONArray) data).length());%0A%09%09%09%0A%09
 %09%09Li
@@ -1595,89 +1595,11 @@
 ;%0A%09%09
+%09
 %0A%09
-%09int totalNumberOfMessages = jsonArray.length();%0A%09%09int numberOfDuplicates = 0;%0A
 %09%09if
@@ -1665,16 +1665,17 @@
 0) %7B%0A%09%09%09
+%09
 numberOf
@@ -1687,16 +1687,31 @@
 cates = 
+String.valueOf(
 duplicat
@@ -1731,17 +1731,64 @@
 ze()
+)
 ; %0A
+%09%09%09%7D else %7B%0A%09%09%09%09numberOfDuplicates = %220%22;%0A%09
 %09%09%7D%0A%09%09
+%7D%09%0A
 %09%09%0A%09
@@ -1941,17 +1941,16 @@
 %09%09%0A%09%09if(
- 
 awReques
@@ -2447,16 +2447,19 @@
 ing());%0A
+%09%09%0A
 %09%7D%0A%0A%09pri
@@ -2864,44 +2864,26 @@
 hat%0A
+%09%09
 %0A%09%09
-JSONArray jsonArray = (JSONArray)
+Object data =
  awR
@@ -2914,16 +2914,171 @@
 nData%22);
+ // could either be a String or a JSONArray depending on where the main%0A%09%09                                                  // application processing ended
 %0A%09%09%0A%09%09tr
@@ -3225,25 +3225,24 @@
 d.json%22))));
- 
 %0A%09%09%09printWri
@@ -3251,25 +3251,20 @@
 r.write(
-jsonArray
+data
 .toStrin
@@ -3453,24 +3453,31 @@
 leName  + %22-
+failed-
 upload-respo
@@ -4028,17 +4028,24 @@
 ray(
-jsonArray
+(JSONArray) data
 , in
@@ -4180,18 +4180,19 @@
 hen logg
-er
+ing
  upload 

put logic in place to handle logging for uploads that fail anywhere during app processing