/**
   * Use the localization field to build the reset direction alert dialog. This dialog builds
   * ResetDirectionDialogOption objects to refer to the dialog choices.
   *
   * @param screen the dialog alert owner Screen
   */
  public void showRefreshDirectionDialog(Screen screen) {
    DialogOption[] opt = new DialogOption[3];

    opt[0] =
        new ResetDirectionDialogOption(
            screen,
            localization.getLanguage("dialog_refresh_from"),
            SynchronizationController.REFRESH_FROM_SERVER);

    opt[1] =
        new ResetDirectionDialogOption(
            screen,
            localization.getLanguage("dialog_refresh_to"),
            SynchronizationController.REFRESH_TO_SERVER);

    opt[2] = new ResetDirectionDialogOption(screen, localization.getLanguage("dialog_cancel"), -1);

    displayManager.promptSelection(
        screen,
        localization.getLanguage("dialog_refresh_which")
            + "\n"
            + localization.getLanguage("dialog_refresh_warn2"),
        opt,
        -1,
        displayManager.REFRESH_DIRECTION_DIALOG_ID);
  }
  /**
   * Use the localization field to build the reset type alert dialog that use the DisplayManager
   * client implementation to ask the user whose sources must be refreshed. This dialog builds
   * ResetTypeDialogOption objects to refer to the dialog choiches. Actual client implementation
   * requires this alert to be diaplayed after the showRefreshDirectionDialog call in order to have
   * full information abaout the direction.
   *
   * @param screen the dialog alert owner Screen
   * @param int the refresh direction for the selected sources.
   */
  public void showRefreshTypeDialog(Screen screen, int direction) {
    ResetTypeDialogOption[] options = null;
    // Count the number of enabled and refreshable sources
    Vector opts = new Vector();

    int numEnabledSources = -1;
    Enumeration enabledSources = appSyncSourceManager.getEnabledAndWorkingSources();

    int allId = 0;
    while (enabledSources.hasMoreElements()) {
      AppSyncSource source = (AppSyncSource) enabledSources.nextElement();
      if (source.isRefreshSupported(direction)
          && source.isVisible()
          && source.getConfig().getActive()
          && source.isWorking()) {

        if (Log.isLoggable(Log.DEBUG)) {
          Log.debug(
              TAG_LOG,
              "Source: "
                  + source.getName()
                  + " direction "
                  + direction
                  + " supported "
                  + source.isRefreshSupported(direction));
        }
        opts.addElement(
            new ResetTypeDialogOption(screen, source.getName(), source.getId(), direction));
        numEnabledSources++;
        allId |= source.getId();
      }
    }

    if ((numEnabledSources + 1) > 1) {
      opts.addElement(
          new ResetTypeDialogOption(
              screen, localization.getLanguage("type_all_enabled"), allId, direction));
    }

    opts.addElement(
        new ResetTypeDialogOption(screen, localization.getLanguage("dialog_cancel"), 0, direction));

    options = new ResetTypeDialogOption[opts.size()];

    opts.copyInto(options);

    displayManager.promptSelection(
        screen,
        localization.getLanguage("dialog_refresh")
            + " "
            + (direction == SynchronizationController.REFRESH_FROM_SERVER
                    ? localization.getLanguage("dialog_refresh_from").toLowerCase()
                    : localization.getLanguage("dialog_refresh_to"))
                .toLowerCase(),
        options,
        -1,
        displayManager.REFRESH_TYPE_DIALOG_ID);
  }
  /**
   * Use the localization field to build the wifi not available alert dialog. This dialog builds
   * WIFINotAvailableDialogOption objects to refer to the dialog choices.
   *
   * @param screen the dialog alert owner Screen
   */
  public void showNoWIFIAvailableDialog(
      Screen screen,
      String syncType,
      Vector filteredSources,
      boolean refresh,
      int direction,
      int delay,
      boolean fromOutside) {
    DialogOption[] opt = new DialogOption[2];

    opt[0] =
        new WIFINotAvailableDialogOption(
            screen,
            localization.getLanguage("dialog_continue"),
            0,
            syncType,
            filteredSources,
            refresh,
            direction,
            delay,
            fromOutside);

    opt[1] =
        new WIFINotAvailableDialogOption(
            screen,
            localization.getLanguage("dialog_cancel"),
            -1,
            syncType,
            filteredSources,
            refresh,
            direction,
            delay,
            fromOutside);

    lastWifiNotAvailableDialogState.update(
        syncType, filteredSources, refresh, direction, delay, fromOutside);

    displayManager.promptSelection(
        screen,
        localization.getLanguage("dialog_no_wifi_availabale"),
        opt,
        0,
        displayManager.NO_WIFI_AVAILABLE_ID);
  }
  /**
   * Show the first sync alert dialogs for all the sources that are listed into the given
   * appSourceList array.
   *
   * @param appSourceList the list of appSyncSources
   * @param syncType the String representation for the sync type (manual...)
   * @param filteredSources the sources Vector to be updated in case the user select to sync now
   * @param refresh specifies if this sync is a refresh
   * @param direction in case of refresh, this is the direction (client to server or server to
   *     client)
   * @param delay request the sync scheduler to be initiate the sync after the given amount of
   *     milliseconds
   * @param fromOutside used by the sync scheduler to manage the incoming sync request from outside
   *     if true
   * @param questionCounter the number of question to be displayed to the user. This number depends
   *     by the number of sources that have a warning messgae to be displayed at the first sync
   * @param sourceIndex the sync source index source which this dialog alert is related.
   */
  public void showFirstSyncDialog(
      Screen screen,
      AppSyncSource[] appSourceList,
      String syncType,
      Vector filteredSources,
      boolean refresh,
      int direction,
      int delay,
      boolean fromOutside,
      int questionCounter,
      int sourceIndex) {
    // This is just a safety check
    if (sourceIndex >= appSourceList.length) {
      Log.error(TAG_LOG, "Invalid source id, cannot show first sync dialog");
      return;
    }

    // Set the last variables to be used in case of unexpected resume
    // (for example a device screen rotation or a incoming call or in general
    // an event that pauses the application and require a resume action)
    String warning = appSourceList[sourceIndex].getWarningOnFirstSync();
    FirstSyncDialogOption[] options = new FirstSyncDialogOption[2];
    options[0] =
        new FirstSyncDialogOption(
            screen,
            localization.getLanguage("dialog_sync_now"),
            0,
            appSourceList,
            syncType,
            filteredSources,
            refresh,
            direction,
            delay,
            fromOutside,
            questionCounter,
            sourceIndex);
    options[1] =
        new FirstSyncDialogOption(
            screen,
            localization.getLanguage("dialog_try_later"),
            1,
            appSourceList,
            syncType,
            filteredSources,
            refresh,
            direction,
            delay,
            fromOutside,
            questionCounter,
            sourceIndex);
    lastFirstSyncDialogState.update(
        appSourceList,
        syncType,
        filteredSources,
        refresh,
        direction,
        delay,
        fromOutside,
        questionCounter,
        sourceIndex);
    displayManager.promptSelection(
        screen, warning, options, 0, displayManager.FIRST_SYNC_DIALOG_ID);
  }
 /**
  * Show a message to the user, with a classic "Ok" button, and the user must press the button in
  * order to dismiss the dialog
  *
  * @param message text to display
  */
 public void showMessageAndWaitUserConfirmation(String message) {
   String okMessage = localization.getLanguage("dialog_ok");
   askGenericQuestion(message, new String[] {okMessage});
 }
  /**
   * Handles the response error if any
   *
   * @param response
   * @param signupUrl
   * @throws JSONException
   */
  private void handleResponseError(JSONObject response, String signupUrl) throws Exception {

    try {
      // Check for errors
      if (response.has(JSON_OBJECT_ERROR)) {
        JSONObject error = response.getJSONObject(JSON_OBJECT_ERROR);

        if (error != null) {
          String code = error.getString(JSON_OBJECT_ERROR_FIELD_CODE);
          String message = error.getString(JSON_OBJECT_ERROR_FIELD_MESSAGE);
          String cause = error.getString(JSON_OBJECT_ERROR_FIELD_CAUSE);

          if (Log.isLoggable(Log.DEBUG)) {
            StringBuffer logMsg = new StringBuffer("Error in SAPI response").append("\r\n");
            logMsg.append("code: ").append(code).append("\r\n");
            logMsg.append("cause: ").append(cause).append("\r\n");
            logMsg.append("message: ").append(message).append("\r\n");

            JSONArray parameters = error.getJSONArray(JSON_OBJECT_ERROR_FIELD_PARAMETERS);
            for (int i = 0; i < parameters.length(); i++) {
              JSONObject parameter = parameters.getJSONObject(i);
              String param = parameter.getString(JSON_OBJECT_ERROR_FIELD_PARAM);
              logMsg.append("param: ").append(param).append("\r\n");
            }
            Log.debug(TAG_LOG, logMsg.toString());
          }

          // Handle error codes
          boolean handled = false;
          if (JSON_ERROR_CODE_PRO_1000.equals(code)) {
            // Unknown exception in profile handling
          } else if (JSON_ERROR_CODE_PRO_1001.equals(code)) {
            // Missing the following mandatory parameter(s).
          } else if (JSON_ERROR_CODE_PRO_1106.equals(code)) {
            // The userid is not valid. Only letters (a-z), numbers (0-9),
            // and periods (.) are allowed. Userid must be less than 16
            // characters and include at least one letter.
          } else if (JSON_ERROR_CODE_PRO_1107.equals(code)) {
            // You can not specify an existing e-mail address.
          } else if (JSON_ERROR_CODE_PRO_1113.equals(code)) {
            // You can not specify an existing username.
            String msg = localization.getLanguage("signup_failed_username_exists");
            signupScreenController.signupFailed(msg);
            signupScreenController.promptCredentials();
            handled = true;
          } else if (JSON_ERROR_CODE_PRO_1115.equals(code)) {
            // The password is not valid. Only letters (a-z) and numbers
            // (0-9) are allowed. Minimum 4, maximum 16 characters.
            signupScreenController.signupFailed(
                localization.getLanguage("signup_failed_bad_password_message"));
            signupScreenController.promptCredentials();
            handled = true;
          } else if (JSON_ERROR_CODE_PRO_1122.equals(code)) {
            // The e-mail address is not valid.
          } else if (JSON_ERROR_CODE_PRO_1126.equals(code)
                  && customization.getDefaultMSUValidationMode() == VALIDATION_MODE_CAPTCHA
              || customization.getDefaultMSUValidationMode() == VALIDATION_MODE_SMS_CAPTCHA) {
            // Invalid CAPTCHA token
            signupScreenController.signupFailed(null, false);
            signupScreenController.requestNewCaptcha(true);
            handled = true;
          } else if (JSON_ERROR_CODE_PRO_1127.equals(code)) {
            // Phone number already exist
            String msg = localization.getLanguage("signup_failed_username_exists");
            signupScreenController.signupFailed(msg);
            signupScreenController.promptCredentials();
            handled = true;
          } else if (JSON_ERROR_CODE_PRO_1128.equals(code)) {
            // The phone number provided is not valid.
            signupScreenController.signupFailed(
                localization.getLanguage("signup_failed_bad_phone_message"));
            signupScreenController.promptCredentials();
            handled = true;
          } else if (JSON_ERROR_CODE_COM_1006.equals(code)) {
            // Invalid timezone.
          } else if (JSON_ERROR_CODE_COM_1008.equals(code)) {
            // Invalid data type or data format is not as expected.
          }
          if (!handled) {
            Log.error(TAG_LOG, "Unhandled error code: " + code);
            throw new Exception("Unhandled error code: " + code);
          }
        }
      } else {
        // No errors, the user needs a manual action in order to
        // activate the account. We show a message here to inform the
        // user that he needs to perform such an action, and then the
        // signup process will continue from here
        signupScreenController.showActivationRequiredActionDialog();
      }
    } catch (JSONException ex) {
      if (Log.isLoggable(Log.DEBUG)) {
        Log.debug(TAG_LOG, "Failed to retrieve error json object");
      }
    }
  }
  public void run() {
    if (Log.isLoggable(Log.INFO)) {
      Log.info(TAG_LOG, "Signing up");
    }

    signupScreen.disableSignup();
    signupScreenController.signupStarted();

    // Get the current values from UI
    String serverUrl = signupScreen.getSyncUrl();
    String phoneNumber = signupScreen.getUsername();
    String password = signupScreen.getPassword();
    String token = signupScreen.getCaptchaToken();

    String signupUrl = StringUtil.extractAddressFromUrl(serverUrl);

    SapiHandler sapiHandler = new SapiHandler(signupUrl);
    String jsessionId = signupScreenController.getCurrentJSessionId();
    if (jsessionId != null) {
      sapiHandler.enableJSessionAuthentication(true);
      sapiHandler.forceJSessionId(jsessionId);
    }
    try {
      if (Log.isLoggable(Log.DEBUG)) {
        Log.debug(TAG_LOG, "Sending Signup SAPI request");
      }
      JSONObject request = createMobileSignupRequest(phoneNumber, password);
      Vector params = new Vector();
      StringBuffer tokenParam = new StringBuffer();
      tokenParam.append("token=").append(token);
      params.addElement(tokenParam.toString());
      JSONObject res = sapiHandler.query("mobile", "signup", params, null, request);
      if (!userActivated(res)) {
        if (Log.isLoggable(Log.DEBUG)) {
          Log.debug(TAG_LOG, "Account not activated by the server");
        }
        handleResponseError(res, signupUrl);
        return;
      } else {
        if (Log.isLoggable(Log.INFO)) {
          Log.info(TAG_LOG, "Account activated by the server");
        }
      }
    } catch (NotAuthorizedCallException ex) {
      // This is a non authorized error
      Log.error(TAG_LOG, "Unable to signup", ex);
      signupScreenController.signupFailed(
          localization.getLanguage("signup_failed_generic_message"));
      signupScreenController.promptCredentials();
    } catch (IOException ex) {
      // This is a network failure
      Log.error(TAG_LOG, "Unable to signup", ex);
      signupScreenController.signupFailed(localization.getLanguage("signup_failed_network"));
      signupScreenController.promptCredentials();
      return;
    } catch (Exception ex) {
      // This is a generic failure
      Log.error(TAG_LOG, "Unable to signup", ex);
      signupScreenController.signupFailed(
          localization.getLanguage("signup_failed_generic_message"));
      signupScreenController.promptCredentials();
      return;
    }
    // Signup Succeeded
    signupScreenController.signupSucceeded();
  }