package com.atlassian.confluence.extra.workflow;

import com.atlassian.confluence.core.ContentPropertyManager;
import com.atlassian.confluence.event.EventManager;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.renderer.PageContext;
import com.atlassian.confluence.renderer.radeox.macros.MacroUtils;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.confluence.util.VelocityUtils;
import com.atlassian.renderer.RenderContext;
import com.atlassian.renderer.v2.RenderMode;
import com.atlassian.renderer.v2.SubRenderer;
import com.atlassian.renderer.v2.macro.BaseMacro;
import com.atlassian.renderer.v2.macro.MacroException;
import com.atlassian.user.User;
import com.opensymphony.webwork.ServletActionContext;
import org.apache.log4j.Category;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;


/**
 * Created by IntelliJ IDEA.
 * User: Tomd
 * Date: 3/05/2005
 * Time: 10:07:22
 * To change this template use File | Settings | File Templates.
 */
public class WorkflowMacro extends BaseMacro
{
    protected static final Category log = Category.getInstance(WorkflowMacro.class);
    private ContentPropertyManager contentPropertyManager;
    private EventManager eventManager;
    private SubRenderer subRenderer;

    public boolean isInline()
    {
        return false;
    }

    public boolean hasBody()
    {
        return false;
    }

    // irrelevant since we have no body
    public RenderMode getBodyRenderMode()
    {
        return RenderMode.NO_RENDER;
    }

    public String execute(Map parameters, String body, RenderContext renderContext) throws MacroException
    {
        User user = AuthenticatedUserThreadLocal.getUser();
        PageContext pageContext = (PageContext) renderContext;

        Page page = (Page) pageContext.getEntity();
        if (!page.isLatestVersion())
        {
            return "";
        }
        String workflowType = (String) parameters.get("0");

        if (workflowType == null)
        {
            throw new MacroException("No workflow type name specified. usage {workflow:<i>typeName</i>}");
        }
        WorkflowType t = WorkflowManager.findType(workflowType);
        if (t == null)
        {
            throw new MacroException("The workflow type '" + workflowType + "' is unknown.");
        }
        WorkflowClient client = new ConfluencePageWorkflowClient(page, t, contentPropertyManager);

        if (user == null || !t.isUserParticipating(user))
        {
            String message = client.getState().getUninvolvedMarkup();
            if (message != null)
            {
                return subRenderer.render(message, renderContext);
            }
            else
            {
                return "";
            }
        }
        Map operations = t.getAvailableOperations(client, user);
        final HttpServletRequest request = ServletActionContext.getRequest();
        if (request.getParameter("workflowOp") != null)
        {
            Operation o = (Operation) operations.get(request.getParameter("workflowOp"));
            if (o == null)
            {
                throw new MacroException("Invalid operation " + request.getParameter("workflowOp"));
            }
            PageEditListener.ignoreEventsForPage(page);
            eventManager.publishEvent(new WorkflowEvent(this, o, client, user));
            PageEditListener.acceptEventsForPage(page);

            // set of valid operations may have changed
            operations = t.getAvailableOperations(client, user);
            try
            {
                StringBuffer url = new StringBuffer(request.getRequestURL().toString());
                String sep = "?";
                for (Enumeration e = request.getParameterNames(); e.hasMoreElements();)
                {
                    String name = (String) e.nextElement();
                    if (!name.equals("workflowOp"))
                    {
                        url.append(sep + name + "=" + request.getParameter(name));
                        sep = "&";
                    }
                }
                ServletActionContext.getResponse().sendRedirect(url.toString());
            }
            catch (IOException ioe)
            {
                throw new RuntimeException(ioe);
            }
        }

        Map contextMap = MacroUtils.defaultVelocityContext();
        contextMap.put("client", client);
        contextMap.put("operations", operations);
        contextMap.put("type", t);
        contextMap.put("content", page);
        try
        {
            return VelocityUtils.getRenderedTemplate("templates/extra/workflow/workflowmacro.vm", contextMap);
        }
        catch (Exception e)
        {
            log.error("Error while trying to display Macro!", e);
            throw new MacroException(e.getMessage(), e);
        }
    }

    public void setContentPropertyManager(ContentPropertyManager contentPropertyManager)
    {
        this.contentPropertyManager = contentPropertyManager;
    }

    public void setEventManager(EventManager eventManager)
    {
        this.eventManager = eventManager;
    }

    public void setSubRenderer(SubRenderer subRenderer)
    {
        this.subRenderer = subRenderer;
    }
}
