package org.jboss.installer.postinstall.task;

import org.jboss.installer.core.DatabaseDriver;
import org.jboss.installer.core.InstallationData;
import org.jboss.installer.postinstall.TaskPrinter;
import org.jboss.installer.postinstall.server.DomainServer;
import org.jboss.installer.postinstall.server.StandaloneServer;
import org.jboss.installer.test.utils.TestServer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import java.util.Collections;

import static org.jboss.installer.test.utils.TestServer.TARGET_PATH;

public class JDBCDriverTaskTest {

    @ClassRule
    public static TestServer testServer = new TestServer();
    private StandaloneServer standaloneServer;
    private DomainServer domainServer;
    private InstallationData iData;
    private XPath xPath =  XPathFactory.newInstance().newXPath();
    private DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    private DocumentBuilder builder;
    private TaskPrinter printer = new NoopPrinter();

    @Before
    public void setUp() throws Exception {
        standaloneServer = new StandaloneServer(TARGET_PATH);
        domainServer = new DomainServer(TARGET_PATH);
        iData = new InstallationData();
        iData.setTargetFolder(TARGET_PATH);
        builder = factory.newDocumentBuilder();
    }

    @Test
    public void driverAddedInDomainMode() throws Exception {
        JDBCDriverTask.Config config = new JDBCDriverTask.Config(DatabaseDriver.IBM_DB2, Collections.emptyList(), Collections.emptyList());
        iData.putConfig(config);
        domainServer.start("host.xml");
        try {
            Assert.assertTrue(new JDBCDriverTask().applyToDomain(iData, domainServer, printer));
            Document doc = builder.parse(TARGET_PATH.resolve("domain").resolve("configuration").resolve("domain.xml").toFile());
            for (String profile : DomainServer.PROFILES) {
                String prefix = String.format("//profile[@name=\"%s\"]/subsystem/datasources/", profile);
                Assert.assertEquals(config.getDatabaseDriver().getModuleName(), getModuleName(doc, prefix + "/drivers/driver"));
                Assert.assertEquals(config.getDatabaseDriver().getXaClassName(), getXaClassName(doc, prefix + "/drivers/driver"));
            }
        } finally {
            domainServer.shutdown();
        }
    }

    @Test
    public void driverAddedInStandaloneMode() throws Exception {
        JDBCDriverTask.Config config = new JDBCDriverTask.Config(DatabaseDriver.IBM_DB2, Collections.emptyList(), Collections.emptyList());
        iData.putConfig(config);
        String serverConfig = "standalone.xml";
        standaloneServer.start(serverConfig);
        try {
            Assert.assertTrue(new JDBCDriverTask().applyToStandalone(iData, standaloneServer, printer));
            Document doc = builder.parse(TARGET_PATH.resolve("standalone").resolve("configuration").resolve(serverConfig).toFile());
            Assert.assertEquals(config.getDatabaseDriver().getModuleName(), getModuleName(doc, "//drivers/driver"));
            Assert.assertEquals(config.getDatabaseDriver().getXaClassName(), getXaClassName(doc, "//drivers/driver"));
        } finally {
            standaloneServer.shutdown();
        }
    }

    public String getXaClassName(Document doc, String expression) throws XPathExpressionException {
        NodeList jdbcDriver = (NodeList) xPath.compile(expression).evaluate(
                doc, XPathConstants.NODESET);
        return jdbcDriver.item(1).getChildNodes().item(1).getTextContent();
    }

    public String getModuleName(Document doc, String expression) throws XPathExpressionException {
        NodeList jdbcDriver = (NodeList) xPath.compile(expression).evaluate(
                doc, XPathConstants.NODESET);
        return jdbcDriver.item(1).getAttributes().getNamedItem("module").getNodeValue();
    }
}
