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

import com.arsdigita.bebop.Component;
import com.arsdigita.bebop.Image;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.Link;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Table;
import com.arsdigita.bebop.event.TableActionAdapter;
import com.arsdigita.bebop.event.TableActionEvent;
import com.arsdigita.bebop.table.DefaultTableCellRenderer;
import com.arsdigita.bebop.table.TableCellRenderer;
import com.arsdigita.bebop.table.TableModel;
import com.arsdigita.bebop.table.TableModelBuilder;
import com.arsdigita.cms.ArticleImageAssociation;
import com.arsdigita.cms.ImageAsset;
import com.arsdigita.cms.SecurityManager;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.mimetypes.MimeType;
import com.arsdigita.mimetypes.image.ImageSizer;
import com.arsdigita.persistence.OID;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.web.URL;
import java.awt.Dimension;
import java.math.BigDecimal;
import org.apache.log4j.Logger;

/**
 * Displays a list of images in a Table. The table will look
 * something like this:
 *
 * <blockquote><pre><code>
 * +-----------+-------+-------+------+----------+
 * | Thumbnail | Name  | Size  | Type |          |
 * +-----------+-------+-------+------+----------+
 * |   .  .    |       |       |      |          |
 * | {   V  }  | smile | 20x42 | Jpeg | (select) |
 * |   ----    |       |       |      |          |
 * +-----------+-------+-------+------+----------+
 * |           |       |       |      |          |
 * </code></pre></blockquote>
 *
 * @author Stanislav Freidin
 * @version $Id: //cms/dev/src/com/arsdigita/cms/ui/ImageBrowser.java#15 $
 */
public class ImageBrowser extends Table {

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

    private ImageBrowserModelBuilder m_builder;

    private static final String[] HEADERS =
    {"Thumbnail", "Name", "Size", "Type", "Action", ""};
    private static final int THUMB = 0;
    private static final int NAME = 1;
    private static final int SIZE = 2;
    private static final int TYPE = 3;
    private static final int LINK = 4;
    private static final int DELETE = 5;
    private static final int NUM_COLUMNS = 6;

    private int m_thumbSize;

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

    /**
     * Construct a new ImageBrowser
     *
     * @param builder the {@link ImageBrowserModelBuilder} that will supply this
     * component with its {@link ImageBrowserModel} during each request
     */
    public ImageBrowser(ImageBrowserModelBuilder b) {
        super(new BuilderAdapter(b), HEADERS);
        setThumbnailSize(50);
        m_builder = b;

        getHeader().setDefaultRenderer(new DefaultTableCellRenderer(false));
        getColumn(0).setCellRenderer(new ThumbnailCellRenderer());
        getColumn(1).setCellRenderer(new DefaultTableCellRenderer(false));
        getColumn(2).setCellRenderer(new DefaultTableCellRenderer(false));
        getColumn(3).setCellRenderer(new DefaultTableCellRenderer(false));
        getColumn(4).setCellRenderer(new DefaultTableCellRenderer(true));
        getColumn(5).setCellRenderer(new DeleteCellRenderer());

        setCellPadding("4");
        setBorder("1");

        setClassAttr("imageBrowser");
    }

    /**
     * @return the size, in pixels, of the thumbnail images
     */
    public int getThumbnailSize() {
        return m_thumbSize;
    }

    /**
     * Set the thumbnail size
     * @param size  the size, in pixels, of the thumbnail images
     */
    public void setThumbnailSize(int size) {
        m_thumbSize = size;
    }

    /**
     * @return the {@link ImageBrowserModelBuilder}
     */
    public ImageBrowserModelBuilder getImageBrowserModelBuilder() {
        return m_builder;
    }

    /**
     * @param state The current page state
     * @return the {@link ImageBrowserModel} used in the current
     *   request
     */
    public ImageBrowserModel getImageBrowserModel(PageState state) {
        return ((ImageModelAdapter)getTableModel(state)).getModel();
    }

    /**
     * An action listener that only gets fired when the "select"
     * link is clicked. Child classes should override the
     * linkClicked method.
     */
    public static abstract class LinkActionListener
        extends TableActionAdapter {

        public void cellSelected(TableActionEvent e) {
            int c = e.getColumn().intValue();
            if(c == LINK) {
                linkClicked(e.getPageState(), new BigDecimal((String)e.getRowKey()));
            } else if (c==DELETE) {
                deleteClicked(e.getPageState(), new BigDecimal((String)e.getRowKey()));
            }
        }

        public abstract void linkClicked(PageState state, BigDecimal imageId);
        public abstract void deleteClicked(PageState state, BigDecimal imageId);
    }

