package org.iotivity.bridge.homeserver.handler;

import android.content.Context;
import android.util.Log;

import org.iotivity.OCFactoryPresetsHandler;
import org.iotivity.OCPki;
import org.iotivity.OCSpTypesMask;
import org.iotivity.bridge.homeserver.BridgeServerActivity;
import org.iotivity.bridge.homeserver.BridgeService;
import org.iotivity.bridge.homeserver.utils.Utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class FactoryPresetsHandler implements OCFactoryPresetsHandler {

    private static final String TAG = FactoryPresetsHandler.class.getSimpleName();

    private BridgeService service;

    public FactoryPresetsHandler(BridgeService service) {
        this.service = service;
    }

    @Override
    public void handler(long deviceIndex) {
        Log.d(TAG, "inside the FactoryPresetsHandler, deviceIndex  = " + deviceIndex);

        // TODO : when attempting to add an identity certificate chain, could not parse identity cert's private key

        boolean isMfgCertSupport = true;
        if (isMfgCertSupport && deviceIndex != 0)
            return; // TODO : Only Bridge will use pki certs in this case

        setPKISecurityMfgCert(deviceIndex);
    }

    private void setPKISecurityMfgCert(long deviceIndex) {

        // load End Endtity cert
        byte[] cert = getFileBytes("pki_certs/ee.pem");
        if (cert == null) {
            Log.e(TAG, "Failed to read certificates");
            return;
        }

        // load End Endtity private key
        byte[] key = getFileBytes("pki_certs/key.pem");
        if (key == null) {
            Log.e(TAG, "Failed to read private key");
            return;
        }

        // add End Entity Cert
        int eeCredId = OCPki.addMfgCert(deviceIndex, cert, key);
        Log.d(TAG, "addMfgCert() credId = " + eeCredId);
        if (eeCredId < 0) {
            Log.e(TAG, "Error installing manufacturer ee certificate");
            return;
        }

        // load Sub CA
        byte[] subCa = getFileBytes("pki_certs/subca1.pem");
        if (subCa == null) {
            Log.e(TAG, "Failed to read sub ca cetificate");
            return;
        }
        // add Sub CA
        int subCaCredId = OCPki.addMfgIntermediateCert(deviceIndex, eeCredId, subCa);
        Log.d(TAG, "addMfgIntermediateCert() result = " + subCaCredId);
        if (subCaCredId < 0) {
            Log.e(TAG, "Error installing intermediate ca certificate");
            return;
        }

        // load Root CA
        byte[] rootCa = getFileBytes("pki_certs/rootca1.pem");
        if (rootCa == null) {
            Log.e(TAG, "Failed to read root ca cetificate");
            return;
        }
        // add Root CA
        int rootCaCredId = OCPki.addMfgTrustAnchor(deviceIndex, rootCa);
        Log.d(TAG, "addMfgTrustAnchor() result = " + rootCaCredId);
        if (rootCaCredId < 0) {
            Log.e(TAG, "Error installing root ca certificate");
            return;
        }

        //load Root CA 3
        rootCa = getFileBytes("pki_certs/rootca3.pem");
        if (rootCa == null) {
            Log.e(TAG, "Failed to read root ca cetificate");
            return;
        }
        // add Root CA 3
        rootCaCredId = OCPki.addMfgTrustAnchor(deviceIndex, rootCa);
        Log.d(TAG, "addMfgTrustAnchor() result = " + rootCaCredId);
        if (rootCaCredId < 0) {
            Log.e(TAG, "Error installing root ca certificate");
            return;
        }

        OCPki.setSecurityProfile(deviceIndex, OCSpTypesMask.BLACK, OCSpTypesMask.BLACK, eeCredId);
        Log.d(TAG, "setSecurityProfile()");

    }

    private byte[] getFileBytes(String filepath) {

        ByteArrayOutputStream baos = null;
        try {
            InputStream is = service.getAssets().open(filepath);
            Log.d(TAG, "reading file " + filepath);

            try {
                byte[] buffer = new byte[8192];
                baos = new ByteArrayOutputStream();
                int length = 0;
                while ((length = is.read(buffer)) != -1) {
                    Log.d(TAG, "bytes read = " + length);
                    baos.write(buffer, 0, length);
                }
            } catch (IOException e) {
                Log.e(TAG, "Error reading file " + filepath);
            } finally {
                try {
                    if (baos != null) {
                        baos.close();
                    }
                } catch (IOException e) {
                    // ignore
                }
                try {
                    if (is != null) {
                        is.close();
                    }
                } catch (IOException e) {
                    // ignore
                }
            }

        } catch (IOException e) {
            Log.e(TAG, "Failed to read " + filepath);
        }

        return ((baos != null) ? baos.toByteArray() : null);
    }
}
