/**
   * @param state The state object
   * @param mode The mode (e.g. standard, Trezor etc)
   */
  public WelcomeWizardModel(WelcomeWizardState state, WelcomeWizardMode mode) {
    super(state);

    log.debug("Welcome wizard starting in state '{}' with mode '{}'", state.name(), mode.name());

    this.seedPhraseGenerator = CoreServices.newSeedPhraseGenerator();
    this.restoringSoftWallet = WelcomeWizardState.WELCOME_SELECT_WALLET.equals(state);
    this.mode = mode;

    // If restoring a Trezor hard wallet, work out the initial screen to show
    if (WelcomeWizardState.RESTORE_WALLET_SELECT_BACKUP.equals(state)) {
      calculateRestoreMethod();
      log.debug("Starting hard wallet restore with state: {}", state);
    }
  }
  @Override
  public void showNext() {

    Optional<HardwareWalletService> hardwareWalletService;

    switch (state) {
      case WELCOME_LICENCE:
        state = WELCOME_SELECT_LANGUAGE;
        break;
      case WELCOME_SELECT_LANGUAGE:
        state = WELCOME_ATTACH_HARDWARE_WALLET;
        break;
      case WELCOME_ATTACH_HARDWARE_WALLET:
        hardwareWalletService = CoreServices.getOrCreateHardwareWalletService();
        if (hardwareWalletService.isPresent() && hardwareWalletService.get().isDeviceReady()) {
          // A Trezor is connected
          mode = WelcomeWizardMode.TREZOR;
          if (hardwareWalletService.get().isWalletPresent()) {
            // User may want to create or restore since they have an initialised device
            state = WELCOME_SELECT_WALLET;
          } else {
            // User can only create from an uninitialised device
            state = TREZOR_CREATE_WALLET_PREPARATION;
          }
        } else {
          // Standard mode
          mode = WelcomeWizardMode.STANDARD;
          state = WELCOME_SELECT_WALLET;
        }
        break;
      case WELCOME_SELECT_WALLET:
        hardwareWalletService = CoreServices.getOrCreateHardwareWalletService();
        if (RESTORE_WALLET_SELECT_BACKUP.equals(selectWalletChoice)) {
          if (hardwareWalletService.isPresent()
              && hardwareWalletService.get().isDeviceReady()
              && hardwareWalletService.get().isWalletPresent()) {
            // Initialised hardware wallet is attached
            calculateRestoreMethod();
            break;
          }
        } else {
          // Ensure Trezor is reset if it is attached and initialised
          if (hardwareWalletService.isPresent() && hardwareWalletService.get().isDeviceReady()) {
            hardwareWalletService.get().requestCancel();
            hardwareWalletService.get().getContext().resetToConnected();
          }
          state = selectWalletChoice;
        }
        break;
      case CREATE_WALLET_PREPARATION:
        state = CREATE_WALLET_SELECT_BACKUP_LOCATION;
        break;
      case CREATE_WALLET_SELECT_BACKUP_LOCATION:
        state = CREATE_WALLET_SEED_PHRASE;
        break;
      case CREATE_WALLET_SEED_PHRASE:
        state = CREATE_WALLET_CONFIRM_SEED_PHRASE;
        // Fail safe to ensure that the generator hasn't gone screwy
        Preconditions.checkState(
            SeedPhraseSize.isValid(getCreateWalletSeedPhrase().size()),
            "'actualSeedPhrase' is not a valid length");
        break;
      case CREATE_WALLET_CONFIRM_SEED_PHRASE:
        state = CREATE_WALLET_CREATE_PASSWORD;
        break;
      case CREATE_WALLET_CREATE_PASSWORD:
        state = CREATE_WALLET_REPORT;
        break;
      case CREATE_WALLET_REPORT:
        throw new IllegalStateException("'Next' is not permitted here");
      case TREZOR_CREATE_WALLET_PREPARATION:
        state = TREZOR_CREATE_WALLET_SELECT_BACKUP_LOCATION;
        break;
      case TREZOR_CREATE_WALLET_SELECT_BACKUP_LOCATION:
        state = TREZOR_CREATE_WALLET_ENTER_DETAILS;
        break;
      case TREZOR_CREATE_WALLET_ENTER_DETAILS:
        state = TREZOR_CREATE_WALLET_REQUEST_CREATE_WALLET;
        break;
      case TREZOR_CREATE_WALLET_REQUEST_CREATE_WALLET:
        state = TREZOR_CREATE_WALLET_CONFIRM_CREATE_WALLET;
        break;
      case TREZOR_CREATE_WALLET_CONFIRM_CREATE_WALLET:
        state = TREZOR_CREATE_WALLET_CONFIRM_ENTROPY;
        break;
      case TREZOR_CREATE_WALLET_CONFIRM_ENTROPY:
        state = TREZOR_CREATE_WALLET_ENTER_NEW_PIN;
        break;
      case TREZOR_CREATE_WALLET_ENTER_NEW_PIN:
        state = TREZOR_CREATE_WALLET_CONFIRM_NEW_PIN;
        break;
      case TREZOR_CREATE_WALLET_CONFIRM_NEW_PIN:
        state = TREZOR_CREATE_WALLET_CONFIRM_WORD;
        break;
      case TREZOR_CREATE_WALLET_CONFIRM_WORD:
        state = TREZOR_CREATE_WALLET_REPORT;
        break;
      case TREZOR_CREATE_WALLET_REPORT:
        break;
      case RESTORE_PASSWORD_SEED_PHRASE:
        state = RESTORE_PASSWORD_REPORT;
        break;
      case RESTORE_PASSWORD_REPORT:
        break;
      case RESTORE_WALLET_SEED_PHRASE:
        if (!isLocalZipBackupPresent()) {
          restoreMethod = RESTORE_WALLET_SELECT_BACKUP_LOCATION;
        } else {
          restoreMethod = RESTORE_WALLET_SELECT_BACKUP;
        }
        state = restoreMethod;
        break;
      case RESTORE_WALLET_SELECT_BACKUP_LOCATION:
        if (isCloudBackupPresent()) {
          restoreMethod = RESTORE_WALLET_SELECT_BACKUP;
        } else {
          restoreMethod = RESTORE_WALLET_TIMESTAMP;
        }
        state = restoreMethod;
        break;
      case RESTORE_WALLET_SELECT_BACKUP:
        state = RESTORE_WALLET_REPORT;
        break;
      case RESTORE_WALLET_TIMESTAMP:
        state = RESTORE_WALLET_REPORT;
        break;
      case RESTORE_WALLET_REPORT:
        throw new IllegalStateException("'Next' is not permitted here");
      default:
        throw new IllegalStateException("Unknown state: " + state.name());
    }
  }