/*
 * File:     GridRenderer.java
 * Project:  MPI Linguistic Application
 * Date:     03 April 2006
 *
 * Copyright (C) 2001-2006  Max Planck Institute for Psycholinguistics
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package mpi.eudico.client.annotator.grid;

import mpi.eudico.client.annotator.Constants;

import mpi.eudico.client.annotator.viewer.AbstractViewer;

import mpi.eudico.server.corpora.clom.AnnotationCore;

import mpi.eudico.util.TimeRelation;

import java.awt.Component;
import java.awt.Graphics;

import java.io.File;

import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.AbstractTableModel;


/**
  * Renders a media time pointer and the 'active annotation'
  *
  * NOTE: Selection rendering is done NOT via the selection mechanism of the JTable;
  * selections are set 'manually' with the setFirst/LastSelectedRow methods!
  */
public class GridRenderer extends AnnotationTableCellRenderer {
    final static protected Border activeBorder = new LineBorder(Constants.ACTIVEANNOTATIONCOLOR);

    /** delivers mediaTime and activeAnnotation */
    final protected AbstractViewer viewer;

    /** delivers annotation (value + time)*/
    final protected AbstractTableModel tableModel;

    /** Holds value of property DOCUMENT ME! */
    private int iconWidth = -1;

    /** Holds value of property DOCUMENT ME! */
    private int iconHeight = -1;

    /** Icons for rendering mediaTimePointer in first row of the table */
    private Icon completeTriangleIcon;
    private Icon upperHalfTriangleIcon;
    private Icon lowerHalfTriangleIcon;

    /**
     * Creates a new GridRenderer instance
     */
    public GridRenderer(AbstractViewer viewer, AbstractTableModel tableModel) {
        this.viewer = viewer;
        this.tableModel = tableModel;
    }

    /**
     * Returns a configured JLabel for every cell in the table.
     *
     * @param table the table
     * @param value the cell value
     * @param isSelected selected state of the cell
     * @param hasFocus whether or not the cell has focus
     * @param row the row index
     * @param column the column index
     *
     * @return this JLabel
     */
    public Component getTableCellRendererComponent(JTable table, Object value,
        boolean isSelected, boolean hasFocus, int row, int column) {
        String columnName = table.getColumnName(column);
        setAlignment(label, columnName);

        int annotationColumn = tableModel.findColumn(GridViewerTableModel.ANNOTATION);

        boolean isInSelection = isSelected;

        if (viewer != null) {
            isInSelection = TimeRelation.overlaps((AnnotationCore) tableModel.getValueAt(
                        row, annotationColumn), viewer.getSelectionBeginTime(),
                    viewer.getSelectionEndTime());
        }

        boolean isActive = false;

        if (viewer != null) {
            isActive = value instanceof AnnotationCore &&
                (viewer.getActiveAnnotation() == value);
        }

        setComponentLayout(label, table, isInSelection, isActive);

        if (GridViewerTableModel.TIMEPOINT.equals(columnName)) {
            label.setBorder(null);

            if (viewer != null) {
                //create icons only if cell size has changed
                int iconWidth = table.getCellRect(row, column, true).width - 1;
                int iconHeight = table.getCellRect(row, column, true).height -
                    1;

                if ((iconWidth != this.iconWidth) ||
                        (iconHeight != this.iconHeight)) {
                    createIcons(iconWidth, iconHeight);
                }

                renderTimePointerColumn(label, row);
            }
        } else {
            label.setIcon(null);

            String renderedText = getRenderedText(value);

            if (GridViewerTableModel.FILENAME.equals(columnName) &&
                    !renderedText.equals("")) {
                String fileName = new File(renderedText).getName();
                label.setText(fileName.substring(0, fileName.lastIndexOf('.')));
            } else {
                label.setText(renderedText);
            }

            if (!"".equals(renderedText)) {
                label.setToolTipText(renderedText);
            }
        }

        return label;
    }

    static protected void setComponentLayout(JComponent component,
        JTable table, boolean isSelected, boolean isActive) {
        setComponentLayout(component, table, isSelected);

        if (isActive) {
            component.setBorder(activeBorder);
        }
    }

