package ca.cumulonimbus.barometernetwork;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.HashMap;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.os.Handler;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.widget.Toast;
import ca.cumulonimbus.pressurenetsdk.CbCurrentCondition;
import ca.cumulonimbus.pressurenetsdk.CbForecastAlert;
import ca.cumulonimbus.pressurenetsdk.CbScience;
import ca.cumulonimbus.pressurenetsdk.CbService;

import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import com.mixpanel.android.mpmetrics.MixpanelAPI;

public class NotificationSender extends BroadcastReceiver {

	Context mContext;
	public static final int PRESSURE_NOTIFICATION_ID  = 101325;
	public static final int CONDITION_NOTIFICATION_ID = 100012;
	public static final int ALERT_NOTIFICATION_ID = 100013;
	
	private long lastNearbyConditionReportNotification = System.currentTimeMillis() 
			- (1000 * 60 * 60);
	private long lastConditionsSubmit = System.currentTimeMillis() 
			- (1000 * 60 * 60 * 4);
	
	Handler notificationHandler = new Handler();
	
	MixpanelAPI mixpanel;
	

	/**
	 * Enum used to identify the tracker that needs to be used for tracking.
	 *
	 * A single tracker is usually enough for most purposes. In case you do need multiple trackers,
	 * storing them all in Application object helps ensure that they are created only once per
	 * application instance.
	 */
	public enum TrackerName {
	  APP_TRACKER, // Tracker used only in this app.
	  GLOBAL_TRACKER, // Tracker used by all the apps from a company. eg: roll-up tracking.

	}

	HashMap<TrackerName, Tracker> mTrackers = new HashMap<TrackerName, Tracker>();
	
	synchronized Tracker getTracker(TrackerName trackerId) {
		  if (!mTrackers.containsKey(trackerId)) {

		    GoogleAnalytics analytics = GoogleAnalytics.getInstance(mContext);
		    Tracker t = (trackerId == TrackerName.APP_TRACKER) ? analytics.newTracker(PressureNETConfiguration.GA_TOKEN)
		        : (trackerId == TrackerName.GLOBAL_TRACKER) ? analytics.newTracker(R.xml.global_tracker)
		            : analytics.newTracker(R.xml.global_tracker);
		    mTrackers.put(trackerId, t);

		  }
		  return mTrackers.get(trackerId);
		}
	
	public NotificationSender() {
		super();
	}
	
	public class NotificationCanceler implements Runnable {

		Context cancelContext;
		int id;
		
		public NotificationCanceler (Context context, int notID) {
			cancelContext = context;
			id = notID;
		}
		
		@Override
		public void run() {
			 if (cancelContext!=null) {
				 String ns = Context.NOTIFICATION_SERVICE;
				 NotificationManager nMgr = (NotificationManager) cancelContext.getSystemService(ns);
				 nMgr.cancel(id);
			 }
		}
		
	}
	
