package nordpol.android;

import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;

import nordpol.IsoCard;
import nordpol.OnCardErrorListener;

public class AndroidCard implements IsoCard {
    private static final int DEFAULT_TIMEOUT = 15000;
    private static final int SAMSUNG_S5_MINI_MAX = 253;

    private IsoDep card;
    private List<OnCardErrorListener> errorListeners =
        new CopyOnWriteArrayList<OnCardErrorListener>();

    private AndroidCard(IsoDep card) {
        this.card = card;
    }

    public static AndroidCard get(Tag tag) throws IOException {
        IsoDep card = IsoDep.get(tag);

        /* Workaround for the Samsung Galaxy S5 (since the
         * first connection always hangs on transceive).
         * TODO: This could be improved if we could identify
         * Samsung Galaxy S5 devices
         */
        card.connect();
        card.close();

        if(card != null) {
            return new AndroidCard(card);
        } else {
            return null;
        }
    }

    private void notifyListeners(IOException exception) {
        for(OnCardErrorListener listener: errorListeners) {
            listener.error(this, exception);
        }
    }

    public void addOnCardErrorListener(OnCardErrorListener listener) {
        errorListeners.add(listener);
    }

    public void removeOnCardErrorListener(OnCardErrorListener listener) {
        errorListeners.remove(listener);
    }

    public boolean isConnected() {
        return card.isConnected();
    }

    public void connect() throws IOException {
        try {
            card.connect();
            card.setTimeout(DEFAULT_TIMEOUT);
        } catch(IOException e) {
            notifyListeners(e);
            throw e;
        }
    }

    public int getMaxTransceiveLength() throws IOException {
        /* TODO: This could be improved if we could identify
         * Samsung Galaxy S5 mini devices
         */
        return Math.min(card.getMaxTransceiveLength(), SAMSUNG_S5_MINI_MAX);
    }

    public int getTimeout() {
        return card.getTimeout();
    }

    public void setTimeout(int timeout) {
        card.setTimeout(timeout);
    }

    public void close() throws IOException {
        try {
            card.close();
        } catch(IOException e) {
            notifyListeners(e);
            throw e;
        }
    }

    public byte[] transceive(byte [] command) throws IOException {
        try {
            return card.transceive(command);
        } catch(IOException e) {
            notifyListeners(e);
            throw e;
        }
    }

    public List<byte[]> transceive(List<byte[]> commands) throws IOException {
        try {
            ArrayList<byte[]> responses = new ArrayList<byte[]>();
            for(byte[] command: commands) {
                responses.add(card.transceive(command));
            }
            return responses;
        } catch(IOException e) {
            notifyListeners(e);
            throw e;
        }
    }

    public Tag getTag() {
        return card.getTag();
    }
}

@@ -733,24 +733,55 @@
 .get(tag);%0A%0A
+        if(card != null) %7B%0A    
         /* W
@@ -836,16 +836,20 @@
         
+ 
+   
 * first 
@@ -888,16 +888,20 @@
 ceive).%0A
+    
         
@@ -954,32 +954,36 @@
 entify%0A         
+   
+ 
 * Samsung Galaxy
@@ -995,32 +995,36 @@
 evices%0A         
+    
 */%0A        card.
@@ -1010,32 +1010,36 @@
      */%0A        
+ 
+   
 card.connect();%0A
@@ -1038,32 +1038,36 @@
 nect();%0A        
+  
+  
 card.close();%0A%0A 
@@ -1067,36 +1067,8 @@
 e();
-%0A%0A        if(card != null) %7B
 %0A   

Fix #12