/**
 * Utility to setup the application state.
 *
 * 1) Initialize LibOSSO (this will connect to D-Bus)
 * 2) Create a mainloop object
 * 3) Register the device state change callback
 *    The callback will be called once immediately on registration.
 *    The callback will reset the state->running to FALSE when the
 *    program needs to terminate so we'll know whether the program
 *    should run at all. If not, display an error dialog.
 *    (This is the case if the device will be in "Flight"-mode when
 *    the program starts.)
 * 4) Register the timer callback (which will keep the screen from
 *    blanking).
 * 5) Un-blank the screen.
 * 6) Display a dialog to the user (on the background) warning about
 *    battery drain.
 * 7) Send the first "delay backlight dimming" command.
 *
 * Returns TRUE when everything went ok, FALSE when caller should call
 * releaseAppState and terminate. The code below will print out the
 * errors if necessary.
 */
static gboolean setupAppState(ApplicationState* state) {

  osso_return_t result;

  g_assert(state != NULL);

  g_print(PROGNAME ":setupAppState starting\n");

  /* Zero out the state. Has the benefit of setting all pointers to
     NULLs and all gbooleans to FALSE. This is useful when we'll need
     to determine what to release later. */
  memset(state, 0, sizeof(ApplicationState));

  g_print(PROGNAME ":setupAppState Initializing LibOSSO\n");

  /*... Listing cut for brevity ...*/

  state->ossoContext = osso_initialize(ProgName, "1.0", FALSE, NULL);
  if (state->ossoContext == NULL) {
    g_printerr(PROGNAME ": Failed to initialize LibOSSO\n");
    return FALSE;
  }

  g_print(PROGNAME ":setupAppState Creating a GMainLoop object\n");
  /* Create a new GMainLoop object, with default context (NULL) and
     initial "running"-state set to FALSE. */
  state->mainloop = g_main_loop_new(NULL, FALSE);
  if (state->mainloop == NULL) {
    g_printerr(PROGNAME ": Failed to create a GMainLoop\n");
    return FALSE;
  }

  g_print(PROGNAME
          ":setupAddState Adding hw-state change callback.\n");
  /* The callback will be called immediately with the state, so we
     need to know whether we're in offline mode to start with. If so,
     the callback will set the running-member to FALSE (and we'll
     check it below). */
  state->running = TRUE;
  /* In order to receive information about device state and changes
     in it, we register our callback here.

     Parameters for the osso_hw_set_event_cb():
       osso_context_t* :  LibOSSO context object to use.
       osso_hw_state_t* : Pointer to a device state type that we're
                          interested in. NULL for "all states".
       osso_hw_cb_f* :    Function to call on state changes.
       gpointer :         User-data passed to callback. */
  result = osso_hw_set_event_cb(state->ossoContext,
                                NULL, /* We're interested in all. */
                                deviceStateChanged,
                                state);
  if (result != OSSO_OK) {
    g_printerr(PROGNAME
               ":setupAppState Failed to get state change CB\n");
    /* Since we cannot reliably know when to terminate later on
       without state information, we will refuse to run because of the
       error. */
    return FALSE;
  }
  /* We're in "Flight" mode? */
  if (state->running == FALSE) {
    g_print(PROGNAME ":setupAppState In offline, not continuing.\n");
    displayExitMessage(state, ProgName " not available in Offline mode");
    return FALSE;
  }

  g_print(PROGNAME ":setupAppState Adding blanking delay timer.\n");
  if (g_timeout_add(45000,
                    (GSourceFunc)delayBlankingCallback,
                    state) == 0) {
    /* If g_timeout_add returns 0, it signifies an invalid event
       source id. This means that adding the timer failed. */
    g_printerr(PROGNAME ": Failed to create a new timer callback\n");
    return FALSE;
  }

  /* Un-blank the display (will always succeed in the SDK). */
  g_print(PROGNAME ":setupAppState Unblanking the display\n");
  result = osso_display_state_on(state->ossoContext);
  if (result != OSSO_OK) {
    g_printerr(PROGNAME ": Failed in osso_display_state_on (%s)\n",
               ossoErrorStr(result));
    /* If the RPC call fails, odds are that nothing else will work
       either, so we decide to quit instead. */
    return FALSE;
  }

  /* Display a "Note"-dialog with a WARNING icon.
     The Dialog is MODAL, so user cannot do anything with the stylus
     until the Ok is selected, or the Back-key is pressed. */

  /*... Listing cut for brevity ...*/

  /* Other icons available:
      OSSO_GN_NOTICE: For general notices.
     OSSO_GN_WARNING: For warning messages.
       OSSO_GN_ERROR: For error messages.
        OSSO_GN_WAIT: For messages about "delaying" for something (an
                      hourglass icon is displayed).
                   5: Animated progress indicator. */

  /*... Listing cut for brevity ...*/

  g_print(PROGNAME ":setupAppState Displaying Note dialog\n");
  result = osso_system_note_dialog(state->ossoContext,
                                   /* UTF-8 text into the dialog */
                                   "Started " ProgName ".\n"
                       "Please remember to stop it when you're done, "
                                "in order to conserve battery power.",
                                   /* Icon to use */
                                   OSSO_GN_WARNING,
                                   /* We're not interested in the RPC
                                      return value. */
                                   NULL);
  if (result != OSSO_OK) {
    g_error(PROGNAME ": Error displaying Note dialog (%s)\n",
            ossoErrorStr(result));
  }
  g_print(PROGNAME ":setupAppState Requested for the dialog\n");

  /* Then delay the blanking timeout so that our timer callback has a
     chance to run before that. */
  delayDisplayBlanking(state);

  g_print(PROGNAME ":setupAppState Completed\n");

  /* State set up. */
  return TRUE;
}
