@Override
    public void parse() {
      if (Constants.MIMETYPE_TRANSACTION.equals(inputType)) {
        try {
          final Transaction tx = new Transaction(Constants.NETWORK_PARAMETERS, input);

          handleDirectTransaction(tx);
        } catch (final VerificationException x) {
          log.info("got invalid transaction", x);

          error(R.string.input_parser_invalid_transaction, x.getMessage());
        }
      } else if (PaymentProtocol.MIMETYPE_PAYMENTREQUEST.equals(inputType)) {
        try {
          parseAndHandlePaymentRequest(input);
        } catch (final PaymentProtocolException.PkiVerificationException x) {
          log.info("got unverifyable payment request", x);

          error(R.string.input_parser_unverifyable_paymentrequest, x.getMessage());
        } catch (final PaymentProtocolException x) {
          log.info("got invalid payment request", x);

          error(R.string.input_parser_invalid_paymentrequest, x.getMessage());
        }
      } else {
        cannotClassify(inputType);
      }
    }
    @Override
    public void parse() {
      if (PaymentProtocol.MIMETYPE_PAYMENTREQUEST.equals(inputType)) {
        ByteArrayOutputStream baos = null;

        try {
          baos = new ByteArrayOutputStream();
          Io.copy(is, baos);
          parseAndHandlePaymentRequest(baos.toByteArray());
        } catch (final IOException x) {
          log.info("i/o error while fetching payment request", x);

          error(R.string.input_parser_io_error, x.getMessage());
        } catch (final PaymentProtocolException.PkiVerificationException x) {
          log.info("got unverifyable payment request", x);

          error(R.string.input_parser_unverifyable_paymentrequest, x.getMessage());
        } catch (final PaymentProtocolException x) {
          log.info("got invalid payment request", x);

          error(R.string.input_parser_invalid_paymentrequest, x.getMessage());
        } finally {
          try {
            if (baos != null) baos.close();
          } catch (IOException x) {
            x.printStackTrace();
          }

          try {
            is.close();
          } catch (IOException x) {
            x.printStackTrace();
          }
        }
      } else {
        cannotClassify(inputType);
      }
    }
  /**
   * @param e The payment protocol exception (specific problem)
   * @param hostName The host name
   * @return A suitable payment session summary
   */
  public static PaymentSessionSummary newPaymentSessionFromException(
      PaymentProtocolException e, String hostName) {

    log.warn("Failed payment session: Host={} Failure={}", hostName, e.getMessage());

    // Default handling is ERROR

    if (e instanceof PaymentProtocolException.Expired) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_EXPIRED,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidNetwork) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_INVALID_NETWORK,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidOutputs) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_INVALID_OUTPUTS,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidPaymentRequestURL) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_INVALID_REQUEST_URL,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidPaymentURL) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_INVALID_PAYMENT_URL,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidVersion) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_INVALID_VERSION,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidPkiData) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_PKI_INVALID,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.InvalidPkiType) {
      return new PaymentSessionSummary(
          Optional.<PaymentSession>absent(),
          Optional.<PaymentProtocol.PkiVerificationData>absent(),
          PaymentSessionStatus.UNTRUSTED,
          RAGStatus.AMBER,
          CoreMessageKey.PAYMENT_SESSION_PKI_INVALID_TYPE,
          new String[] {hostName, e.getMessage()});
    }
    if (e instanceof PaymentProtocolException.PkiVerificationException) {

      // This is a bit lame but the only way to differentiate PKI failures from untrusted
      if (e.getCause() != null && e.getCause() instanceof CertPathValidatorException) {
        // Untrusted CA (user might want to add it to the trust store)
        return new PaymentSessionSummary(
            Optional.<PaymentSession>absent(),
            Optional.<PaymentProtocol.PkiVerificationData>absent(),
            PaymentSessionStatus.UNTRUSTED,
            RAGStatus.AMBER,
            CoreMessageKey.PAYMENT_SESSION_PKI_UNTRUSTED_CA,
            new String[] {hostName, e.getMessage()});
      } else {
        return new PaymentSessionSummary(
            Optional.<PaymentSession>absent(),
            Optional.<PaymentProtocol.PkiVerificationData>absent(),
            PaymentSessionStatus.UNTRUSTED,
            RAGStatus.AMBER,
            CoreMessageKey.PAYMENT_SESSION_PKI_MISSING,
            new String[] {hostName, e.getMessage()});
      }
    }

    // Unknown
    return new PaymentSessionSummary(
        Optional.<PaymentSession>absent(),
        Optional.<PaymentProtocol.PkiVerificationData>absent(),
        PaymentSessionStatus.ERROR,
        RAGStatus.AMBER,
        CoreMessageKey.PAYMENT_SESSION_ERROR,
        new String[] {hostName, e.getMessage()});
  }
    @Override
    public void parse() {
      if (input.startsWith("MINTCOIN:-")) {
        try {
          final byte[] serializedPaymentRequest = Qr.decodeBinary(input.substring(9));

          parseAndHandlePaymentRequest(serializedPaymentRequest);
        } catch (final IOException x) {
          log.info("i/o error while fetching payment request", x);

          error(R.string.input_parser_io_error, x.getMessage());
        } catch (final PaymentProtocolException.PkiVerificationException x) {
          log.info("got unverifyable payment request", x);

          error(R.string.input_parser_unverifyable_paymentrequest, x.getMessage());
        } catch (final PaymentProtocolException x) {
          log.info("got invalid payment request", x);

          error(R.string.input_parser_invalid_paymentrequest, x.getMessage());
        }
      } else if (input.startsWith("mintcoin:")) {
        try {
          final BitcoinURI bitcoinUri = new BitcoinURI(null, input);
          final Address address = bitcoinUri.getAddress();
          if (address != null && !Constants.NETWORK_PARAMETERS.equals(address.getParameters()))
            throw new BitcoinURIParseException("mismatched network");

          handlePaymentIntent(PaymentIntent.fromBitcoinUri(bitcoinUri));
        } catch (final BitcoinURIParseException x) {
          log.info("got invalid bitcoin uri: '" + input + "'", x);

          error(R.string.input_parser_invalid_bitcoin_uri, input);
        }
      } else if (PATTERN_BITCOIN_ADDRESS.matcher(input).matches()) {
        try {
          final Address address = new Address(Constants.NETWORK_PARAMETERS, input);

          handlePaymentIntent(PaymentIntent.fromAddress(address, null));
        } catch (final AddressFormatException x) {
          log.info("got invalid address", x);

          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_DUMPED_PRIVATE_KEY_UNCOMPRESSED.matcher(input).matches()
          || PATTERN_DUMPED_PRIVATE_KEY_COMPRESSED.matcher(input).matches()) {
        try {
          final VersionedChecksummedBytes key =
              new DumpedPrivateKey(Constants.NETWORK_PARAMETERS, input);

          handlePrivateKey(key);
        } catch (final AddressFormatException x) {
          log.info("got invalid address", x);

          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_BIP38_PRIVATE_KEY.matcher(input).matches()) {
        try {
          final VersionedChecksummedBytes key =
              new BIP38PrivateKey(Constants.NETWORK_PARAMETERS, input);

          handlePrivateKey(key);
        } catch (final AddressFormatException x) {
          log.info("got invalid address", x);

          error(R.string.input_parser_invalid_address);
        }
      } else if (PATTERN_TRANSACTION.matcher(input).matches()) {
        try {
          final Transaction tx =
              new Transaction(Constants.NETWORK_PARAMETERS, Qr.decodeDecompressBinary(input));

          handleDirectTransaction(tx);
        } catch (final IOException x) {
          log.info("i/o error while fetching transaction", x);

          error(R.string.input_parser_invalid_transaction, x.getMessage());
        } catch (final ProtocolException x) {
          log.info("got invalid transaction", x);

          error(R.string.input_parser_invalid_transaction, x.getMessage());
        }
      } else {
        cannotClassify(input);
      }
    }