    // Renders a static image for the current asset
    private class ThumbnailCellRenderer implements TableCellRenderer {

        public Component getComponent(Table table, PageState state, Object value,
                                      boolean isSelected, Object key,
                                      int row, int column) {
            ImageAsset a = (ImageAsset)value;
            String url = Utilities.getImageURL(a);

            Image img = new Image(URL.getDispatcherPath() + url);
            img.setBorder("0");
            img.setAlt(a.getName());

            BigDecimal width = a.getWidth(), height = a.getHeight();
            int w, h;

            if (width == null || height == null) {
                w = m_thumbSize;
                h = m_thumbSize;
            } else {
                Dimension d = ImageSizer.getScaledSize (
                    width.intValue(), height.intValue(), m_thumbSize, m_thumbSize
                );
                w = (int)d.getWidth();
                h = (int)d.getHeight();
            }

            img.setWidth(Integer.toString(w));
            img.setHeight(Integer.toString(h));

            return new Link(img, url);
        }
    }

    // Renders the delete link if the user has permission to delete
    // the asset and it's not used in an article.
    private class DeleteCellRenderer extends DefaultTableCellRenderer {
        public DeleteCellRenderer() {
            super(true);
        }
        public Component getComponent(Table table, PageState state, Object value,
                                      boolean isSelected, Object key,
                                      int row, int column)
        {
            boolean canDelete = false;
            SecurityManager sm = Utilities.getSecurityManager(state);
            if (sm.canAccess(state.getRequest(),SecurityManager.DELETE_IMAGES) ) {
                try {
                    ImageAsset asset = (ImageAsset) DomainObjectFactory.newInstance
                        (new OID(ImageAsset.BASE_DATA_OBJECT_TYPE,(BigDecimal) key));
                    if (!ArticleImageAssociation.imageHasAssociation(asset)) {
                        canDelete = true;
                    }
                } catch (DataObjectNotFoundException e) {
                    // can't find asset, can't delete it
                }

            }

            if (canDelete) {
                return super.getComponent(table, state, value, isSelected, key, row, column);
            } else {
                return new Label("");
            }
        }


    }

    // Converts an ImageBrowserModelBuilder to a TableModelBuilder
    private static class BuilderAdapter extends LockableImpl
        implements TableModelBuilder {

        private ImageBrowserModelBuilder m_builder;

        public BuilderAdapter(ImageBrowserModelBuilder b) {
            m_builder = b;
        }

        public TableModel makeModel(Table t, PageState s) {
            return new ImageModelAdapter(
                m_builder.makeModel((ImageBrowser)t, s)
            );
        }

        public void lock() {
            m_builder.lock();
            super.lock();
        }
    }

    // Converts an ImageBrowserModel to a TableModel
    private static class ImageModelAdapter implements TableModel {

        private ImageBrowserModel m_model;

        public ImageModelAdapter(ImageBrowserModel m) {
            m_model = m;
        }

        public int getColumnCount() {
            return ImageBrowser.NUM_COLUMNS;
        }

        public boolean nextRow() {
            return m_model.nextRow();
        }

        public Object getElementAt(int columnIndex) {
            ImageAsset a = m_model.getImageAsset();

            switch(columnIndex) {
            case ImageBrowser.THUMB:
                return a;

            case ImageBrowser.NAME:
                return a.getName();

            case ImageBrowser.SIZE:
                StringBuffer buf = new StringBuffer();
                BigDecimal v;

                v = a.getWidth();
                if(v == null) buf.append("???"); else buf.append(v.toString());
                buf.append(" x ");

                v = a.getHeight();
                if(v == null) buf.append("???"); else buf.append(v.toString());

                return buf.toString();

            case ImageBrowser.TYPE:
                MimeType m = a.getMimeType();
                if(m == null) return "???";

                return m.getMimeType();

            case ImageBrowser.LINK:
                return "select";

            case ImageBrowser.DELETE:
                return "delete";

            default:
                return null;
            }
        }

        public Object getKeyAt(int columnIndex) {
            return m_model.getImageAsset().getID();
        }

        public ImageBrowserModel getModel() {
            return m_model;
        }
    }

}
