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

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.wso2.carbon.device.mgt.ios.core.exception.IOSEnrollmentException;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class AppConfigurations {

	public static final String PROFILE_URL = "iOSProfileURL";
	public static final String CHECKIN_URL = "iOSCheckinURL";
	public static final String SERVER_URL = "iOSServerURL";
	public static final String ENROLL_URL = "iOSEnrollURL";
	public static final String PATH_KEYSTORE = "Location";
	public static final String PATH_MDM_KEYSTORE = "MDMKeystoreLocation";
	public static final String KEY_ALIAS_KEYSTORE = "KeyAlias";
	public static final String KEYSTORE_PASSWORD = "Password";
	public static final String MDM_KEYSTORE_PASSWORD = "MDMKeystorePassword";
	public static final String KEYSTORE_KEY_PASSWORD = "KeyPassword";
	public static final String KEYSTORE_CA_CERT_PRIV_PASSWORD = "MDMCAPrivateKeyPassword";
	public static final String KEYSTORE_RA_CERT_PRIV_PASSWORD = "MDMRAPrivateKeyPassword";
	public static final String CA_CERT_ALIAS = "MDMCACertAlias";
	public static final String RA_CERT_ALIAS = "MDMRACertAlias";
	private static final String CARBON_KEY_STORE_PARENT = "KeyStore";
	public static final String SIGNATUREALGO = "SHA1withRSA";
	public static final String PROVIDER = "BC";
	public static final String KEYSTORE = "Type";
	public static final String MDM_KEYSTORE = "MDMKeystoreType";
	public static final String RSA = "RSA";
	public static final String UTF_8 = "UTF-8";
	public static final String SHA256_RSA = "SHA256WithRSAEncryption";
	public static final String X_509 = "X.509";
	public static final String POST_BODY_CA_CAPS = "POSTPKIOperation\nSHA-1\nDES3\n";
	public static final String DES_EDE = "DESede";
	public static final String I_PAD = "iPad";
	public static final String I_POD = "iPod";
	public static final String I_PHONE = "iPhone";
    private static final String TOKEN_URL = "TokenURL";
    public static final String CONF_LOCATION = "conf.location";
    private static final String CARBON_HOME = "carbon.home";
    private static final String IOS_CONFIG_XML = "ios-config.xml";
    private static final String CARBON_HOME_ENTRY = "${carbon.home}";
    private static final String CARBON_XML = "carbon.xml";
    public static final String DEFAULT_PRINCIPAL = "O=WSO2, OU=Mobile, C=LK";
    public static final String RSA_PRIVATE_KEY_BEGIN_TEXT = "-----BEGIN RSA PRIVATE KEY-----\n";
    public static final String RSA_PRIVATE_KEY_END_TEXT = "-----END RSA PRIVATE KEY-----";
    public static final String EMPTY_TEXT = "";
    public static final int RSA_KEY_LENGTH = 1024;

    private static AppConfigurations appConfigurations;
    private static final String[] emmConfigEntryNames = { ENROLL_URL, PROFILE_URL, CHECKIN_URL, SERVER_URL, TOKEN_URL,
            CA_CERT_ALIAS, RA_CERT_ALIAS, MDM_KEYSTORE, PATH_MDM_KEYSTORE, MDM_KEYSTORE_PASSWORD,
            KEYSTORE_CA_CERT_PRIV_PASSWORD, KEYSTORE_RA_CERT_PRIV_PASSWORD };

    private static final String[] carbonConfigEntryNames = { PATH_KEYSTORE, KEY_ALIAS_KEYSTORE, KEYSTORE,
            KEYSTORE_PASSWORD, KEYSTORE_KEY_PASSWORD };

    private static Map<String, String> configMap;

    private static Map<String, String> readEMMConfigurations() throws IOSEnrollmentException {

        String emmConfLocation = System.getProperty(CONF_LOCATION) + File.separator + IOS_CONFIG_XML;

        if (appConfigurations == null || configMap == null) {

            appConfigurations = new AppConfigurations();
            configMap = new HashMap<>();

			Document document;
			try {
				File fXmlFile = new File(emmConfLocation);
				DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
				DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
				document = documentBuilder.parse(fXmlFile);
			} catch (ParserConfigurationException e) {
				throw new IOSEnrollmentException("Error parsing configuration in ios-config.xml file");
			} catch (SAXException e) {
                throw new IOSEnrollmentException("SAX exception in ios-config.xml file");
            } catch (IOException e) {
                throw new IOSEnrollmentException("Error reading ios-config.xml file");
            }

			for (String configEntry : emmConfigEntryNames) {
				NodeList elements = document.getElementsByTagName(configEntry);
				if (elements != null && elements.getLength() > 0) {
					configMap.put(configEntry, elements.item(0).getTextContent());
				}
			}

            NodeList emmKeyStoreEntry = document.getElementsByTagName(CARBON_KEY_STORE_PARENT);
            NodeList keyStoreChildElements;

            if (emmKeyStoreEntry == null || emmKeyStoreEntry.getLength() == 0) {
                throw new IOSEnrollmentException("Error reading carbon.xml file");
            } else {
                keyStoreChildElements = emmKeyStoreEntry.item(0).getChildNodes();
            }

			for (int i = 0; i < keyStoreChildElements.getLength(); i++) {
				Node currentNode = keyStoreChildElements.item(i);
				if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
					for (String configEntry : carbonConfigEntryNames) {
						if (configEntry.equalsIgnoreCase(currentNode.getNodeName())) {
							configMap.put(configEntry, currentNode.getTextContent());
						}
					}
				}
			}

			String carbonKeyStoreLocation = replaceCarbonHomeEnvEntry(configMap.get(PATH_KEYSTORE));
			if (carbonKeyStoreLocation != null) {
				configMap.put(PATH_KEYSTORE, carbonKeyStoreLocation);
			}

			String emmKeyStoreLocation = replaceCarbonHomeEnvEntry(configMap.get(PATH_MDM_KEYSTORE));
			if (emmKeyStoreLocation != null) {
				configMap.put(PATH_MDM_KEYSTORE, emmKeyStoreLocation);
			}
		}

		return configMap;
	}

	public static String getConfigEntry(final String entry) throws IOSEnrollmentException {

		Map<String, String> configurationMap = readEMMConfigurations();
		String configValue = configurationMap.get(entry);

		if (configValue == null) {
			throw new IOSEnrollmentException(String.format("Configuration entry %s not available", entry));
		}

		return configValue.trim();
	}

	private static String replaceCarbonHomeEnvEntry(String entry) {
		if (entry != null && entry.toLowerCase().contains(CARBON_HOME_ENTRY)) {
			return entry.replace(CARBON_HOME_ENTRY, System.getProperty(CARBON_HOME));
		}

		return null;
	}

    public static AppConfigurations getInstance() {
        if (appConfigurations == null) {
            synchronized (AppConfigurations.class) {
                if (appConfigurations == null) {
                    appConfigurations = new AppConfigurations();
                }
            }
        }
        return appConfigurations;
    }
}
