package com.example.geocachingapp;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.EllipticCurve;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

public class MainActivity extends Activity {
    ArrayList<String> list;

    static {
        Security.removeProvider("BC");//first remove default os provider
        Security.insertProviderAt(new BouncyCastleProvider(), 1);//add new provider
    }

    private static final String SPEC = "secp192k1";
    private static final String ALGO = "SHA1withECDSA";

    static byte[] APDU=null;
    static byte[] rAPDU=null;

    boolean cardDetected=false;
    static IsoDep myTag;
    private NfcAdapter Adapter=null;
    private PendingIntent mPendingIntent;
    private String[][] TechLists;
    private IntentFilter[] Filters;

    private Button mSendAIDButton;
    static ImageView iconCard;
    static TextView TextCard;
    static TextView txtLog;
    static ImageView rewardImage;

    // Value types
    final static byte CACHE_ID = (byte)0x01;
    final static byte GAMER_ID = (byte)0x02;
    final static byte GAMER_TRAV_ITEM_ID = (byte)0x03;
    final static byte CACHE_TRAV_ITEM_ID = (byte)0x04;
    final static byte CERT = (byte)0x05;
    final static byte CACHE_PUB_KEY = (byte)0x06;
    final static byte GAMER_PUB_KEY = (byte)0x07;
    final static byte CACHE_SIGN = (byte)0x08;
    final static byte GAMER_SIGN = (byte)0x09;
    final static byte CACHE_RNDM_NUMB = (byte)0x10;
    final static byte GAMER_RNDM_NUMB = (byte)0x11;
    final static byte CACHE_CONF_MSG = (byte)0x12;
    final static byte GAMER_MSG = (byte)0x13;
    final static byte DISC_ORDER = (byte)0x14;
    final static byte CA_PUB_KEY = (byte)0x15;
    final static byte CA_SIGN = (byte)0x16;
    //final static byte CACHE_PRIV_KEY = (byte)0x17;

    // CLA byte
    final static String Geocaching_CLA = "90";

    // INS byte
    final static String START = "01";
    final static String STOP = "02";
    final static String GAME = "03";

