package com.atlassian.confluence.extra.script;

import bucket.container.ContainerManager;
import com.atlassian.renderer.v2.macro.MacroException;
import com.opensymphony.util.TextUtils;
import org.apache.bsf.BSFManager;

import java.util.Iterator;
import java.util.Set;

public class ScriptMacro extends com.atlassian.renderer.v2.macro.BaseMacro
{
    private static OurBSFManager manager = new OurBSFManager();
    private static class OurBSFManager extends BSFManager
    {
        public OurBSFManager()
        {
            registerScriptingEngine("groovy",
			"org.codehaus.groovy.bsf.GroovyEngine",
			 new String[] { "groovy", "gy" });
            registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[] { "rb" });

        }
        public Set getRegisteredLanguages()
        {

            return registeredEngines.keySet();
        }

        public Set getLoadedLanguages()
        {
            if (loadedEngines.size() == 0)
            {
                for (Iterator i = getRegisteredLanguages().iterator(); i.hasNext();)
                {
                    try
                    {
                        loadScriptingEngine((String) i.next());
                    }
                    catch (org.apache.bsf.BSFException e)
                    {
                        // ignore errors
                    }
                }
            }
            return loadedEngines.keySet();
        }
    }

    private static final org.apache.log4j.Category log = org.apache.log4j.Category.getInstance(ScriptMacro.class);
    private com.atlassian.renderer.v2.SubRenderer subRenderer;

    public boolean isInline()
    {
        return false;
    }

    public boolean hasBody()
    {
        return true;
    }

    public com.atlassian.renderer.v2.RenderMode getBodyRenderMode()
    {
        return com.atlassian.renderer.v2.RenderMode.NO_RENDER;
    }

    public synchronized String execute(java.util.Map parameters, String body,
                          com.atlassian.renderer.RenderContext renderContext
                          ) throws com.atlassian.renderer.v2.macro.MacroException
    {
        // retrieve the first parameter passed, in our case the name of the task list.
        String scriptLanguageName = (String) parameters.get("0");
        //OurBSFManager manager = new OurBSFManager();
        if (!TextUtils.stringSet(scriptLanguageName))
        {
            throw new MacroException("No script language specified. Use {script:<i>language</i>}.");
        }
        if (!OurBSFManager.isLanguageRegistered(scriptLanguageName))
        {
            String availableLanguages = "";
            String sep = "";
            for (java.util.Iterator i = manager.getLoadedLanguages().iterator(); i.hasNext();)
            {
                String s = (String) i.next();
                availableLanguages += sep + s;
                sep = ", ";
            }
            throw new MacroException("Language '" + scriptLanguageName +
                                     "' is not available. Available languages are " + availableLanguages);
        }
        try
        {
            manager.declareBean("renderContext", renderContext, com.atlassian.renderer.RenderContext.class);
            String injections = (String) parameters.get("inject");
            if (injections != null)
            {
                String[] names = injections.split(",");
                for (int i = 0; i < names.length; i++)
                {
                    String name = names[i];
                    Object obj = ContainerManager.getInstance().getContainerContext().getComponent(name.trim());
                    if (obj != null)
                    {
                        manager.declareBean(name.trim(),obj,obj.getClass());
                    }
                    else
                    {
                        throw new MacroException("couldn't inject '" + name.trim() + "'");
                    }
                }
            }
            manager.declareBean("result", new StringBuffer(), StringBuffer.class);
            manager.exec(scriptLanguageName, "script macro", 1, 1, body);
            Object result = ((StringBuffer)manager.lookupBean("result")).toString();
            manager.undeclareBean("result");
            return subRenderer.render((String) result, renderContext);
        }
        catch (org.apache.bsf.BSFException bsfe)
        {
            throw new MacroException("Error:" + bsfe.getMessage(), bsfe.getTargetException());
        }

    }

    public void setSubRenderer(
            com.atlassian.renderer.v2.SubRenderer subRenderer
            )
    {
        this.subRenderer = subRenderer;
    }
}
