/*
 * Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.cms.ui.authoring;

import com.arsdigita.bebop.SimpleComponent;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.developersupport.DeveloperSupport;

import com.arsdigita.domain.DomainObjectFactory;

import com.arsdigita.xml.Element;
import com.arsdigita.xml.XML;

import com.arsdigita.web.RedirectSignal;

import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryCollection;
import com.arsdigita.categorization.RootCategoryCollection;

import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.SecurityManager;

import com.arsdigita.persistence.OID;

import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.util.Assert;

import java.io.IOException;
import javax.servlet.ServletException;

import java.util.Map;
import java.util.HashMap;
import java.math.BigDecimal;

import org.apache.log4j.Logger;

public class ItemCategorySummary extends SimpleComponent {

    private static final Logger s_log = Logger.getLogger(ItemCategorySummary.class);

    public static final String ACTION_DELETE = "delete";
    public static final String ACTION_ADD = "add";
    public static final String ACTION_ADD_JS = "addJS";

    private Map m_listeners = new HashMap();

    public ItemCategorySummary() {
        registerAction(ACTION_DELETE,
                       new DeleteActionListener());
    }

    protected void registerAction(String name,
                                  ActionListener listener) {
        m_listeners.put(name, listener);
    }

    public void respond(PageState state) throws ServletException {
        super.respond(state);

        Assert.truth(canEdit(state), "User can edit item");

        String name = state.getControlEventName();
        ActionListener listener = (ActionListener)m_listeners.get(name);

        if (s_log.isDebugEnabled()) {
            s_log.debug("Got event " + name + " listener " + listener);
        }

        if (listener != null) {
            listener.actionPerformed(new ActionEvent(this, state));
        }
    }

    private boolean canEdit(PageState state) {
        SecurityManager sm = new SecurityManager(
            CMS.getContext().getContentSection());
        return sm.canAccess(state.getRequest(),
                            SecurityManager.EDIT_ITEM,
                            CMS.getContext().getContentItem());
    }

    public void generateXML(PageState state,
                            Element parent) {
        ContentSection section = CMS.getContext().getContentSection();
        ContentItem item = CMS.getContext().getContentItem();

        boolean canEdit = canEdit(state);

        Element content = parent.newChildElement("cms:categoryStepSummary",
                                                 CMS.CMS_XML_NS);
        exportAttributes(content);

        Element rootCats = content.newChildElement("cms:categoryRoots",
                                               CMS.CMS_XML_NS);

        RootCategoryCollection roots = Category.getRootCategories(section);
        while (roots.next()) {
            Element root = rootCats.newChildElement("cms:categoryRoot",
                                                    CMS.CMS_XML_NS);

            root.addAttribute("name", roots.getName());
            root.addAttribute("description", roots.getDescription());
            root.addAttribute("context", roots.getUseContext());

            if (canEdit) {
                state.setControlEvent(this,
                                      ACTION_ADD,
                                      roots.getCategory().getID().toString());
                try {
                    root.addAttribute("addAction", XML.format(state.stateAsURL()));
                } catch (IOException ex) {
                    throw new UncheckedWrapperException("cannot generate URL", ex);
                }
                state.clearControlEvent();
                state.setControlEvent(this,
                                      ACTION_ADD_JS,
                                      roots.getCategory().getID().toString());
                try {
                    root.addAttribute("addJSAction", XML.format(state.stateAsURL()));
                } catch (IOException ex) {
                    throw new UncheckedWrapperException("cannot generate URL", ex);
                }
                state.clearControlEvent();
            }
        }

        Element itemCats = content.newChildElement("cms:itemCategories",
                                                   CMS.CMS_XML_NS);
        CategoryCollection cats = item.getCategoryCollection();
        while (cats.next()) {
            Category cat = (Category)cats.getCategory();


            // This is lame, but there is no way to get full path
            // and thus avoid this DOS attack using categorization API
            StringBuffer path = new StringBuffer();
            CategoryCollection parents = cat.getDefaultAscendants();
            parents.addOrder(Category.DEFAULT_ANCESTORS);

            while (parents.next()) {
                Category par = (Category)parents.getCategory();
                if (path.length() != 0) {
                    path.append(" -> ");
                }
                path.append(par.getName());
            }

            Element el = itemCats.newChildElement("cms:itemCategory",
                                                  CMS.CMS_XML_NS);
            el.addAttribute("name", cat.getName());
            el.addAttribute("description", cat.getDescription());
            el.addAttribute("path", XML.format(path));

            if (canEdit) {
                state.setControlEvent(this,
                                      ACTION_DELETE,
                                      cat.getID().toString());
                try {
                    el.addAttribute("deleteAction", XML.format(state.stateAsURL()));
                } catch (IOException ex) {
                    throw new UncheckedWrapperException("cannot generate URL", ex);
                }
                state.clearControlEvent();
            }
        }
    }

    private class DeleteActionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            PageState state = e.getPageState();
            String value = state.getControlEventValue();

            Category cat = (Category)DomainObjectFactory
                .newInstance(new OID(Category.BASE_DATA_OBJECT_TYPE,
                                     new BigDecimal(value)));
            ContentItem item = CMS.getContext().getContentItem();

            if (s_log.isDebugEnabled()) {
                s_log.debug("Removing category " + cat + " from " +
                            item + " parent " + item.getParent());
            }
            cat.removeChild(item.getParent());

            state.clearControlEvent();
            throw new RedirectSignal(state.toURL(), true);
        }
    }
}
