package org.bndtools.core.ui.wizards.shared;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.bndtools.templating.Resource;
import org.bndtools.templating.ResourceMap;
import org.bndtools.templating.Template;
import org.bndtools.templating.TemplateEngine;
import org.bndtools.templating.util.ObjectClassDefinitionImpl;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.Version;
import org.osgi.service.metatype.ObjectClassDefinition;

/**
 * Used as a bare-bones template for scenarios where no repository or workspace is available to load real templates.
 */
public class BuiltInTemplate implements Template {

    private final Bundle bundle = FrameworkUtil.getBundle(BuiltInTemplate.class);

    private final ResourceMap inputResources = new ResourceMap();
    private final String name;
    private final String engineName;
    private final Version version = Version.parseVersion("1.0.0");

    private URI helpUri = null;

    public BuiltInTemplate(String name, String templateEngine) {
        this.name = name;
        this.engineName = templateEngine;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getShortDescription() {
        return "built-in";
    }

    @Override
    public String getCategory() {
        return "mmm/Bndtools";
    }

    @Override
    public int getRanking() {
        return -1000;
    }

    @Override
    public Version getVersion() {
        return version;
    }

    @Override
    public ObjectClassDefinition getMetadata() throws Exception {
        return getMetadata(new NullProgressMonitor());
    }

    @Override
    public ObjectClassDefinition getMetadata(IProgressMonitor monitor) throws Exception {
        return new ObjectClassDefinitionImpl(name, getShortDescription(), null);
    }

    @Override
    public ResourceMap generateOutputs(Map<String, List<Object>> parameters) throws Exception {
        return generateOutputs(parameters, new NullProgressMonitor());
    }

    @Override
    public ResourceMap generateOutputs(Map<String, List<Object>> parameters, IProgressMonitor monitor) throws Exception {
        BundleContext context = bundle.getBundleContext();
        Collection<ServiceReference<TemplateEngine>> svcRefs = context.getServiceReferences(TemplateEngine.class, String.format("(name=%s)", engineName));
        if (svcRefs == null || svcRefs.isEmpty())
            throw new Exception(String.format("Unable to generate built-in template '%s': no Template Engine available matching '%s'", name, engineName));
        ServiceReference<TemplateEngine> svcRef = svcRefs.iterator()
            .next();
        TemplateEngine engine = context.getService(svcRef);
        if (engine == null)
            throw new Exception(String.format("Unable to generate built-in template '%s': no Template Engine available matching '%s'", name, engineName));
        try {
            return engine.generateOutputs(inputResources, parameters, monitor);
        } finally {
            context.ungetService(svcRef);
        }
    }

    public void addInputResource(String path, Resource resource) {
        inputResources.put(path, resource);
    }

    public void setHelpPath(String path) {
        this.helpUri = getResourceURI(path);
    }

    @Override
    public URI getIcon() {
        return getResourceURI("icons/template_empty.gif");
    }

    @Override
    public URI getHelpContent() {
        return helpUri;
    }

    private URI getResourceURI(String path) {
        URI uri = null;
        URL url = bundle.getResource(path);
        if (url != null) {
            try {
                uri = url.toURI();
            } catch (URISyntaxException e) {
                // ignore, we'll just see a missing icon
            }
        }
        return uri;
    }

    @Override
    public void close() throws IOException {
        // nothing to do
    }

}
