/*
 * 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;


import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Link;
import com.arsdigita.bebop.Page;
import com.arsdigita.bebop.RequestLocal;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.PaginationModelBuilder;
import com.arsdigita.bebop.Paginator;
import com.arsdigita.bebop.SimpleContainer;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.ActionEvent;
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.TableActionAdapter;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.event.TableActionListener;
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.table.AbstractTableModelBuilder;
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
import com.arsdigita.bebop.table.TableColumn;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.cms.CMS;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.ContentType;
import com.arsdigita.cms.Folder;
import com.arsdigita.cms.SecurityManager;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.ui.folder.FolderManipulator;
import com.arsdigita.cms.ui.folder.FolderSelectionModel;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.Assert;
import com.arsdigita.web.URL;

import java.math.BigDecimal;


/**
 * Browse folders and items. If the user clicks on a folder, the folder
 * selection model is updated. If the user clicks on any other item, an
 * separate item selection model is updated.
 *
 * @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
 * @version $Revision: #8 $ $DateTime: 2004/04/07 16:07:11 $
 */
public class ItemSearchFolderBrowser extends Table {

    public static final String versionId = "$Id: //cms/dev/src/com/arsdigita/cms/ui/ItemSearchFolderBrowser.java#8 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    private static final org.apache.log4j.Logger s_log = 
        org.apache.log4j.Logger.getLogger(ItemSearchFolderBrowser.class);

    public static final int MAX_ROWS = 15;

    private static GlobalizedMessage[] s_headers = {
        globalize("cms.ui.folder.name"),
        globalize("cms.ui.folder.title"),
        globalize("cms.ui.folder.type") };

    private FolderSelectionModel m_currentFolder;

    private TableActionListener m_folderChanger;

    private TableActionListener m_deleter;

    private TableActionListener m_indexChanger;

    private TableColumn m_nameColumn;

    private Paginator m_paginator;

    public ItemSearchFolderBrowser(FolderSelectionModel currentFolder) {
        super((FolderTableModelBuilder)null, s_headers);

        FolderTableModelBuilder builder = new FolderTableModelBuilder();
        setModelBuilder( builder );

        m_paginator = new Paginator( builder, MAX_ROWS );

        m_currentFolder = currentFolder;

        setClassAttr("dataTable");

        getHeader().setDefaultRenderer(
            new com.arsdigita.cms.ui.util.DefaultTableCellRenderer());
        m_nameColumn = getColumn(0);
        m_nameColumn.setCellRenderer(new NameCellRenderer());

        m_folderChanger = new FolderChanger();
        addTableActionListener(m_folderChanger);

        setEmptyView(new Label(globalize("cms.ui.folder.no_items")));

        Assert.assertNotNull( m_currentFolder.getStateParameter() );
    }

    public Paginator getPaginator() {
        return m_paginator;
    }