    // Identificators
    final static byte[] H = new byte[]{(byte) 'P', (byte) '9', (byte) '9', (byte) '8', (byte) '7', (byte) '6', (byte) '5', (byte) '4', (byte) '3', (byte) '2', (byte) '1', (byte) '0', (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9'};

    private byte[] S;
    private byte[] Scrt;
    private byte[] Srecv;

    byte[] Uh = new byte[]{(byte) 'T', (byte) 'G', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7', (byte) '7'};
    final static short UhLen = 22;

    byte[] Us;
    final static short UsLen = 22;

    final static byte[] emptyU = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};

    List<String> IDs;


    // Certificates
    private byte[] CRTh = new byte[]{(byte) 0x05, (byte) 0x01, (byte) 0xB3,
            (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0xAC, (byte) 0x30, (byte) 0x82, (byte) 0x01, (byte) 0x63, (byte) 0x02, (byte) 0x06, (byte) 0x01, (byte) 0x79, (byte) 0x84, (byte) 0xCF, (byte) 0x06, (byte) 0x68, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE, (byte) 0x3D, (byte) 0x04, (byte) 0x01, (byte) 0x30, (byte) 0x15, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x13, (byte) 0x0A, (byte) 0x47, (byte) 0x65, (byte) 0x6F, (byte) 0x63, (byte) 0x61, (byte) 0x63, (byte) 0x68, (byte) 0x69, (byte) 0x6E, (byte) 0x67, (byte) 0x30, (byte) 0x1E, (byte) 0x17, (byte) 0x0D, (byte) 0x32, (byte) 0x31, (byte) 0x30, (byte) 0x35, (byte) 0x31, (byte) 0x39, (byte) 0x31, (byte) 0x33, (byte) 0x32, (byte) 0x37, (byte) 0x31, (byte) 0x30, (byte) 0x5A, (byte) 0x17, (byte) 0x0D, (byte) 0x32, (byte) 0x36, (byte) 0x30, (byte) 0x35, (byte) 0x31, (byte) 0x39, (byte) 0x31, (byte) 0x33, (byte) 0x32, (byte) 0x37, (byte) 0x31, (byte) 0x30, (byte) 0x5A, (byte) 0x30, (byte) 0x21, (byte) 0x31, (byte) 0x1F, (byte) 0x30, (byte) 0x1D, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x13, (byte) 0x16, (byte) 0x50, (byte) 0x39, (byte) 0x39, (byte) 0x38, (byte) 0x37, (byte) 0x36, (byte) 0x35, (byte) 0x34, (byte) 0x33, (byte) 0x32, (byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x30, (byte) 0x81, (byte) 0xF3, (byte) 0x30, (byte) 0x81, (byte) 0xBC, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE, (byte) 0x3D, (byte) 0x02, (byte) 0x01, (byte) 0x30, (byte) 0x81, (byte) 0xB0, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x24, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE, (byte) 0x3D, (byte) 0x01, (byte) 0x01, (byte) 0x02, (byte) 0x19, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE, (byte) 0xFF, (byte) 0xFF, (byte) 0xEE, (byte) 0x37, (byte) 0x30, (byte) 0x34, (byte) 0x04, (byte) 0x18, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x18, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x04, (byte) 0x31, (byte) 0x04, (byte) 0xDB, (byte) 0x4F, (byte) 0xF1, (byte) 0x0E, (byte) 0xC0, (byte) 0x57, (byte) 0xE9, (byte) 0xAE, (byte) 0x26, (byte) 0xB0, (byte) 0x7D, (byte) 0x02, (byte) 0x80, (byte) 0xB7, (byte) 0xF4, (byte) 0x34, (byte) 0x1D, (byte) 0xA5, (byte) 0xD1, (byte) 0xB1, (byte) 0xEA, (byte) 0xE0, (byte) 0x6C, (byte) 0x7D, (byte) 0x9B, (byte) 0x2F, (byte) 0x2F, (byte) 0x6D, (byte) 0x9C, (byte) 0x56, (byte) 0x28, (byte) 0xA7, (byte) 0x84, (byte) 0x41, (byte) 0x63, (byte) 0xD0, (byte) 0x15, (byte) 0xBE, (byte) 0x86, (byte) 0x34, (byte) 0x40, (byte) 0x82, (byte) 0xAA, (byte) 0x88, (byte) 0xD9, (byte) 0x5E, (byte) 0x2F, (byte) 0x9D, (byte) 0x02, (byte) 0x19, (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFE, (byte) 0x26, (byte) 0xF2, (byte) 0xFC, (byte) 0x17, (byte) 0x0F, (byte) 0x69, (byte) 0x46, (byte) 0x6A, (byte) 0x74, (byte) 0xDE, (byte) 0xFD, (byte) 0x8D, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x32, (byte) 0x00, (byte) 0x04, (byte) 0x45, (byte) 0x64, (byte) 0x0C, (byte) 0x90, (byte) 0xE1, (byte) 0x83, (byte) 0xBF, (byte) 0x66, (byte) 0x3A, (byte) 0xCF, (byte) 0x6D, (byte) 0x34, (byte) 0x4A, (byte) 0x8D, (byte) 0x65, (byte) 0x4F, (byte) 0x9A, (byte) 0x94, (byte) 0x08, (byte) 0x23, (byte) 0xD4, (byte) 0x22, (byte) 0x29, (byte) 0xDE, (byte) 0x7F, (byte) 0xCD, (byte) 0x76, (byte) 0x34, (byte) 0xC7, (byte) 0x95, (byte) 0x4D, (byte) 0x62, (byte) 0x5F, (byte) 0x11, (byte) 0xCD, (byte) 0xF0, (byte) 0xAC, (byte) 0xD5, (byte) 0xEB, (byte) 0x1E, (byte) 0xDB, (byte) 0x0C, (byte) 0x3F, (byte) 0xC4, (byte) 0x9E, (byte) 0xF2, (byte) 0x41, (byte) 0x3B, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x07, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0xCE, (byte) 0x3D, (byte) 0x04, (byte) 0x01, (byte) 0x03, (byte) 0x38, (byte) 0x00, (byte) 0x30, (byte) 0x35, (byte) 0x02, (byte) 0x18, (byte) 0x08, (byte) 0x6E, (byte) 0x3D, (byte) 0x74, (byte) 0xFE, (byte) 0x8C, (byte) 0x59, (byte) 0x1C, (byte) 0x0D, (byte) 0x7F, (byte) 0xA7, (byte) 0x41, (byte) 0x5F, (byte) 0x99, (byte) 0xDB, (byte) 0x5F, (byte) 0x37, (byte) 0x68, (byte) 0x7C, (byte) 0xC7, (byte) 0xAA, (byte) 0x72, (byte) 0x99, (byte) 0xA7, (byte) 0x02, (byte) 0x19, (byte) 0x00, (byte) 0xCC, (byte) 0xE8, (byte) 0xC8, (byte) 0xBB, (byte) 0x09, (byte) 0x03, (byte) 0x39, (byte) 0x3C, (byte) 0x60, (byte) 0x81, (byte) 0xEF, (byte) 0x5A, (byte) 0x28, (byte) 0x4A, (byte) 0x40, (byte) 0xB7, (byte) 0x75, (byte) 0xBB, (byte) 0xF0, (byte) 0x1D, (byte) 0x10, (byte) 0x01, (byte) 0xA8, (byte) 0x40};

    private byte[] CRTs;

    // Keys
    final static byte[] bSKh = new byte[]{(byte) 0xC8, (byte) 0x1E, (byte) 0x1F, (byte) 0x9A, (byte) 0x19, (byte) 0x49, (byte) 0x3A, (byte) 0x28, (byte) 0x29, (byte) 0xC0, (byte) 0x8F, (byte) 0x36, (byte) 0x7F, (byte) 0xB7, (byte) 0xD8, (byte) 0x73, (byte) 0xD9, (byte) 0xCC, (byte) 0xCD, (byte) 0x3C, (byte) 0xFD, (byte) 0xAB, (byte) 0x67, (byte) 0x68};
    final static byte[] bVKh = new byte[]{(byte) 0x04, (byte) 0x45, (byte) 0x64, (byte) 0x0C, (byte) 0x90, (byte) 0xE1, (byte) 0x83, (byte) 0xBF, (byte) 0x66, (byte) 0x3A, (byte) 0xCF, (byte) 0x6D, (byte) 0x34, (byte) 0x4A, (byte) 0x8D, (byte) 0x65, (byte) 0x4F, (byte) 0x9A, (byte) 0x94, (byte) 0x08, (byte) 0x23, (byte) 0xD4, (byte) 0x22, (byte) 0x29, (byte) 0xDE, (byte) 0x7F, (byte) 0xCD, (byte) 0x76, (byte) 0x34, (byte) 0xC7, (byte) 0x95, (byte) 0x4D, (byte) 0x62, (byte) 0x5F, (byte) 0x11, (byte) 0xCD, (byte) 0xF0, (byte) 0xAC, (byte) 0xD5, (byte) 0xEB, (byte) 0x1E, (byte) 0xDB, (byte) 0x0C, (byte) 0x3F, (byte) 0xC4, (byte) 0x9E, (byte) 0xF2, (byte) 0x41, (byte) 0x3B};
    private ECPrivateKey SKh;
    private ECPublicKey VKh;

    byte[] bVKs;
    private ECPublicKey VKs;

    final static byte[] bVKca = new byte[]{(byte) 0x04, (byte) 0x86, (byte) 0xEF, (byte) 0x1D, (byte) 0x16, (byte) 0x37, (byte) 0x01, (byte) 0xBC, (byte) 0xC0, (byte) 0xEC, (byte) 0x96, (byte) 0x28, (byte) 0xEB, (byte) 0x8F, (byte) 0x12, (byte) 0x94, (byte) 0x47, (byte) 0xA3, (byte) 0xF2, (byte) 0xEB, (byte) 0x5B, (byte) 0x73, (byte) 0xC4, (byte) 0x05, (byte) 0xFF, (byte) 0xC7, (byte) 0x87, (byte) 0x7B, (byte) 0xEE, (byte) 0x8A, (byte) 0xF1, (byte) 0xEC, (byte) 0x4C, (byte) 0x36, (byte) 0xA1, (byte) 0x2A, (byte) 0xF6, (byte) 0xFF, (byte) 0xD9, (byte) 0xCB, (byte) 0x52, (byte) 0xA4, (byte) 0x16, (byte) 0xC1, (byte) 0x83, (byte) 0x90, (byte) 0x4E, (byte) 0x05, (byte) 0x2B};
    private ECPublicKey VKca;

    // Random numbers
    private byte[] Rh;
    private byte[] Rs;

    private short rndNumbLength = 5;

    // Buffers
    byte[] recvAPDUData = null;
    private byte[] Zh;
    int ZhLen;
    private byte[] Zs;
    int ZsLen;
    private byte[] Ps;
    private byte[] cacheData;

    // Counter
    private byte[] N;
    short NLen = 2;

    // Other variables
    int normalLCLen = 1;
    int extendedLCLen = 3;
    int LClen = extendedLCLen;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        IDs = new ArrayList<String>();
        IDs.add("GC2222222222");
        IDs.add("GC3333333333");
        IDs.add("GC4444444444");
        IDs.add("GC5555555555");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        list = new ArrayList<>();

        APDU=null;
        rAPDU=null;

        iconCard = (ImageView) findViewById(R.id.imageCard);
        iconCard.setImageResource(R.drawable.ic_icc_off);

        TextCard = (TextView) findViewById(R.id.textCard);

        txtLog = (TextView) findViewById(R.id.textLog);

        rewardImage = (ImageView) findViewById(R.id.imageReward);

        resolveIntent(getIntent());

        Adapter = NfcAdapter.getDefaultAdapter(this);
        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
        try
        {
            ndef.addDataType("*/*");
        }
        catch (IntentFilter.MalformedMimeTypeException e)
        {
            throw new RuntimeException("fail", e);
        }
        Filters = new IntentFilter[] { ndef, };
        TechLists = new String[][] { new String[] { IsoDep.class.getName() } };



        mSendAIDButton = (Button) findViewById(R.id.button_SendAID);
        mSendAIDButton.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                if( cardDetected==true && myTag.isConnected())
                {
                    iconCard.setImageResource(R.drawable.ic_icc_on);

                    boolean caheLog = false;

                    if(sendAID()) {
                        /*try {
                            sendBigData();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }*/

                        if(sendStartAPDU()) {
                            /*File file = new File(MainActivity.this.getFilesDir(), "text");
                            if (!file.exists()) {
                                file.mkdir();
                            }*/
                            try {
                                if(checkCacheList(S)) {
                                    sendStopAPDU();
                                    showPreviouslyFoundCacheError();
                                    try {
                                        myTag.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                                else {
                                    try {
                                        if(sendPlayerData()) {
                                            caheLog = storeCacheData();
                                        }
                                    } catch (InvalidKeySpecException e) {
                                        e.printStackTrace();
                                    } catch (InvalidKeyException e) {
                                        e.printStackTrace();
                                    } catch (NoSuchAlgorithmException e) {
                                        e.printStackTrace();
                                    } catch (NoSuchProviderException e) {
                                        e.printStackTrace();
                                    } catch (SignatureException e) {
                                        e.printStackTrace();
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        else {
                            showLogFailedError();
                        }
                    }
                    else {
                        showIncompatibleCardError();
                    }

                    sendStopAPDU();

                    if(caheLog == true) {

                        //String finalAnswer = "AAA";
                        //print(finalAnswer);
                        showTravItemMssg();
                        getReward(v);
                    }
                }
                else
                {
                    iconCard.setImageResource(R.drawable.ic_icc_off);
                    TextCard.setText("Prosím, priložte smartfón k skrýši");
                }
            }
        });

    }

    @Override
    public void onResume()
    {
        super.onResume();

        APDU=null;
        rAPDU=null;

        if(  (cardDetected==true) && (myTag.isConnected()) ) {
            iconCard.setImageResource(R.drawable.ic_icc_on);
            TextCard.setText("Smartfón je teraz v spojení so skrýšou");
        }
        else {
            iconCard.setImageResource(R.drawable.ic_icc_off);
        }

        if( (Adapter == null) || (!Adapter.isEnabled()) ) {
            TextCard.setText("PROSÍM, ZAPNITE SI NFC");
        }

        if (Adapter != null) {
            if (Adapter.isEnabled() && (cardDetected==false)) {
                TextCard.setText("Prosím priložte smartfón k skrýši");
            }

            if (Adapter.isEnabled() && (cardDetected==true)) {
                TextCard.setText("Smartfón je teraz v spojení so skrýšou");
            }

            Adapter.enableForegroundDispatch(this, mPendingIntent, Filters, TechLists);
        }
        else{
            TextCard.setText("TOTO ZARIADENIE PRAVDEPODOBNE NEPODPORUJE NFC");
        }
    }

    public void onPause()
    {
        super.onPause();

        APDU=null;
        rAPDU=null;

        if( (cardDetected==true) && (myTag.isConnected()) ) {
            iconCard.setImageResource(R.drawable.ic_icc_on);
            TextCard.setText("Smartfón je teraz v spojení so skrýšou");
        }
        else {
            iconCard.setImageResource(R.drawable.ic_icc_off);
        }
        Adapter.disableForegroundDispatch(this);
    }

    @Override
    protected void onNewIntent(Intent intent)
    {
        setIntent(intent);
        resolveIntent(intent);
    }

    private void resolveIntent(Intent intent)
    {
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
            Parcelable tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            final Tag t = (Tag) tag;
            myTag = IsoDep.get(t);
            cardDetected=true;
            if( !myTag.isConnected() ) {
                try{
                    myTag.connect();
                    myTag.setTimeout(5000);
                }
                catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
            }
            if( myTag.isConnected() ) {
                iconCard.setImageResource(R.drawable.ic_icc_on);
                TextCard.setText("Smartfón je teraz v spojení so skrýšou");
            }
            else {
                iconCard.setImageResource(R.drawable.ic_icc_off);
            }
        }

        if( cardDetected==true && myTag.isConnected() )  {
            iconCard.setImageResource(R.drawable.ic_icc_on);
            TextCard.setText("Smartfón je teraz v spojení so skrýšou");
        }
        else {
            iconCard.setImageResource(R.drawable.ic_icc_off);
        }
    }


    // Core methods
    private boolean sendAID()
    {

        String StringAPDU = "00A4040008ABCDEFFEDC12345600";

        APDU = APDUtohex(StringAPDU);
        rAPDU = transceives(APDU);

        try{
            if (checkCorrectAnswer(rAPDU) == true) {
                receiveData(rAPDU);
                return true;
            }
            else {
                return false;
            }
        }
        catch (Exception e){
            txtLog.setText("");
            print("Response is not TLV format !!!");
        }

        return true;
    }

    private boolean sendStartAPDU()
    {
        String StringAPDU = Geocaching_CLA + START + "000000";

        APDU = APDUtohex(StringAPDU);
        rAPDU = transceives(APDU);

        try{
            if (checkCorrectAnswer(rAPDU) == true) {
                byte[] data = receiveData(rAPDU);

                storeRsS(data);

                return true;
            }
            else {
                return false;
            }
        }
        catch (Exception e){
            txtLog.setText("");
            print("Response is not TLV format !!!");
        }

        return true;
    }

    private boolean sendStopAPDU()
    {
        String StringAPDU = Geocaching_CLA + STOP + "000000";

        APDU = APDUtohex(StringAPDU);
        rAPDU = transceives(APDU);

        try{
            if (checkCorrectAnswer(rAPDU) == true) {

                return true;
            }
            else {
                return false;
            }
        }
        catch (Exception e){
            txtLog.setText("");
            print("Response is not TLV format !!!");
        }

        return true;
    }

    private boolean sendPlayerData() throws Exception
    {
        byte[] data = new byte[1000];
        int ZsOffs = 0;
        int PsOffs = 0;
        int dataEnd = 0;

        ZsOffs = prepareCertToSend(data);
        PsOffs = prepareZhToSend(data, ZsOffs);
        dataEnd = preparePsToSend(data, ZsOffs, PsOffs);

        byte[] dataToSend = new byte[dataEnd];
        System.arraycopy(data, 0, dataToSend, 0, dataToSend.length);

        byte[] bLC = intToByteArray(dataToSend.length, LClen);

        String StringAPDUHeader = Geocaching_CLA + GAME + "0000";
        String LC = bytesToHex(bLC);
        String APDUdata = bytesToHex(dataToSend);

        String StringAPDU = StringAPDUHeader + LC + APDUdata;

        APDU = APDUtohex(StringAPDU);
        rAPDU = transceives(APDU);

        recvAPDUData = rAPDU;
        String r = bytesToHex(recvAPDUData);

        return checkCorrectAnswer(rAPDU);

    }



    // sendStartAPDU additional methods
    private void storeRsS(byte[] data)
    {
        int rndNumbLength = data[1];
        int cacheIdLength = data[rndNumbLength + 1];
        if (data[0] == CACHE_RNDM_NUMB && data[rndNumbLength] ==  CACHE_ID){
            Rs = new byte[rndNumbLength - 2];
            System.arraycopy(data, 2, Rs, 0, (rndNumbLength - 2));
            S = new byte[cacheIdLength - 2];
            System.arraycopy(data, (rndNumbLength + 2), S, 0, (cacheIdLength - 2));
        }
        else {
            showWrongDataReceivedError();
        }
    }

    private boolean checkCacheList(byte[] id) throws IOException
    {
        boolean result = IDs.contains(id);

        return result;
    }



    // sendPlayerData additional methods
    private int prepareCertToSend(byte[] data)
    {

        System.arraycopy(CRTh, 0, data, 0, CRTh.length);

        return (CRTh.length);
    }

    private int prepareZhToSend(byte[] data, int offs)
    {
        Rh = generateRandomNumber();

        byte[] playerRndmNumb = valueToAVPformat(GAMER_RNDM_NUMB, Rh);
        byte[] cacheRndmNumb = valueToAVPformat(CACHE_RNDM_NUMB, Rs);
        byte[] cacheId = valueToAVPformat(CACHE_ID, S);
        byte[] playerTravelItem = valueToAVPformat(GAMER_TRAV_ITEM_ID, Uh);

        System.arraycopy(playerRndmNumb, 0, data, offs, (playerRndmNumb.length));
        System.arraycopy(cacheRndmNumb, 0, data, (offs + playerRndmNumb.length), cacheRndmNumb.length);
        System.arraycopy(cacheId, 0, data, (offs + playerRndmNumb.length + cacheRndmNumb.length), cacheId.length);
        System.arraycopy(playerTravelItem, 0, data, (offs + playerRndmNumb.length + cacheRndmNumb.length + cacheId.length), playerTravelItem.length);

        offs = (offs + playerRndmNumb.length + cacheRndmNumb.length + cacheId.length + playerTravelItem.length);

        return offs;
    }

    private int preparePsToSend(byte[] data, int ZsOffs, int PsOffs) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, SignatureException
    {
        int signBlockLen = 0;

        signBlockLen = sign(data, ZsOffs, PsOffs);

        return (signBlockLen + PsOffs);
    }

    private int sign(byte[] data, int dataOffs, int signOffs) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, InvalidKeyException
    {
        int mssgLen = signOffs - dataOffs;
        byte[] mssg = new byte[mssgLen];
        System.arraycopy(data, dataOffs, mssg, 0, mssgLen);

        createPlayerPrivKey();

        Signature ecdsaSign = Signature.getInstance(ALGO);

        ecdsaSign.initSign(SKh);
        ecdsaSign.update(mssg);
        byte[] signature = ecdsaSign.sign();

        int signLen = signature.length;
        data[signOffs] = GAMER_SIGN;
        data[signOffs + 1] = (byte)(signLen + 2);
        System.arraycopy(signature, 0, data, (signOffs + 2), signature.length);

        return (signLen + 2);
    }

    private boolean storeCacheData() throws InvalidKeySpecException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException
    {
        int ZhOffs = getCRTsFromData();
        if (verifyCRT()){
            int PhOffs = getZsFromData(ZhOffs);
            getPsFromData(PhOffs);
            if (verifyPs()) {
                if (getAndCheckSubdataFromZs()) {
                    return true;
                }
                else {
                    showWrongDataReceivedError();
                    return false;
                }
            }
            else {
                showWrongDataReceivedError();
                return false;
            }
        }
        else {
            showWrongDataReceivedError();
            return false;
        }

    }

    private int getCRTsFromData()
    {
        if (recvAPDUData[0] == CERT) {
            byte[] cl = new byte[2];
            System.arraycopy(recvAPDUData, 1, cl, 0, cl.length);
            int CERTlen = byteArrayToInt(cl, cl.length);

            CRTs = new byte[CERTlen];
            System.arraycopy(recvAPDUData, 0, CRTs, 0, (short) CERTlen);
            return CERTlen;
        }
        else
            showWrongDataReceivedError();
        return (short)0;
    }

    private boolean verifyCRT() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, SignatureException
    {
        int avpCertHeaderLen = 3;
        int dataOffs = (avpCertHeaderLen + 4);
        byte[] dl = new byte[2];
        System.arraycopy(CRTs, (dataOffs + 2), dl, 0, dl.length);
        int dataLen = byteArrayToInt(dl, dl.length) + 4;
        int signSpecOffs = dataOffs + dataLen;
        int signSpecLen = CRTs[signSpecOffs + 1] + 2;
        int signBlockOffs = (signSpecOffs + signSpecLen);
        int signBlockLen = CRTs[signBlockOffs + 1] + 2;

        byte[] dataToVerify = new byte[dataLen];
        System.arraycopy(CRTs, dataOffs, dataToVerify, 0, dataLen);

        int signLen = signBlockLen - 3;
        byte[] sign = new byte[signLen];
        System.arraycopy(CRTs, (signBlockOffs + 3), sign, 0, signLen);

        createCAPubKey();

        Signature ecdsaVerify = Signature.getInstance(ALGO);

        ecdsaVerify.initVerify(VKca);
        ecdsaVerify.update(dataToVerify);
        boolean result = ecdsaVerify.verify(sign);
        System.out.println("Res: " + result);

        if (result == true){
            getIDFromCert(CRTs, Scrt);
            getPubKFromCert(CRTs, bVKs);

            return true;
        }

        return false;
    }

    private int getZsFromData(int offs)
    {
        int RsLen = (recvAPDUData[offs + 1]);
        int RhLen = (recvAPDUData[offs + 1 + RsLen]);
        int Slen = (recvAPDUData[offs + 1 + RsLen + RhLen]);
        int Hlen = (recvAPDUData[offs + 1 + RsLen + RhLen + Slen]);
        int Nlen = (recvAPDUData[offs + 1 + RsLen + RhLen + Slen + Hlen]);
        int UsLen = (recvAPDUData[offs + 1 + RsLen + RhLen + Slen + Hlen + Nlen]);
        int UhLen = (recvAPDUData[offs + 1 + RsLen + RhLen + Slen + Hlen + Nlen + UsLen]);

        ZsLen = (RsLen + RhLen + Slen + Hlen + Nlen + UsLen + UhLen);

        Zs = new byte[ZsLen];

        System.arraycopy(recvAPDUData, offs, Zs, 0, ZsLen);

        return offs + ZsLen;
    }

    private int getPsFromData(int offs)
    {
        if (recvAPDUData[offs] == CACHE_SIGN) {
            int PsLen = (recvAPDUData[offs + 1]);

            Ps = new byte[ZsLen];

            System.arraycopy(recvAPDUData, (short) offs, Ps, (short) 0, (short) PsLen);

            return (offs + PsLen);
        }
        else
            showWrongDataReceivedError();
        return 0;
    }

    private boolean verifyPs() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException, SignatureException
    {
        int signLen = Ps[1] - 2;
        byte[] sign = new byte[signLen];
        System.arraycopy(Ps, 2, sign, 0, signLen);

        createCachePubKey();

        Signature ecdsaVerify = Signature.getInstance(ALGO);

        ecdsaVerify.initVerify(VKs);
        ecdsaVerify.update(Zs);
        boolean result = ecdsaVerify.verify(sign);

        return result;
    }

    private boolean getAndCheckSubdataFromZs()
    {
        String Z = bytesToHex(Zs);

        int RsLen = (Zs[1]);
        int RhLen = (Zs[1 + RsLen]);
        int Slen = (Zs[1 + RsLen + RhLen]);
        int Hlen = (Zs[1 + RsLen + RhLen + Slen]);
        int Nlen = (Zs[1 + RsLen + RhLen + Slen + Hlen]);
        int UsLen = (Zs[1 + RsLen + RhLen + Slen + Hlen + Nlen]);
        int UhLen = (Zs[1 + RsLen + RhLen + Slen + Hlen + Nlen + UsLen]);

        int RsOffs = 2;
        int RhOffs = 2 + RsLen;
        int SOffs = 2 + RsLen + RhLen;
        int HOffs = 2 + RsLen + RhLen + Slen;
        int NOffs = 2 + RsLen + RhLen + Slen + Hlen;
        int Usffs = 2 + RsLen + RhLen + Slen + Hlen + Nlen;
        int Uhffs = 2 + RsLen + RhLen + Slen + Hlen + Nlen + UsLen;

        if((Zs[RsOffs-2] == CACHE_RNDM_NUMB) && (Zs[RhOffs-2] == GAMER_RNDM_NUMB) && (Zs[SOffs-2] == CACHE_ID) && (Zs[HOffs-2] == GAMER_ID) && (Zs[NOffs-2] == DISC_ORDER) && (Zs[Usffs-2] == CACHE_TRAV_ITEM_ID) && (Zs[Uhffs-2] == GAMER_TRAV_ITEM_ID)) {
            byte[] Rsr = new byte[5];
            System.arraycopy(Zs, RsOffs, Rsr, 0, Rsr.length);
            if (compareTwoByteArrays(Rs, Rsr) == false)
                return false;

            byte[] Rhr = new byte[5];
            System.arraycopy(Zs, RhOffs, Rhr, 0, Rhr.length);
            if (compareTwoByteArrays(Rh, Rhr) == false)
                return false;

            byte[] Sr = new byte[Slen-2];
            System.arraycopy(Zs, SOffs, Sr, 0, Sr.length);
            if (compareTwoByteArrays(S, Sr) == false)
                return false;

            byte[] Hr = new byte[Hlen-2];
            System.arraycopy(Zs, HOffs, Hr, 0, Hr.length);
            if (compareTwoByteArrays(H, Hr) == false)
                return false;

            N = new byte[Nlen-2];
            System.arraycopy(Zs, NOffs, N, 0, N.length);
            String Nst = bytesToHex(N);

            byte[] Uhr = new byte[UhLen-2];
            System.arraycopy(Zs, Uhffs, Uhr, 0, Uhr.length);
            String Uhrst = bytesToHex(Uhr);
            if (compareTwoByteArrays(Uh, Uhr) == false)
                return false;

            Us = new byte[UsLen-2];
            System.arraycopy(Zs, Usffs, Us, 0, Us.length);
            String Usst = bytesToHex(Us);
            System.arraycopy(Us, 0, Uh, 0, Uh.length);

            return true;
        }

        else {
            showWrongDataReceivedError();
        }

        return false;
    }

    private void getIDFromCert(byte[] CRT, byte[] id)
    {
        int avpCertHeaderLen = 3;
        int dataOffs = avpCertHeaderLen + 4;
        //int dataLen = (Util.getShort(CRT, (dataOffs + 2)) + 4);
        int offs1 = (dataOffs + 4);
        int len1 = (CRT[offs1 + 1] + 2);
        int offs2 = (offs1 + len1);
        int len2 = (CRT[offs2 + 1] + 2);
        int offs3 = (offs2 + len2);
        int len3 = (CRT[offs3 + 1] + 2);
        int offs4 = (offs3 + len3);
        int len4 = (CRT[offs4 + 1] + 2);
        int offs5 = (offs4 + len4);
        int offs6 = (offs5 + 2);
        int offs7 = (offs6 + 2);
        int offs8 = (offs7 + 2);
        int len8 = (CRT[offs8 + 1] + 2);
        int offs9 = (offs8 + len8);
        int len9 = (CRT[offs9 + 1] + 2);
        int offsH = (offs9 + 2);
        int lenH = (len9 - 2);

        Scrt = new byte[lenH];

        System.arraycopy(CRT, offsH, Scrt, 0, lenH);
    }

    private void getPubKFromCert(byte[] CRT, byte[] key)
    {
        int avpCertHeaderLen = 3;
        int dataOffs = (avpCertHeaderLen + 4);
        //int dataLen = (Util.getShort(CRT, (short)(dataOffs + 2)) + 4);
        int offs1 = (dataOffs + 4);
        int len1 = (CRT[offs1 + 1] + 2);
        int offs2 = (offs1 + len1);
        int len2 = (CRT[offs2 + 1] + 2);
        int offs3 = (offs2 + len2);
        int len3 = (CRT[offs3 + 1] + 2);
        int offs4 = (offs3 + len3);
        int len4 = (CRT[offs4 + 1] + 2);
        int offs5 = (offs4 + len4);
        int len5 = (CRT[offs5 + 1] + 2);
        int offs6 = (offs5 + len5);
        int offs7 = (offs6 + 3);
        int len7 = (getIntFromByteArray(CRT, (short)(offs7 + 2)) + 3);
        int offs8 = (offs7 + len7);
        int len8 = (CRT[offs8 + 1] + 2);
        int offsKey = (offs8 + 3);
        int lenKey = (len8 - 3);

        bVKs = new byte[lenKey];

        System.arraycopy(CRT, offsKey, bVKs, 0, lenKey);
    }

    public void getReward(View view)
    {
        GameClass gameClass = new GameClass();
        gameClass.showGameWindow(view);
    }





    // send/receive methods
    public static byte[]  transceives(byte[] data)
    {
        byte[] ra = null;

        try {
            ra = myTag.transceive(data);
        }
        catch (IOException e) {
            print("KOMUNIKACIA ZLYHALA");
        }

        return (ra);
    }

    private byte[] receiveData(byte[] ansData) throws Exception
    {
        try
        {
            if (ansData.length != 2) {
                try
                {
                    byte[] data = new byte[ansData.length-2];
                    System.arraycopy(ansData, 0, data, 1, data.length);

                    return data;
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }

            if (ansData.length == 2) {
                showWrongDataReceivedError();
                return ansData;
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return ansData;
    }

    public static boolean checkCorrectAnswer(byte[] data) throws Exception
    {
        if (data.length != 2) {
            String answer = getHexString(data);

            String sw12 = answer.substring(answer.length()-6);

            try
            {
                if (sw12.equals("90 00 "))
                    return true;
                else
                    return false;
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        if (data.length == 2) {
            String sw12 = getHexString(data);

            try
            {
                if (sw12.equals("90 00 "))
                    return true;
                else
                    return false;
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        return false;
    }



    // create key methods
    private void createPlayerPrivKey() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException
    {
        int slen = bSKh.length;
        byte[] sa = new byte[slen];
        System.arraycopy(bSKh, 0, sa, 0, sa.length);
        String sb = bytesToHex(sa);
        BigInteger s = new BigInteger(sb, 16);

        KeyFactory kf = KeyFactory.getInstance("ECDSA", "BC");

        Secp192k1 secp192k1 = new Secp192k1();

        ECFieldFp ecffp = new ECFieldFp(secp192k1.getp());
        //ECField ecf = new ECField();
        EllipticCurve elc = new EllipticCurve(ecffp, secp192k1.geta(), secp192k1.getb());

        ECPoint G = new ECPoint(secp192k1.getGx(), secp192k1.getGy());

        ECParameterSpec domainparameters = new ECParameterSpec(elc, G, secp192k1.getn(), secp192k1.geth());

        ECPrivateKeySpec specPrivK = new ECPrivateKeySpec(s, domainparameters);

        SKh = (ECPrivateKey)kf.generatePrivate(specPrivK);
    }

    private void createCAPubKey() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException
    {
        int xlen = ((bVKca.length - 1) / 2);
        int ylen = ((bVKca.length - 1) / 2);
        byte[] xa = new byte[xlen];
        byte[] ya = new byte[ylen];
        System.arraycopy(bVKca, 1, xa, 0, xa.length);
        System.arraycopy(bVKca, (xa.length + 1), ya, 0, ya.length);
        String xb = bytesToHex(xa);
        String yb = bytesToHex(ya);
        BigInteger x = new BigInteger(xb, 16);
        BigInteger y = new BigInteger(yb, 16);

        KeyFactory kf = KeyFactory.getInstance("ECDSA", "BC");

        ECPoint point = new ECPoint(x, y);

        Secp192k1 secp192k1 = new Secp192k1();

        ECFieldFp ecffp = new ECFieldFp(secp192k1.getp());
        //ECField ecf = new ECField();
        EllipticCurve elc = new EllipticCurve(ecffp, secp192k1.geta(), secp192k1.getb());

        ECPoint G = new ECPoint(secp192k1.getGx(), secp192k1.getGy());

        ECParameterSpec domainparameters = new ECParameterSpec(elc, G, secp192k1.getn(), secp192k1.geth());

        ECPublicKeySpec specPubK = new ECPublicKeySpec(point, domainparameters);

        VKca = (ECPublicKey)kf.generatePrivate(specPubK);
    }

    private void createCachePubKey() throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException
    {
        int xlen = ((bVKs.length - 1) / 2);
        int ylen = ((bVKs.length - 1) / 2);
        byte[] xa = new byte[xlen];
        byte[] ya = new byte[ylen];
        System.arraycopy(bVKs, 1, xa, 0, xa.length);
        System.arraycopy(bVKs, (xa.length + 1), ya, 0, ya.length);
        String xb = bytesToHex(xa);
        String yb = bytesToHex(ya);
        BigInteger x = new BigInteger(xb, 16);
        BigInteger y = new BigInteger(yb, 16);

        KeyFactory kf = KeyFactory.getInstance("ECDSA", "BC");

        ECPoint point = new ECPoint(x, y);

        Secp192k1 secp192k1 = new Secp192k1();

        ECFieldFp ecffp = new ECFieldFp(secp192k1.getp());
        //ECField ecf = new ECField();
        EllipticCurve elc = new EllipticCurve(ecffp, secp192k1.geta(), secp192k1.getb());

        ECPoint G = new ECPoint(secp192k1.getGx(), secp192k1.getGy());

        ECParameterSpec domainparameters = new ECParameterSpec(elc, G, secp192k1.getn(), secp192k1.geth());

        ECPublicKeySpec specPubK = new ECPublicKeySpec(point, domainparameters);

        VKs = (ECPublicKey)kf.generatePrivate(specPubK);
    }



    // show message/error methods
    public void showTravItemMssg()
    {
        if (compareTwoByteArrays(Uh, emptyU)){
            String finalAnswer = "V skrýši sa nenachádzal žiadny putovný predmet. Pokiaľ si prajete do ďalšej skrýše vložiť nový predmet, zaregistrujte ho na hráčškom serveri.";
            print(finalAnswer);
        }
        else{
            String d = new String(Uh);
            String finalAnswer = "V skrýši sa nachádzal putovný predmet s identifikátorom " + d + ". Teraz ste držiteľom tohto putovného predmetu a pri najbližšom nájdení novej skrýše s podporou putovných predmetov sa vloží do tejto skrýše.";
            print(finalAnswer);
        }

    }

    public void showIncompatibleCardError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Táto skrýša nie je kompatibilná s touto aplikáciou alebo sa nepodarilo spustiť aplikáciu v skrýši";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }

    public void showCardAppletError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Nepodarilo sa spustiť aplikáciu v skrýši. Prosím kontaktujte zakladateľa tejto skrýše";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }

    public void showLogFailedError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Nepodarilo sa zahájiť proces zápisu skrýše.";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }

    public void showWrongDataReceivedError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Z karty sa nepodarilo prijať potrebné dáta. Skúste to znovu";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }

    public void showPreviouslyFoundCacheError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Túto skrýšu ste už v minulosti našli. Spojenie so skrýšou bolo prerušené.";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }

    public void showSomethingWentWrongError()
    {
        Context context = getApplicationContext();
        CharSequence text = "Niečo sa pokazilo";
        int duration = Toast.LENGTH_LONG;
        Toast toast = Toast.makeText(context, text, duration);
        toast.show();
    }



    // other methods
    public byte[] intToByteArray(int value, int arrayLen)
    {
        byte[] a = ByteBuffer.allocate(4).putInt(value).array();
        byte[] array = new byte[arrayLen];

        System.arraycopy(a, (4-arrayLen), array, 0, arrayLen);

        return array;
    }

    private int getIntFromByteArray(byte[] array, short offs)
    {
        byte[] a = new byte[2];

        a[(short)0] = 0x00;
        a[(short)1] = array[(short)offs];

        return byteArrayToInt(a, a.length);
    }

    public int byteArrayToInt(byte[] bytes, int length)
    {
        int val = 0;
        if(length>4) throw new RuntimeException("Too big to fit in int");
        for (int i = 0; i < length; i++) {
            val=val<<8;
            val=val|(bytes[i] & 0xFF);
        }
        return val;
    }

    public String bytesToHex(byte[] bytes)
    {
        char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] APDUtohex(String data)
    {
        String hexchars = "0123456789abcdef";

        data = data.replaceAll(" ","").toLowerCase();
        if (data == null)
        {
            return null;
        }
        byte[] hex = new byte[data.length() / 2];

        for (int ii = 0; ii < data.length(); ii += 2)
        {
            int i1 = hexchars.indexOf(data.charAt(ii));
            int i2 = hexchars.indexOf(data.charAt(ii + 1));
            hex[ii/2] = (byte)((i1 << 4) | i2);
        }
        return hex;
    }

    public static String getHexString(byte[] data) throws Exception
    {
        String szDataStr = "";
        for (int ii=0; ii < data.length; ii++)
        {
            szDataStr += String.format("%02X ", data[ii] & 0xFF);
        }
        return szDataStr;
    }

    private byte[] valueToAVPformat(byte type, byte[] value)
    {
        byte[] avp = new byte[value.length + 2];
        avp[0] = type;
        avp[1] = (byte)(avp.length);
        System.arraycopy(value, 0, avp, 2, value.length);

        return avp;
    }

    public byte[] generateRandomNumber()
    {
        byte[] r = new byte[5];
        new Random().nextBytes(r);

        return r;
    }

    private boolean compareTwoByteArrays(byte[] a1, byte[] a2)
    {
        if (a1.length != a2.length)
            return false;

        for (short i = 0; i < a1.length; i++){
            if (a1[i] != a2[i])
                return false;
        }

        return true;
    }

    public static void print(String s)
    {
        txtLog.append(s);
        txtLog.append("\r\n");
        return;
    }

    private String readFile() throws IOException
    {
        Context context = getApplicationContext();
        File path = context.getFilesDir();

        File file = new File(path, "text.txt");

        int length = (int) file.length();

        byte[] bytes = new byte[length];

        FileInputStream in = new FileInputStream(file);
        try {
            in.read(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            in.close();
        }

        String contents = new String(bytes);


        String result = Arrays.toString(new ArrayList[]{list});
        return result;
    }

    public void showImage(String name, View view) throws Exception
    {
        if (name.equals("Skladačka")){
            print("Vo vašej skladačke sa previedol ďalší krok");
            rewardImage.setImageResource(R.drawable.jigsaw);
        }
        else if (name.equals("Prírodné javy")){
            print("Do zbierky ste získali tento nový obrázok");
            rewardImage.setImageResource(R.drawable.collect_image);
        }
        else
            showSomethingWentWrongError();

    }









}