package com.atlassian.confluence.extra.masterdetail;

import com.atlassian.renderer.v2.macro.MacroException;
import com.atlassian.renderer.v2.RenderMode;
import com.atlassian.renderer.v2.RenderUtils;
import com.atlassian.renderer.RenderContext;
import com.atlassian.confluence.util.LabelUtil;
import com.atlassian.confluence.util.GeneralUtil;
import com.atlassian.confluence.util.VelocityUtils;
import com.atlassian.confluence.core.ContentEntityObject;
import com.atlassian.confluence.core.SpaceContentEntityObject;
import com.atlassian.confluence.renderer.PageContext;
import com.atlassian.confluence.renderer.radeox.macros.MacroUtils;
import com.atlassian.confluence.labels.Label;
import com.atlassian.confluence.spaces.Space;
import com.opensymphony.util.TextUtils;

import java.util.*;

import bucket.util.PairType;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.exception.ResourceNotFoundException;

public class DetailsSummaryMacro extends AbstractMasterDetailsMacro
{
    public static class DetailLine
    {
        ContentEntityObject content;
        Map details;

        public DetailLine(ContentEntityObject content, List detailPairs)
        {
            this.content = content;
            this.details = new HashMap();
            for (Iterator it = detailPairs.iterator(); it.hasNext();)
            {
                PairType pairType = (PairType) it.next();
                details.put(pairType.getKey(), pairType.getValue());
            }
        }

        public ContentEntityObject getContent()
        {
            return content;
        }

        public Map getDetails()
        {
            return details;
        }
    }

    public boolean isInline()
    {
        return false;
    }

    public boolean hasBody()
    {
        return false;
    }

    public RenderMode getBodyRenderMode()
    {
        return RenderMode.NO_RENDER;
    }

    public String execute(Map parameters, String body, RenderContext renderContext) throws MacroException
    {
        String labelName = (String) parameters.get("label");
        String headingsString = (String) parameters.get("headings");

        if (!TextUtils.stringSet(labelName))
            return RenderUtils.blockError("No 'label' value supplied for the details macro.", renderErrorBody(body, renderContext));

        if (!LabelUtil.isValidLabelName(labelName))
            return RenderUtils.blockError(GeneralUtil.escapeXml(labelName) + " is not a valid label name", renderErrorBody(body, renderContext));

        ContentEntityObject owner = ((PageContext)renderContext).getEntity();

        if (!(owner instanceof SpaceContentEntityObject))
            return RenderUtils.blockError("Master view must be inside a space", renderErrorBody(body, renderContext));

        Label label = labelManager.getLabel(new Label(labelName));
        Space space = ((SpaceContentEntityObject)owner).getSpace();

        List content = labelManager.getCurrentContentForLabelAndSpace(label, space.getKey());
        Collections.sort(content);

        List detailLines = getDetailsFromContent(content, labelName, renderContext);

        Set headings = getHeadingsFromHeadingsString(headingsString);
        if (headings.size() == 0)
            addAllHeadings(detailLines, headings);

        return renderTemplate(headings, detailLines, body, renderContext);
    }

    private String renderTemplate(Set headings, List detailLines, String body, RenderContext renderContext)
    {
        Map contextMap = MacroUtils.defaultVelocityContext();
        contextMap.put("headings", headings);
        contextMap.put("details", detailLines);

        try
        {
            return VelocityUtils.getRenderedTemplateWithoutSwallowingErrors("/templates/extra/masterdetail/detailssummary.vm", new VelocityContext(contextMap));
        }
        catch (ResourceNotFoundException e)
        {
            return RenderUtils.blockError("System error: could not find template /templates/extra/masterdetail/detailssummary.vm", renderErrorBody(body, renderContext));
        }
        catch (Exception e)
        {
            return RenderUtils.blockError("Unknown error drawing details summary: " + e.getMessage(), renderErrorBody(body, renderContext));
        }
    }

    private void addAllHeadings(List detailLines, Set headings)
    {
        for (Iterator it = detailLines.iterator(); it.hasNext();)
        {
            DetailLine detailLine = (DetailLine) it.next();
            Set keySet = detailLine.getDetails().keySet();
            for (Iterator it2 = keySet.iterator(); it2.hasNext();)
            {
                headings.add(it2.next());
            }
        }
    }

    private Set getHeadingsFromHeadingsString(String headingsString)
    {
        // Maintain order of headings as best we can
        Set headings = new LinkedHashSet();

        if (TextUtils.stringSet(headingsString))
        {
            String[] splitHeadings = headingsString.split(",");
            for (int i = 0; i < splitHeadings.length; i++)
            {
                headings.add(GeneralUtil.escapeXml(splitHeadings[i].trim()));
            }
        }
        return headings;
    }

    private List getDetailsFromContent(List content, String labelName, RenderContext renderContext)
    {
        List detailLines = new ArrayList(content.size());

        for (Iterator it = content.iterator(); it.hasNext();)
        {
            ContentEntityObject ceo = (ContentEntityObject) it.next();
            String detailsString = contentPropertyManager.getTextProperty(ceo, "masterdetail." + labelName);
            if (TextUtils.stringSet(detailsString))
            {
                RenderContext subRenderContext = new PageContext(ceo, (PageContext) renderContext);
                List details = toDetails(detailsString, subRenderContext);
                for (Iterator it2 = details.iterator(); it2.hasNext();)
                {
                    PairType detail = (PairType) it2.next();
                }
                detailLines.add(new DetailLine(ceo, details));
            }
        }
        return detailLines;
    }
}
