package jc;

import javacard.framework.*;
import javacardx.framework.*;

public class Student extends Applet{

	final static byte	SELECT	= (byte)0xA4;	//az ISO 7816-4 SELECT utasítás INS bájtja
	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 bájtja
    final static byte	STUD_CLA	= (byte)0xAD;	//a Student applet CLA bájtja
    final static byte 	SET_EXP_DATE	= (byte)0x10;	//a SetExpDate utasítás INS bájtja
    final static byte 	IS_VALID	= (byte)0x20;	//az IsValid utasítás INS bájtja
    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[] dateBuf = new byte[DATE_LENGTH];
	private byte[] expDate= new byte[DATE_LENGTH];
	boolean justSelected;

    private Student(){	
	}//Student()

    public static void install( APDU apdu ){
    	Student stud = new Student();
    	stud.register();
    }
    public boolean select(){
    	justSelected = true;
    	return true;
    }

    public void process(APDU apdu){
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO.OFFSET_CLA] == STUD_CLA) {
	        switch (buffer[ISO.OFFSET_INS]){
	        	case SET_EXP_DATE:
					processSetExpDate(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 processSetExpDate(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
		if (tdk.ID.p_masterPIN.isValidated()){ //már megadták a Master PIN-t
			Util.arrayCopyNonAtomic(buffer,ISO.OFFSET_CDATA,dateBuf,START,DATE_LENGTH);
			if (!goodDate(dateBuf))
				ISOException.throwIt(ISO.SW_DATA_INVALID);
			else //helyes formátumú dátumok
			{
				Util.arrayCopy(buffer,ISO.OFFSET_CDATA,expDate,START,DATE_LENGTH);
				Util.arrayCopyNonAtomic(expDate,START,buffer,START,DATE_LENGTH);
				apdu.setOutgoingAndSend(START, 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,dateBuf,START,DATE_LENGTH);
		if (!goodDate(dateBuf))
			ISOException.throwIt(ISO.SW_DATA_INVALID);
		if (!(lessThan(dateBuf,expDate) || equals(dateBuf,expDate)))
			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);
	}

}//Student