/*
 * Licensed to The OpenNMS Group, Inc (TOG) under one or more
 * contributor license agreements.  See the LICENSE.md file
 * distributed with this work for additional information
 * regarding copyright ownership.
 *
 * TOG licenses this file to You under the GNU Affero General
 * Public License Version 3 (the "License") or (at your option)
 * any later version.  You may not use this file except in
 * compliance with the License.  You may obtain a copy of the
 * License at:
 *
 *      https://www.gnu.org/licenses/agpl-3.0.txt
 *
 * 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 org.opennms.features.graphml.service.impl;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Properties;

import org.graphdrawing.graphml.GraphmlType;
import org.opennms.core.xml.JaxbUtils;
import org.opennms.features.graphml.service.GraphmlRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;

public class GraphmlRepositoryImpl implements GraphmlRepository {

    protected static final String TOPOLOGY_CFG_FILE_PREFIX = "org.opennms.features.topology.plugins.topo.graphml";
    protected static final String GRAPH_CFG_FILE_PREFIX = "org.opennms.netmgt.graph.provider.graphml";
    protected static final String TOPOLOGY_LOCATION = "topologyLocation";
    protected static final String GRAPH_LOCATION = "graphLocation";
    protected static final String LABEL = "label";

    private static final Logger LOG = LoggerFactory.getLogger(GraphmlRepositoryImpl.class);

    public GraphmlRepositoryImpl() {
        Preconditions.checkState(System.getProperty("opennms.home") != null, "No opennms.home defined. Bailing out...");
    }

    @Override
    public GraphmlType findByName(String name) throws IOException {
        Objects.requireNonNull(name);
        if (!exists(name)) {
            throw new NoSuchElementException("No GraphML file found with name  " + name);
        }
        GraphmlType graphmlType = JaxbUtils.unmarshal(GraphmlType.class, new File(buildGraphmlFilepath(name)));
        return graphmlType;
    }

    @Override
    public void save(String name, String label, GraphmlType graphmlType) throws IOException {
        LOG.debug("Saving GraphML file {} with label", name, label);
        Objects.requireNonNull(name);
        Objects.requireNonNull(label);
        Objects.requireNonNull(graphmlType);
        if (exists(name)) {
            LOG.warn("GraphML file with name {} already exists", name);
            throw new IOException(name + " already exists");
        }

        File graphFile = new File(buildGraphmlFilepath(name));
        File topologyCfgFile = new File(buildTopologyCfgFilepath(name));
        File graphServiceCfgFile = new File(buildGraphCfgFilepath(name));
        LOG.debug("GraphML xml location: {}", graphFile);
        LOG.debug("GraphML topology cfg location: {}", topologyCfgFile);
        LOG.debug("GraphML graph cfg location: {}", graphServiceCfgFile);

        // create directories if not yet created
        graphFile.getParentFile().mkdirs();
        topologyCfgFile.getParentFile().mkdirs();
        graphServiceCfgFile.getParentFile().mkdirs();

        // Write file to disk
        JaxbUtils.marshal(graphmlType, graphFile);

        // create Cfg file for Topology
        Properties properties = new Properties();
        properties.put(TOPOLOGY_LOCATION, graphFile.toString());
        properties.put(LABEL, label);
        properties.store(new FileWriter(topologyCfgFile), "Generated by " + getClass().getSimpleName() + ". DO NOT EDIT!");

        // Create Cfg file for Graph Service
        properties = new Properties();
        properties.put(GRAPH_LOCATION, graphFile.toString());
        properties.store(new FileWriter(graphServiceCfgFile), "Generated by " + getClass().getSimpleName() + ". DO NOT EDIT!");
    }

    @Override
    public void delete(String name) throws IOException {
        LOG.debug("Delete GraphML file with name {}", name);
        Objects.requireNonNull(name);
        findByName(name);
        Files.delete(Paths.get(buildTopologyCfgFilepath(name)));
        Files.delete(Paths.get(buildGraphCfgFilepath(name)));
        Files.delete(Paths.get(buildGraphmlFilepath(name)));
    }

    @Override
    public boolean exists(String name) {
        String filename = buildGraphmlFilepath(name);
        return new File(filename).exists() && new File(filename).isFile();
    }

    protected static String buildCfgFilepath(final String filename, final String cfgFilePrefix) {
        return Paths.get(System.getProperty("opennms.home"), "etc", cfgFilePrefix + "-" + filename + ".cfg").toString();
    }

    protected static String buildTopologyCfgFilepath(String filename) {
        return buildCfgFilepath(filename, TOPOLOGY_CFG_FILE_PREFIX);
    }

    protected static String buildGraphCfgFilepath(String filename) {
        return buildCfgFilepath(filename, GRAPH_CFG_FILE_PREFIX);
    }

    protected static String buildGraphmlFilepath(String filename) {
        return Paths.get(System.getProperty("opennms.home"), "etc", "graphml", filename + ".xml").toString();
    }
}
