import AcsCommon.*;
import Pcsc.PcscReader;

public class ISO15693 {
	private PcscReader pcscReader_;

	public PcscReader getPcscConnection() {
		return this.pcscReader_;
	}

	public void setPcscConnection(PcscReader pcscConnection) {
		this.pcscReader_ = pcscConnection;
	}

	public ISO15693() {
		pcscReader_ = null;
	}

	public ISO15693(PcscReader pcscReader) {
		setPcscConnection(pcscReader);
	}

	public void getData() throws Exception {
		Apdu apdu = new Apdu();

		apdu.setCommand(new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x80, (byte) 0x00, (byte) 0x00 });
		apdu.setLengthExpected(256);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception(
					"[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Get Data failed");
	}

	public void getSystemInformation() throws Exception {
		Apdu apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, 0x01});
		apdu.setSendData(new byte[] {0x2B});
		apdu.setLengthExpected(256);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception(
					"[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Get System Information failed");
	}

	public void readSingleBlock(byte blockNo) throws Exception {
		Apdu apdu;
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, 0x02});
		apdu.setSendData(new byte[] {0x20, blockNo});
		apdu.setLengthExpected(256);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Read Single Block failed");
	}

	public void writeSingleBlock(byte blockNo, byte[] data) throws Exception {
		Apdu apdu;
		byte[] sendData = new byte[2 + data.length];
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, (byte)(sendData.length)});
		System.arraycopy(new byte[] {0x21, blockNo}, 0, sendData, 0, 2);
		System.arraycopy(data,  0,  sendData,  2,  data.length);
		apdu.setSendData(sendData);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Write Single Block failed");
	}

	public void readMultipleBlocks(byte firstBlockNo, byte numBlocks) throws Exception {
		Apdu apdu;
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, 0x03});
		apdu.setSendData(new byte[] {0x23, firstBlockNo, (byte)(numBlocks - 1)});
		apdu.setLengthExpected(256);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Read Multiple Blocks failed");
	}

	public void writeMultipleBlocks(byte firstBlockNo, byte numBlocks, byte[] data) throws Exception {
		Apdu apdu;
		byte[] sendData = new byte[3 + data.length];
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, (byte)(sendData.length)});
		System.arraycopy(new byte[] {0x24, firstBlockNo, (byte)(numBlocks - 1)}, 0, sendData, 0, 3);
		System.arraycopy(data,  0,  sendData,  3,  data.length);
		apdu.setSendData(sendData);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Write Single Block failed");
	}

	public void getMultipleBlocksSecurityStatus(byte firstBlockNo, byte numBlocks) throws Exception {
		Apdu apdu;
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, 0x03});
		apdu.setSendData(new byte[] {0x2C, firstBlockNo, (byte)(numBlocks - 1)});
		apdu.setLengthExpected(256);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Get Multiple Blocks Security Status failed");
	}

	public void lockBlock(byte blockNo) throws Exception {
		Apdu apdu;
		apdu = new Apdu();
		apdu.setCommand(new byte[] {(byte) 0xFF, (byte) 0xFB, 0x00, 0x00, 0x02});
		apdu.setSendData(new byte[] {0x22, blockNo});
		apdu.setLengthExpected(2);

		getPcscConnection().sendApduCommand(apdu);

		if (apdu.getStatusWord()[0] != (byte) 0x90)
			throw new Exception("[" + Helper.byteAsString(apdu.getStatusWord(), false) + "]" + " Lock Block failed");
	}
}
