/*
 * Created on 14.10.2005
 *
 */
package org.jdesktop.swingx.decorator;

import java.awt.Color;
import java.awt.Component;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

import javax.swing.DefaultListModel;
import javax.swing.JTable;
import javax.swing.ListModel;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import org.jdesktop.swingx.JXEditorPaneTest;
import org.jdesktop.swingx.JXList;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.JXTree;
import org.jdesktop.swingx.decorator.HighlighterFactory.UIColorHighlighter;
import org.jdesktop.swingx.hyperlink.LinkModel;
import org.jdesktop.swingx.renderer.DefaultTreeRenderer;
import org.jdesktop.test.AncientSwingTeam;


public class HighlighterIssues extends org.jdesktop.swingx.InteractiveTestCase {
    private static final Logger LOG = Logger.getLogger(HighlighterIssues.class
            .getName());
    
    protected Color ledger = new Color(0xF5, 0xFF, 0xF5);
    protected Color background = Color.RED;
    protected Color foreground = Color.BLUE;

    protected ColorHighlighter emptyHighlighter;
    // flag used in setup to explicitly choose LF
    protected boolean defaultToSystemLF;
    
    public static void main(String args[]) {
//        setSystemLF(true);
        HighlighterIssues test = new HighlighterIssues();
        try {
           test.runInteractiveTests();
        } catch (Exception e) {
            System.err.println("exception when executing interactive tests:");
            e.printStackTrace();
        }
    }
    
    //---------------- uidependent
    

    /**
     * test if background changes with LF.
     * 
     * PENDING: this is not entirely correct, might fail because
     *   both LFs fall back to GenericGray.
     */
    public void testLookupUIColor() {
        UIColorHighlighter hl = new UIColorHighlighter();
        Color color = hl.getBackground();
        String lf = UIManager.getLookAndFeel().getName();
        Color uiColor = UIManager.getColor("UIColorHighlighter.stripingBackground");
        assertNotNull(uiColor);
        // switch LF
        setSystemLF(!defaultToSystemLF);
        if (lf.equals(UIManager.getLookAndFeel().getName())) {
            LOG.info("cannot run lookupUIColor - same LF" + lf);
            return;
        }
        Color uiColor2 = UIManager.getColor("UIColorHighlighter.stripingBackground");
        assertNotNull(uiColor2);
        // hmm ... how to force the reloading in the addon?
        LOG.info("color must be different " + uiColor + "/" + uiColor2);
        assertFalse("color must be different " + uiColor + "/" + uiColor2 , uiColor2.equals(uiColor));
        hl.updateUI();
        assertFalse("highlighter background must be changed", 
                color.equals(hl.getBackground()));
    }
    /**
     * test if background changes with LF.
     * 
     * PENDING: this is not entirely correct, might fail because
     *   both LFs fall back to GenericGray.
     */
    public void testLookupUIColorInCompound() {
        UIColorHighlighter hl = new UIColorHighlighter();
        Color color = hl.getBackground();
        CompoundHighlighter compound = new CompoundHighlighter(hl);
        String lf = UIManager.getLookAndFeel().getName();
        // switch LF
        setSystemLF(!defaultToSystemLF);
        if (lf.equals(UIManager.getLookAndFeel().getName())) {
            LOG.info("cannot run lookupUIColor - same LF" + lf);
            return;
        }
        compound.updateUI();
        assertFalse("highlighter background must be changed", 
                color.equals(hl.getBackground()));
    }

    /**
     * Issue #258-swingx: DefaultTableCellRenderer has memory. 
     * How to formulate as test?
     * this is testing the hack (reset the memory in ResetDTCR to null), not
     * any highlighter!
     */
    public void testTableUnSelectedDoNothingHighlighter() {
        JXTable table = new JXTable(10, 2);
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
        renderer.setForeground(foreground);
        table.setHighlighters(new ColorHighlighter());
        Component comp = table.prepareRenderer(renderer, 0, 0);
        assertEquals("do nothing highlighter must not change foreground", foreground, comp.getForeground());
        fail("testing the hack around DefaultTableCellRenderer memory - not the memory itself");
    }


