/*
 * Copyright (C) 2003-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.category;

import com.arsdigita.bebop.ActionLink;
import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.SingleSelectionModel;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.categorization.CategorizedCollection;
import com.arsdigita.categorization.Category;
import com.arsdigita.categorization.CategoryNotFoundException;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ui.BaseItemPane;
import com.arsdigita.cms.ui.CMSForm;
import com.arsdigita.cms.ui.VisibilityComponent;
import com.arsdigita.cms.ui.permissions.CMSPermissionsPane;
import com.arsdigita.cms.ui.templates.CategoryTemplates;
import com.arsdigita.kernel.ACSObject;
import com.arsdigita.kernel.permissions.ObjectPermissionCollection;
import com.arsdigita.kernel.permissions.PermissionDescriptor;
import com.arsdigita.kernel.permissions.PermissionService;
import com.arsdigita.kernel.permissions.PrivilegeDescriptor;
import com.arsdigita.kernel.ui.ACSObjectSelectionModel;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.toolbox.ui.ActionGroup;
import com.arsdigita.toolbox.ui.PropertyList;
import com.arsdigita.toolbox.ui.Section;
import com.arsdigita.util.Assert;
import java.util.HashMap;
import org.apache.log4j.Logger;

/**
 * Edits a single category.
 *
 * @author Justin Ross &lt;jross@redhat.com&gt;
 * @version $Id: //cms/dev/src/com/arsdigita/cms/ui/category/CategoryItemPane.java#24 $
 */
class CategoryItemPane extends BaseItemPane {
    public static final String versionId =
        "$Id: //cms/dev/src/com/arsdigita/cms/ui/category/CategoryItemPane.java#24 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

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

    private final SingleSelectionModel m_model;
    private final CategoryRequestLocal m_category;

    private final SimpleContainer m_detailPane;

    public CategoryItemPane(final SingleSelectionModel model,
                            final CategoryRequestLocal category,
                            final ActionLink addLink,
                            final ActionLink editLink,
                            final ActionLink deleteLink) {
        m_model = model;
        m_category = category;

        // Details

        m_detailPane = new SimpleContainer();
        add(m_detailPane);
        setDefault(m_detailPane);

        final ActionLink orderItemsLink = 
            new ActionLink(new Label(gz("cms.ui.category.categorized_objects"))) {
                public boolean isVisible(PageState state) {
                    // update for live items only
                    if (!super.isVisible(state)) {
                        return false;
                    }
                    CategorizedCollection items = m_category.getCategory
                        (state).getObjects(ContentItem.BASE_DATA_OBJECT_TYPE);
                    items.addEqualsFilter(ContentItem.VERSION,ContentItem.LIVE);
                    boolean canOrder = items.size() > 1;
                    items.close();
                    return canOrder;
                }
            };

        final Form orderItemsForm = new OrderItemsForm(m_category);
        add(orderItemsForm);

        final ActionLink indexLink = new ActionLink
            (new Label(gz("cms.ui.category.change_index_item")));
        final Form indexForm = new IndexItemSelectionForm(m_category);
        add(indexForm);

        m_detailPane.add(new SummarySection(editLink, deleteLink, indexLink, orderItemsLink));
        m_detailPane.add(new SubcategorySection(addLink));

        // Linked categories

        final ActionLink linkAddLink = new ActionLink
            (new Label(gz("cms.ui.category.linked.add")));

        final Form linkForm = new LinkForm(m_category);
        add(linkForm);

        linkAddLink.addActionListener(new NavigationListener(linkForm));
        linkForm.addSubmissionListener(new CancelListener(linkForm));

        m_detailPane.add(new LinkedCategorySection(linkAddLink));

        // Templates

        m_detailPane.add(new AdminVisible(new CategoryTemplateSection()));

        // Permissions

        m_detailPane.add(new PermissionsSection());

        connect(indexLink, indexForm);
        connect(indexForm);

        connect(orderItemsLink, orderItemsForm);
        connect(orderItemsForm);

    }

    private class EditVisible extends VisibilityComponent {
        EditVisible(final Component child) {
            super(child, null);
        }

        public boolean hasPermission(PageState ps) {
            return m_category.getCategory(ps).canEdit();
        }
    }

    private class AdminVisible extends VisibilityComponent {
        AdminVisible(final Component child) {
            super(child, null);
        }

        public boolean hasPermission(PageState ps) {
            return m_category.getCategory(ps).canAdmin();
        }
    }

    private class SummarySection extends Section {
        SummarySection(final ActionLink editLink,
                       final ActionLink deleteLink,
                       final ActionLink indexLink,
                       final ActionLink orderItemsLink) {
            setHeading(new Label(gz("cms.ui.category.details")));

            final ActionGroup group = new ActionGroup();
            setBody(group);

            group.setSubject(new Properties());

            group.addAction(new EditVisible(editLink), ActionGroup.EDIT);
            group.addAction(new EditVisible(orderItemsLink));
            group.addAction(new EditVisible(indexLink));
            group.addAction(new AdminVisible(deleteLink), ActionGroup.DELETE);
        }

        private class Properties extends PropertyList {
            protected final java.util.List properties(final PageState state) {
                final java.util.List props = super.properties(state);
                final Category category = m_category.getCategory(state);
                final ACSObject item = category.getDirectIndexObject();

                String itemTitle = "";

                if (item != null) {
                    itemTitle = item.getDisplayName();
                }

                props.add(new Property(gz("cms.ui.name"),
                                       category.getName()));
                props.add(new Property(gz("cms.ui.description"),
                                       category.getDescription()));
                props.add(new Property(gz("cms.ui.category.url"),
                                       category.getURL()));
                props.add(new Property(gz("cms.ui.category.is_not_abstract"),
                                       category.isAbstract() ?
                                       gz("cms.ui.no") :
                                       gz("cms.ui.yes")));
                props.add(new Property(gz("cms.ui.category.is_enabled"),
                                       category.isEnabled() ?
                                       gz("cms.ui.yes") :
                                       gz("cms.ui.no")));
                props.add(new Property(gz("cms.ui.category.index_item"),
                                       itemTitle));

                return props;
            }
        }
    }

