package com.gmt.core;

import java.io.IOException;

//#ifdef ${card.access.none}
//# public class CardConnection
//# {
//# }
//#else


//#ifdef ${card.access.nokia}	
//# import com.nokia.nfc.sc.SecureChipConnection;
//# import com.nokia.nfc.sc.SecureChipEvent;
//# import com.nokia.nfc.sc.SCCMode;
//# import com.nokia.tus.midlet.se.CommandApdu;
//# import com.nokia.tus.midlet.se.ResponseApdu;
//#endif

//#ifdef ${card.access.iso14443}
//# import javax.microedition.contactless.sc.ISO14443Connection;
//# import javax.microedition.io.Connection;
//# import javax.microedition.io.Connector;
//# import javax.microedition.io.SocketConnection;
//#endif

//#ifdef ${card.access.satsa}
import javax.microedition.apdu.APDUConnection ;
import javax.microedition.io.Connector;
import javax.microedition.io.SocketConnection;
//#endif

import javax.microedition.io.StreamConnection;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;


/**
 * This class models a connection to an internal SecureChip. In order to 
 * achieve independence from different implementation of SecureChip SDK,
 * the connection does not use any Connector framework. The object is modelled
 * as a singleton, so different clients actually share the same instance of the 
 * object. Methods are synchronized, so there are no chances of two calls being
 * run at the same time, but it may happen that two clients may issue conflicting
 * commands.
 *
 */
public class CardConnection 
//#ifdef ${card.access.nokia}	
	//# implements com.nokia.nfc.sc.SecureChipListener