    //---------------
    
    /**
     * Issue #258-swingx: Background LegacyHighlighter must not change custom
     * foreground.
     * <p>
     * 
     * Visualizing effect of hack: table-internally, a ResetDTCRColorHighlighter
     * tries to neutralize DefaultTableCellRenderer's color memory.
     * 
     * <ul>
     * <li> a DTCR subclass with value-based custom foreground
     * <li> the renderer is shared between a table with background highlighter
     * (alternateRowHighlighter) and a table without highlighter
     * <li> the custom value-based foreground must show in both
     * (AlternateRowHighlighter overwrite both striped and unstriped back)
     * </ul>
     * 
     * This behaves as expected after moving the hack to _before_ calling 
     * super.prepareRenderer.
     */
    public void interactiveTableCustomCoreRendererColorBasedOnValue() {
        TableModel model = new AncientSwingTeam();
        JXTable table = new JXTable(model);
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                    Object value, boolean isSelected, boolean hasFocus,
                    int row, int column) {
                // TODO Auto-generated method stub
                super.getTableCellRendererComponent(table, value, isSelected,
                        hasFocus, row, column);
                if (!isSelected) {
                    if (getText().contains("y")) {
                        setForeground(Color.RED);
                    } else {
                        setForeground(Color.GREEN);
                    }
                }
                return this;
            }

        };
        table.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));

        table.setDefaultRenderer(Object.class, renderer);
        JXTable nohighlight = new JXTable(model);
        nohighlight.setDefaultRenderer(Object.class, renderer);
        showWithScrollingInFrame(table, nohighlight,
                "core - value-based fg renderer with bg highlighter <--> shared without highl");
    }
    

    
    /**
     * Issue #258-swingx: Background LegacyHighlighter must not change custom
     * foreground.
     * <p>
     * 
     * Visualizing effect of hack: table-internally, a ResetDTCRColorHighlighter
     * tries to neutralize DefaultTableCellRenderer's color memory.
     * 
     * <ul>
     * <li> a DTCR with custom foreground and custom background
     * <li> the renderer is shared between a table with background highlighter
     * (alternateRowHighlighter) and a table without highlighter
     * <li> the custom foreground must show in both
     * <li> the custom background must show in the table without highlighter
     * <li> the custom background must not show in the table with highlighter
     * (AlternateRowHighlighter overwrite both striped and unstriped back)
     * </ul>
     * 
     */
    public void interactiveTableCustomCoreRendererColor() {
        TableModel model = new AncientSwingTeam();
        JXTable table = new JXTable(model);
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
        renderer.setForeground(foreground);
        renderer.setBackground(background);
        table.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));

        table.setDefaultRenderer(Object.class, renderer);
        JXTable nohighlight = new JXTable(model);
        nohighlight.setDefaultRenderer(Object.class, renderer);
        showWithScrollingInFrame(table, nohighlight,
                "core: custom colored renderer with bg highlighter <--> shared without highl");
    }
    
    
    /**
     * Issue #258-swingx: Background LegacyHighlighter must not change custom
     * foreground.
     * <p>
     * 
     * Visualizing effect of hack: table-internally, a ResetDTCRColorHighlighter
     * tries to neutralize DefaultTableCellRenderer's color memory.
     * 
     * Problem: if pre-hack-highlighting and selected on first rendering,
     * the renderer always uses the selection color. Bug in hacking highlighter?
     * Not much it can do about it: the hacking does not store the color if
     * the adapter isSelected - so in the next round the previously configured
     * color - which was for selected state - is stored as to color to restore to.
     * <p>
     * Arrggghhh...
     * 
     */
    public void interactiveTableCoreRendererFirstSelected() {
        TableModel model = new AncientSwingTeam();
        DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
//        JXTable table = new JXTable(model);
//        table.addHighlighter(AlternateRowHighlighter.genericGrey);
//        table.setDefaultRenderer(Object.class, renderer);
        JXTable nohighlight = new JXTable(model);
        nohighlight.setDefaultRenderer(Object.class, renderer);
        nohighlight.setRowSelectionInterval(0, 0);
//        showWithScrollingInFrame(table, nohighlight,
        showWithScrollingInFrame(nohighlight,
                "core: very first match is against selected");
    }
    
    
    /**
     * UIHighlighter: check if highlighter is updated when toggling LF.
     */
    public void interactiveUITableWithAlternateRow() {
        JXTable table = new JXTable(10, 2);
        table.setBackground(ledger);
        table.setHighlighters(HighlighterFactory.createSimpleStriping());
        JXTable nohighlight = new JXTable(10, 2);
        nohighlight.setBackground(ledger);
       showWithScrollingInFrame(table, nohighlight, "colored table with ui highlighter <--> without highlighter");
    }

    /**
     * Effect of background highlighters on list with custom background.
     * 
     */
    public void interactiveColoredListWithAlternateRow() {
        JXList list = new JXList(createListModel());
        list.setBackground(ledger);
        list.addHighlighter(
                HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));

        JXList nohighlight = new JXList(createListModel());
        nohighlight.setBackground(ledger);
        showWithScrollingInFrame(list, nohighlight, "colored list with striping <--> without ");
    }

    /**
     * 
     * Effect of background highlighters on tree with custom background. Note:
     * background highlighters don't work at all with DefaultTreeCellRenderers.
     */
    public void interactiveColoredTreeWithAlternateRow() {
        JXTree coreRendering = new JXTree();
        coreRendering.setHighlighters(HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));
        coreRendering.setBackground(ledger);
        JXTree tree = new JXTree();
        tree.setCellRenderer(new DefaultTreeRenderer()); 
        tree.setHighlighters(HighlighterFactory.createSimpleStriping(HighlighterFactory.GENERIC_GRAY));
        tree.setBackground(ledger);
        showWithScrollingInFrame(tree, coreRendering, "colored tree with striping: swingx <--> core");
    }
    

    @SuppressWarnings("all")
    private TableModel createTableModelWithLinks() {
        String[] columnNames = { "text only", "Link editable", "Link not-editable", "Bool editable", "Bool not-editable" };
        
        DefaultTableModel model = new DefaultTableModel(columnNames, 0) {
            public Class<?> getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }

            @Override
            public boolean isCellEditable(int row, int column) {
                    return !getColumnName(column).contains("not");
            }
            
        };
        for (int i = 0; i < 4; i++) {
            try {
                LinkModel link = new LinkModel("a link text " + i, null, new URL("http://some.dummy.url" + i));
                if (i == 1) {
                    URL url = JXEditorPaneTest.class.getResource("resources/test.html");

                    link = new LinkModel("a link text " + i, null, url);
                }
                model.addRow(new Object[] {"text only " + i, link, link, Boolean.TRUE, Boolean.TRUE });
            } catch (MalformedURLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return model;
    }

    
    /**
     * Issue #178-swingx: Highlighters must not change the selection color if selection colors 
     * not set.
     * 
     * Compare table with empty highlighter to table without highlighter.
     */
    public void interactiveTableWithDoNothingHighlighter() {
        JXTable table = new JXTable(new AncientSwingTeam());
        table.addHighlighter(emptyHighlighter);
        showWithScrollingInFrame(table, new JXTable(table.getModel()), "selection: empty highlighter <--> no highlighter");
        
    }
    

//------------------ helpers
    
    private ListModel createListModel() {
        DefaultListModel model = new DefaultListModel();
        for (int i = 0; i < 10; i++) {
            model.add(i, i);
        }
        return model;
    }


}
