package BFTSmartBlockchain;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.util.HashSet;
import java.util.Set;

public class BlockchainTest {

	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {

		int clientId = Integer.parseInt(args[0]);
		BlockchainClient blockchain = new BlockchainClient(clientId);
		
		// Select an Elliptic Curve (discrete logarithm) based key generator
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
		// Set algorithm parameters for key pair generator
		ECGenParameterSpec curveSpec = new ECGenParameterSpec("secp256k1");
		// Initialize the key pair generator with the curve specification and the random number generator
	    keyPairGen.initialize(curveSpec);	
	    // Generate a key pair
		KeyPair ECKeyPair = keyPairGen.generateKeyPair();
		ECPublicKey publicKey = (ECPublicKey) ECKeyPair.getPublic();
		ECPrivateKey privateKey = (ECPrivateKey) ECKeyPair.getPrivate();
		
		Set<Transaction> transactions1 = new HashSet<Transaction>();
		transactions1.add(new Transaction("Hello World".getBytes(), publicKey).Sign(privateKey));
		transactions1.add(new Transaction("I Love Blockchains".getBytes(), publicKey).Sign(privateKey));

		boolean exit = false;
		String key, value, result;
		while(!exit) {
			System.out.println("Select an option:");
			System.out.println("0 - Exit");
			System.out.println("1 - Create a new transaction");
			System.out.println("2 - Get blockchain head");
			System.out.println("3 - Get block b blocks back from head");
			
			int cmd = Integer.parseInt(System.console().readLine("Option:"));
			
			switch (cmd) {
				case 0:
					exit = true;
					break;
				case 1:
					System.out.println("Create a new transaction");
					String data = System.console().readLine("Enter the data value:");
					Transaction tx = new Transaction(data.getBytes(), publicKey).Sign(privateKey);
					BlockchainReplyType result = blockchain.addTransaction(tx);
					switch (result) {
					case OK:
						System.out.println("Succesfully added Transaction to pool");
						break;
					case DUPLICATE:
						System.out.println("Transaction was duplicate");
						break;
					case BLOCK:
						System.out.println("Transaction added and new block mined");
				}

					value = console.readLine("Enter the value:");
					result =  map.put(key, value);
					System.out.println("Previous value: " + result);
					break;
				case 2:
					System.out.println("Reading value from the map");
					key = console.readLine("Enter the key:");
					result =  map.get(key);
					System.out.println("Value read: " + result);
					break;
				case 3:
					System.out.println("Removing value in the map");
					key = console.readLine("Enter the key:");
					result =  map.remove(key);
					System.out.println("Value removed: " + result);
					break;
				case 4:
					System.out.println("Getting the map size");
					int size = map.size();
					System.out.println("Map size: " + size);
					break;
				case 5:
					System.out.println("Getting all keys");
					Set<String> keys = map.keySet();
					System.out.println("Total number of keys found: " + keys.size());
					for (String k : keys)
						System.out.println("---> " + k);
					break;
				default:
					break;
			}
		}
	}
		
		
		
		
		Block block1 = new Block(transactions1, null);
		// create a new block with these transactions
		chain.AddBlock(block1);
		System.out.println(chain);
		System.out.println(chain.VerifyChain());
		
		// create and sign some more transactions
		Set<Transaction> transactions2 = new HashSet<Transaction>();
		transactions2.add(new Transaction("Osnabrueck is the center of the world".getBytes(), publicKey).Sign(privateKey));
		transactions2.add(new Transaction("Blockchains are cool".getBytes(), publicKey).Sign(privateKey));
		
		Block block2 = new Block(transactions2, block1.blockHash);
		// create a new block with these transactions
		chain.AddBlock(block2);
		System.out.println(chain);		
		System.out.println(chain.VerifyChain());
	}

}