	@Override
	public void onReceive(Context context, Intent intent) {
		mContext = context;
		mixpanel = MixpanelAPI.getInstance(context, PressureNETConfiguration.MIXPANEL_TOKEN);
		if(intent.getAction().equals(CbService.LOCAL_CONDITIONS_ALERT)) {
			log("app received intent local conditions alert");
			// potentially notify about nearby conditions
			SharedPreferences sharedPreferences = PreferenceManager
					.getDefaultSharedPreferences(mContext);
			boolean isOkayToDeliver = sharedPreferences.getBoolean("send_condition_notifications", false);
			if(isOkayToDeliver) {
				try { 
					if(intent.hasExtra("ca.cumulonimbus.pressurenetsdk.conditionNotification")) {
						CbCurrentCondition receivedCondition = (CbCurrentCondition) intent.getSerializableExtra("ca.cumulonimbus.pressurenetsdk.conditionNotification");
						if(receivedCondition != null) {
							if(receivedCondition.getLocation()==null) {
								Location loc = new Location("network");
								loc.setLatitude(receivedCondition.getLat());
								loc.setLongitude(receivedCondition.getLon());
								receivedCondition.setLocation(loc);
							}

							deliverConditionNotification(receivedCondition);
							
						}
					} else {
						log("local conditions intent not sent, doesn't have extra");
					}
				} catch(RuntimeException re) {
					log("notificationsender runtime exception " + re.getMessage());
				}
			} else {
				log("not delivering conditions notification, disabled in prefs");
			}
			
		} else if(intent.getAction().equals(CbService.WEATHER_FORECAST_ALERT)) {
			log("app received intent weather forecast alert");
			// potentially notify about weather forecasts
			SharedPreferences sharedPreferences = PreferenceManager
					.getDefaultSharedPreferences(mContext);

				CbForecastAlert alert = (CbForecastAlert) intent.getSerializableExtra("ca.cumulonimbus.pressurenetsdk.alertNotification");
				CbCurrentCondition condition = (CbCurrentCondition) intent.getSerializableExtra("ca.cumulonimbus.pressurenetsdk.alertNotificationCondition");
				if(alert != null) {

					if(condition != null) {
						log("notificationsender alert condition is good, assigning a location");
						Location loc = new Location("network");
						LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
						Location location = lm
								.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
						loc.setLatitude(condition.getLat());
						loc.setLongitude(condition.getLon());
						condition.setLocation(loc);
						alert.setCondition(condition);

						Calendar cal = Calendar.getInstance();
						condition.setTzoffset(cal.getTimeZone().getRawOffset());


						alert.setCondition(condition);

						log("delivering weather forecast alert");
						boolean isOkayToDeliver = sharedPreferences.getBoolean("send_condition_notifications", false);
						if(isOkayToDeliver) {
							log("notification sender delivering forecast alert, permission granted");
							deliverAlertNotification(alert);
						} else {
							log("notification sender NOT delivering forecast alert, permission denied");
						}
					} else {
						log("notificationsender not sending alert, condition is null");
					}
				}
			
		} else if(intent.getAction().equals(CbService.PRESSURE_CHANGE_ALERT)) {
			log("app received intent pressure change alert");
			if(intent.hasExtra("ca.cumulonimbus.pressurenetsdk.tendencyChange")) {
				String tendencyChange = intent.getStringExtra("ca.cumulonimbus.pressurenetsdk.tendencyChange");
				deliverNotification(tendencyChange);
				
			} else {
				log("pressure change intent not sent, doesn't have extra");
			}
			
		} else if(intent.getAction().equals(CbService.PRESSURE_SENT_TOAST)) {
			log("app received intent pressure sent toast");
			if(intent.hasExtra("ca.cumulonimbus.pressurenetsdk.pressureSent")) {
				double pressureSent = intent.getDoubleExtra("ca.cumulonimbus.pressurenetsdk.pressureSent", 0.0);
				// Toast.makeText(context, "Sent " + displayPressureValue(pressureSent), Toast.LENGTH_SHORT).show();
			} else {
				log("pressure sent intent not sent, doesn't have extra");
			}
			
		} else if(intent.getAction().equals(CbService.CONDITION_SENT_TOAST)) {
			log("app received intent pressure sent toast");
			if(intent.hasExtra("ca.cumulonimbus.pressurenetsdk.conditionSent")) {
				String conditionSent = intent.getStringExtra("ca.cumulonimbus.pressurenetsdk.conditionSent");
				Toast.makeText(context, "Sent " + conditionSent, Toast.LENGTH_SHORT).show();
			} else {
				log("condition sent intent not sent, doesn't have extra");
			}
			
		} else if(intent.getAction().equals("ca.cumulonimbus.barometernetwork.CANCEL_CONDITION")) {
			log("app notificationsender receiving condition cancel");
			NotificationCanceler cancel = new NotificationCanceler(mContext, CONDITION_NOTIFICATION_ID);
			notificationHandler.post(cancel);
						
    	} else if(intent.getAction().equals("ca.cumulonimbus.barometernetwork.CANCEL_PRESSURE")) {
    		log("app notificationsender receiving pressure cancel");
			NotificationCanceler cancel = new NotificationCanceler(mContext, PRESSURE_NOTIFICATION_ID);
			notificationHandler.post(cancel);
    					
    	} else if(intent.getAction().equals("ca.cumulonimbus.barometernetwork.CANCEL_ALERT")) {
			log("app notificationsender receiving alert cancel");
			NotificationCanceler cancel = new NotificationCanceler(mContext, ALERT_NOTIFICATION_ID);
			notificationHandler.post(cancel);
						
    	} 
		
		else {
			log("no matching code for " + intent.getAction());
		}	
	}

	/**
	 * Check the Android SharedPreferences for important values. Save relevant
	 * ones to CbSettings for easy access in submitting readings
	 */
	public String getUnitPreference() {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(mContext);
		return sharedPreferences.getString("units", "millibars");
	}
	
