package com.silentmission.ewallet.cardservices;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;

import opencard.core.util.HexString;
import opencard.core.service.CardServiceOperationFailedException;
import opencard.core.service.CardChannel;
import opencard.core.terminal.CommandAPDU;
import opencard.core.terminal.ResponseAPDU;
import opencard.core.terminal.CardTerminalException;

import com.silentmission.ewallet.exceptions.*;

public class TestWalletCardService
    extends opencard.core.service.CardService
{

    final static byte[] readCardData = HexString.parseHexString("B040000000");
    
    private byte[] readCardData()	
		throws CardServiceOperationFailedException,
	       CardTerminalException {
    	
    	allocateCardChannel();
    	CardChannel channel = getCardChannel();
	
    	selectTestWalletApplet(channel);

    	CommandAPDU cmd = new CommandAPDU(32);
    	cmd.append(readCardData);
    	ResponseAPDU rsp = channel.sendCommandAPDU(cmd);

    	if (rsp.sw() != 0x9000)
    		throw new CardServiceOperationFailedException("readCardData Error " + Integer.toHexString(rsp.sw()));

    	releaseCardChannel();
    	return rsp.data();
    }

    final static byte[] writeCardData= HexString.parseHexString("B020000054");
    public void writeCardData(byte[] data)
	throws CardServiceOperationFailedException,
	       CardTerminalException
    {
	allocateCardChannel();
	CardChannel channel = getCardChannel();

	selectTestWalletApplet(channel);

	CommandAPDU cmd = new CommandAPDU(128);
	cmd.append(writeCardData);
	cmd.append(data);
	ResponseAPDU rsp = channel.sendCommandAPDU(cmd);

	int sw = rsp.sw();	
	if (sw != 0x9000)
	    throw new CardServiceOperationFailedException("writeCardData Error" + Integer.toHexString(rsp.sw()));

	releaseCardChannel();
    }

    public String getCardHolderName()
	throws CardServiceOperationFailedException,
	       CardTerminalException
    {
	byte[] buffer = readCardData();

	System.out.println("bytes from card : " + buffer.length);
	System.out.println("just read");
	System.out.println(HexString.dump(buffer));

	DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buffer));
	byte[] nameBytes = new byte[52];
	try
	{	
	    dis.readFully(nameBytes, 0, 50);
	}
	catch(Exception e)
	{
	    System.out.println("error in getCardHolderName : " + e);
	}
	String name = new String(nameBytes);
	name = name.substring(0, name.indexOf(0));

	System.out.println(name);

	return name;
    }

    public int walletBalance()
		throws CardServiceOperationFailedException, CardTerminalException {
	
    	int balance = 0;

    	byte[] buffer = readCardData();
    	DataInputStream dis = new DataInputStream(new ByteArrayInputStream(buffer));
    	
    	try {	
	      dis.skipBytes(52);
	      balance = dis.readInt();
    	}
    	catch(Exception e) {
    		System.out.println("error in walletBalance : " + e);
    	}
    	
    	System.out.println("in balance : " + balance);
    	return balance;
    }

    public void creditWallet(int amount)
	throws CardServiceOperationFailedException,
	       CardTerminalException
    {
	int balance = 0;
	int rp  = 0;
	int tcr = 0;
	int trr = 0;
	int pcn = 0;
	int re  = 0;
	int uv  = 0;
	int mp  = 0;
	byte[] readBuffer = readCardData();
	byte[] tempBuffer = new byte[64];
	DataInputStream dis = new DataInputStream(new ByteArrayInputStream(readBuffer));
	ByteArrayOutputStream bos = new ByteArrayOutputStream(90);
	DataOutputStream dos = new DataOutputStream(bos);
	try
	{
	    dis.readFully(tempBuffer, 0, 52);
	    balance = dis.readInt();
	    rp  = dis.readInt();
	    tcr = dis.readInt();
	    trr = dis.readInt();
	    pcn = dis.readInt();
	    re  = dis.readInt();
	    uv  = dis.readInt();
	    mp  = dis.readInt();

	    dos.write(tempBuffer, 0, 52);
	    dos.writeInt(balance + amount);
	    dos.writeInt(rp);
	    dos.writeInt(tcr);
	    dos.writeInt(trr);
	    dos.writeInt(pcn);
	    dos.writeInt(re);
	    dos.writeInt(uv);
	    dos.writeInt(mp);
	}
	catch(Exception e)
	{
	    System.out.println("error in creditWallet : " + e);
	}
	writeCardData(bos.toByteArray());
    }

    public void debitWallet(int amount)
	throws CardServiceOperationFailedException,
	       CardTerminalException,
	       NegativeBalanceException
    {
	int balance = 0;
	int rp  = 0;
	int tcr = 0;
	int trr = 0;
	int pcn = 0;
	int re  = 0;
	int uv  = 0;
	int mp  = 0;
	byte[] readBuffer = readCardData();
	byte[] tempBuffer = new byte[64];
	DataInputStream dis = new DataInputStream(new ByteArrayInputStream(readBuffer));
	ByteArrayOutputStream bos = new ByteArrayOutputStream(90);
	DataOutputStream dos = new DataOutputStream(bos);
	try
	{	
	    dis.readFully(tempBuffer, 0, 52);
	    balance = dis.readInt();
	    rp  = dis.readInt();
	    tcr = dis.readInt();
	    trr = dis.readInt();
	    pcn = dis.readInt();
	    re  = dis.readInt();
	    uv  = dis.readInt();
	    mp  = dis.readInt();
	    int newbalance = balance - amount;
	    if(newbalance < 0)
		throw new NegativeBalanceException();

	    dos.write(tempBuffer, 0, 52);
	    dos.writeInt(newbalance);
	    dos.writeInt(rp);
	    dos.writeInt(tcr + amount);
	    dos.writeInt(trr);
	    dos.writeInt(pcn);
	    dos.writeInt(re);
	    dos.writeInt(uv);
	    dos.writeInt(mp);
	}
	catch(Exception e)
	{
	    System.out.println("error in creditWallet : " + e);
	}
	writeCardData(bos.toByteArray());

    }

    final static byte[] selectTestWalletApplet = HexString.parseHexString("00A404000644656D6F4944");
    
    void selectTestWalletApplet(CardChannel channel)
	throws CardServiceOperationFailedException,
	       CardTerminalException
    {
	CommandAPDU cmd = new CommandAPDU(32);
	cmd.append(selectTestWalletApplet);
	ResponseAPDU rsp = channel.sendCommandAPDU(cmd);
       
	if (rsp.sw() != 0x9000)
	    throw new CardServiceOperationFailedException("selectTestWalletApplet Error " + Integer.toHexString(rsp.sw()));
    }
}
