/***
 * File neve: Terminal.java
 * Szerző: Szatmáry Botond
 * Utolsó módosítás: 1998. jun. 15.
 * Leírás: Ez az alkalmazás kell gyűrűn való adatok tárolásához,
 * visszanyeréséhez. Ezt az osztály kell a gyűrűre tölteni, majd ennek az
 * osztálynak a metódusait lehet használni.
 ***/

import javacard.framework.*;

public class Terminal extends Applet
{
  // Fo CLA amit a Terminal applet tamogat
  final static byte T_CLA     = (byte) 0x81;

  // Ezeket az utasitasokat tamogatja a Terminal applet
  final static byte T_INS_STORE       = 0x01;
  final static byte T_INS_RETRIEVE    = 0x02;
  final static byte T_INS_STORE_CP    = 0x03;
  final static byte T_INS_RETRIEVE_CP = 0x04;

  // Paramterek a T_INS_STORE -hoz 
  final static byte T_P1_SET_LENGTH  = 0x01; 
  final static byte T_P1_NEXT_PACKET = 0x02; 
  final static byte T_P1_LAST_PACKET = 0x03; 

  // APDU header. Az applet kivalasztasahoz kell.
  final static byte SELECT_CLA = 0x00;
  final static byte SELECT_INS = (byte) 0xA4;

  // An sw for a bad instruction sequence
  final static short SW_BAD_INS_SEQUENCE = (short) 0x9101;

  // Tomb a adatok tarolasara.
  byte[] tData;

  // Array to contain the coffee preference data
  byte[] coffeeData;
  
  /* 
   * Tarolashoz szukseges valtozok.
   */
  short  offset;
  int    teljesHossz;
  byte[] temp; 
  
  /**
   * Konstruktor.
   */
  Terminal()
  {
    coffeeData = new byte[200];
    register();
  }
  
  /**
   * Installalja a Terminal a Java iButton -ra.
   */
  public static void install(APDU apdu)
  {
    new Terminal();
  }
  
  /**
   * Ezt az appletet allitja aktualisan kivalasztottnak a Java iButton -on.
   * @param apdu APDU
   */
  public boolean select(APDU apdu)
  {
    return true;
  }
  
  /**
   * Dispatch APDUs
   */
  public void process(APDU apdu) throws ISOException 
  {
    byte[] buffer = apdu.getBuffer();
    
    // process is called on applet selection but we don't do anything in this applet
    if ((buffer[ISO.OFFSET_CLA] == SELECT_CLA) && (buffer[ISO.OFFSET_INS] == SELECT_INS))
      return;
    
    if (buffer[ISO.OFFSET_CLA] != T_CLA)
      {
	// Don't know what to do with this instruction
	throw new ISOException(ISO.SW_CLA_NOT_SUPPORTED);
      }
    else 
      {
	switch (buffer[ISO.OFFSET_INS])
	  {
	  default:
	    // Don't know what to do with this instruction
	    throw new ISOException(ISO.SW_INS_NOT_SUPPORTED);
	    
	  case T_INS_STORE:
	    TerminalStore(apdu);
	    break;
	    
	  case T_INS_RETRIEVE:
	    TerminalRetrieve(apdu);
	    break;
	    
	  case T_INS_STORE_CP:
	    TerminalStoreCP(apdu);
	    break;
	    
	  case T_INS_RETRIEVE_CP:
	    TerminalRetrieveCP(apdu);
	    break;
	  }
      }
  }
  
  /** 
   * Uj informaciot ment el.
   * Temporalis tombot hasznal es darabonkent menti el.
   */
  protected void TerminalStore(APDU apdu) throws ISOException
  {
    byte[] buffer    = apdu.getBuffer();
    short  bytesRead = apdu.setIncomingAndReceive();
    
    switch (buffer[ISO.OFFSET_P1])
      {
      case T_P1_SET_LENGTH: 
	offset = 0; 
	
	// 2 hosszusagut var
	if (buffer[ISO.OFFSET_LC] == 2)
	  {
	    teljesHossz  = buffer[ISO.OFFSET_CDATA] << 8;
	    teljesHossz |= (buffer[ISO.OFFSET_CDATA+1] & 0xFF);
	  }
	else
	  throw new ISOException(ISO.SW_DATA_INVALID);
	
	/* 
	 * Egy temporalis tombot keszit az adatok tarolasara.
	 * Amikor mind megvan bemasolja a tData-ba.
	 */
	temp = new byte[teljesHossz];
	break;
   
      case T_P1_NEXT_PACKET:
	if (teljesHossz > 0)
	  {
	    while (bytesRead > 0)
	      {
		Util.arrayCopy(buffer, ISO.OFFSET_CDATA, temp, offset, bytesRead);
		offset += bytesRead;
		// Megkapja a kov. darab infot
		bytesRead = apdu.receiveBytes(ISO.OFFSET_CDATA);
	      }
	  }
	else 
	  throw new ISOException(SW_BAD_INS_SEQUENCE);
	
	break;
	
      case T_P1_LAST_PACKET:
	if (teljesHossz > 0)
	  {
	    while (bytesRead > 0)
	      {
		Util.arrayCopy(buffer, ISO.OFFSET_CDATA,
			       temp,offset, bytesRead);
		
		offset += bytesRead;
		// Megkapja a kov. darab infot
		bytesRead = apdu.receiveBytes(ISO.OFFSET_CDATA);
	      }
	    
	    tData = new byte[teljesHossz];
	    // Atmasolja az APDU tartalmat a tData tombbe.
	    Util.arrayCopy(temp, (short) 0, tData, 
			   (short) 0, (short) teljesHossz);
	  }
	else 
	  throw new ISOException(SW_BAD_INS_SEQUENCE);
	
	break;
	
      default:
	throw new ISOException(ISO.SW_WRONG_P1P2);
      }
  }

  /** 
   * Visszakap terminal info
   * @param apdu APDU
   */
  protected void TerminalRetrieve(APDU apdu)
  {
    if (tData != null)
      {
	apdu.setOutgoing();
	apdu.sendBytesLong(tData, (short) 0, (short) tData.length);
      }
  }

  /** 
   * Tarol ...
   */
  protected void TerminalStoreCP(APDU apdu) 
  {
    byte[] buffer    = apdu.getBuffer();
    short  bytesRead = apdu.setIncomingAndReceive();
    // A 'command APDU'-t atmasolja a coffeeData tombbe
    Util.arrayCopy(buffer, ISO.OFFSET_CDATA, coffeeData, (short) 0, bytesRead);
  }
  
  /** 
   * Visszakapja a coffee preferrence adatokat. 
   */
  protected void TerminalRetrieveCP(APDU apdu)
  {
    apdu.setOutgoing();
    apdu.sendBytesLong(coffeeData, (short) 0, (short) coffeeData.length);
  }
}

