package com.yoghurt.crypto.transactions.client.util;

import com.googlecode.gwt.crypto.bouncycastle.util.encoders.Hex;
import com.yoghurt.crypto.transactions.client.place.ApplicationPlace;
import com.yoghurt.crypto.transactions.client.place.BlockPlace;
import com.yoghurt.crypto.transactions.client.place.BlockPlace.BlockDataType;
import com.yoghurt.crypto.transactions.client.place.MinePlace;
import com.yoghurt.crypto.transactions.client.place.MinePlace.MineDataType;
import com.yoghurt.crypto.transactions.client.place.TransactionPlace;
import com.yoghurt.crypto.transactions.client.place.TransactionPlace.TransactionDataType;
import com.yoghurt.crypto.transactions.shared.domain.Block;
import com.yoghurt.crypto.transactions.shared.domain.Transaction;
import com.yoghurt.crypto.transactions.shared.util.block.BlockParseUtil;
import com.yoghurt.crypto.transactions.shared.util.transaction.TransactionParseUtil;

public final class PlaceTokenParseUtil {
  private static final String MINE_TOKEN = "mine";
  private static final String LAST_BLOCK_TOKEN = "last";

  // Bunch of zeroes every valid block starts with
  private static final String BLOCK_TOKEN_START = "0000000000";

  // Hash length (256 bit) if encoded into hex
  private static final int HASH_LENGTH = 64;

  // Allows for block heights up to 9999999, will last until the year 2190 or so, I guess we're good
  private static final int MAX_BLOCK_HEIGHT_NUMBER_LENGTH = 7;

  private PlaceTokenParseUtil() {}

  public static ApplicationPlace parseToken(final String token) {
    // Check for keywords first
    if (MINE_TOKEN.equals(token)) {
      return new MinePlace(MineDataType.LAST);
    }
    if (LAST_BLOCK_TOKEN.equals(token)) {
      return new BlockPlace(BlockDataType.LAST);
    }

    // Check if the token is exactly equal to the length of a hash, meaning this is probably a transaction or block hash
    if (token.length() == HASH_LENGTH) {
      // If it starts with a bunch of zeroes, it's probably a block
      if (token.startsWith(BLOCK_TOKEN_START)) {
        return new BlockPlace(BlockDataType.ID, token);
      }
    }

    // If the token is longer than the hash size, this could be a raw transaction or a raw block, so try and parse it
    if(token.length() > HASH_LENGTH) {
      try {
        // If this works out, it's a transaction!
        final Transaction t = new Transaction();
        TransactionParseUtil.parseTransactionBytes(Hex.decode(token), t);
        return new TransactionPlace(TransactionDataType.RAW, token);
      } catch (final Exception e1) {
        try {
          // If this works out, it's a block!
          final Block b = new Block();
          BlockParseUtil.parseBlockBytes(Hex.decode(token), b);
          return new BlockPlace(BlockDataType.RAW, token);
        }catch (final Exception e2) {
          // Eat, this is neither a raw transaction or block
        }
      }
    }

    // Check if the token is a number, probably block height if it is
    if(token.length() <= MAX_BLOCK_HEIGHT_NUMBER_LENGTH) {
      try {
        final int possibleBlockHeight = Integer.parseInt(token);
        return new BlockPlace(BlockDataType.HEIGHT, possibleBlockHeight);
      } catch (final NumberFormatException e) {
        // Eat, this is probably not a number ;)
      }
    }

    // Nope, don't know what to do with this, return null
    return null;
  }
}

@@ -1530,24 +1530,111 @@
 ng token) %7B%0A
+    // Clean up the token first%0A    final String cleanToken = token.replace(%22 %22, %22%22);%0A%0A
     // Check
@@ -1646,22 +1646,16 @@
 keywords
- first
 %0A    if 
@@ -1665,33 +1665,38 @@
 NE_TOKEN.equals(
-t
+cleanT
 oken)) %7B%0A      r
@@ -1773,17 +1773,22 @@
 .equals(
-t
+cleanT
 oken)) %7B
@@ -1969,25 +1969,30 @@
 ash%0A    if (
-t
+cleanT
 oken.length(
@@ -2089,17 +2089,22 @@
     if (
-t
+cleanT
 oken.sta
@@ -2181,17 +2181,22 @@
 ype.ID, 
-t
+cleanT
 oken);%0A 
@@ -2326,33 +2326,38 @@
 parse it%0A    if(
-t
+cleanT
 oken.length() %3E 
@@ -2540,25 +2540,30 @@
 (Hex.decode(
-t
+cleanT
 oken), t);%0A 
@@ -2614,33 +2614,38 @@
 onDataType.RAW, 
-t
+cleanT
 oken);%0A      %7D c
@@ -2823,17 +2823,22 @@
 .decode(
-t
+cleanT
 oken), b
@@ -2891,17 +2891,22 @@
 pe.RAW, 
-t
+cleanT
 oken);%0A 
@@ -3105,17 +3105,22 @@
 %0A    if(
-t
+cleanT
 oken.len
@@ -3231,17 +3231,22 @@
 arseInt(
-t
+cleanT
 oken);%0A 

Clean up the token before parsing