package com.jthink.jaikoz.cellrenderer;

import com.explodingpixels.macwidgets.MacColorUtils;
import com.explodingpixels.macwidgets.MacWidgetFactory;
import com.explodingpixels.macwidgets.plaf.EmphasizedLabelUI;
import org.jdesktop.swingx.JXPanel;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.border.IconBorder;
import org.jdesktop.swingx.decorator.SortOrder;
import org.jdesktop.swingx.icon.SortArrowIcon;
import org.jdesktop.swingx.painter.Painter;
import org.jdesktop.swingx.plaf.ColumnHeaderRendererAddon;
import org.jdesktop.swingx.plaf.LookAndFeelAddons;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * Renderer for the table headers
 * <p/>
 * With additional support to make more Mac Like
 */
public class JaikozColumnHeaderRenderer extends JXPanel implements TableCellRenderer
{
    private org.jdesktop.swingx.painter.Painter<Component> fBackgroundPainter;

    private static Color LEFT_BORDER_COLOR = new Color(255, 255, 255, 77);
    private static Color RIGHT_BORDER_COLOR = new Color(0, 0, 0, 51);
    private static Color UNFOCUSED_FONT_COLOR = new Color(0x8f8f8f);
    private JLabel fLabel = MacWidgetFactory.makeEmphasizedLabel(new JLabel(), EmphasizedLabelUI.DEFAULT_FOCUSED_FONT_COLOR, UNFOCUSED_FONT_COLOR, EmphasizedLabelUI.DEFAULT_EMPHASIS_COLOR);

    private static Icon defaultDownIcon = new SortArrowIcon(false);
    private static Icon defaultUpIcon = new SortArrowIcon(true);

    private Icon downIcon = defaultDownIcon;
    private Icon upIcon = defaultUpIcon;
    private IconBorder iconBorder = new IconBorder();
    private int fSelectedColumn = -1;
    private int fPressedColumn = -1;
    private JTable fTable;

    static
    {
        LookAndFeelAddons.contribute(new ColumnHeaderRendererAddon());
    }

    public JaikozColumnHeaderRenderer()
    {
        super();
    }

    public JaikozColumnHeaderRenderer(JTable table)
    {
        fTable = table;
        table.getTableHeader().addMouseListener(new HeaderClickHandler());
        setLayout(new BorderLayout());
        add(fLabel, BorderLayout.CENTER);
    }

    @Override
    /**
     * This paints the vertical dividing line between adjacent table header cells
     */
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D graphics2d = (Graphics2D) g.create();

        graphics2d.setColor(LEFT_BORDER_COLOR);
        graphics2d.drawLine(0, 0, 0, getHeight() - getInsets().bottom);
        graphics2d.setColor(RIGHT_BORDER_COLOR);
        graphics2d.drawLine(getWidth() - 1, 0, getWidth() - 1, getHeight() - getInsets().bottom);

