// Gemplus Imports
import com.gemplus.opencard.service.gpk.access.GPKSecretCodeRef;
import com.gemplus.opencard.service.gpk.admin.AdministrativeCardService;
import com.gemplus.opencard.service.gpk.admin.GPKAdministrativeService;
import com.gemplus.opencard.service.gpk.file.FileUtilityCardService;
import com.gemplus.opencard.service.gpk.file.GPKFileInfo;
import com.gemplus.opencard.service.gpk.file.GPKFileSystemService;
import com.gemplus.opencard.service.gpk.file.GPKFileUtilityService;
import com.gemplus.opencard.service.gpk.GPKObjectRegistry;
import com.gemplus.opencard.service.gpk.GPKProperties;
import com.gemplus.opencard.service.gpk.security.GPKAdministrativeCredential;
import com.gemplus.opencard.service.gpk.security.GPKAuthenticationCredential;
import com.gemplus.opencard.service.gpk.security.GPKAuthorityKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKCredentialStore;
import com.gemplus.opencard.service.gpk.security.GPKRSAKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKSignatureKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKSignatureUnwrapKeyFile;
import com.gemplus.opencard.service.gpk.security.GPKUnwrapKeyFile;
import com.gemplus.opencard.service.gpk.signature.GPKKeyGenerationService;
import com.gemplus.opencard.service.gpk.signature.GPKKeyImportService;
import com.gemplus.opencard.service.gpk.signature.GPKKeyManagementService;
import com.gemplus.opencard.service.gpk.signature.GPKSignatureService;
import com.gemplus.opencard.service.gpk.signature.GPKStandardNames;
import com.gemplus.opencard.service.gpk.signature.KeyManagementCardService;
import com.gemplus.opencard.service.util.ArrayUtils;
import com.gemplus.opencard.service.util.CryptoUtils;

// Java Imports
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.util.Enumeration;
import java.util.Random;
import java.util.Random;
import java.util.Vector;
import javax.crypto.spec.SecretKeySpec;

// Opencard Imports
import opencard.core.service.CardRequest;
import opencard.core.service.CardServiceException;
import opencard.core.service.SmartCard;
import opencard.core.terminal.*;
import opencard.core.util.HexString;
import opencard.opt.iso.fs.CardFile;
import opencard.opt.iso.fs.CardFilePath;
import opencard.opt.iso.fs.FileAccessCardService;
import opencard.opt.iso.fs.FileSystemCardService;
import opencard.opt.security.CredentialBag;
import opencard.opt.security.PublicKeyRef;
import opencard.opt.security.RSACRTKey;
import opencard.opt.security.RSAPrivateKey;
import opencard.opt.security.RSAPublicKey;
import opencard.opt.signature.KeyGenerationCardService;
import opencard.opt.signature.KeyImportCardService;
import opencard.opt.signature.SignatureCardService;

// Class TestMPCOS
public class TestMPCOS{
  
  private SmartCard                    sc = null;  
    
  private GPKFileSystemService     fss;
  private GPKFileUtilityService    fus;
  
  private static final CardFilePath    root = new CardFilePath(":3F00");
  private static final CardFilePath    ef_3F01 = new CardFilePath(":3F00:3F01");
  private static final CardFilePath    df_0200 = new CardFilePath(":3F00:0200");
  private static final CardFilePath    ef_0201 = new CardFilePath(":3F00:0200:0201");  
  
  // Constructor
  public TestMPCOS(SmartCard sc)
      throws CardServiceException, ClassNotFoundException, CardServiceException,
	     CardTerminalException, ClassNotFoundException, InvalidKeyException {
    
    this.sc = sc;   
    
    boolean extAuth = false;
    
    // Instanciate file CardServices    
    fss = (GPKFileSystemService)
	sc.getCardService(FileSystemCardService.class, true);
    fus = (GPKFileUtilityService)
	sc.getCardService(FileUtilityCardService.class, true);

    // Provide credentials for Administrative key :3F00:3F01
    CredentialBag               bag = new CredentialBag();
    GPKCredentialStore          store = new GPKCredentialStore();
    GPKAdministrativeCredential credential = new GPKAdministrativeCredential();

    store.storeCredential(0, credential);
    bag.addCredentialStore(store);
    fss.provideCredentials(ef_3F01, bag);            
    
    // Erase Card
    System.out.println("Erasing Card...");
    fus.eraseCard();        

    // create DF(0x0200)
    System.out.println("\nCreate DF " + df_0200);
    fus.createDF(df_0200, extAuth, null);
           
    // create EF(0x0201)
    System.out.println("\nCreate EF " + ef_0201);
    fus.createTransparentFile(ef_0201, 100, null);

    // update binary
    System.out.println("\nUpdate to " + ef_0201);
    byte[] updateData = new byte[100];
    for(int i = 0; i < 100; i++) {
      updateData[i] = (byte)i;
    }
    Util.printBytes("updateData = \n", updateData);
    fss.update(ef_0201, 0, updateData, 0, 100);    

    // read binary
    System.out.println("\nRead from " + ef_0201);
    byte[] readData = fss.read(ef_0201, 0, 100);
    Util.printBytes("readData = \n", readData);    
    
  }

  // Main()
  public static void main(String[] args) {
    try {
      SmartCard.start();

      // wait for a smartcard with file access support
      System.out.println("\nWaiting for card...\n");
      CardRequest cr = new CardRequest();
      SmartCard   card = SmartCard.waitForCard(cr);  
      System.out.println("Card detected\n");

      // Instantiate the TestMPCOS class
      TestMPCOS test1 = new TestMPCOS(card);
      
    } catch(Exception e) {
      e.printStackTrace();
    } 
    finally {
      try {
        SmartCard.shutdown();
        System.exit(0);
      } catch(Exception e) {
        e.printStackTrace();
      } 
    } 
  }     
}
