/**
 * Copyright (C) 2014 Stratio (http://stratio.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.stratio.decision.service;

import com.stratio.decision.commons.constants.ColumnType;
import com.stratio.decision.commons.messages.ColumnNameTypeValue;
import com.stratio.decision.commons.messages.StratioStreamingMessage;
import org.apache.commons.io.FileUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.common.params.CoreAdminParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class SolrOperationsService {

    private static final Logger log = LoggerFactory.getLogger(SolrOperationsService.class);

    private String solrHosts;

    private String zkHosts;

    private String dataDir;

    private Boolean isCloud;

    public SolrOperationsService(String solrHosts, String zkHosts, String dataDir, Boolean isCloud) {
        this.solrHosts = solrHosts;
        this.zkHosts = zkHosts;
        this.dataDir = dataDir;
        this.isCloud = isCloud;
    }

    public void createCore(StratioStreamingMessage message) throws IOException, URISyntaxException, SolrServerException, ParserConfigurationException, SAXException, TransformerException, InterruptedException {
        String core = message.getStreamName();
        String dataPath = this.dataDir + '/' + core + "/data";
        String confPath = this.dataDir + '/' + core + "/conf";
        createDirs(dataPath, confPath);
        createSolrConfig(confPath);
        createSolrSchema(message.getColumns(), confPath);
        SolrClient solrClient = getSolrclient(core);
        CoreAdminRequest.Create createCore = new CoreAdminRequest.Create();
        createCore.setDataDir(dataPath);
        createCore.setInstanceDir(dataDir + '/' + core);
        createCore.setCoreName(core);
        createCore.setSchemaName("schema.xml");
        createCore.setConfigName("solrconfig.xml");
        if (solrClient instanceof CloudSolrClient) {
            ((CloudSolrClient)solrClient).uploadConfig(Paths.get(confPath), core);
        }
        solrClient.request(createCore);
    }

    public void createDirs(String dataPath, String confPath) {
        File dataDir = new File(dataPath);
        File dir = new File(this.dataDir);
        File confDir = new File(confPath);
        // Comprobar resultado de esta operaciĆ³n
        dir.mkdirs();
        dataDir.mkdirs();
        confDir.mkdirs();
    }

    public void createSolrConfig(String confPath) throws URISyntaxException, IOException {
        FileUtils.copyFile(new File(ClassLoader.getSystemResource("./solr-config/solrconfig.xml").toURI()), new File(confPath + "/solrconfig.xml"));
    }

    public void createSolrSchema(List<ColumnNameTypeValue> columns, String confpath) throws ParserConfigurationException, URISyntaxException, IOException, SAXException, TransformerException {
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setIgnoringComments(true);
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(new File(ClassLoader.getSystemResource("./solr-config/schema.xml").toURI()));
        NodeList nodes = doc.getElementsByTagName("schema");
        for (ColumnNameTypeValue column: columns) {
            Element field = doc.createElement("field");
            field.setAttribute("name", column.getColumn());
            field.setAttribute("type", streamingToSolr(column.getType()));
            field.setAttribute("indexed", "true");
            field.setAttribute("stored", "true");
            nodes.item(0).appendChild(field);
        }
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(doc);
        StreamResult streamResult =  new StreamResult(new File(confpath+"/schema.xml"));
        transformer.transform(source, streamResult);
    }

    private String streamingToSolr(ColumnType column) {
        switch (column) {
        case BOOLEAN:
            return "boolean";
        case DOUBLE:
            return "double";
        case FLOAT:
            return "float";
        case INTEGER:
            return "int";
        case LONG:
            return "long";
        case STRING:
            return "string";
        default:
            throw new RuntimeException("Unsupported Column type");
        }
    }

    public List<String> getCoreList() throws IOException, SolrServerException {
        SolrClient solrClient = getSolrclient(null);
        CoreAdminRequest coreAdminRequest = new CoreAdminRequest();
        coreAdminRequest.setAction(CoreAdminParams.CoreAdminAction.STATUS);
        CoreAdminResponse cores = coreAdminRequest.process(solrClient);

        List<String> coreList = new ArrayList<String>();
        for (int i = 0; i < cores.getCoreStatus().size(); i++) {
            coreList.add(cores.getCoreStatus().getName(i));
        }
        return coreList;
    }

    private SolrClient getSolrclient(String core) {
        SolrClient solrClient;
        if (isCloud) {
            solrClient = new CloudSolrClient(zkHosts);
        } else {
            solrClient = new HttpSolrClient("http://" + solrHosts + "/solr");
        }
        return solrClient;
    }

}