        graphics2d.dispose();
    }

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int rowIndex, int columnIndex)
    {
        if (value == null)
        {
            fLabel.setText("");
        }
        else
        {
            fLabel.setText(value.toString());
        }

        setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, MacColorUtils.LEOPARD_BORDER_COLOR), BorderFactory.createEmptyBorder(1, 5, 0, 5)));

        Painter<Component> painter = createIAppUnpressedUnselectedHeaderPainter();


        SortOrder sortOrder = ((JXTable) table).getSortOrder(columnIndex);
        int modelIndex = table.convertColumnIndexToModel(columnIndex);
        if (sortOrder.isSorted())
        {
            iconBorder.setIcon(sortOrder.isAscending() ? upIcon : downIcon);
            Border origBorder = this.getBorder();
            Border border = new CompoundBorder(origBorder, iconBorder);
            this.setBorder(border);
            painter = createIAppUnpressedSelectedHeaderPainter();

            if (isColumnPressed(modelIndex) && isColumnSelected(modelIndex))
            {
                painter = createIAppPressedSelectedHeaderPainter();
            }
            else if (isColumnPressed(modelIndex))
            {
                painter = createIAppPressedUnselectedHeaderPainter();
            }
            else if (isColumnSelected(modelIndex))
            {
                painter = createIAppUnpressedSelectedHeaderPainter();
            }

        }
        setBackgroundPainter(painter);
        return this;
    }


    public static org.jdesktop.swingx.painter.Painter<Component> createIAppUnpressedUnselectedHeaderPainter()
    {
        return new org.jdesktop.swingx.painter.Painter<Component>()
        {
            private Color TOP_GRADIENT_COLOR = new Color(0xdbdbdb);
            private Color BOTTOM_GRADIENT_COLOR = new Color(0xbbbbbb);

            public void paint(Graphics2D graphics2D, Component component, int width, int height)
            {
                paintLeopardGradientSelection(TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, graphics2D, width, height);
            }
        };
    }

    public static Painter<Component> createIAppPressedUnselectedHeaderPainter()
    {
        return new Painter<Component>()
        {

            private Color TOP_GRADIENT_COLOR = new Color(0xc4c4c4);
            private Color BOTTOM_GRADIENT_COLOR = new Color(0x959595);

            public void paint(Graphics2D graphics2D, Component component, int width, int height)
            {
                paintLeopardGradientSelection(TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, graphics2D, width, height);
            }
        };
    }

    public static Painter<Component> createIAppUnpressedSelectedHeaderPainter()
    {
        return new Painter<Component>()
        {

            private Color TOP_GRADIENT_COLOR = new Color(0xc2cfdd);
            private Color BOTTOM_GRADIENT_COLOR = new Color(0x7d93b2);

            public void paint(Graphics2D graphics2D, Component component, int width, int height)
            {
                paintLeopardGradientSelection(TOP_GRADIENT_COLOR, MacColorUtils.LEOPARD_BORDER_COLOR, TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, graphics2D, width, height);
            }
        };
    }


    public static Painter<Component> createIAppPressedSelectedHeaderPainter()
    {
        return new Painter<Component>()
        {

            private Color TOP_GRADIENT_COLOR = new Color(0xa6b7cb);
            private Color BOTTOM_GRADIENT_COLOR = new Color(0x536b90);

            public void paint(Graphics2D graphics2D, Component component, int width, int height)
            {
                paintLeopardGradientSelection(TOP_GRADIENT_COLOR, MacColorUtils.LEOPARD_BORDER_COLOR, TOP_GRADIENT_COLOR, BOTTOM_GRADIENT_COLOR, graphics2D, width, height);
            }
        };
    }

    private static void paintLeopardGradientSelection(Color topLineColor, Color bottomLineColor, Color topGradientColor, Color bottomGradientColor, Graphics2D graphics2D, int width, int height)
    {
        // create the paint - start the gradient one pixel from the top
        // of the component and finish the gradient one pixel from the
        // bottom.
        GradientPaint paint = new GradientPaint(0, 1, topGradientColor, 0, height - 2, bottomGradientColor);
        // install the paint and fill a rectangle with it.
        graphics2D.setPaint(paint);
        graphics2D.fillRect(0, 0, width, height);
        // set the graphics color and draw a line across the top of the
        // component.
        graphics2D.setColor(topLineColor);
        graphics2D.drawLine(0, 0, width, 0);
        // set the graphics color and draw a line across the bottom of the
        // component.
        graphics2D.setColor(bottomLineColor);
        graphics2D.drawLine(0, height - 1, width, height - 1);
    }

    private boolean isColumnSelected(int column)
    {
        return column == fSelectedColumn;
    }

    private boolean isColumnPressed(int column)
    {
        return column == fPressedColumn;
    }

    private class HeaderClickHandler extends MouseAdapter
    {

        private boolean mouseEventIsPerformingPopupTrigger = false;

        public void mouseClicked(MouseEvent mouseEvent)
        {

            // if the cursor indicates we're resizing columns, do not sort
            if (fTable.getTableHeader().getCursor() == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR))
            {
                return;
            }

            final TableColumnModel columnModel = fTable.getColumnModel();
            int viewColumn = columnModel.getColumnIndexAtX(mouseEvent.getX());
            fSelectedColumn = fTable.convertColumnIndexToModel(viewColumn);

            fTable.getTableHeader().repaint();
        }

        public void mousePressed(MouseEvent mouseEvent)
        {
            if (fTable.getTableHeader().getCursor() != Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR))
            {
                final TableColumnModel columnModel = fTable.getColumnModel();
                int viewColumn = columnModel.getColumnIndexAtX(mouseEvent.getX());
                fPressedColumn = fTable.convertColumnIndexToModel(viewColumn);

                fTable.getTableHeader().repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e)
        {
            fPressedColumn = -1;
            fTable.getTableHeader().repaint();
        }
    }
}
