package com.atlassian.stash.internal.plugin;

import com.atlassian.plugin.spring.AvailableToPlugins;
import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.plugin.Plugin;
import com.atlassian.plugin.hostcontainer.HostContainer;
import com.atlassian.plugin.module.ContainerManagedPlugin;
import com.atlassian.plugin.util.ClassLoaderUtils;
import com.atlassian.plugin.web.Condition;
import com.atlassian.plugin.web.ContextProvider;
import com.atlassian.plugin.web.WebFragmentHelper;
import com.atlassian.plugin.web.conditions.ConditionLoadingException;
import com.atlassian.bitbucket.view.VelocityHelper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@AvailableToPlugins(WebFragmentHelper.class)
@Component("webFragmentHelper")
public class StashWebFragmentHelper implements WebFragmentHelper {

    private static final Object[] EMPTY_OBJECT = new Object[]{};

    private final HostContainer hostContainer;
    private final I18nService i18nService;
    private final VelocityHelper velocityHelper;

    @Autowired
    public StashWebFragmentHelper(OsgiServiceProxyFactory osgiServiceProxyFactory, I18nService i18nService,
                                  HostContainer hostContainer) {
        this.hostContainer = hostContainer;
        this.i18nService = i18nService;
        this.velocityHelper = osgiServiceProxyFactory.createProxy(VelocityHelper.class, 1000);
    }

    @Override
    public String getI18nValue(String key, List<?> arguments, Map<String, Object> context) {
        return i18nService.getText(key, null, arguments == null ? EMPTY_OBJECT : arguments.toArray());
    }

    @Override
    public Condition loadCondition(String className, Plugin plugin) throws ConditionLoadingException {
        assertClassNameNotBlank(className, plugin, "condition");
        return loadComponent(className, plugin);
    }

    @Override
    public ContextProvider loadContextProvider(String className, Plugin plugin) throws ConditionLoadingException {
        assertClassNameNotBlank(className, plugin, "context provider");
        return loadComponent(className, plugin);
    }

    @Override
    public String renderVelocityFragment(String fragment, Map<String, Object> params) {
        return velocityHelper.renderFragment(fragment, params);
    }

    private void assertClassNameNotBlank(String className, Plugin plugin, String type) throws ConditionLoadingException {
        if (StringUtils.isBlank(className)) {
            throw new ConditionLoadingException("null or empty " + type + " class name in plugin " + plugin.getKey());
        }
    }

    private <T> T loadComponent(String className, Plugin plugin) throws ConditionLoadingException {
        Class<T> clazz;
        try {
            clazz = plugin.loadClass(className, StashWebFragmentHelper.class);
        } catch (ClassNotFoundException e) {
            try {
                clazz = ClassLoaderUtils.loadClass(className, StashWebFragmentHelper.class);
            } catch (ClassNotFoundException e1) {
                throw new ConditionLoadingException("Failed to load class '" + className + "' for plugin " + plugin.getName(), e);
            }
        }

        if (plugin instanceof ContainerManagedPlugin) {
            return ((ContainerManagedPlugin) plugin).getContainerAccessor().createBean(clazz);
        } else {
            return hostContainer.create(clazz);
        }
    }
}