/*
 * $Id: JXHeaderTest.java,v 1.11 2009/01/27 22:53:23 rah003 Exp $
 *
 * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdesktop.swingx;

import java.awt.Color;
import java.awt.Font;
import java.net.URL;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.IconUIResource;

import junit.framework.TestCase;

import org.jdesktop.swingx.test.XTestUtils;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.junit.Test;


/**
 * Unit test for <code>JXHeader</code>.
 * <p>
 *
 * All test methods in this class are expected to pass.
 * 
 * PENDING JW: some of the tests are dirty in that they rely on hidden (from the
 * perspective of the JXHeader) implementation
 * details of BasicHeaderUI (like how the different parts are implemented). 
 * What/How else to test that? A minor improvement could be reached by testing
 * the ui delegate directly, as the children are visible to subclasses. So we 
 * would end up testing its contract to extension.  
 *
 * @author Jeanette Winzenburg
 */
@RunWith(JUnit4.class)
public class JXHeaderTest extends TestCase {

//---------------- testing icon property, similar to #925
// except that it's not a property normally controlled by the ui defaults.
    
    /**
     * Test that header's icon property set to default value, if any.
     */
    @Test
    public void testIconDefaultA() {
        Icon icon = XTestUtils.loadDefaultIcon();
        assertNotNull("sanity: default icon loaded", icon);
        UIManager.put("Header.defaultIcon", icon);
        JXHeader header = new JXHeader();
        try {
            assertSame(icon, header.getIcon());
        } finally {
            UIManager.put("Header.defaultIcon", null);
        }
    }


    /**
     * Test that header's icon property set to default value, if any.
     */
    @Test
    public void testIconLabelDefaultB() {
        Icon icon = XTestUtils.loadDefaultIcon();
        assertNotNull("sanity: default icon loaded", icon);
        UIManager.put("Header.defaultIcon", icon);
        JXHeader header = new JXHeader();
        try {
            assertSame(icon, getIconLabel(header).getIcon());
        } finally {
            UIManager.put("Header.defaultIcon", null);
        }
    }

    /**
     * Test that header's icon property set to default value, if any.
     */
    @Test
    public void testIconLabelCustomC() {
        Icon icon = XTestUtils.loadDefaultIcon();
        assertNotNull("sanity: default icon loaded", icon);
        JXHeader header = new JXHeader();
        header.setIcon(icon);
        SwingUtilities.updateComponentTreeUI(header);
        assertSame(icon, header.getIcon());
        assertSame(icon, getIconLabel(header).getIcon());
    }