	private String displayPressureValue(double value) {
		String preferencePressureUnit = getUnitPreference();
		DecimalFormat df = new DecimalFormat("####.0");
		PressureUnit unit = new PressureUnit(preferencePressureUnit);
		unit.setValue(value);
		unit.setAbbreviation(preferencePressureUnit);
		double pressureInPreferredUnit = unit.convertToPreferredUnit();
		return df.format(pressureInPreferredUnit) + " " + unit.fullToAbbrev();
	}
	
	public boolean wasRecentlyDelivered(CbCurrentCondition condition) {
		PnDb pn = new PnDb(mContext);
		pn.open();
		Cursor recentDeliveries = pn.fetchRecentDeliveries();
		boolean delivered = false;
		while(recentDeliveries.moveToNext()) {
			String general = recentDeliveries.getString(1);
			if(condition.getGeneral_condition().equals(general)) {
				log("notification recently delivered: " + general);
				delivered = true;
			}
		}
		pn.close();
		
		return delivered;
	}
	
	/**
	 * Send an Android notification to the user about 
	 * weather forecast details
	 *
	 */
	private void deliverAlertNotification(CbForecastAlert alert) {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(mContext);

		CbCurrentCondition condition = alert.getCondition();
		
		long now = System.currentTimeMillis();
		
		// feed it with the initial condition
		// clear, fog, cloud, precip, thunderstorm
		String initial = "";
		int icon = R.drawable.ic_launcher;
		String politeReportText = condition.getGeneral_condition();
		if(condition.getGeneral_condition().equals(mContext.getString(R.string.sunny))) {
			initial = "clear";
			// pick the right clear icon
			icon = getResIdForClearIcon(condition);
			// vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.foggy))) {
			initial = "fog";
			icon = R.drawable.ic_wea_on_fog1;
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.cloudy))) {
			// don't notify on cloudy
			
			initial = "cloud";
			icon = R.drawable.ic_wea_on_cloud;
			
			if(condition.getCloud_type().equals(mContext.getString(R.string.partly_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy1;
				politeReportText = mContext.getString(R.string.partly_cloudy);
			} else if(condition.getCloud_type().equals(mContext.getString(R.string.mostly_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy2;
				politeReportText = mContext.getString(R.string.mostly_cloudy);
			} else if(condition.getCloud_type().equals(mContext.getString(R.string.very_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy;
				politeReportText = mContext.getString(R.string.very_cloudy);
			} else {
				icon = R.drawable.ic_wea_on_cloud;
			}
			
			// vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.precipitation))) {
			
			if(condition.getPrecipitation_type().equals(mContext.getString(R.string.rain))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_rain1;
					politeReportText = mContext.getString(R.string.lightRain);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_rain2;
					politeReportText = mContext.getString(R.string.moderateRain);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_rain3;
					politeReportText = mContext.getString(R.string.heavyRain);
					break;
				default:
					icon = R.drawable.ic_wea_on_rain1;
					politeReportText = mContext.getString(R.string.rain);
				}
			} else if (condition.getPrecipitation_type().equals(mContext.getString(R.string.snow))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_snow1;
					politeReportText = mContext.getString(R.string.lightSnow);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_snow2;
					politeReportText = mContext.getString(R.string.moderateSnow);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_snow3;
					politeReportText = mContext.getString(R.string.heavySnow);
					break;
				default:
					icon = R.drawable.ic_wea_on_snow1;
					politeReportText = mContext.getString(R.string.snow);
				}
			} else if (condition.getPrecipitation_type().equals(mContext.getString(R.string.hail))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_hail1;
					politeReportText = mContext.getString(R.string.lightHail);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_hail2;
					politeReportText = mContext.getString(R.string.moderateHail);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_hail3;;
					politeReportText = mContext.getString(R.string.heavyHail);
					break;
				default:
					icon = R.drawable.ic_wea_on_hail1;
					politeReportText = mContext.getString(R.string.hail);
				}
			} else {
				icon = R.drawable.ic_wea_on_precip;
			}
			
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.thunderstorm))) {
			initial = "thunderstorm";
			icon = R.drawable.ic_wea_on_lightning2;
			
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.extreme))) {
			initial = "severe";
			icon = R.drawable.ic_wea_on_severe;
			
			if(condition.getUser_comment().equals(mContext.getString(R.string.flooding))) {
				icon = R.drawable.ic_wea_on_flooding;
				politeReportText = mContext.getString(R.string.flooding);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.wildfire))) {
				icon = R.drawable.ic_wea_on_fire;
				politeReportText = mContext.getString(R.string.wildfire);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.tornado))) {
				icon = R.drawable.ic_wea_on_tornado;
				politeReportText = mContext.getString(R.string.tornado);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.duststorm))) {
				icon = R.drawable.ic_wea_on_dust;
				politeReportText = mContext.getString(R.string.duststorm);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.tropicalstorm))) {
				icon = R.drawable.ic_wea_on_tropical_storm;
				politeReportText = mContext.getString(R.string.tropicalstorm);
			}
		} 
		alert.composeNotificationText();



		// Current Conditions activity likes to know the location in the Intent
		// Also needed for Haversine calculation
		double notificationLatitude = 0.0;
		double notificationLongitude = 0.0;
		try {
			LocationManager lm = (LocationManager) mContext
					.getSystemService(Context.LOCATION_SERVICE);
			Location loc = lm
					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			if (loc.getLatitude() != 0) {
				notificationLatitude = loc.getLatitude();
				notificationLongitude = loc.getLongitude();
			}
		} catch (Exception e) {

		}


		Notification.Builder mBuilder = new Notification.Builder(
				mContext).setSmallIcon(icon)
				.setContentTitle(alert.getNotificationTitle()).setContentText(alert.getNotificationContent());
		// Creates an explicit intent for an activity
		Intent resultIntent = new Intent(mContext,
				CurrentConditionsActivity.class);


		resultIntent.putExtra("latitude", notificationLatitude);
		resultIntent.putExtra("longitude", notificationLongitude);
		resultIntent.putExtra("cancelNotification", true);
		resultIntent.putExtra("initial", initial);
		resultIntent.putExtra("backToApp", true);

		try {
		
			android.support.v4.app.TaskStackBuilder stackBuilder = android.support.v4.app.TaskStackBuilder
					.create(mContext);
	
			stackBuilder.addNextIntent(resultIntent);
			PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
					PendingIntent.FLAG_UPDATE_CURRENT);
			mBuilder.setContentIntent(resultPendingIntent);
			NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
			// mId allows you to update the
			// notification later on.
			mNotificationManager.notify(ALERT_NOTIFICATION_ID, mBuilder.build());
	
			AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
			Intent i = new Intent("ca.cumulonimbus.barometernetwork.CANCEL_ALERT");
			PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
			am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + (1000 * 60 * 60 * 1), pi);
					
			
			// Get tracker.
			Tracker t = getTracker(
			    TrackerName.APP_TRACKER);
			// Build and send an Event.
			t.send(new HitBuilders.EventBuilder()
			    .setCategory(BarometerNetworkActivity.GA_CATEGORY_NOTIFICATIONS)
			    .setAction("forecast_notification_delivered")
			    .setLabel(condition.getGeneral_condition())
			    .build());
			
			try {
				JSONObject props = new JSONObject();
				props.put("Condition", condition.getGeneral_condition());
				mixpanel.track("Forecast Alert Delivered", props);	
			} catch (JSONException jsone) {
				log("forecast notification json exception " + jsone.getMessage());
			}
			
			mixpanel.flush();
			
			// save the time
			SharedPreferences.Editor editor = sharedPreferences.edit();
			editor.putLong("lastConditionTime", now);
			editor.commit();
		} catch(NoSuchMethodError nsme) {
			// 
		}
		
		// Get tracker.
		Tracker t = getTracker(
		    TrackerName.APP_TRACKER);
		// Build and send an Event.
		t.send(new HitBuilders.EventBuilder()
		    .setCategory(BarometerNetworkActivity.GA_CATEGORY_MAIN_APP)
		    .setAction("conditions_notification_delivered_final")
		    .setLabel(condition.getGeneral_condition())
		    .build());
	}
	
	/**
	 * Send an Android notification to the user about nearby users
	 * reporting current conditions.
	 *
	 */
	private void deliverConditionNotification(CbCurrentCondition condition) {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(mContext);

		long now = System.currentTimeMillis();
		// don't deliver if recently interacted with
		lastConditionsSubmit = sharedPreferences.getLong(
				"lastConditionsSubmit", System.currentTimeMillis()
				- (1000 * 60 * 60 * 12));
		
		String prefTimeWait = sharedPreferences.getString("condition_refresh_frequency", "3 hours");
		
		boolean alsoAlertClearCloudy = sharedPreferences.getBoolean("also_alert_clear_cloudy", false);
		
		lastNearbyConditionReportNotification = sharedPreferences.getLong(
				"lastConditionTime", System.currentTimeMillis()
						- (1000 * 60 * 60 * 12));
		
		long waitDiff = CbService.stringTimeToLongHack(prefTimeWait);
		
		boolean isCriticalToDeliver = (condition.getGeneral_condition().equals(mContext.getString(R.string.extreme))) || 
										(condition.getGeneral_condition().equals(mContext.getString(R.string.thunderstorm)));
		
		if(!isCriticalToDeliver) {
			if(now - lastConditionsSubmit < waitDiff) {
				log("bailing on conditions notifications, recently submitted one");
				return;
			}
			if (now - lastNearbyConditionReportNotification < waitDiff) {
				log("bailing on conditions notification, not 1h wait yet");
				return;
			}
		}
		
		if(wasRecentlyDelivered(condition)) {
			return;
		}
		
	
		if(condition.getLocation()!=null) {
			PnDb pn = new PnDb(mContext);
			pn.open();
			pn.addDelivery(condition.getGeneral_condition(), condition.getLocation().getLatitude(), condition.getLocation().getLongitude(), condition.getTime());
			pn.close();
		} else {
			log("condition out for notification has no location, bailing");
			return;
		}
		
		String deliveryMessage = mContext.getString(R.string.conditionPrompt);
		
		// Current Conditions activity likes to know the location in the Intent
		// Also needed for Haversine calculation
		double notificationLatitude = 0.0;
		double notificationLongitude = 0.0;
		try {
			LocationManager lm = (LocationManager) mContext
					.getSystemService(Context.LOCATION_SERVICE);
			Location loc = lm
					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			if (loc.getLatitude() != 0) {
				notificationLatitude = loc.getLatitude();
				notificationLongitude = loc.getLongitude();
			}
		} catch (Exception e) {

		}
		
		log("haversine inputs: " + notificationLatitude + " " + notificationLongitude + " " + condition.getLat() + " " + condition.getLon());
		double distance = CbScience.haversine(notificationLatitude, notificationLongitude, condition.getLat(), condition.getLon());
		
		if(distance > 20000) {
			log("conditiion notification bailing, distance too large, " + distance + "m away");
			return;
		}
		
		double angle = CbScience.angle(notificationLatitude, notificationLongitude, condition.getLat(), condition.getLon());
		// double angle = CbScience.angleEstimate(condition.getLat(), condition.getLon(), notificationLatitude, notificationLongitude);
		log("notification location " + distance + " " + angle);
		
		String vectorString = "nearby";
		
		// feed it with the initial condition
		// clear, fog, cloud, precip, thunderstorm
		String initial = "";
		int icon = R.drawable.ic_launcher;
		String politeReportText = condition.getGeneral_condition();
		if(condition.getGeneral_condition().equals(mContext.getString(R.string.sunny))) {
			// don't notify on clear
			if(!alsoAlertClearCloudy) {
				log("notification sender not sending, condition is clear and pref not set to deliver");
				return;
			} else {
				log("notification sender: condition is clear and pref set to deliver");				
			}
			
			initial = "clear";
			// pick the right clear icon
			icon = getResIdForClearIcon(condition);
			// vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.foggy))) {
			initial = "fog";
			icon = R.drawable.ic_wea_on_fog1;
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.cloudy))) {
			// don't notify on cloudy
			if(!alsoAlertClearCloudy) {
				log("notification sender not sending, condition is cloudy and pref not set to deliver");
				return;
			} else {
				log("notification sender: condition is cloudy and pref set to deliver");				
			}
			
			initial = "cloud";
			icon = R.drawable.ic_wea_on_cloud;
			
			if(condition.getCloud_type().equals(mContext.getString(R.string.partly_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy1;
				politeReportText = mContext.getString(R.string.partly_cloudy);
			} else if(condition.getCloud_type().equals(mContext.getString(R.string.mostly_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy2;
				politeReportText = mContext.getString(R.string.mostly_cloudy);
			} else if(condition.getCloud_type().equals(mContext.getString(R.string.very_cloudy))) {
				icon = R.drawable.ic_wea_on_cloudy;
				politeReportText = mContext.getString(R.string.very_cloudy);
			} else {
				icon = R.drawable.ic_wea_on_cloud;
			}
			
			// vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.precipitation))) {
			initial = "precip";
			vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
			if(condition.getPrecipitation_type().equals(mContext.getString(R.string.rain))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_rain1;
					politeReportText = mContext.getString(R.string.lightRain);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_rain2;
					politeReportText = mContext.getString(R.string.moderateRain);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_rain3;
					politeReportText = mContext.getString(R.string.heavyRain);
					break;
				default:
					icon = R.drawable.ic_wea_on_rain1;
					politeReportText = mContext.getString(R.string.rain);
				}
			} else if (condition.getPrecipitation_type().equals(mContext.getString(R.string.snow))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_snow1;
					politeReportText = mContext.getString(R.string.lightSnow);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_snow2;
					politeReportText = mContext.getString(R.string.moderateSnow);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_snow3;
					politeReportText = mContext.getString(R.string.heavySnow);
					break;
				default:
					icon = R.drawable.ic_wea_on_snow1;
					politeReportText = mContext.getString(R.string.snow);
				}
			} else if (condition.getPrecipitation_type().equals(mContext.getString(R.string.hail))) {
				switch((int)condition.getPrecipitation_amount()) {
				case 0:
					icon = R.drawable.ic_wea_on_hail1;
					politeReportText = mContext.getString(R.string.lightHail);
					break;
				case 1:
					icon = R.drawable.ic_wea_on_hail2;
					politeReportText = mContext.getString(R.string.moderateHail);
					break;
				case 2:
					icon = R.drawable.ic_wea_on_hail3;;
					politeReportText = mContext.getString(R.string.heavyHail);
					break;
				default:
					icon = R.drawable.ic_wea_on_hail1;
					politeReportText = mContext.getString(R.string.hail);
				}
			} else {
				icon = R.drawable.ic_wea_on_precip;
			}
			
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.thunderstorm))) {
			initial = "thunderstorm";
			icon = R.drawable.ic_wea_on_lightning2;
			vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
		} else if(condition.getGeneral_condition().equals(mContext.getString(R.string.extreme))) {
			initial = "severe";
			icon = R.drawable.ic_wea_on_severe;
			vectorString = displayDistance(distance) + " " + CbScience.englishDirection(angle);
			if(condition.getUser_comment().equals(mContext.getString(R.string.flooding))) {
				icon = R.drawable.ic_wea_on_flooding;
				politeReportText = mContext.getString(R.string.flooding);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.wildfire))) {
				icon = R.drawable.ic_wea_on_fire;
				politeReportText = mContext.getString(R.string.wildfire);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.tornado))) {
				icon = R.drawable.ic_wea_on_tornado;
				politeReportText = mContext.getString(R.string.tornado);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.duststorm))) {
				icon = R.drawable.ic_wea_on_dust;
				politeReportText = mContext.getString(R.string.duststorm);
			} else if(condition.getUser_comment().equals(mContext.getString(R.string.tropicalstorm))) {
				icon = R.drawable.ic_wea_on_tropical_storm;
				politeReportText = mContext.getString(R.string.tropicalstorm);
			}
		} 
		
		Notification.Builder mBuilder = new Notification.Builder(
				mContext).setSmallIcon(icon)
				.setContentTitle(politeReportText + " " + vectorString).setContentText(deliveryMessage);
		// Creates an explicit intent for an activity
		Intent resultIntent = new Intent(mContext,
				CurrentConditionsActivity.class);

		
		resultIntent.putExtra("latitude", notificationLatitude);
		resultIntent.putExtra("longitude", notificationLongitude);
		resultIntent.putExtra("cancelNotification", true);
		resultIntent.putExtra("initial", initial);
		resultIntent.putExtra("backToApp", true);

		try {
		
			android.support.v4.app.TaskStackBuilder stackBuilder = android.support.v4.app.TaskStackBuilder
					.create(mContext);
	
			stackBuilder.addNextIntent(resultIntent);
			PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
					PendingIntent.FLAG_UPDATE_CURRENT);
			mBuilder.setContentIntent(resultPendingIntent);
			NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
			// mId allows you to update the
			// notification later on.
			mNotificationManager.notify(CONDITION_NOTIFICATION_ID, mBuilder.build());
	
			AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
			Intent i = new Intent("ca.cumulonimbus.barometernetwork.CANCEL_CONDITION");
			PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
			am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + (1000 * 60 * 60 * 2), pi);
					
			
			// Get tracker.
			Tracker t = getTracker(
			    TrackerName.APP_TRACKER);
			// Build and send an Event.
			t.send(new HitBuilders.EventBuilder()
			    .setCategory(BarometerNetworkActivity.GA_CATEGORY_NOTIFICATIONS)
			    .setAction("conditions_notification_delivered")
			    .setLabel(condition.getGeneral_condition())
			    .build());
			
			try {
				JSONObject props = new JSONObject();
				props.put("Condition", condition.getGeneral_condition());
				mixpanel.track("Notification Delivered", props);	
			} catch (JSONException jsone) {
				log("condition notification json exception " + jsone.getMessage());
			}
			
			mixpanel.flush();
			
			// save the time
			SharedPreferences.Editor editor = sharedPreferences.edit();
			editor.putLong("lastConditionTime", now);
			editor.commit();
		} catch(NoSuchMethodError nsme) {
			// 
		}
		
		// Get tracker.
		Tracker t = getTracker(
		    TrackerName.APP_TRACKER);
		// Build and send an Event.
		t.send(new HitBuilders.EventBuilder()
		    .setCategory(BarometerNetworkActivity.GA_CATEGORY_MAIN_APP)
		    .setAction("conditions_notification_delivered_final")
		    .setLabel(condition.getGeneral_condition())
		    .build());
	}
	
	private String displayDistance(double distance) {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(mContext);
		String preferredDistanceUnit = sharedPreferences.getString("distance_units", "Kilometers (km)");
		
		// Use km instead of m, even if preference is m
		if (preferredDistanceUnit.equals("Meters (m)")) {
			preferredDistanceUnit = "Kilometers (km)";
		}
		
		// Use mi instead of ft, even if preference is ft
		if (preferredDistanceUnit.equals("Feet (ft)")) {
			preferredDistanceUnit = "Miles (mi)";
		}
		
		DecimalFormat df = new DecimalFormat("##");
		DistanceUnit unit = new DistanceUnit(preferredDistanceUnit);
		unit.setValue(distance);
		unit.setAbbreviation(preferredDistanceUnit);
		double distanceInPreferredUnit = unit.convertToPreferredUnit();
		return df.format(distanceInPreferredUnit) + unit.fullToAbbrev();
	}
	
	
	/**
	 * Send an Android notification to the user with a notice of pressure
	 * tendency change.
	 * 
	 * @param tendencyChange
	 */
	private void deliverNotification(String tendencyChange) {
		SharedPreferences sharedPreferences = PreferenceManager
				.getDefaultSharedPreferences(mContext);

		long lastNotificationTime = sharedPreferences.getLong(
				"lastNotificationTime", System.currentTimeMillis()
						- (1000 * 60 * 60 * 10));
		long now = System.currentTimeMillis();
		long waitDiff = 1000 * 60 * 60 * 6;
		if (now - lastNotificationTime < waitDiff) {
			log("bailing on notification, not 6h wait yet");
			return;
		}

		String deliveryMessage = "";
		if (!tendencyChange.contains(",")) {
			// not returning to directional values? don't deliver notification
			return;
		}

		String first = tendencyChange.split(",")[0];
		String second = tendencyChange.split(",")[1];
		
		int smallIconId = R.drawable.ic_launcher;

		if ((first.contains("Rising")) && (second.contains("Falling"))) {
			deliveryMessage = mContext.getString(R.string.pressureDropNotification);
			smallIconId = R.drawable.ic_stat_notify_falling;
		} else if ((first.contains("Steady")) && (second.contains("Falling"))) {
			deliveryMessage = mContext.getString(R.string.pressureDropNotification);
			smallIconId = R.drawable.ic_stat_notify_falling;
		} else if ((first.contains("Steady")) && (second.contains("Rising"))) {
			deliveryMessage = mContext.getString(R.string.pressureRiseNotification);
			smallIconId = R.drawable.ic_stat_notify_rising;
		} else if ((first.contains("Falling")) && (second.contains("Rising"))) {
			deliveryMessage = mContext.getString(R.string.pressureRiseNotification);
			smallIconId = R.drawable.ic_stat_notify_rising;
		} else {
			deliveryMessage = mContext.getString(R.string.pressureSteadyNotification);
			// don't deliver this message
			log("bailing on notification, pressure is steady");
			return;
		}

		// View graph button
		Intent intent = new Intent(mContext, LogViewerActivity.class);
		PendingIntent graphIntent = PendingIntent.getActivity(mContext, 0, intent, 0);

		// Creates an explicit intent for an activity
		android.support.v4.app.TaskStackBuilder stackBuilder = android.support.v4.app.TaskStackBuilder
				.create(mContext);
		Intent resultIntent = new Intent(mContext,
				CurrentConditionsActivity.class);
		// Current Conditions activity likes to know the location in the Intent
		double notificationLatitude = 0.0;
		double notificationLongitude = 0.0;
		try {
			LocationManager lm = (LocationManager) mContext
					.getSystemService(Context.LOCATION_SERVICE);
			Location loc = lm
					.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
			if (loc.getLatitude() != 0) {
				notificationLatitude = loc.getLatitude();
				notificationLongitude = loc.getLongitude();
			}
		} catch (Exception e) {

		}
		resultIntent.putExtra("latitude", notificationLatitude);
		resultIntent.putExtra("longitude", notificationLongitude);
		resultIntent.putExtra("cancelNotification", true);
		stackBuilder.addNextIntent(resultIntent);
		PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
				PendingIntent.FLAG_UPDATE_CURRENT);
		
		Notification.Builder mBuilder = new Notification.Builder(
				mContext).setSmallIcon(smallIconId)
				.setContentTitle(mContext.getString(R.string.app_name)).setContentText(deliveryMessage)
				.addAction(R.drawable.ic_menu_dark_stats, mContext.getString(R.string.viewGraph), graphIntent)
				.addAction(R.drawable.ic_menu_dark_weather, mContext.getString(R.string.reportWeather), resultPendingIntent);
		
		
		stackBuilder.addNextIntent(resultIntent);
		
		mBuilder.setContentIntent(resultPendingIntent);
		NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
		// mId allows you to update the
		// notification later on.
		mNotificationManager.notify(PRESSURE_NOTIFICATION_ID, mBuilder.build());
		
		AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
		Intent i = new Intent("ca.cumulonimbus.barometernetwork.CANCEL_PRESSURE");
		PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
		am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + (1000 * 60 * 60 * 12), pi); // 12h
		
		

		// Get tracker.
		Tracker t = getTracker(
		    TrackerName.APP_TRACKER);
		// Build and send an Event.
		t.send(new HitBuilders.EventBuilder()
		    .setCategory(BarometerNetworkActivity.GA_CATEGORY_MAIN_APP)
		    .setAction("pressure_notification_delivered")
		    .setLabel(deliveryMessage)
		    .build());
				
			
		
		// save the time
		SharedPreferences.Editor editor = sharedPreferences.edit();
		editor.putLong("lastNotificationTime", now);
		editor.commit();

	}
	
	/**
	 * Given a condition, 
	 * @param condition
	 * @return
	 */
	private int getResIdForClearIcon(CbCurrentCondition condition) {
		int moonNumber = getMoonPhaseIndex();
		int sunDrawable = R.drawable.ic_wea_on_sun;
		LocationManager lm = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
		Location location = lm.getLastKnownLocation("network");
		if(location != null) {
			if (!CurrentConditionsActivity.isDaytime(location
					.getLatitude(), location.getLongitude(), System.currentTimeMillis(), Calendar.getInstance().getTimeZone().getRawOffset())) {
				switch (moonNumber) {
				case 1:
					sunDrawable = R.drawable.ic_wea_on_moon1;
					break;
				case 2:
					sunDrawable = R.drawable.ic_wea_on_moon2;
					break;
				case 3:
					sunDrawable = R.drawable.ic_wea_on_moon3;
					break;
				case 4:
					sunDrawable = R.drawable.ic_wea_on_moon4;
					break;
				case 5:
					sunDrawable = R.drawable.ic_wea_on_moon5;
					break;
				case 6:
					sunDrawable = R.drawable.ic_wea_on_moon6;
					break;
				case 7:
					sunDrawable = R.drawable.ic_wea_on_moon7;
					break;
				case 8:
					sunDrawable = R.drawable.ic_wea_on_moon8;
					break;
				default:
					sunDrawable = R.drawable.ic_wea_on_moon2;
					break;
				}
			}
		}
		
		return sunDrawable;
	}
	
	/**
	 * Moon phase info
	 */
	private int getMoonPhaseIndex() {
		MoonPhase mp = new MoonPhase(Calendar.getInstance());
		return mp.getPhaseIndex();
	}
	
	private void log(String message) {
		if(PressureNETConfiguration.DEBUG_MODE) {
    		//logToFile(message);
    		System.out.println(message);
    	}
	}
}