content: package edu.berkeley.cs.amplab.carat.android.protocol;
  
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.SortedMap;
  import java.util.SortedSet;
  import java.util.TreeSet;
  
  import android.content.Context;
  import android.content.SharedPreferences;
  import android.preference.PreferenceManager;
  import android.util.Log;
  import edu.berkeley.cs.amplab.carat.android.CaratApplication;
  import edu.berkeley.cs.amplab.carat.android.Constants;
  import edu.berkeley.cs.amplab.carat.android.R;
  import edu.berkeley.cs.amplab.carat.android.sampling.SamplingLibrary;
  import edu.berkeley.cs.amplab.carat.android.storage.CaratSampleDB;
  import edu.berkeley.cs.amplab.carat.thrift.Sample;
  
  /**
   * Communicates with the Carat Server. Sends samples stored in CaratDB every
   * COMMS_INTERVAL ms.
   * 
   * @author Eemil Lagerspetz
   * 
   */
  public class SampleSender {
      
      private static final String TAG = "sendSamples";
      
      private static final String TRY_AGAIN = " will try again later.";
      
      private static final Object sendLock = new Object();
  
      CaratApplication app = null;
  
      // Prevent instantiation
      private SampleSender(){}
      
      public static void sendSamples(CaratApplication app) {
          synchronized(sendLock){
              Context c = app.getApplicationContext();
      
              String networkStatus = SamplingLibrary.getNetworkStatus(c);
              String networkType = SamplingLibrary.getNetworkType(c);
      
              final SharedPreferences p = PreferenceManager
                      .getDefaultSharedPreferences(c);
              final boolean useWifiOnly = p.getBoolean(Constants.WIFI_ONLY_PREFERENCE_KEY, false);
              Log.i("wifi-preference-SampleSender", String.valueOf(useWifiOnly));
      
              boolean connected = (!useWifiOnly && networkStatus == SamplingLibrary.NETWORKSTATUS_CONNECTED)
                      || networkType.equals("WIFI");
              
              if (connected) {
                  CaratSampleDB db = CaratSampleDB.getInstance(c);
                  int samples = db.countSamples();
                  
                  /* Click Tracking: Track sample sending. */
                  String uuId = p.getString(CaratApplication.getRegisteredUuid(), "UNKNOWN");
                  HashMap<String, String> options = new HashMap<String, String>();
                  options.put("count", samples+"");
                  ClickTracking.track(uuId, "sendingsamples", options, c);
                  /* End Click Tracking: Track sample sending. */
                  
                  int successSum = 0;
                  for (int batches = 0; batches < Constants.COMMS_MAX_BATCHES
                          && batches < samples
                                  / Constants.COMMS_MAX_UPLOAD_BATCH + 1; batches++) {
                      SortedMap<Long, Sample> map = CaratSampleDB.getInstance(c)
                              .queryOldestSamples(
                                      Constants.COMMS_MAX_UPLOAD_BATCH);
                      if (map.size() > 0) {
                          int progress = (int) (successSum * 1.0 / samples * 100.0);
                          CaratApplication.setActionProgress(progress, successSum + "/"
                                  + samples +" "+ app.getString(R.string.samplesreported), false);
                          if (app.commManager != null) {
                              int tries = 0;
                              while (tries < 2) {
                                  try {
                                      int success = app.commManager.uploadSamples(map.values());
      
                                      tries = 2;
                                      // FlurryAgent.logEvent("UploadSamples");
                                      Log.d(TAG, "Uploaded " + success
                                              + " samples out of " + map.size());
                                      if (success > 0)
                                          CaratApplication.storage.samplesReported(success);
                                      Sample last = map.get(map.lastKey());
                                      
  									/*
  									 * converting (to human readable date-time format) 
  									 * the "timestamp" of the last sample (which is
  									 * uploaded now, and should be deleted along the other 
  									 * uploaded samples). The "timestamp" is computed this way:
  									 * CurrentTimeMillis / 1000 
  									 * (see getSample() in SamplingLibrary)
  									 */ 
                                      long lastSampleTime = (long) last.getTimestamp() * 1000; // in currentTimeMillis
                                      SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm");
                                      Date resultdate = new Date(lastSampleTime);
                                      
                                      Log.d(TAG,
                                              "Deleting " + success
                                                      + " samples older than "
                                                      + sdf.format(resultdate));
                                      /*
                                       * Log.i(TAG, "Sent samples:"); for (Sample k:
                                       * map.values()){ Log.i(TAG, k.getTimestamp() +
                                       * " " + k.getBatteryLevel()); }
                                       */
                                      SortedSet<Long> uploaded = new TreeSet<Long>();
                                      int i = 0;
                                      for (Long s : map.keySet()) {
                                          if (i < success)
                                              uploaded.add(s);
                                          i += 1;
                                      }
                                      int deleted = CaratSampleDB.getInstance(c)
                                              .deleteSamples(uploaded);
                                      // Log.d(TAG, "Deleted " + deleted + " samples.");
                                      successSum += success;
                                  } catch (Throwable th) {
                                      // Any sort of malformed response, too short
                                      // string, etc...
                                      Log.w(TAG, "Failed to refresh reports: "
                                              + th
                                              + (tries < 1 ? "Trying again now"
                                                      : TRY_AGAIN), th);
                                      tries++;
                                  }
                              }
                          } else {
                              Log.w(TAG, "CommunicationManager is not ready yet."
                                      + TRY_AGAIN);
                          }
                      } else {
                          Log.w(TAG, "No samples to send." + TRY_AGAIN);
                      }
                  }
                  
                  /* Click Tracking: Track sample sending. */
                  options.put("count", successSum+"");
                  ClickTracking.track(uuId, "sentsamples", options, c);
                  /* End Click Tracking: Track sample sending. */
                  
              }/* else if (networkStatus
                      .equals(SamplingLibrary.NETWORKSTATUS_CONNECTING)) {
                  Log.w(TAG, "Network status: " + networkStatus
                          + ", trying again in 10s.");
                  connecting = true;
              } else {
                  Log.w(TAG, "Network status: " + networkStatus + TRY_AGAIN);
                  connecting = false;
              }
              if (connecting) {
                  // wait for wifi to come up
                  try {
                      Thread.sleep(CaratApplication.COMMS_WIFI_WAIT);
                  } catch (InterruptedException e1) {
                      // ignore
                  }
                  connecting = false;
              } else {
                  try {
                      Thread.sleep(CaratApplication.COMMS_INTERVAL);
                  } catch (InterruptedException e) {
                      // wait for wifi to come up
                      try {
                          Thread.sleep(CaratApplication.COMMS_WIFI_WAIT);
                      } catch (InterruptedException e1) {
                          // ignore
                      }
                  }
              }*/
          }
      }
  }
  