content: package edu.berkeley.cs.amplab.carat.android.storage;
  
  import java.io.DataInputStream;
  import java.io.DataOutputStream;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.lang.ref.WeakReference;
  import java.util.LinkedList;
  import java.util.List;
  
  import android.app.Application;
  import android.content.Context;
  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.sampling.SamplingLibrary;
  import edu.berkeley.cs.amplab.carat.thrift.HogBugReport;
  import edu.berkeley.cs.amplab.carat.thrift.HogsBugs;
  import edu.berkeley.cs.amplab.carat.thrift.Reports;
  
  public class CaratDataStorage {
  
      public static final String FILENAME = "carat-reports.dat";
      public static final String BLACKLIST_FILE = "carat-blacklist.dat";
      public static final String QUESTIONNAIRE_URL_FILE = "questionnaire-url.txt";
      public static final String BLACKLIST_FRESHNESS = "carat-blacklist-freshness.dat";
      public static final String QUICKHOGS_FRESHNESS = "carat-quickhogs-freshness.dat";
      public static final String GLOBLIST_FILE = "carat-globlist.dat";
      public static final String BUGFILE = "carat-bugs.dat";
      public static final String HOGFILE = "carat-hogs.dat";
      public static final String SETTINGSFILE = "carat-settings.dat";
  
      public static final String SAMPLES_REPORTED = "carat-samples-reported.dat";
      
      public static final String FRESHNESS = "carat-freshness.dat";
      private Application a = null;
  
      private long freshness = 0;
      private long blacklistFreshness = 0;
      private long quickHogsFreshness = 0;
      private long samples_reported = 0;
      private String questionnaireUrl = null;
      private WeakReference<Reports> caratData = null;
      private WeakReference<SimpleHogBug[]> bugData = null;
      private WeakReference<SimpleHogBug[]> hogData = null;
      private WeakReference<SimpleHogBug[]> settingsData = null;
      private WeakReference<List<String>> blacklistedApps = null;
      private WeakReference<List<String>> blacklistedGlobs = null;
  
      public CaratDataStorage(Application a) {
          this.a = a;
          freshness = readFreshness();
          blacklistFreshness = readBlacklistFreshness();
          quickHogsFreshness = readQuickHogsFreshness();
          caratData = new WeakReference<Reports>(readReports());
          readBugReport();
          readHogReport();
          readBlacklist();
          samples_reported = readSamplesReported();
      }
  
      public void writeReports(Reports reports) {
          if (reports == null)
              return;
          caratData = new WeakReference<Reports>(reports);
          writeObject(reports, FILENAME);
      }
  
      public void writeFreshness() {
          freshness = System.currentTimeMillis();
          writeText(freshness + "", FRESHNESS);
      }
      
      public void writeBlacklistFreshness() {
          blacklistFreshness = System.currentTimeMillis();
          writeText(blacklistFreshness + "", BLACKLIST_FRESHNESS);
      }
      
      public void writeQuickHogsFreshness() {
          quickHogsFreshness = System.currentTimeMillis();
          writeText(quickHogsFreshness + "", QUICKHOGS_FRESHNESS);
      }
  
  
      public void writeObject(Object o, String fname) {
          FileOutputStream fos = getFos(fname);
          if (fos == null)
              return;
          try {
              ObjectOutputStream dos = new ObjectOutputStream(fos);
              dos.writeObject(o);
              dos.close();
          } catch (IOException e) {
              Log.e(this.getClass().getName(), "Could not write object:" + o
                      + "!");
              e.printStackTrace();
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem writing object", th);
          }
      }
  
      public Object readObject(String fname) {
          FileInputStream fin = getFin(fname);
          if (fin == null)
              return null;
          try {
              ObjectInputStream din = new ObjectInputStream(fin);
              Object o = din.readObject();
              din.close();
              return o;
          } catch (IOException e) {
              Log.e(this.getClass().getName(), "Could not read object from "
                      + fname + "!");
              e.printStackTrace();
          } catch (ClassNotFoundException e) {
              Log.e(this.getClass().getName(),
                      "Could not find class: " + e.getMessage()
                              + " reading from " + fname + "!");
              e.printStackTrace();
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem reading object", th);
          }
          return null;
      }
  
      public void writeText(String thing, String fname) {
          FileOutputStream fos = getFos(fname);
          if (fos == null)
              return;
          try {
              DataOutputStream dos = new DataOutputStream(fos);
              dos.writeUTF(thing);
              dos.close();
          } catch (IOException e) {
              Log.e(this.getClass().getName(), "Could not write text:" + thing
                      + "!");
              e.printStackTrace();
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem writing text in "+fname, th);
          }
      }
  
      public String readText(String fname) {
          FileInputStream fin = getFin(fname);
          if (fin == null)
              return null;
          try {
              DataInputStream din = new DataInputStream(fin);
              String s = din.readUTF();
              din.close();
              return s;
          } catch (IOException e) {
              Log.e(this.getClass().getName(), "Could not read text from "
                      + fname + "!");
              e.printStackTrace();
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem reading text", th);
          }
          return null;
      }
  
      private FileInputStream getFin(String fname) {
          try {
              return a.openFileInput(fname);
          } catch (FileNotFoundException e) {
              Log.w(this.getClass().getName(), "File "
                      + fname + " does not exist yet. Wait for reports.");
              // e.printStackTrace();
              return null;
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem opening file "+fname+" for input", th);
          	return null;
          }
      }
  
      private FileOutputStream getFos(String fname) {
          try {
              return a.openFileOutput(fname, Context.MODE_PRIVATE);
          } catch (FileNotFoundException e) {
              Log.w(this.getClass().getName(), "File "
                      + fname + " does not exist yet. Wait for reports.");
              // e.printStackTrace();
              return null;
          } catch (Throwable th){
          	Log.e(this.getClass().getName(), "Problem opening file "+fname+" for output", th);
          	return null;
          }
      }
  
      public long readFreshness() {
          String s = readText(FRESHNESS);
          Log.d("CaratDataStorage", "Read freshness: " + s);
          if (s != null)
              return Long.parseLong(s);
          else
              return -1;
      }
  
      public Reports readReports() {
          Object o = readObject(FILENAME);
          Log.d("CaratDataStorage", "Read Reports: " + o);
          if (o != null) {
              caratData = new WeakReference<Reports>((Reports) o);
              return (Reports) o;
          } else
              return null;
      }
  
      /**
       * @return the freshness
       */
      public long getFreshness() {
          return freshness;
      }
      
      
      public long readBlacklistFreshness() {
          String s = readText(BLACKLIST_FRESHNESS);
          Log.d("CaratDataStorage", "Read freshness: " + s);
          if (s != null)
              return Long.parseLong(s);
          else
              return -1;
      }
      
      public long getBlacklistFreshness() {
          return blacklistFreshness;
      }
      
      public long readQuickHogsFreshness() {
          String s = readText(QUICKHOGS_FRESHNESS);
          Log.d("CaratDataStorage", "Read freshness: " + s);
          if (s != null)
              return Long.parseLong(s);
          else
              return -1;
      }
      
      public long getQuickHogsFreshness() {
          return quickHogsFreshness;
      }
      
      /**
       * @return a list of blacklisted apps
       */
      public List<String> getBlacklist() {
          if (blacklistedApps != null && blacklistedApps.get() != null)
              return blacklistedApps.get();
          else
              return readBlacklist();
      }
      
      /**
       * @return a list of blacklisted expressions
       */
      public List<String> getGloblist() {
          if (blacklistedGlobs != null && blacklistedGlobs.get() != null)
              return blacklistedGlobs.get();
          else
              return readGloblist();
      }
      
      /**
       * 
       * @return a list of blacklisted apps
       */
      public List<String> readBlacklist() {
          Object o = readObject(BLACKLIST_FILE);
          //Log.d("CaratDataStorage", "Read blacklist: " + o);
          if (o != null) {
              blacklistedApps = new WeakReference<List<String>>((List<String>) o);
              return (List<String>) o;
          } else
              return null;
      }
      
      /**
       * 
       * @param blacklist the list of blacklisted apps to write.
       */
      public void writeBlacklist(List<String> blacklist) {
          if (blacklist == null)
              return;
          blacklistedApps = new WeakReference<List<String>>(blacklist);
          writeObject(blacklist, BLACKLIST_FILE);
      }
      
      /**
       * 
       * @return a list of blacklisted expressions
       */
      public List<String> readGloblist() {
          Object o = readObject(GLOBLIST_FILE);
          //Log.d("CaratDataStorage", "Read glob blacklist: " + o);
          if (o != null) {
              blacklistedGlobs = new WeakReference<List<String>>((List<String>) o);
              return (List<String>) o;
          } else
              return null;
      }
      
      /**
       * 
       * @param globlist the list of blacklisted expressions to write.
       */
      public void writeGloblist(List<String> globlist) {
          if (globlist == null)
              return;
          blacklistedGlobs = new WeakReference<List<String>>(globlist);
          writeObject(globlist, GLOBLIST_FILE);
      }
      
      /**
       * @return the questionnaire base URL, read from storage or memory.
       */
      public String getQuestionnaireUrl() {
          if (questionnaireUrl != null)
              return questionnaireUrl;
          else
              return readQuestionnaireUrl();
      }
      
      /**
       * 
       * @return the questionnaire base URL, read from storage.
       */
      public String readQuestionnaireUrl() {
          String url = readText(QUESTIONNAIRE_URL_FILE);
          //Log.d("CaratDataStorage", "Read blacklist: " + o);
          if (url != null) {
              return url;
          } else
              return null;
      }
      
      /**
       * Write questionnaire URL to permanent storage.
       * @param url the questionnaire base URL.
       */
      public void writeQuestionnaireUrl(String url) {
          if (url == null)
              return;
          questionnaireUrl = url;
          writeText(url, QUESTIONNAIRE_URL_FILE);
      }
      
      public void samplesReported(int howmany) {
      	samples_reported += howmany;
          writeText(samples_reported+ "", SAMPLES_REPORTED);
      }
      
   
      public long readSamplesReported() {
          String s = readText(SAMPLES_REPORTED);
          Log.d("CaratDataStorage", "Read samples reported: " + s);
          // here is the bug. s is null!
          if (s != null)
              return Long.parseLong(s);
          else
              return -1;
      }
  
      /**
       * @return the freshness
       */
      public long getSamplesReported() {
          return samples_reported;
      }
  
      /**
       * @return the caratData
       */
      public Reports getReports() {
          if (caratData != null && caratData.get() != null)
              return caratData.get();
          else
              return readReports();
      }
  
      /**
       * @return the bug reports
       */
      public SimpleHogBug[] getBugReport() {
          if (bugData == null || bugData.get() == null) {
              readBugReport();
          }
          if (bugData == null || bugData.get() == null)
              return null;
          return bugData.get();
      }
  
      /**
       * @return the hog reports
       */
      public SimpleHogBug[] getHogReport() {
          if (hogData == null || hogData.get() == null) {
              readHogReport();
          }
          if (hogData == null || hogData.get() == null)
              return null;
          return hogData.get();
      }
      
      public SimpleHogBug[] getSettingsReport() {
          if (settingsData == null || settingsData.get() == null) {
              readSettingsReport();
          }
          if (settingsData == null || settingsData.get() == null)
              return null;
          return settingsData.get();
      }
  
      public void writeBugReport(HogBugReport r) {
          if (r != null) {
              SimpleHogBug[] list = convertAndFilter(r.getHbList(), true);
              if (list != null){
                  bugData = new WeakReference<SimpleHogBug[]>(list);
                  writeObject(list, BUGFILE);
              }
          }
      }
  
      public void writeHogReport(HogBugReport r) {
          if (r != null) {
              SimpleHogBug[] list = convertAndFilter(r.getHbList(), false);
              if (list != null){
                  hogData = new WeakReference<SimpleHogBug[]>(list);
                  writeObject(list, HOGFILE);
              }
          }
      }
  
      public void writeSettingsReport(HogBugReport r) {
          if (r != null) {
              SimpleHogBug[] list = convertAndFilter(r.getHbList(), false);
              if (list != null){
                  settingsData = new WeakReference<SimpleHogBug[]>(list);
                  writeObject(list, SETTINGSFILE);
              }
          }
      }
  
      /**
       * For Settings, we need more than a boolean here.
       * @param list the list of bugs or hogs received from the server.
       * @param isBug True if the list contains Bugs, false if Hogs.
       * @return The list of non-hidden bugs or hogs.
       */
      private SimpleHogBug[] convertAndFilter(List<HogsBugs> list, boolean isBug) {
          if (list == null)
              return null;
          List<SimpleHogBug> result = new LinkedList<SimpleHogBug>();
          int size = list.size();
          for (int i = 0; i < size; ++i) {
              HogsBugs item = list.get(i);
              String n = fixName(item.getAppName());
              if (SamplingLibrary.isHidden(CaratApplication.getContext(), n))
                  continue;
              SimpleHogBug h = new SimpleHogBug(n, isBug ? Constants.Type.BUG:Constants.Type.HOG);
              h.setAppLabel(item.getAppLabel());
              String priority = item.getAppPriority();
              if (priority == null || priority.length() == 0)
                  priority = "Foreground app";
              h.setAppPriority(priority);
              h.setExpectedValue(item.getExpectedValue());
              h.setExpectedValueWithout(item.getExpectedValueWithout());
              h.setwDistance(item.getWDistance());
              //result[i].setxVals(convert(item.getXVals()));
              h.setError(item.getError());
              h.setErrorWithout(item.getErrorWithout());
              h.setSamples(item.getSamples());
              h.setSamplesWithout(item.getSamplesWithout());
              //result[i].setSignificance(item.getSignificance());
              /*result[i].setyVals(convert(item.getYVals()));
              result[i].setxValsWithout(convert(item.getXValsWithout()));
              result[i].setyValsWithout(convert(item.getYValsWithout()));*/
              result.add(h);
          }
          return result.toArray(new SimpleHogBug[result.size()]);
      }
  
      public static double[] convert(List<Double> dbls) {
          if (dbls == null)
              return new double[0];
          for (int j = 0; j < dbls.size(); ++j) {
              if (dbls.get(j) == 0.0) {
                  dbls.remove(j);
                  j--;
              }
          }
          double[] arr = new double[dbls.size()];
          for (int j = 0; j < dbls.size(); ++j) {
              arr[j] = dbls.get(j);
          }
          return arr;
      }
  
      private String fixName(String name) {
          if (name == null)
              return null;
          int idx = name.lastIndexOf(':');
          if (idx <= 0)
              idx = name.length();
          String n = name.substring(0, idx);
          return n;
      }
  
      public SimpleHogBug[] readBugReport() {
          Object o = readObject(BUGFILE);
          //Log.d("CaratDataStorage", "Read Bugs: " + o);
          if (o == null || !(o instanceof SimpleHogBug[]))
              return null;
          SimpleHogBug[] r = (SimpleHogBug[]) o;
          bugData = new WeakReference<SimpleHogBug[]>(r);
          return r;
      }
  
      public SimpleHogBug[] readHogReport() {
          Object o = readObject(HOGFILE);
          //Log.d("CaratDataStorage", "Read Hogs: " + o);
          if (o == null || !(o instanceof SimpleHogBug[]))
              return null;
          SimpleHogBug[] r = (SimpleHogBug[]) o;
          hogData = new WeakReference<SimpleHogBug[]>(r);
          return r;
      }
      
      public SimpleHogBug[] readSettingsReport() {
          Object o = readObject(SETTINGSFILE);
          if (o == null || !(o instanceof SimpleHogBug[]))
              return null;
          SimpleHogBug[] r = (SimpleHogBug[]) o;
          settingsData = new WeakReference<SimpleHogBug[]>(r);
          return r;
      }
  }
  