/** 
* File: Send.java 
* Date: 98.06
* Location: Terminal
*/

public class Send implements Constants{

	final static String MYGETCOMM=new String("3355");
	final static String MYSETCOMM=new String("3366");
	final static String MYAPPFILE=new String("3333");	

	final static int WRONG_PIN=0x6b10;

	static Reader reader;

	/**
	*This is the procedure, to determine the ID and the holder's name 
	*@param PIN the pin code 
	*@param name to this StringBuffer appends the name of card holder
	*@param id to this StringBuffer appends the card id
	*@exeption in case of any error, allso in case of wrong pin code
	*/
	public static void GetNameAndID(
			String PIN, 
			StringBuffer name, 
			StringBuffer id)
			throws STUDException{
	
		if(PIN.length()!=4) 
			throw new STUDException("Wrong pin code length");

		//variables:
		reader=new Reader();
		StringBuffer response=new StringBuffer("");
		StatusWord statusword=new StatusWord();

		//init the reader:
		try{
			reader.ReaderAllocate("Reflex60","COM2");
			reader.ReaderPowerUp();
			reader.ReaderReset(response);
		}catch(Exception e){
			showerror("ffff","Can't allocate the reader\n");
		}
			
		//init my cardlet:		
		try{
			response=new StringBuffer("");
			//System.out.println("Send:F0F2"+MYAPPFILE+"010F");
			reader.ReaderSendIsoOutT0("F0F2"+MYAPPFILE+"010F",
				response,statusword);
		}catch(Exception ex){
			showerror("ffff","Can't init the cardlet\n");
		}

		//test the ST.SUCCESS
		if(!response.toString().equals("9000"))
			showerror(response.toString(),"Error at init cardlet:");

		//RESET: 
		try{
			response=new StringBuffer("");
			//System.out.println("RESET");
			reader.ReaderReset(response);
		}catch(Exception ex){
			showerror("ffff","Can't RESET the card\n");
		}

		//communication with my cardlet:
		try{
			response=new StringBuffer("");

			//System.out.println("Send:"+				
				//(MYGETCOMM+PIN+"00").toUpperCase());
                        reader.ReaderSendIsoOutT0(
				(MYGETCOMM+PIN+"00").toUpperCase(),
					response,statusword);
		}catch(Exception e){
			showerror("ffff","Problem with cardlet\n");
		}

		//test the ST.SUCCESS
		String sw=response.toString();
			//cat the last 4 digits:
		sw=sw.substring((sw.length()<4)? 0 : sw.length()-4 ,sw.length()); 
		if(!sw.equals("9000"))
			showerror(sw,"Error at send command:");
		
		//transform the result and append 
		//  to id and name StringBuffers:
		id.append(response.toString().substring(4,2*0x10));
		String str=response.toString().substring(2*0x10,2*0x30);
		for(int i=0;i<2*0x20;i+=2)
			name.append((char)Integer.parseInt(str.substring(i,i+2),16));

		//turn off the reader
		try{
			reader.ReaderFree();
		}catch(Exception e){
			throw new STUDException("Can't deallocate the reader\n",false);
		}
	}


	/**
	*This is the procedure, to set the pin code, Id and the holder's name 
	*@param oldPIN the actual pin code
	*@param newPIN the new pin code
	*@param the new name
	*@param the new id
	*@exception in case of error or wrong pin code
	*/
	public static void SetNameAndID(
			String oldPIN,
			String newPIN, 
			StringBuffer name, 
			StringBuffer id)
			throws STUDException{

		if(oldPIN.length()!=4)    //pin's
			throw new STUDException("Wrong old pin code length");
		if(newPIN.length()!=4) 
			throw new STUDException("Wrong new pin code length");

		if(id.length()!=2*14)     //id 
			throw new STUDException("Wrong Id length");

			//update newdata:
		StringBuffer newdata=new StringBuffer(newPIN);
		newdata.append(id.toString().toUpperCase());
		for(int i=0;i<0x20;i++){    //name
			if(name.length()>i){
				newdata.append(
					Integer.toHexString( 
					(int)name.charAt(i) ));
			}else{
				newdata.append("00");
			}
		}
		//System.out.println("New data:"+newdata);

		//variables:
		reader=new Reader();
		StringBuffer response=new StringBuffer("");
		StatusWord statusword=new StatusWord();

		//init the reader:
		try{
			reader.ReaderAllocate("Reflex60","COM2");
			reader.ReaderPowerUp();
			reader.ReaderReset(response);
		}catch(Exception e){
			showerror("ffff","Can't allocate the reader\n");
		}
			
		//Init my cardlet:		
		try{
			response=new StringBuffer("");
			//System.out.println("Send:F0F2"+MYAPPFILE+"010F");
			reader.ReaderSendIsoOutT0("F0F2"+MYAPPFILE+"010F",
				response,statusword);
		}catch(Exception ex){
			showerror("ffff","Can't init the cardlet\n");
		}

		//test the ST.SUCCESS
		if(!response.toString().equals("9000"))
			showerror(response.toString(),"Error at init cardlet:");

		//RESET: 
		try{
			response=new StringBuffer("");
			//System.out.println("RESET");
			reader.ReaderReset(response);
		}catch(Exception ex){
			showerror("ffff","Can't RESET the card\n");
		}

		//communication with my cardlet:
		try{
			response=new StringBuffer("");
			//System.out.println("Send:"+
				//(MYSETCOMM+oldPIN+"30"+newdata).toUpperCase());

			reader.ReaderSendIsoInT0(
				(MYSETCOMM+oldPIN+"30"+newdata).toUpperCase(),
				response,statusword);
		}catch(Exception e){
			showerror("ffff","Problem with cardlet\n");
		}

		//test the ST.SUCCESS
		String sw=response.toString();
		sw=sw.substring((sw.length()<4)? 0 : sw.length()-4 ,sw.length());
		if(!sw.equals("9000"))
			showerror(sw,"Error at send command:");
		
		//turn off the reader
		try{
			reader.ReaderFree();
		}catch(Exception e){
			throw new STUDException("Can't deallocate the reader\n",false);
		}
	}

