package jc;

import javacard.framework.*;
import javacardx.framework.*;

public class BTC_Pass extends Applet{

	final static byte	SELECT	= (byte)0xA4;	//az ISO 7816-4 SELECT utasítás INS byte-ja
	final static short	DATE_LENGTH =  4;		//a dátumot 4 byte-on tároljuk ÉÉHN formában
    final static byte   ISO_CLA = (byte)0x00;	//az ISO 7816-4 fájlkezelő utasítások CLA byte-ja
    final static byte	PASS_CLA	= (byte)0xAC;	//a BTC_Pass applet CLA byte-ja
    final static byte 	SET_VALID	= (byte)0x10;	//a SetValid utasítás INS byte-ja
    final static byte 	IS_VALID	= (byte)0x20;	//az IsValid utasítás INS byte-ja
    final static byte 	START	=	0;			//nullás offszet buffer-műveletekhez
    final static short	NOT_VALID 
    	= (short) 0x9101; //SW bájtok a "nem érvényes" esemény jelzésére

	byte[] date1Buf = new byte[DATE_LENGTH];
	byte[] date2Buf = new byte[DATE_LENGTH];
	private byte[] beginDate= new byte[DATE_LENGTH];
	private byte[] endDate= new byte[DATE_LENGTH];
	boolean justSelected;

    private BTC_Pass(){	
	}//BTC_Pass()

    public static void install( APDU apdu ){
    	BTC_Pass pass = new BTC_Pass();
    	pass.register();
    }
    public boolean select(){
    	justSelected = true;
    	return true;
    }

    public void process(APDU apdu){
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO.OFFSET_CLA] == PASS_CLA) {
	        switch (buffer[ISO.OFFSET_INS]){
	        	case SET_VALID:
					processSetValid(apdu); break;
				case IS_VALID:
					processIsValid(apdu); break;
				default:
					ISOException.throwIt(ISO.SW_INS_NOT_SUPPORTED);
			}//switch
        }//if
        else if (buffer[ISO.OFFSET_CLA] == ISO_CLA) {
        	if ((buffer[ISO.OFFSET_INS] == SELECT) & justSelected) {
        	// most választották ki az appletünket
				processSelected();
			}else ISOException.throwIt(ISO.SW_INS_NOT_SUPPORTED);
		}else ISOException.throwIt(ISO.SW_CLA_NOT_SUPPORTED);
	}//process
	
	void processSelected(){
		justSelected = false;
	}


	void processSetValid(APDU apdu){
		byte[] buffer = apdu.getBuffer();
		if (buffer[ISO.OFFSET_P1] != 0)
			ISOException.throwIt(ISO.SW_INCORRECT_P1P2);
		if (buffer[ISO.OFFSET_P2] != 0)
			ISOException.throwIt(ISO.SW_INCORRECT_P1P2);
		if (buffer[ISO.OFFSET_LC] != (short)(2*DATE_LENGTH))
			ISOException.throwIt(ISO.SW_WRONG_LENGTH);
		apdu.setIncomingAndReceive();    //beolvassuk az adatokat
		if (tdk.ID.p_masterPIN.isValidated()){ //már megadták a Master PIN-t
			Util.arrayCopyNonAtomic(buffer,ISO.OFFSET_CDATA,date1Buf,START,DATE_LENGTH);
			Util.arrayCopyNonAtomic(buffer,(short)(ISO.OFFSET_CDATA+DATE_LENGTH),date2Buf,START,DATE_LENGTH);
			if (!goodDate(date1Buf))
				ISOException.throwIt(ISO.SW_DATA_INVALID);
			else if (!goodDate(date2Buf))
				ISOException.throwIt(ISO.SW_DATA_INVALID);
			else if (!(lessThan(date1Buf,date2Buf) || equals(date1Buf,date2Buf)))
				ISOException.throwIt(ISO.SW_DATA_INVALID);
			else //helyes formátumú dátumok
			{
				
				javacard.framework.System.beginTransaction();
				//két bájtvektort kell konzisztensen állítani, ezért
				//kell a tranzakciókezelés
				
				Util.arrayCopy(buffer,ISO.OFFSET_CDATA,beginDate,START,DATE_LENGTH);
				Util.arrayCopy(buffer,(short)(ISO.OFFSET_CDATA+DATE_LENGTH),endDate,START,DATE_LENGTH);
		
				javacard.framework.System.commitTransaction();
				
				Util.arrayCopyNonAtomic(beginDate,START,buffer,START,DATE_LENGTH);
				Util.arrayCopyNonAtomic(endDate,START,buffer,DATE_LENGTH,DATE_LENGTH);
				apdu.setOutgoingAndSend(START, (short)(2*DATE_LENGTH));
			}
		} else ISOException.throwIt(ISO.SW_CONDITIONS_NOT_SATISFIED);
	}

	void processIsValid(APDU apdu){
		byte[] buffer = apdu.getBuffer();
		if (buffer[ISO.OFFSET_P1] != 0)
			ISOException.throwIt(ISO.SW_INCORRECT_P1P2);
		if (buffer[ISO.OFFSET_P2] != 0)
			ISOException.throwIt(ISO.SW_INCORRECT_P1P2);
		if (buffer[ISO.OFFSET_LC] != DATE_LENGTH)
			ISOException.throwIt(ISO.SW_WRONG_LENGTH);
		apdu.setIncomingAndReceive();    //beolvassuk az adatokat
		Util.arrayCopyNonAtomic(buffer,ISO.OFFSET_CDATA,date1Buf,START,DATE_LENGTH);
		if (!goodDate(date1Buf))
			ISOException.throwIt(ISO.SW_DATA_INVALID);
		if (!(lessThan(date1Buf,endDate) || equals(date1Buf,endDate)))
			ISOException.throwIt(NOT_VALID);
		else if (lessThan(date1Buf,beginDate))
			ISOException.throwIt(NOT_VALID);
	}

	/**Megadja, hogy date helyes formátumú-e.
	Date akkor helyes formátumú, ha ÉÉHN (É=év H=hónap N=nap) formátumú
	és minden dátum mező értelmes, illetve az év 1980 és 2050 között van,
	a határokat nem beleértve */
	boolean goodDate(byte[] date){
		short year;
		byte month;
		byte day;
		
		year=Util.getShort(date,START);
		month=date[2];
		day=date[3];
		if (!((short)1980<year && year<(short)2050))
			return false;
		else if (!((byte)0<month && month<(byte)13))
			return false;
		else if (!((byte)0<day && day<(byte)32))
			return false;
		else return true;
	}

	/** Megadja, hogy date1 kisebb-e mint date2 */
	boolean lessThan(byte[] date1, byte[] date2){
		return (Util.arrayCompare(date1,START,date2,START,DATE_LENGTH) == (byte)-1);
	}

	/** Megadja, hogy date1 és date2 egyenlőek-e */
	boolean equals(byte[] date1, byte[] date2){
		return (Util.arrayCompare(date1,START,date2,START,DATE_LENGTH) == (byte)0);
	}

}//BTC_Pass