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


import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.ControlLink;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.cms.util.GlobalizationUtil;
import com.arsdigita.globalization.GlobalizedMessage;
import com.arsdigita.util.Assert;
import com.arsdigita.util.LockableImpl;

/**
 * The default renderer for table cells. This renderer is used by the
 * {@link com.arsdigita.bebop.Table} component for rendering the table
 * headers and cells if no other renderer is specified.
 *
 * <p> This renderer can operate in two different modes: <em>active</em>
 * and <em>inactive</em> mode. In inactive mode, all objects are rendered
 * by converting them to a string and enclosing that string in a {@link
 * com.arsdigita.bebop.Label}. If the renderer is in active mode, this
 * label is further enclosed in a control link. When the user clicks on
 * this link, the table will fire an <code>TableActionEvent</code> whose
 * <code>getKey()</code> and <code>getColumn()</code> method return the
 * values of the <code>key</code> and <code>column</code> parameters that
 * were passed into {@link #getComponent getComponent}.
 *
 * <p> In a nutshell, an active renderer will let the user click a link
 * that causes a <code>TableActionEvent</code> for the corresponding cell,
 * while an inactive renderer will display the values just as strings, thus
 * making it impossible for the user to cause such an event.
 *
 * @author <a href="mailto:lutter@arsdigita.com">David Lutterkort</a>
 * @author Michael Pih (pihman@arsdigita.com)
 * @see com.arsdigita.bebop.Table
 * @see com.arsdigita.bebop.event.TableActionEvent
 *
 * @version $Id: //cms/dev/src/com/arsdigita/cms/ui/util/DefaultTableCellRenderer.java#8 $ */
public class DefaultTableCellRenderer extends LockableImpl
    implements TableCellRenderer {

    private boolean m_active;
    private ThreadLocal m_label;
    private ThreadLocal m_controlLink;

    /**
     * Creates a new table cell renderer. The table cell renderer is in
     * inactive mode.
     */
    public DefaultTableCellRenderer() {
        this(false);
    }

    /**
     * Creates a new table cell renderer. The <code>active</code> argument
     * specifies whether the renderer should be active or not.
     *
     * @param active <code>true</code> if the renderer should generate links
     * instead of just static labels.
     */
    public DefaultTableCellRenderer(boolean active) {
        m_active = active;
        m_label = new ThreadLocal() {
                protected Object initialValue() {
                    return new Label("");
                }
            };
        m_controlLink = new ThreadLocal() {
                protected Object initialValue() {
                    return new ControlLink((Label) m_label.get());
                }
            };
    }

    /**
     * Return <code>true</code> if the renderer is in active mode. A
     * rendererin active mode will enclose the objects it renders in links
     * that, when clicked, will cause the containing table to fire a
     * <code>TableActionEvent</code>.
     *
     * @return <code>true</code> if the renderer is in active mode.
     */
    public final boolean isActive() {
        return m_active;
    }

    /**
     * Set the renderer to active or inactive mode.
     *
     * @param v <code>true</code> if the renderer should operate in active
     * mode.
     * @pre ! isLocked()
     */
    public void setActive(boolean v) {
        Assert.assertNotLocked(this);
        m_active = v;
    }

    /**
     * Return the component that should be used to render the given
     * <code>value</code>. Returns a {@link com.arsdigita.bebop.Label} if the
     * renderer is active, and a {@link com.arsdigita.bebop.ControlLink} if
     * the renderer is inactive.
     *
     * @pre table == null || table != null
     */
    public Component getComponent(Table table, PageState state, Object value,
                                  boolean isSelected, Object key,
                                  int row, int column)
    {
        if ( ! isLocked() && table != null && table.isLocked() ) {
            lock();
        }

        Label l = (Label) m_label.get();
        if ( value == null ) {
            l.setLabel( (String) GlobalizationUtil.globalize("cms.ui.util.").localize());
            l.setOutputEscaping(false);
        } else {
            l.setLabel((GlobalizedMessage) value);
            l.setOutputEscaping(true);
        }
        l.setFontWeight( (isSelected && m_active) ? Label.BOLD : null );
        if (m_active && ! isSelected) {
            return (ControlLink) m_controlLink.get();
        } else {
            return l;
        }
    }
}