//#endif
{
	private static CardConnection singleton = null;
	
//#ifdef ${card.access.nokia}	
		//# private SecureChipConnection scc;
		//# private boolean connected ;
//#endif
//#ifdef ${card.access.iso14443}
		//# private ISO14443Connection scc;
		//# private static final String INTERNAL_URL_PROP = "nfc:sc;type=iso4a;mode=internal";
//#endif
//#ifdef ${card.access.jcop}
		//# private JcopSimul scc;
		//# private static final String JCOP_SIMUL_URL = "localhost:8050" ;
//#endif
//#ifdef ${card.access.satsa}
		private APDUConnection scc;
		private static final String INTERNAL_URL_PROP = "apdu0:target=a0.00.00";
//#endif
		
	private CardConnection() {
		scc = null;
//#ifdef ${card.access.nokia}	
		//# connected=false ;
//#endif
	}

	/** Returns the singleton object represeting the connection to the Secure Element. 
	 * @return the singleton object represeting the connection to the Secure Element
	 * @throws  CardException if an error accurs while connecting to the secure element  
	 */
	public static synchronized CardConnection openConnection() throws CardException {
		if (singleton == null) {
			singleton = new CardConnection();
			try {
//#ifdef ${card.access.nokia}
				//# singleton.scc = SecureChipConnection.openConnection(null, singleton);
				//# synchronized (singleton) {
					//# singleton.wait();
				//# }
				//# if (singleton.connected) {
					//# singleton.scc.setSCCMode(SCCMode.SC_INTERNAL, true, null, 0);
				//# } else {
					//# singleton.scc.disconnect();
					//# throw new CardException(CardException.NO_CONNECTION) ;
				//# }
			//# }
			//# catch(InterruptedException e)
			//# {
				//# throw new CardException(CardException.IO_ERROR) ;
			//# }
//#endif
//#ifdef ${card.access.iso14443}
			//# 
				//# Connection connection =  Connector.open(INTERNAL_URL_PROP);
				//# if (connection instanceof ISO14443Connection) {
					//# singleton.scc = (ISO14443Connection) connection;
				//# }
				//# 
				//# if (singleton.scc == null) {
					//# throw new CardException(CardException.NO_CONNECTION) ;
				//# }
			//# } 
//#endif	
//#ifdef ${card.access.satsa}
		
		APDUConnection connection = (APDUConnection) Connector.open(INTERNAL_URL_PROP);
		if (connection instanceof APDUConnection) {
			singleton.scc = (APDUConnection) connection;
		}
		
		if (singleton.scc == null) {
			throw new CardException(CardException.NO_CONNECTION) ;
		}
	} 
//#endif	
//#ifdef ${card.access.jcop}
				//# singleton.scc = JcopSimul.createConnection(JCOP_SIMUL_URL);
			//# }
//#endif		
		
			catch (IOException e)
			{
				throw new CardException(CardException.IO_ERROR) ;
			}
		}
		return singleton;
	}
	
	/** Performs a data exchange with the SecureElement. 
	 * @param apdu the command APDU to be sent to the chip
	 * @return the response APDU received from the chip
	 * @throws CardException if an error occurs in the underlying SecureChip libraries
	 */
	public synchronized ResponseApdu exchangeApdu(final Apdu apdu) throws CardException
	{
		if (scc == null)
			throw new CardException(CardException.SCC_NOT_DEFINED) ;
		try {
//#ifdef ${card.access.jcop}
			//# ResponseApdu resp = scc.exchangeAPDU(apdu.getApdu()) ;
			//# return resp ;
//#endif
//#ifdef ${card.access.nokia}
			//# byte[] responseData = scc.exchangeAPDU(apdu.getApdu()) ;
			//# return new ResponseApdu(responseData);
//#endif				
//#ifdef ${card.access.iso14443}
			//# byte[] responseData = scc.exchangeData(apdu.getApdu());
			//# return new ResponseApdu(responseData);
//#endif				
//#ifdef ${card.access.satsa}
			byte[] responseData = scc.exchangeData(apdu.getApdu());
			return new ResponseApdu(responseData);
//#endif				
		} catch (Exception e) {
			throw new CardException(CardException.TRANSMITION_ERROR) ;
		}
	}
	
	/**
	 * Closes the connection to the secure element.
	 * @throws CardException if an error occurs in the underlying SecureChip libraries
	 */
	public static synchronized void closeConnection() throws CardException {
		if (singleton != null) {
			if (singleton.scc != null) {
//#ifdef ${card.access.nokia}
				//# singleton.scc.disconnect();
//#endif
//#ifdef ${card.access.iso14443}
				//# try {
					//# singleton.scc.close();
				//# } catch (IOException ioe) {
					//# throw new CardException(CardException.CLOSE_ERROR) ; 
				//# }
				//# //singleton.scc = null;
//#endif
//#ifdef ${card.access.satsa}
				try {
					singleton.scc.close();
				} catch (IOException ioe) {
					throw new CardException(CardException.CLOSE_ERROR) ; 
				}
				//singleton.scc = null;
//#endif
//#ifdef ${card.access.jcop}
                //# try {
                    //# singleton.scc.close();
                //# } catch (IOException ioe) {
                    //# throw new CardException(CardException.CLOSE_ERROR) ;
                //# }
                //# //singleton.scc = null;
//#endif
              singleton.scc = null;
			}
			singleton = null;
		}
	}

//#ifdef ${card.access.nokia}
	//# /* (non-Javadoc)
	 //# * @see com.nokia.nfc.sc.SecureChipListener#handleEvent(com.nokia.nfc.sc.SecureChipEvent)
	 //# * 
	 //# * just set the connected flag to true
	 //# */
	//# public void handleEvent(final SecureChipEvent event) {
		//# if ((event.getType() == SecureChipEvent.TYPE_CONNECTION_STATUS) && 
				//# (event.getStatus() == SecureChipEvent.STATUS_CONNECTED)) {
			//# connected = true;
		//# }
		//# synchronized (this) {
			//# this.notify();
		//# }
	//# }
//#endif
	
	/**
	 *Send Apdu to the card to  select the applet 
	 * 
	 */
	
	
	public synchronized int selectApplet(final String appletName/*, final byte logicalChannel*/) throws IOException,CardException {
		final Apdu command = Apdu.createSelectApdu(appletName/*, logicalChannel*/);
		//try{
			final ResponseApdu response = exchangeApdu(command);		
		//}catch(CardException e){}
		final int result = response.getStatusWord();
//		if (result == ResponseApdu.STATUS_OK) {
//			channels[logicalChannel].appletName = appletName;	
//		} else {
//			channels[logicalChannel].appletName = null;
//		}
		return result;
	}
	
//	public String getSelectedApplet()
//	{
//		return appletName;
//	}
//		
//	
	
}
//#endif