    /**
     * create icons
     * @param iconWidth
     * @param iconHeight
     */
    private void createIcons(int iconWidth, int iconHeight) {
        completeTriangleIcon = new GridViewerIcon(new int[] { 0, iconWidth, 0 },
                new int[] { 0, iconHeight / 2, iconHeight });
        upperHalfTriangleIcon = new GridViewerIcon(new int[] { 0, 0, iconWidth },
                new int[] { 0, iconHeight / 2, 0 });
        lowerHalfTriangleIcon = new GridViewerIcon(new int[] { 0, iconWidth, 0 },
                new int[] { iconHeight / 2, iconHeight, iconHeight });
    }

    /**
     * Determines some values needed for drawing the red triangle
     *
     * @param row DOCUMENT ME!
     */
    private void renderTimePointerColumn(JLabel label, int row) {
        long beginTime;
        long endTime;
        long previousEndTime = 0;
        long nextBeginTime = Long.MAX_VALUE;
        label.setText("");

        try {
            int annotationColumn = 1;

            while (!GridViewerTableModel.ANNOTATION.equals(
                        tableModel.getColumnName(annotationColumn)))
                annotationColumn++;

            AnnotationCore aa = (AnnotationCore) tableModel.getValueAt(row,
                    annotationColumn);

            beginTime = aa.getBeginTimeBoundary();
            endTime = aa.getEndTimeBoundary();

            if (row > 0) {
                aa = (AnnotationCore) tableModel.getValueAt(row - 1,
                        annotationColumn);
                previousEndTime = aa.getEndTimeBoundary();
            }

            if (row < (tableModel.getRowCount() - 1)) {
                aa = (AnnotationCore) tableModel.getValueAt(row + 1,
                        annotationColumn);
                nextBeginTime = aa.getBeginTimeBoundary();
            }

            label.setIcon(chooseIcon(previousEndTime, beginTime, endTime,
                    nextBeginTime, viewer.getMediaTime()));
        } catch (ClassCastException e) {
            System.out.println("Warning: " + e.getMessage());
        }
    }

    /**
     * Handles the drawing of the red triangle
     *
     * @param row DOCUMENT ME!
     */
    private Icon chooseIcon(long previousEndTime, long beginTime, long endTime,
        long nextBeginTime, long mediaTime) {
        if ((mediaTime >= beginTime) && (mediaTime < endTime)) { //complete triangle

            return completeTriangleIcon;
        } else if ((mediaTime > 0) && (mediaTime >= previousEndTime) &&
                (mediaTime < beginTime)) { //upper half triangle

            return upperHalfTriangleIcon;
        } else if ((mediaTime < (viewer.getMediaDuration() - 1000)) //allow for inaccuracy of player of 1 ms
                 &&(mediaTime < nextBeginTime) && (mediaTime >= endTime)) { //lower half triangle

            return lowerHalfTriangleIcon;
        } else {
            return null;
        }
    }

    /**
     * Class which represenst a red triangle
     */
    private class GridViewerIcon implements Icon {
        /** Holds value of property DOCUMENT ME! */
        int[] x_arr;

        /** Holds value of property DOCUMENT ME! */
        int[] y_arr;

        /**
         * Creates a new GridViewerIcon instance
         *
         * @param x_arr DOCUMENT ME!
         * @param y_arr DOCUMENT ME!
         */
        GridViewerIcon(int[] x_arr, int[] y_arr) {
            this.x_arr = x_arr;
            this.y_arr = y_arr;
        }

        /**
         * DOCUMENT ME!
         *
         * @param c DOCUMENT ME!
         * @param g DOCUMENT ME!
         * @param x DOCUMENT ME!
         * @param y DOCUMENT ME!
         */
        public void paintIcon(Component c, Graphics g, int x, int y) {
            g.setColor(Constants.CROSSHAIRCOLOR);
            g.fillPolygon(x_arr, y_arr, x_arr.length);
        }

        /**
         * DOCUMENT ME!
         *
         * @return DOCUMENT ME!
         */
        public int getIconWidth() {
            return iconWidth;
        }

        /**
         * DOCUMENT ME!
         *
         * @return DOCUMENT ME!
         */
        public int getIconHeight() {
            return iconHeight;
        }
    }

    //end GridViewerIcon
}