    private class SubcategorySection extends Section {
        SubcategorySection(final ActionLink addLink) {
            setHeading(new Label(gz("cms.ui.category.subcategories")));

            final ActionGroup group = new ActionGroup();
            setBody(group);

            group.setSubject(new SubcategoryList(m_category, m_model));
            group.addAction(new AdminVisible(addLink), ActionGroup.ADD);
        }
    }

    private class LinkedCategorySection extends Section {
        LinkedCategorySection(final ActionLink linkAddLink) {
            setHeading(new Label(gz("cms.ui.category.linked")));

            final ActionGroup group = new ActionGroup();
            setBody(group);

            group.setSubject(new CategoryLinks(m_category, m_model));
            group.addAction(new EditVisible(linkAddLink), ActionGroup.EDIT);
        }

        public final boolean isVisible(final PageState state) {
            return !m_category.getCategory(state).isRoot();
        }
    }

    private class CategoryTemplateSection extends Section {
        //CategoryTemplateSection(final ActionLink link) {
        CategoryTemplateSection() {
            setHeading(new Label(gz("cms.ui.category.templates")));

            final ActionGroup group = new ActionGroup();
            setBody(group);

            group.setSubject(new CategoryTemplates(m_category));
            // XXX secvis
            //group.addAction(link);
        }
    }

    private class PermissionsSection extends Section {
        public boolean isVisible(PageState ps) {
            Category cat = m_category.getCategory(ps);
            return !cat.isRoot() && cat.canAdmin();
        }

        PermissionsSection() {
            setHeading(new Label(gz("cms.ui.permissions")));

            final ActionGroup group = new ActionGroup();
            setBody(group);

            PrivilegeDescriptor[] privs = new PrivilegeDescriptor[] {
                PrivilegeDescriptor.EDIT,
                Category.MAP_DESCRIPTOR,
                PrivilegeDescriptor.DELETE,
                PrivilegeDescriptor.ADMIN
            };

            HashMap privMap = new HashMap();
            privMap.put("edit", "Edit");
            privMap.put("delete", "Delete");
            privMap.put(Category.MAP_DESCRIPTOR.getName(), "Categorize Items");
            privMap.put("admin", "Admin");

            final CMSPermissionsPane permPane = new CMSPermissionsPane
                (privs, privMap, new ACSObjectSelectionModel(m_model)) {
                public void showAdmin(PageState ps) {
                    Assert.exists(m_model.getSelectedKey(ps));

                    super.showAdmin(ps);
                    getAdminListingPanel().setVisible(ps, false);
                }
            };

            final ActionLink restoreDefault = new ActionLink(new Label(gz("cms.ui.restore_default_permissions"))) {
                public boolean isVisible(PageState ps) {
                    Category cat = m_category.getCategory(ps);
                    return PermissionService.getContext(cat) == null;
                }
            };

            final ActionLink useCustom = new ActionLink(new Label(gz("cms.ui.use_custom_permissions"))) {
                public boolean isVisible(PageState ps) {
                    Category cat = m_category.getCategory(ps);
                    return PermissionService.getContext(cat) != null;
                }
            };

            ActionListener al = new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    PageState state = event.getPageState();
                    // if this is the root then we cannot revert to anything
                    // since there is not a parent
                    Category cat = m_category.getCategory(state);
                    if (!cat.canAdmin()) {
                        throw new com.arsdigita.cms.dispatcher.AccessDeniedException();
                    }
                    DataObject context = PermissionService.getContext(cat);
                    if (context != null) {
                        PermissionService.clonePermissions(cat);
                    } else {
                        ACSObject parent;
                        try {
                            parent = cat.getDefaultParentCategory();
                        } catch (CategoryNotFoundException ce) {
                            throw new IllegalStateException(
                                "link shouldn't exist for root categories");
                        }
                        PermissionService.setContext(cat, parent);

                        // revoke all direct permissions so category will only
                        // have inherited permissions
                        ObjectPermissionCollection perms =
                            PermissionService.getDirectGrantedPermissions(
                                cat.getOID());
                        while (perms.next()) {
                            PermissionService.revokePermission(
                                new PermissionDescriptor(
                                    perms.getPrivilege(), cat.getOID(),
                                    perms.getGranteeOID()));
                        }
                    }
                    permPane.reset(state);
                }
            };

            restoreDefault.addActionListener(al);
            useCustom.addActionListener(al);

            SimpleContainer links = new SimpleContainer();
            links.add(restoreDefault);
            links.add(useCustom);

            group.setSubject(permPane);
            group.addAction(links);

            m_model.addChangeListener(new ChangeListener() {
                public void stateChanged(ChangeEvent e) {
                    PageState ps = e.getPageState();
                    // XXX
                    //permPane.showAdmin(ps);
                }
            });
        }
    }

    private static class OrderItemsForm extends CMSForm {

        public OrderItemsForm(CategoryRequestLocal category) {
            super("orderItems", new SimpleContainer());
            Label header = new Label(gz("cms.ui.category.categorized_objects"));
            header.setFontWeight(Label.BOLD);
            add(header);
            add(new CategorizedObjectsList(category));
            
            add(new Submit("Done"));

        }

    }
}
