package org.wso2.carbon.device.mgt.ios.core.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.certificate.mgt.core.exception.KeystoreException;
import org.wso2.carbon.device.mgt.ios.core.exception.IOSEnrollmentException;
import org.wso2.carbon.device.mgt.ios.core.internal.IOSEnrollmentServiceHolder;
import org.wso2.carbon.device.mgt.ios.core.util.AppConfigurations;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.util.Base64;

public class KeyStoreReader {

    private static final Log log = LogFactory.getLog(KeyStoreReader.class);
    public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
    public static final String END_CERT = "-----END CERTIFICATE-----";
    public final static String LINE_SEPARATOR = System.getProperty("line.separator");
    public final static int PEM_LINE_LENGTH = 64;
    public final static int ENCODED_PEM_LINE_LENGTH = 52;

    private KeyStore loadKeyStore(String configEntryKeyStoreType, String configEntryKeyStorePath,
                                  String configEntryKeyStorePassword) throws IOSEnrollmentException {

        InputStream inputStream = null;
        KeyStore keystore;

        try {
            keystore = KeyStore.getInstance(AppConfigurations.getConfigEntry(configEntryKeyStoreType));
            inputStream = new FileInputStream(AppConfigurations.getConfigEntry(configEntryKeyStorePath));
            keystore.load(inputStream, AppConfigurations.getConfigEntry(configEntryKeyStorePassword).toCharArray());

        } catch (KeyStoreException e) {
            String errorMsg = "KeyStore issue occurred when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } catch (FileNotFoundException e) {
            String errorMsg = "KeyStore file not found when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } catch (NoSuchAlgorithmException e) {
            String errorMsg = "Algorithm not found when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } catch (CertificateException e) {
            String errorMsg = "Certificate expired when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } catch (IOException e) {
            String errorMsg = "Input output issue occurred when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                log.error("Error closing KeyStore input stream", e);
            }
        }

        return keystore;
    }

    KeyStore loadCarbonKeyStore() throws IOSEnrollmentException {
        return loadKeyStore(AppConfigurations.KEYSTORE, AppConfigurations.PATH_KEYSTORE,
                AppConfigurations.KEYSTORE_PASSWORD);
    }

    public static String getEncodedCACert() throws IOSEnrollmentException {

        Base64.Encoder encoder = Base64.getMimeEncoder(PEM_LINE_LENGTH, LINE_SEPARATOR
                .getBytes());

        try {
            Certificate certificate = IOSEnrollmentServiceHolder.getInstance()
                    .getCertificateManagementService().getCACertificate();
            byte[] certificateBytes = certificate.getEncoded();
            String certificateEncoded = new String(encoder.encode(certificateBytes));
            String certificatePEM = BEGIN_CERT + LINE_SEPARATOR + certificateEncoded +
                    LINE_SEPARATOR + END_CERT;
            Base64.Encoder certificatePayloadEncorder = Base64.getMimeEncoder
                    (ENCODED_PEM_LINE_LENGTH, LINE_SEPARATOR.getBytes());
            return new String(certificatePayloadEncorder.encode(certificatePEM.getBytes()));
        } catch (KeystoreException e) {
            String errorMsg = "Input output issue occurred when loading KeyStore";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        } catch (CertificateEncodingException e) {
            String errorMsg = "Could not load the CA certificate from keystore.";
            log.error(errorMsg, e);
            throw new IOSEnrollmentException(errorMsg, e);
        }
    }
}
