/*
* Copyright 2013-2014 the original author or authors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package devcoin.wallet.ui;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface.OnClickListener;
import com.google.devcoin.core.*;
import com.google.devcoin.uri.BitcoinURI;
import com.google.devcoin.uri.BitcoinURIParseException;
import devcoin.wallet.Constants;
import devcoin.wallet.R;
import devcoin.wallet.util.Bluetooth;
import devcoin.wallet.util.Qr;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.math.BigInteger;
import java.util.regex.Pattern;
/**
* @author Andreas Schildbach
*/
public abstract class InputParser
{
public abstract static class StringInputParser extends InputParser
{
private final String input;
public StringInputParser(@Nonnull final String input)
{
this.input = input;
}
@Override
public void parse()
{
if (input.startsWith("devcoin:"))
{
try
{
final BitcoinURI bitcoinUri = new BitcoinURI(null, input);
final Address address = bitcoinUri.getAddress();
final String addressLabel = bitcoinUri.getLabel();
final BigInteger amount = bitcoinUri.getAmount();
final String bluetoothMac = (String) bitcoinUri.getParameterByName(Bluetooth.MAC_URI_PARAM);
bitcoinRequest(address, addressLabel, amount, bluetoothMac);
}
catch (final BitcoinURIParseException 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);
bitcoinRequest(address, null, null, null);
}
catch (final AddressFormatException x)
{
error(R.string.input_parser_invalid_address);
}
}
else if (PATTERN_PRIVATE_KEY.matcher(input).matches())
{
try
{
final ECKey key = new DumpedPrivateKey(Constants.NETWORK_PARAMETERS, input).getKey();
final Address address = new Address(Constants.NETWORK_PARAMETERS, key.getPubKeyHash());
bitcoinRequest(address, null, null, null);
}
catch (final AddressFormatException 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.decodeBinary(input));
directTransaction(tx);
}
catch (final IOException x)
{
error(R.string.input_parser_invalid_transaction, x.getMessage());
}
catch (final ProtocolException x)
{
error(R.string.input_parser_invalid_transaction, x.getMessage());
}
}
else
{
cannotClassify(input);
}
}
}
public abstract static class BinaryInputParser extends InputParser
{
private final String inputType;
private final byte[] input;
public BinaryInputParser(@Nonnull final String inputType, @Nonnull final byte[] input)
{
this.inputType = inputType;
this.input = input;
}
@Override
public void parse()
{
if (Constants.MIMETYPE_TRANSACTION.equals(inputType))
{
try
{
final Transaction tx = new Transaction(Constants.NETWORK_PARAMETERS, input);
directTransaction(tx);
}
catch (final ProtocolException x)
{
error(R.string.input_parser_invalid_transaction, x.getMessage());
}
}
else
{
cannotClassify(inputType);
}
}
}
public abstract void parse();
protected abstract void bitcoinRequest(@Nonnull Address address, @Nullable String addressLabel, @Nullable BigInteger amount,
@Nullable String bluetoothMac);
protected abstract void directTransaction(@Nonnull Transaction transaction);
protected abstract void error(int messageResId, Object... messageArgs);
protected void cannotClassify(@Nonnull final String input)
{
error(R.string.input_parser_cannot_classify, input);
}
protected void dialog(final Context context, @Nullable final OnClickListener dismissListener, final int titleResId, final int messageResId,
final Object... messageArgs)
{
final Builder dialog = new AlertDialog.Builder(context);
if (titleResId != 0)
dialog.setTitle(titleResId);
dialog.setMessage(context.getString(messageResId, messageArgs));
dialog.setNeutralButton(R.string.button_dismiss, dismissListener);
dialog.show();
}
private static final Pattern PATTERN_BITCOIN_ADDRESS = Pattern.compile("[" + new String(Base58.ALPHABET) + "]{20,40}");
private static final Pattern PATTERN_PRIVATE_KEY = Pattern.compile("5[" + new String(Base58.ALPHABET) + "]{50,51}");
private static final Pattern PATTERN_TRANSACTION = Pattern.compile("[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$\\*\\+\\-\\.\\/\\:]{100,}");
}