	/**
	*Throws an exception in case of error
	*@param sw the status word returnd from card
	*@param prefix the prefix of exceptions comment, this will be the hole comment in case of another exception
	*/
	public  static void showerror(String sw,String prefix) throws STUDException{

		STUDException exi;
		switch(Integer.parseInt(sw,16)){  
		case 0x6a82:
			exi= new STUDException(prefix+
			"File not found",0x6a82);
			break;
		case 0x6b00:
			exi= new STUDException(prefix+
			"Incorrect parameters",0x6b00);
			break;
		case 0x6a80:
			exi= new STUDException(prefix+
			"Invalid file type",0x6a80);
			break;
		case 0x6300:
			exi= new STUDException(prefix+
			"No action performed",0x6300);
			break;
		case 0x6982:
			exi= new STUDException(prefix+
			"No privilage to execute the application",0x6982);
			break;
		case WRONG_PIN:
			exi= new STUDException(prefix+
			"Wrong PIN code",WRONG_PIN);
			break;
		case 0xffff:
			exi= new STUDException(prefix);
			break;
		default:
			exi= new STUDException(prefix+
			sw,Integer.parseInt(sw,16));
		}

		//turn off the reader:
		try{
			reader.ReaderFree();
			exi.ReaderOff=true;
			throw exi;

		//in case of error set the ReaderFree field false:
		}catch(SLBAPIAbortException ex){
			exi.ReaderOff=false;
			throw exi;
		}catch(SLBAPIErrorException ex){
			exi.ReaderOff=false;
			throw exi;
		}catch(SLBAPITimeOutException ex){
			exi.ReaderOff=false;
			throw exi;

		}

	}


//----------------------------------------------------------------------


	/**
	* The main method for command prompt use, see the usage message.
	*/
	public static void main(String[] args){
		String PIN;

		//if no parameter
		if(args.length<1){   
			System.err.println(
					"Usage: java Send <the command APDUs>\n"+
					"       java Send GET [<pin code>]\n"+
					"       java Send SET <old pin code> <new pin code> <id> <name>\n");
			System.exit(1);

		//execute GET:
		}else if(args[0].equals("GET")){   
			if(args.length>2) {
				System.out.println("Invalid number of arguments");
				System.exit(1);
			}

			if(args.length==1) {  //if no pin code 
				System.out.println("Using default PIN:1234");
				PIN="1234";
			} else PIN=args[1];

			StringBuffer name=new StringBuffer(""),
				id=new StringBuffer("");
			try{
				GetNameAndID(PIN,name,id); //get name and id
				System.out.println(
					"\nName: "+name+
					"\nId:   "+id);
			}catch(STUDException e){
				System.out.println(e.toString()+", id:"+
					Integer.toHexString(e.id));
			}                  

		//execute SET:
		}else if(args[0].equals("SET")){
			if(args.length!=5){
				System.out.println("Wrong number of argument");
				System.exit(1);
			}

			try{
				SetNameAndID(
					args[1],//old pin
					args[2], //new pin
					new StringBuffer(args[4]),//name
					new StringBuffer(args[3]));//id
				System.out.println("Name and id changed");
			}catch(STUDException e){
				System.out.println(e.toString()+", id:"+
					Integer.toHexString(e.id));
			}                  

		//send the APDUs
		}else {
			StringBuffer result=new StringBuffer();
			System.out.println(result=Execute(args));
		}
	}
	
	/**
	* To help the main method. 
	*@param args the String array with the commands
	*@return the messages: {<command>--><respons>} [<error>]
	*/
	public static StringBuffer Execute(String[] args){
		String command=args[0]; 
		Reader reader=new Reader();
		StringBuffer ret=new StringBuffer("");
		
		//init the reader:
		StringBuffer response=new StringBuffer("");
		StatusWord sw=new StatusWord();
		try{
			reader.ReaderAllocate("Reflex60","COM2");
			reader.ReaderPowerUp();
			reader.ReaderReset(response);
		}catch(Exception e){
			ret.append("Can't allocate the reader\n");
			return ret;
		}
			
		//send the commands:
		for(int i=0;i<args.length;i++)
		try{
			command=args[i];
			response=new StringBuffer("");
                                               
			if(command.equals("RESET")){
				reader.ReaderReset(response);
			}else{
				reader.ReaderSendIsoOutT0(command.toUpperCase(),
					response,sw);
                        }
			ret.append(command+"-->"+response/*+":"+sw.toString()*/+"\n");
		}catch(Exception e){
			ret.append("Can't send the command\n");
			return ret;
		}

		//turn off the reader
		try{
			reader.ReaderFree();
		}catch(Exception e){
			System.out.println("Can't deallocate the reader\n");
		}
		return ret;
	}	
}