/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2007-2018 Broad Institute
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


/*
 * TrackPanel.java
 *
 * Created on Sep 5, 2007, 4:09:39 PM
 *
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.broad.igv.ui.panel;

//~--- non-JDK imports --------------------------------------------------------

import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.track.AttributeManager;
import org.broad.igv.ui.FontManager;
import org.broad.igv.ui.IGV;
import org.broad.igv.ui.util.IGVMouseInputAdapter;

import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jrobinso
 */
public class AttributeHeaderPanel extends JPanel implements Paintable {

    final static int MAXIMUM_FONT_SIZE = 10;
    public final static int ATTRIBUTE_COLUMN_WIDTH = 10;
    public final static int COLUMN_BORDER_WIDTH = 1;

    Map<String, Boolean> sortOrder = new HashMap();


    public AttributeHeaderPanel() {
        setBorder(javax.swing.BorderFactory.createLineBorder(Color.black));
        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        addMouseListener();
    }


    public int getAttributeColumnWidth() {
        return ATTRIBUTE_COLUMN_WIDTH;
    }


    private String getAttributeHeading(int x) {
        int idx = x / (ATTRIBUTE_COLUMN_WIDTH + COLUMN_BORDER_WIDTH);
        List<String> keys = AttributeManager.getInstance().getVisibleAttributes();
        if (idx < keys.size()) {
            return keys.get(idx);
        } else {
            return null;
        }
    }

    @Override
    protected void paintComponent(final Graphics graphics) {

        super.paintComponent(graphics);


        List<String> keys = AttributeManager.getInstance().getVisibleAttributes();

        if (keys != null && keys.size() > 0) {

            final Graphics2D graphics2 = (Graphics2D) graphics;
            if (PreferencesManager.getPreferences().getAntiAliasing()) {
                graphics2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            }

            // Divide the remaining space to get column widths
            int columnWidth = getAttributeColumnWidth();

            // Create font and font size
            int fontSize = (int) (0.9 * columnWidth);
            if (fontSize > MAXIMUM_FONT_SIZE) {
                fontSize = MAXIMUM_FONT_SIZE;
            }
            Font font = FontManager.getFont(fontSize);

            FontMetrics fm = graphics2.getFontMetrics();
            int fontAscent = fm.getHeight();

            // Change the origin for the text
            AffineTransform transform = AffineTransform.getTranslateInstance(0, getHeight() - COLUMN_BORDER_WIDTH);
            graphics2.transform(transform);

            // Now rotate text counter-clockwise 90 degrees
            transform = AffineTransform.getQuadrantRotateInstance(-1);
            graphics2.transform(transform);
            graphics2.setFont(font);

            int i = 1;
            int x;
            for (String key : keys) {
                int columnLeftEdge = ((COLUMN_BORDER_WIDTH + ATTRIBUTE_COLUMN_WIDTH) * i++);
                x = columnLeftEdge + ((COLUMN_BORDER_WIDTH + ATTRIBUTE_COLUMN_WIDTH) - fontAscent) / 2;
                String toDraw = key;
                int stringOffset = 2;
                graphics2.drawString(toDraw, stringOffset, x);
            }
        }
    }

    private void addMouseListener() {


        setToolTipText("Click attribute heading to sort");

        MouseInputAdapter listener = new IGVMouseInputAdapter() {

            @Override
            public void igvMouseClicked(MouseEvent e) {

                String attKey = getAttributeHeading(e.getX());
                if (attKey != null) {
                    Boolean tmp = sortOrder.get(attKey);
                    boolean sortAscending = tmp == null ? true : tmp.booleanValue();
                    sortTrackByAttribute(attKey, sortAscending);
                    sortOrder.put(attKey, !sortAscending);
                }
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                String attKey = getAttributeHeading(e.getX());
                if (attKey != null) {
                    AttributeManager.ColumnMetaData md = AttributeManager.getInstance().getColumnMetaData(attKey);
                    if (md != null) {
                        StringBuffer buf = new StringBuffer("<html>" + attKey + "<br>Click to sort");
                        //buf.append("<br>Is numeric = " + md.isNumeric() + "<br>");
                        //buf.append("Is diverging = " + md.isDiverging() + "<br>");
                        //buf.append("getUniqueCount = " + md.getUniqueCount() + "<br>");
                        //buf.append("getTotalCount = " + md.getTotalCount() + "<br>");
                        //buf.append("getUniqueRatio = " + md.getUniqueRatio() + "<br>");
                        // buf.append("# unique = " + md.uniqueValues.size() + "<br>");
                        // buf.append("# total = " + md.totalCount + "<br>");
                        // buf.append("# numeric = " + md.numericCount + "<br>");
                        setToolTipText(buf.toString());
                        return;
                    }
                    setToolTipText("Click attribute heading to sort");
                }

            }

        };
        addMouseMotionListener(listener);
        addMouseListener(listener);
    }


    final public void sortTrackByAttribute(String sortKey, boolean isSortAscending) {

        if (sortKey != null) {
            IGV.getInstance().sortAllTracksByAttributes(new String[]{sortKey}, new boolean[]{isSortAscending});
            IGV.getMainFrame().repaint();
        }
    }

    public void paintOffscreen(Graphics2D g, Rectangle rect) {
        paintComponent(g);

        Color c = g.getColor();
        g.setColor(Color.darkGray);
        g.drawRect(rect.x, rect.y, rect.width, rect.height);
        g.setColor(c);            //super.paintBorder(g);

    }
}

@@ -3123,16 +3123,25 @@
 graphics
+.create()
 ;%0A      
@@ -4667,32 +4667,66 @@
 );%0A            %7D
+%0A%0A            graphics2.dispose();
 %0A        %7D%0A    %7D

Fix attribute header panel painting bug