package ru.rutoken.samples.pkcs11Wrapper;

import com.sun.jna.NativeLong;
import com.sun.jna.ptr.NativeLongByReference;
import ru.rutoken.Pkcs11.*;

public class Init{

    private final static byte[] USER_PIN = {'1', '2', '3', '4', '5', '6', '7', '8'};
    private final static byte[] SO_PIN = {'8', '7', '6', '5', '4', '3', '2', '1'};
    private final static byte[] TOKEN_LABEL = {'M', 'y', ' ', 'R', 'u', 't', 'o', 'k',
                                               'e', 'n', ' ', ' ', ' ', ' ', ' ', ' ',
                                               ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
                                               ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };
    public static void main(String[] args) {
        NativeLong hSession = Pkcs11Constants.CK_INVALID_HANDLE;
        try{
            System.out.println("Example of token initialization using rtpkcs11ecp via JNA");

            System.out.println("Library initialization and acquiring of function list");
            NativeLong rv = RtPkcs11Library.getInstance().C_Initialize(null);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("Failed to initialize library, error code:" + Long.toHexString(rv.longValue()));
            }

            System.out.println("Acquiring list of slots with connected tokens");

            NativeLongByReference slotsCount = new NativeLongByReference();
            rv = RtPkcs11Library.getInstance().C_GetSlotList(true, null, slotsCount);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_GetSlotList failed, error code: " + Long.toHexString(rv.longValue()));
            }
            if (slotsCount.getValue().intValue() == 0)
            {
                throw new Exception("No Rutoken is available!");
            }

            NativeLong[] pSlotList = new NativeLong[slotsCount.getValue().intValue()];
            rv = RtPkcs11Library.getInstance().C_GetSlotList(true, pSlotList, slotsCount);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_GetSlotList failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Token initialization");
            rv = RtPkcs11Library.getInstance().C_InitToken(pSlotList[0], SO_PIN, new NativeLong(SO_PIN.length), TOKEN_LABEL);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_InitToken failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Opening session");
            NativeLongByReference phSession = new NativeLongByReference();
            rv = RtPkcs11Library.getInstance().C_OpenSession(pSlotList[0],
                    new NativeLong(Pkcs11Constants.CKF_SERIAL_SESSION.longValue() | Pkcs11Constants.CKF_RW_SESSION.longValue()),
                    null, null, phSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_OpenSession failed, error code: " + Long.toHexString(rv.longValue()));
            }
            hSession = phSession.getValue();

            System.out.println("Logging in as administrator");
            rv = RtPkcs11Library.getInstance().C_Login(hSession, Pkcs11Constants.CKU_SO, SO_PIN, new NativeLong(SO_PIN.length));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_Login failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("User PIN initialization");
            rv = RtPkcs11Library.getInstance().C_InitPIN(hSession, USER_PIN, new NativeLong(USER_PIN.length));
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                throw new Exception("C_InitPIN failed, error code: " + Long.toHexString(rv.longValue()));
            }
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }
        finally {
            System.out.println("Logging out");
            NativeLong rv = RtPkcs11Library.getInstance().C_Logout(hSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_Logout failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Closing session");
            rv = RtPkcs11Library.getInstance().C_CloseSession(hSession);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_CloseSession failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Finalizing PKCS11 library");
            rv = RtPkcs11Library.getInstance().C_Finalize(null);
            if (!rv.equals(Pkcs11Constants.CKR_OK))
            {
                System.out.println("C_Finalize failed, error code: " + Long.toHexString(rv.longValue()));
            }

            System.out.println("Test has been completed.");
        }
    }
}
