/* ANDROID LIFECYCLE */
  @Override
  public void onCreate() {
    super.onCreate();
    LogPrincipal.configure();
    log.info("Creating ServiceSensorControl");

    // INITIALIZATIONS
    // Warning: getFilesDir is only available after onCreate was called.
    File sensorFile = new File(GlobalContext.getFileRoot(), SENSOR_FILENAME);
    File stageFile = new File(GlobalContext.getFileRoot(), STAGE_FILENAME);

    // Init index
    staticIPS =
        new StaticIPS(
            PPSOptions.INDEX_HORIZONTAL_RESOLUTION,
            PPSOptions.INDEX_VERTICAL_RESOLUTION,
            PPSOptions.INDEX_BY_CENTROID,
            PPSOptions.INDEX_STORE_DEGREE,
            new Callable<InputStream>() {
              @Override
              public InputStream call() throws IOException {
                return getAssets().open(PPSOptions.HELSINKIIPPS_ASSET);
              }
            },
            false,
            PPSOptions.HELSINKI_ID_FIELD,
            PPSOptions.HELSINKI_LAT_FIELD,
            PPSOptions.HELSINKI_LON_FIELD,
            PPSOptions.PROXIMITY);

    // Init sensor consumers
    final ZMQStreamer zmqStreamer = new ZMQStreamer();
    streamer = zmqStreamer.itemNode;

    harPipeline = new HARAdapter();
    ppsPipeline = new PPSAdapter("platform", staticIPS);
    waitingPipeline = new WaitingAdapter("platform", WaitingOptions.WAITING_TRESHOLD);
    gpsCache = new GpsCache();
    publisher = new PublicationPipeline(); // for external communication

    // Serialization used for persisting items
    Function<Item, String> persistorSerialization =
        JSON_PERSISTOR ? Persistor.JSON_SERIALIZATION : Persistor.REGULAR_SERIALIZATION;

    // Persistor taking and storing the items
    persistor =
        ZIPPED_PERSISTOR
            ? new ZipFilePersistor(sensorFile, persistorSerialization)
            : new FilePersistor(sensorFile, persistorSerialization);

    // INIT THREADS
    connectorThread = new ConnectorThread(sensorQueue);
    transferManager =
        INTENT_TRANSFER
            ? new IntentTransfer(persistor, GlobalContext.getFileRoot())
            : new TransferThreadPost(persistor, stageFile);
    monitorThread = new MonitorThread();

    // Restore user id from shared preferences
    restoreUserId();

    // Setup sensor thread
    SensorThread.setup(sensorQueue);

    final int recordingNotificationId = 1;

    // Start Recording once the first consumers connects to connector thread.
    // This should be done once the SensorThread is already running.
    connectorThread.nonEmpty.register(
        new Callback<Consumer<? super Item>>() {
          @Override
          public void call(Consumer<? super Item> consumer) {
            log.debug("Start recording sensors, configuration " + SensorCollectionOptions.con());

            // Notification
            NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

            Notification notification =
                new NotificationCompat.Builder(ServiceSensorControl.this)
                    .setContentTitle("Sensor miner")
                    .setContentText("Recording sensor data")
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setLights(0xff0000ff, 900, 900)
                    .setOngoing(true)
                    .setProgress(0, 0, true)
                    .build();

            notificationManager.notify(recordingNotificationId, notification);

            SensorThread.startAllRecording();
          }
        });
    connectorThread.empty.register(
        new Callback<Consumer<? super Item>>() {
          @Override
          public void call(Consumer<? super Item> consumer) {
            log.debug("Stop recording sensors");

            NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.cancel(recordingNotificationId);

            SensorThread.stopAllRecording();
          }
        });

    // Setup monitoring thread
    monitorThread.registerMonitorable(connectorThread, "SampleCount");
    monitorThread.registerMonitorable(persistor, "Persitor");
    monitorThread.registerMonitorable(transferManager, "Transfer");
    monitorThread.registerMonitorable(sensorQueue, "Queue");

    // Start threads
    connectorThread.start();
    monitorThread.start();
    SensorThread.start();
  }