    public void register(Page p) {
        super.register(p);
        p.addComponentStateParam(this, m_currentFolder.getStateParameter());

        p.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent event) {
                    // MP: This action listener should only be called when the
                    //      folder browser is visible.
                    showHideFolderActions(event.getPageState());
                }
            });
    }

    private Folder getCurrentFolder( PageState state ) {
        return (Folder) m_currentFolder.getSelectedObject( state );
    }

    private void showHideFolderActions(PageState state) {
        SecurityManager sm = Utilities.getSecurityManager(state);
        Folder folder = getCurrentFolder( state );
        Assert.assertNotNull(folder);
    }


    public FolderSelectionModel getFolderSelectionModel() {
        return m_currentFolder;
    }

    private class FolderTableModelBuilder
        extends AbstractTableModelBuilder implements PaginationModelBuilder {

        private RequestLocal m_size = new RequestLocal() {
            protected Object initialValue( PageState state ) {
                Folder.ItemCollection itemColl = getItemCollection( state );

                if( null == itemColl ) return new Integer( 0 );
                return new Integer( (int) itemColl.size() );
            }
        };

        private RequestLocal m_itemColl = new RequestLocal() {
            protected Object initialValue( PageState state ) {
                Folder.ItemCollection itemColl = getItemCollection( state );

                itemColl.addOrder("item.name");
                itemColl.setRange(new Integer(m_paginator.getFirst(state)),
                                  new Integer(m_paginator.getLast(state) + 1));

                return itemColl;
            }
        };

        public TableModel makeModel(Table t, PageState s) {
            FolderSelectionModel sel = ((ItemSearchFolderBrowser) t).getFolderSelectionModel();
            Folder f = getCurrentFolder( s );

            if( s_log.isDebugEnabled() ) {
                if( null == f )
                    s_log.debug( "Selected folder is null" );
                else 
                    s_log.debug( "Selected folder: " + f.getLabel() + " " +
                                 f.getOID().toString() );
            }

            if ( f == null ) {
                return Table.EMPTY_MODEL;
            } else {
                t.getRowSelectionModel().clearSelection(s);
                return new FolderTableModel((Folder.ItemCollection) m_itemColl.get(s));
            }
        }

        private Folder.ItemCollection getItemCollection( PageState state ) {
            Folder f = getCurrentFolder( state );
            Folder.ItemCollection itemColl = f.getPrimaryInstances();

            if( null == itemColl ) return null;

            BigDecimal singleTypeID =
                (BigDecimal) state.getValue (new BigDecimalParameter
                                             (ItemSearch.SINGLE_TYPE_PARAM));
            
            if (singleTypeID != null)
                itemColl.addEqualsFilter (ContentItem.CONTENT_TYPE +
                                          "." + ContentType.ID, singleTypeID);

            itemColl.setOrder("isFolder desc");
            itemColl.addOrder("lower(item." + 
                              ContentItem.NAME + ") ");
            return itemColl;
        }

        public int getTotalSize(Paginator paginator, PageState state) {

            Integer size = (Integer) m_size.get(state);
            return size.intValue();
        }

        /**
         * Indicates whether the paginator should be visible,
         * based on the visibility of the folder browser itself
         * and how many items are displayed
         *
         * @return true if folder browser is visible and there is more
         *         than 1 page of items, false otherwise
         */
        public boolean isVisible(PageState state) {
            int size = ((Integer) m_size.get( state )).intValue();
            
            return ItemSearchFolderBrowser.this.isVisible(state) &&
                   ( size > MAX_ROWS );
        }
    }

    /**
     * Produce links to view an item or control links for folders
     * to change into the folder.
     */
    private class NameCellRenderer extends DefaultTableCellRenderer
    {
        public NameCellRenderer()
        {
            super(true);
        }

        public Component getComponent (Table table, PageState state,
                                       Object value, boolean isSelected,
                                       Object key, int row, int column)
        {
            Folder.ItemCollection coll = (Folder.ItemCollection) value;
            String name = coll.getName();
            if ( coll.isFolder() )
                return super.getComponent(table, state, name,
                                          isSelected, key, row, column);
            else
                {
                    ContentSection section = CMS.getContext().getContentSection();
                    BigDecimal id = (BigDecimal) key;

                    if (section == null)
                        return new Label (name);
                    else
                        {
                            //ItemResolver resolver = section.getItemResolver();

                            //String url =
                            //resolver.generateItemURL
                            //(state, id, name, section, coll.getVersion()));

                            SimpleContainer container = new SimpleContainer ();

                            String widget =
                                (String) state.getValue (new StringParameter
                                                         (ItemSearchPopup.WIDGET_PARAM));
                            boolean useURL = "true".equals
                                (state.getValue(new StringParameter(ItemSearchPopup.URL_PARAM)));

                            String fillString = useURL ? 
                                ItemSearchPopup.getLiveItemURL(state.getRequest(),
                                                               coll.getDomainObject().getOID()) :
                                id + 
                                " (" + name + ")";
                            
                            Label js = new Label (generateJSLabel (id, widget,
                                                                   fillString),
                                                  false);
                            container.add (js);

                            String url = "#";

                            Link link = new Link (name, url);
                            link.setClassAttr ("title");
                            link.setOnClick ("return fillItem" + id + "()");

                            container.add (link);

                            return container;
                        }
                }
        }

        private String generateJSLabel(BigDecimal id, String widget, String fill)
        {
            return " <script language=javascript> " +
                " <!-- \n" +
                " function fillItem" +
                id +
                "() { \n" +
                " window.opener.document." +
                widget + ".value=\"" + fill + "\";\n" +
                " self.close(); \n" +
                " return false; \n" +
                " } \n" +
                " --> \n" +
                " </script> ";
        }
    }

    /**
     * Table model around ItemCollection
     */
    private static class FolderTableModel implements TableModel
    {
        private static final int NAME = 0;
        private static final int TITLE = 1;
        private static final int TYPE = 2;

        private Folder.ItemCollection m_itemColl;

        public FolderTableModel(Folder.ItemCollection itemColl)
        {
            m_itemColl = itemColl;
        }

        public int getColumnCount()
        {
            return 3;
        }

        public boolean nextRow()
        {
            return m_itemColl != null ? m_itemColl.next() : false;
        }

        public Object getElementAt(int columnIndex)
        {
            switch (columnIndex)
                {
                case NAME:
                    return m_itemColl;
                case TITLE:
                    return m_itemColl.getDisplayName();
                case TYPE:
                    return m_itemColl.getTypeLabel();
                default:
                    throw new
                        IndexOutOfBoundsException ("Column index " + columnIndex +
                                                   " not in table model.");
                }
        }

        public Object getKeyAt(int columnIndex)
        {
            // Mark folders by using their negative ID (dirty, dirty)
            return ( m_itemColl.isFolder() ) ?  m_itemColl.getID().negate()
                : m_itemColl.getID();
        }
    }

    private class FolderChanger extends TableActionAdapter {
        public void cellSelected(TableActionEvent e) {
            PageState s = e.getPageState();
            int col = e.getColumn().intValue();

            if ( m_nameColumn != getColumn(col) ) {
                return;
            }
            String key = (String) e.getRowKey();
            if ( key.startsWith("-") ) {
                clearSelection(s);
                getFolderSelectionModel().setSelectedKey(s, key.substring(1));
                m_paginator.reset(s);
            }
        }
    }

    /**
     * Getting the GlobalizedMessage using a CMS Class targetBundle.
     *
     * @param key The resource key
     * @pre ( key != null )
     */
    private static GlobalizedMessage globalize(String key) {
        return FolderManipulator.globalize(key);
    }

}
