package ca.cumulonimbus.pressurenetsdk;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Date;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Messenger;
import android.provider.Settings.Secure;


/**
 * Securely send collected data to servers.
 * 
 * @author jacob
 *
 */

public class CbBatchSender  extends AsyncTask<CbObservation, Integer, String> {

	private String responseText = "";
	private CbLocationManager locationManager;
	
	private CbSettingsHandler settings;
	
	private Messenger messenger = null;
	
	private Context context;
	private String mAppDir;
	private boolean userSent;
	
	public CbBatchSender(Context ctx) {
		this.context = ctx;
		setUpFiles();
	}
	
	public CbSettingsHandler getSettings() {
		return settings;
	}
	public void setSettings(CbSettingsHandler settings, CbLocationManager locationManager, Messenger notifyMessenger, boolean fromUser) {
		this.settings = settings;
		this.locationManager = locationManager;
		this.messenger = notifyMessenger;
		this.userSent = fromUser;
	}

	 private void returnResult(String result, String condition, long time, double pressure) {
    	boolean success = true;
    	String errorMessage = "";
    	try {
    		JSONObject jsonResult = new JSONObject(result);
    		if(jsonResult.has("success")) {
    			success = jsonResult.getBoolean("success");
    		}
    		if(jsonResult.has("errors")) {
    			if(jsonResult.getString("errors").length()> 1) {
    				errorMessage = "error" + jsonResult.getString("errors");
    				log("add errormessage " + errorMessage);
    			}
    		}
    		// notify
			long now = System.currentTimeMillis();
			if(now - time > 1000 * 10) {
				log("cbdatasender not notifying, time too long " + (now - time));
			} else {
				log("cbdatasender notifying, time " + (now - time));
				if(userSent) {
	    			log("cbdatasender notifying result of data submission");
	    			if(condition.length()>1) {
	    				errorMessage = condition;
	    				Intent intent = new Intent();
						intent.setAction(CbService.CONDITION_SENT_TOAST);
						intent.putExtra("ca.cumulonimbus.pressurenetsdk.conditionSent", condition);
						context.sendBroadcast(intent);
	    			} else {
	    				Intent intent = new Intent();
						intent.setAction(CbService.PRESSURE_SENT_TOAST);
						intent.putExtra("ca.cumulonimbus.pressurenetsdk.pressureSent", pressure);
						context.sendBroadcast(intent);
	    			}
	    			
    				userSent = false;
				} else {
					log("cbdatasender not notifying result");
				}
			
			}
			
    		
    	} catch(JSONException jsone) {
    		log("error " + result);
    		jsone.printStackTrace();
    	}
	}
	
	@Override
	protected String doInBackground(CbObservation... allObs) {
		log("cb batch send do in bg");
		DefaultHttpClient client = new DefaultHttpClient();
		try {
			
			 JSONObject data = new JSONObject();
			 JSONArray jsonArray = new JSONArray();
		

			 log("cb batchdata looping through obs");
			 JSONObject object = new JSONObject();
			 for(CbObservation ob : allObs) {
				 
				 if(ob == null) {
					 log("cb batch data encountered null observation, bailing");
					 continue;
				 }
				 
				 String[] params = ob.getObservationAsParams();
				 log("cbbatch object param size " + params.length);
				 
				 for(String singleParam : params) {
					String[] fromCSV = singleParam.split(",");
					String key = fromCSV[0];
					String value = fromCSV[1];
					// TODO: fix hack. put any lost commas back.
					if(fromCSV.length > 2) {
						for(int i = 2; i < fromCSV.length; i++) {
							value += "," + fromCSV[i];
						}
					}
				
				    try {
					  object.put(key, value);
					  log("POST batch adding " + key + ", " + value + " to json");
					  
			        } catch (Exception ex) {
			        	log("cb batch sender exception " + ex.getMessage());
			        }
		
				} 
				 
				jsonArray.put(object);
				 
			 }
			
			String serverURL = CbConfiguration.SERVER_URL_SECONDARY; //settings.getServerURL();
			log("settings url " + serverURL);
			
	
			try {
				
				data.put("data", jsonArray);
				data.put("source", "pressurenet");
				data.put("user_id", getID());
			}catch(JSONException jsone) {
				log("json error " + jsone.getMessage());
			}
		
		
			
			HttpPost httppost = new HttpPost(serverURL);
			//httppost.setEntity(new UrlEncodedFormEntity(nvps));
			String message;
			 
			try {
		        message = data.toString();
			  
			  httppost.setEntity(new StringEntity(message, "UTF8"));
			  httppost.setHeader("Content-type", "application/json");
			  httppost.addHeader("Accept","application/json");
			} catch(Exception e) {
				
			}
			
			log("POST Secondary: " + EntityUtils.toString(httppost.getEntity()));

			
			HttpResponse resp = client.execute(httppost);
			HttpEntity responseEntity = resp.getEntity();

			String addResp = "";
			BufferedReader r = new BufferedReader(new InputStreamReader(
					responseEntity.getContent()));

			StringBuilder total = new StringBuilder();
			String line;
			if (r != null) {
				while ((line = r.readLine()) != null) {
					total.append(line);
				}
				addResp = total.toString();
			///	dataCollector.stopCollectingData();
				
			}
			log("addresp Secondary " + addResp);
			
			
		} catch(ClientProtocolException cpe) {
			cpe.printStackTrace();
		} catch(IOException ioe) {
			ioe.printStackTrace();
		} catch(ArrayIndexOutOfBoundsException aioobe) {
			aioobe.printStackTrace();
		}
		log("responsetext" + responseText);
		return responseText;
	}
	
	/**
	 * Get a hash'd device ID
	 * 
	 * @return
	 */
	public String getID() {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");

			String actual_id = Secure.getString(context
					.getContentResolver(), Secure.ANDROID_ID);
			byte[] bytes = actual_id.getBytes();
			byte[] digest = md.digest(bytes);
			StringBuffer hexString = new StringBuffer();
			for (int i = 0; i < digest.length; i++) {
				hexString.append(Integer.toHexString(0xFF & digest[i]));
			}
			return hexString.toString();
		} catch (Exception e) {
			return "--";
		}
	}
	
	public void log(String message) {
		if(CbConfiguration.DEBUG_MODE) {
			//logToFile(message);
			System.out.println(message);
		}
	}
	
    /**
     * Prepare to write a log to SD card. Not used unless logging enabled.
     */
    public void setUpFiles() {
    	try {
	    	File homeDirectory = context.getExternalFilesDir(null);
	    	if(homeDirectory!=null) {
	    		mAppDir = homeDirectory.getAbsolutePath();
	    	}
    	} catch (Exception e) {
    		//e.printStackTrace();
    	}
    }

   
    
	@Override
	protected void onPostExecute(String result) {
		if(locationManager!=null) {
			locationManager.stopGettingLocations();
		}
		super.onPostExecute(result);
	}
	
	/**
	 * Log data to SD card for debug purposes.
	 * To enable logging, ensure the Manifest allows writing to SD card.
	 * @param text
	 */
	public void logToFile(String text) {
		try {
			OutputStream output = new FileOutputStream(mAppDir + "/log.txt", true);
			String logString = (new Date()).toString() + ": " + text + "\n";
			output.write(logString.getBytes());
			output.close();
		} catch(FileNotFoundException e) {
			//e.printStackTrace();
		} catch(IOException ioe) {
			//ioe.printStackTrace();
		}
	}
	
}