    /**
     * Test that header's icon property set to default value, if any.
     */
    @Test
    public void testIconLabelDefaultUpdateD() {
        Icon uiDefault = UIManager.getIcon("Header.defaultIcon");
        Icon icon = new IconUIResource(XTestUtils.loadDefaultIcon());
        assertNotNull("sanity: default icon loaded", icon);
        JXHeader header = new JXHeader();
        header.setIcon(icon);
        assertSame(icon, getIconLabel(header).getIcon());
        SwingUtilities.updateComponentTreeUI(header);
        assertSame(uiDefault, header.getIcon());
        assertSame(uiDefault, getIconLabel(header).getIcon());
    }
    
/*
 * ----------- start testing #925-swingx
 * 
 * there are several sub-issues: A - property on JXHeader must be set to
 * defaults B - corresponding property on the appropriate child must be set C -
 * (sanity) custom property must be kept on both header and child after laf
 * change D - property on both header and child must be updated to defaults on
 * laf change if not custom
 * 
 * The critical (child) properties are those which have default ui properties
 * controlled by the header, that is font and foreground of description and
 * title label. So we have one group comprised of tests A-D for each of them,
 * denoted by the respective postfix.
 * 
 * PENDING JW: any way to auto-create this tests? The groups are created by c&p
 * and replace ... error-prone and in fact, introduced testing errors. Which
 * passed accidentally because the tested properties had the same default value
 * (f.i. Color.BLACK or so).
 * 
 */    
//-------- property: description font   
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Header property set to uimanager setting.
     */
    @Test
    public void testUpdateUIDescriptionFontA() {
        Font color = UIManager.getFont("JXHeader.descriptionFont");
        assertNotNull("sanity: description font available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, header.getDescriptionFont());
    }

    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Description label property set to uimanager setting.
     */
    @Test
    public void testUpdateUIDescriptionLabelFontB() {
        Font color = UIManager.getFont("JXHeader.descriptionFont");
        assertNotNull("sanity: description font available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, getDescriptionLabel(header).getFont());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Description label custom property kept on LAF change.
     */
    @Test
    public void testUpdateUICustomDescriptionLabelFontC() {
        Font color = new Font("serif", Font.BOLD, 36);
        JXHeader header = new JXHeader();
        header.setDescriptionFont(color);
        assertEquals("sanity: description color taken", color, getDescriptionLabel(header).getFont());
        SwingUtilities.updateComponentTreeUI(header);
        assertEquals(color, header.getDescriptionFont());
        assertEquals(color, getDescriptionLabel(header).getFont());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label property updated to ui default on laf change.
     */
    @Test
    public void testUpdateUIDefaultDescriptionLabelFontD() {
        Font uiDefault = new FontUIResource("serif", Font.PLAIN, 36);
        UIManager.put("JXHeader.descriptionFont", uiDefault);
        Font color = new FontUIResource("serif", Font.ITALIC, 20);
        JXHeader header = new JXHeader();
        header.setDescriptionFont(color);
        try {
            assertEquals(color, header.getDescriptionFont());
            assertEquals(color, getDescriptionLabel(header).getFont());
            SwingUtilities.updateComponentTreeUI(header);
            
            assertEquals(uiDefault, header.getDescriptionFont());
            assertEquals(uiDefault, getDescriptionLabel(header).getFont());
        } finally {
            // reset custom property
           UIManager.put("JXHeader.descriptionFont", null);   
        }
    }


    
    
//--------------   property: description foreground 
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Header property set to uimanager setting.
     */
    @Test
    public void testUpdateUIDescriptionForegroundA() {
        Color color = UIManager.getColor("JXHeader.descriptionForeground");
        assertNotNull("sanity: description font available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, header.getDescriptionForeground());
    }

    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Description label property set to uimanager setting.
     */
    @Test
    public void testUpdateUIDescriptionLabelForegroundB() {
        Color color = UIManager.getColor("JXHeader.descriptionForeground");
        assertNotNull("sanity: description font available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, getDescriptionLabel(header).getForeground());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Description label custom property kept on LAF change.
     */
    @Test
    public void testUpdateUICustomDescriptionLabelForegroundC() {
        Color color = Color.PINK;
        JXHeader header = new JXHeader();
        header.setDescriptionForeground(color);
        assertEquals("sanity: description color taken", color, getDescriptionLabel(header).getForeground());
        SwingUtilities.updateComponentTreeUI(header);
        assertEquals(color, header.getDescriptionForeground());
        assertEquals(color, getDescriptionLabel(header).getForeground());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Description label property updated to ui default on laf change.
     */
    @Test
    public void testUpdateUIDefaultDescriptionLabelForegroundD() {
        Color uiDefault = new ColorUIResource(Color.BLUE);
        UIManager.put("JXHeader.descriptionForeground", uiDefault);
        Color color = new ColorUIResource(Color.PINK);
        JXHeader header = new JXHeader();
        header.setDescriptionForeground(color);
        SwingUtilities.updateComponentTreeUI(header);
        try {
            
            assertEquals(uiDefault, header.getDescriptionForeground());
            assertEquals(uiDefault, getDescriptionLabel(header).getForeground());
        } finally {
            // reset custom property
           UIManager.put("JXHeader.descriptionForeground", null);   
        }
    }


//----------- property title foreground    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Header property set to uimanager setting.
     */
    @Test
    public void testUpdateUITitleForegroundA() {
        Color color = UIManager.getColor("JXHeader.titleForeground");
        assertNotNull("sanity: title foreground available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, header.getTitleForeground());
    }

    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label property set to uimanager setting.
     */
    @Test
    public void testUpdateUITitleLabelForegroundB() {
        Color color = UIManager.getColor("JXHeader.titleForeground");
        assertNotNull("sanity: title foreground available", color);
        JXHeader header = new JXHeader();
        assertEquals(color, getTitleLabel(header).getForeground());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label custom property kept on LAF change.
     */
    @Test
    public void testUpdateUICustomTitleLabelForegroundC() {
        Color color = Color.PINK;
        JXHeader header = new JXHeader();
        header.setTitleForeground(color);
        assertEquals("sanity: title foreground taken", color, getTitleLabel(header).getForeground());
        SwingUtilities.updateComponentTreeUI(header);
        assertEquals(color, header.getTitleForeground());
        assertEquals(color, getTitleLabel(header).getForeground());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label property updated to ui default on laf change.
     */
    @Test
    public void testUpdateUIDefaultTitleLabelForegroundD() {
        Color uiDefault = new ColorUIResource(Color.BLUE);
        UIManager.put("JXHeader.titleForeground", uiDefault);
        Color color = new ColorUIResource(Color.PINK);
        JXHeader header = new JXHeader();
        header.setTitleForeground(color);
        SwingUtilities.updateComponentTreeUI(header);
        try {
            
            assertEquals(uiDefault, header.getTitleForeground());
            assertEquals(uiDefault, getTitleLabel(header).getForeground());
        } finally {
            // reset custom property
           UIManager.put("JXHeader.titleForeground", null);   
        }
    }

//---------- property: title font    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Header property set to uimanager setting.
     */
    @Test
    public void testUpdateUITitleFontA() {
        Font font = UIManager.getFont("JXHeader.titleFont");
        assertNotNull("sanity: title font available", font);
        JXHeader header = new JXHeader();
        assertEquals(font, header.getTitleFont());
    }

    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Test title label property set to UIManager prop
     */
    @Test
    public void testUpdateUITitleLabelFontB() {
        Font font = UIManager.getFont("JXHeader.titleFont");
        assertNotNull("sanity: title font available", font);
        JXHeader header = new JXHeader();
        assertEquals(font, getTitleLabel(header).getFont());
    }

    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label custom property kept on LAF change.
     */
    @Test
    public void testUpdateUICustomTitleLabelFontC() {
        Font color = new Font("serif", Font.BOLD, 36);
        JXHeader header = new JXHeader();
        header.setTitleFont(color);
        assertEquals("sanity: title color taken", color, getTitleLabel(header).getFont());
        SwingUtilities.updateComponentTreeUI(header);
        assertEquals(color, header.getTitleFont());
        assertEquals(color, getTitleLabel(header).getFont());
    }
    
    /**
     * Issue #925-swingx: custom properties lost on updateUI.
     * Title label property updated to ui default on laf change.
     */
    @Test
    public void testUpdateUIDefaultTitleLabelFontD() {
        Font uiDefault = new FontUIResource("serif", Font.PLAIN, 36);
        UIManager.put("JXHeader.titleFont", uiDefault);
        Font color = new FontUIResource("serif", Font.ITALIC, 20);
        JXHeader header = new JXHeader();
        header.setTitleFont(color);
        try {
            assertEquals(color, header.getTitleFont());
            assertEquals(color, getTitleLabel(header).getFont());
            SwingUtilities.updateComponentTreeUI(header);
            
            assertEquals(uiDefault, header.getTitleFont());
            assertEquals(uiDefault, getTitleLabel(header).getFont());
        } finally {
            // reset custom property
           UIManager.put("JXHeader.titleFont", null);   
        }
    }


//--------- end testing #925
    
    
    /**
     * Issue #695-swingx: not-null default values break class invariant.
     * Here initial empty constructor.
     */
    @Test
    public void testTitleSynchInitialEmpty() {
        JXHeader header = new JXHeader();
        assertEquals(header.getTitle(), getTitleLabel(header).getText());
    }


    /**
     * Issue #695-swingx: not-null default values break invariant.
     * Here: initial not-null explicitly set to null and updateUI (to
     * simulate LF toggle).
     */
    @Test
    public void testTitleSynchUpdateUI() {
        JXHeader header = new JXHeader("dummy", null);
        header.setTitle(null);
        header.updateUI();
        assertEquals(header.getTitle(), getTitleLabel(header).getText());
    }

    /**
     * Issue #695-swingx: not-null default values break invariant.
     * Here: initial null params constructor.
     */
    @Test
    public void testTitleSynchInitialNull() {
        JXHeader header = new JXHeader(null, null);
        header.setTitle(null);
        assertEquals(header.getTitle(), getTitleLabel(header).getText());
    }


    /**
     * Issue #403-swingx: JXHeader doesn't show custom values.
     *
     */
    @Test
    public void testIconSet() {
        URL url = getClass().getResource("resources/images/wellTop.gif");
        Icon icon = new ImageIcon(url);
        assertNotNull(url);
        JXHeader header = new JXHeader();
        header.setIcon(icon);
        // sanity: the property is set
        assertEquals(icon, header.getIcon());
        // fishing in the internals ... not really safe, there are 2 labels and 1 jxlabel ... indeed not safe!
        assertEquals("the label's text must be equal to the headers title",
                header.getIcon(), getIconLabel(header).getIcon());
    }

    /**
     * Issue #403-swingx: JXHeader doesn't show custom values.
     *
     */
    @Test
    public void testTitleSet() {
        JXHeader header = new JXHeader();
        String title = "customTitle";
        header.setTitle(title);
        // sanity: the property is set
        assertEquals(title, header.getTitle());
        assertEquals("the label's text must be equal to the headers title",
                header.getTitle(), getTitleLabel(header).getText());
    }

    /**
     * Issue #403-swingx: JXHeader doesn't show custom values.
     * <p>
     *
     * Breaking if values are passed in the constructor.
     */
    @Test
    public void testTitleInContructor() {
        String title = "customTitle";
        JXHeader header = new JXHeader(title, null);
        // sanity: the property is set
        assertEquals(title, header.getTitle());
        assertEquals("the label's text must be equal to the headers title",
                header.getTitle(), getTitleLabel(header).getText());
    }

    /**
     * Issue swingx-900 NPE when top level ancestor is not available, while "some" ancestor is.
     */
    @Test
    public void testNPE() {
        JXHeader header = new JXHeader();
        JPanel panel = new JPanel();
        panel.add( header );
        panel.setBounds( 0, 0, 200, 200 );
    }

// ----------------- private helpers (dirty!)    
    /**
     * Returns the label used for painting the title. Implemented to 
     * return the first child of type JLabel. <p>
     * 
     * NOTE: this is fishing in implementation details of BasicHeaderUI!
     * 
     * @return the label used for painting the title.
     */
    private JLabel getTitleLabel(JXHeader header) {
        for (int i = 0; i < header.getComponentCount(); i++) {
            if (header.getComponent(i) instanceof JLabel) {
                return (JLabel) header.getComponent(i);
            }
        }
        return null;
    }

    /**
     * Returns the label used for painting the description. Implemented to 
     * return the first child of type JXLabel. <p>
     * 
     * NOTE: this is fishing in implementation details of BasicHeaderUI!
     * 
     * @return the label used for painting the description.
     */
    private JLabel getDescriptionLabel(JXHeader header) {
        for (int i = 0; i < header.getComponentCount(); i++) {
            if (header.getComponent(i) instanceof JXLabel) {
                return (JLabel) header.getComponent(i);
            }
         }
        return null;
    }

    /**
     * Returns the label used for painting the icon. Implemented to 
     * return the second child of type JLabel and not of type JXLabel. <p>
     * 
     * NOTE: this is fishing in implementation details of BasicHeaderUI!
     * 
     * @return the label used for painting the icon.
     */
    private JLabel getIconLabel(JXHeader header) {
        JLabel label = null;
        for (int i = 0; i < header.getComponentCount(); i++) {
            if (header.getComponent(i) instanceof JLabel && !(header.getComponent(i) instanceof JXLabel)) {
                boolean second = label != null;
                label = (JLabel) header.getComponent(i);
                if (second) {
                    return label;
                }
            }
        }
        return null;
    }

    
    @Override
    protected void setUp() throws Exception {
        // forcing load of headerAddon
        new JXHeader();
    }

}
