/**
 * @(#)bug4284162.java  1.0 03/10/10
 *
 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;

/**
 * Test for RFE #4284162
 * Assertion:
 * - It checks a specific part of the editor pane for white color,
 *   If found the test is considered to be failed.
 * @author Hemant.Singh@SUN.com
 *
 * - Modified to fix bug #5023183 30 March 20003
 * @author Hemant.Singh@Sun.COM
 */
public class bug4284162 extends JFrame {

    // There will be always slow systems under this earth, so give
    // enough time out
    private final static int PAGELOAD_TIMEOUT = 5 * 60 * 1000;

    // Used for thread synchronization
    private final static Object _lock = new Object();

    // Display console messages
    private final static boolean DEBUG = true;

    // Editor pane used for displaying html
    private JEditorPane editorPane = null;

    //Buffered image
    private BufferedImage bImage;

    // Rectangular area in editor pane which we will capture image.
    private Rectangle rectImage = new Rectangle(10, 10, 20, 150);

    // Used for debugging purpose.
    private boolean markImageArea = false;

    //Flag to keep track of page loading
    private volatile boolean pageLoaded = false;

    // The main method
    public static void main(String[] ergs) {
        bug4284162 test = new bug4284162();
        blockTillDisplayed(test);
        test.runTest();
    }

    /**
     * Constructor.
     */
    private bug4284162() {
        // Assign a name to the frame and obtain a handle
        // on the frame's content pane
        super(bug4284162.class.getName());

        // Add default window listener, So that in case of
        // it hangs user can close it
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent we) {
                exit(1);
            }
        });

        Container container = this.getContentPane();
        // create an editor pane and add it to the content pane
        editorPane = new JEditorPane("text/html", "Loading...") {
            public void paint(Graphics g) {
                super.paint(g);
                if (markImageArea)
                    g.drawRect(rectImage.x, rectImage.y, rectImage.width, rectImage.height);
            }
        };
        editorPane.addPropertyChangeListener(new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals("page")) {
                    URL urlNew = (URL)evt.getNewValue();
                    URL urlOld = (URL)evt.getOldValue();
                    if (urlOld == null && urlNew.toString().contains("bug4284162.html")) {
                        pageLoaded = true;
                        synchronized(_lock) {
                            _lock.notifyAll();
                        }
                    }
                }
            }
        });

        JScrollPane scrollPane = new JScrollPane(editorPane);
        container.add(scrollPane);
        editorPane.setEditable(false);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(600, 400);
        setVisible(true);
        toFront();
    }

    /**
     * Run the test.
     */
    private void runTest() {

        //Consider it will pass
        int status = 0;

        try {
            //First generate the html file which we will need to
            //display in editor pane.
            generateHTMLFile();

            doTest();
        } catch (Throwable e) {
            // Do nothing.
            status = 1;
            e.printStackTrace();
        }
        deleteHTMLFile();
        exit(status);
    }

    /**
     * Run the test.
     * It throws the exception if test fails
     * @throws Exception It throws Runtime exception which
     * contains look and feel name in which test fails.
     */
    private void doTest() throws Exception {

        Robot robot = null;
        try {
            robot = new Robot();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // Get all installed look and feels
        javax.swing.UIManager.LookAndFeelInfo[] lafInfo =
        javax.swing.UIManager.getInstalledLookAndFeels();

        // Iterate in all look and feels and test in each look and feel.
        for (int counter = 0; counter < lafInfo.length; counter++) {
            UIManager.setLookAndFeel(lafInfo[counter].getClassName());
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    try {
                        SwingUtilities.updateComponentTreeUI(bug4284162.this);
                    } catch(Exception e){}

                }
            });

            robot.setAutoDelay(50);
            robot.waitForIdle();
            synchronized(_lock) {
                // If we don't call show page and call show page only once
                // and than keep on switching l&fs than it will pass always
                // key is that we need to display html after the l&f change.
                showPage();
                try {
                    //This ensures that page gets loaded, and we also don't
                    // wait uneccessary
                    _lock.wait(PAGELOAD_TIMEOUT);
                }
                catch (Exception e) {}
            }
            // To ensure UI updates.
            robot.waitForIdle();

            Point ptStart = editorPane.getLocationOnScreen();
            Rectangle rect =
            new Rectangle(
                    (int) ptStart.getX(),
                    (int) ptStart.getY(),
                    editorPane.getWidth(),
                    editorPane.getHeight());

            // Make sure mouse doesn't come in image area.
            robot.mouseMove(getWidth() + 10,0);

            bImage = robot.createScreenCapture(rect);
            bImage = bImage.getSubimage(rectImage.x, rectImage.y, rectImage.width, rectImage.height);

            for (int i = 0, width = bImage.getWidth(); i < width; i++) {
                for (int j = 0, height = bImage.getHeight(); j < height; j++) {
                    if (bImage.getRGB(i, j) == Color.WHITE.getRGB()) {
                        // Test is failed., Throw Runtime exception with
                        // information about failure.
                        throw new RuntimeException(
                                "Test failed in : " + lafInfo[counter].getName()
                                + " RGB is -1 at x:" + i + " y:" + j + " of image");
                    }
                }
            }
        }
    }

    /**
     * Show the html page in EditorPane
     */
    private void showPage() {
        pageLoaded = false;

        // First remove the existing URL, so that page gets reloaded.
        editorPane.getDocument().putProperty(javax.swing.text.Document.StreamDescriptionProperty, null);

        URL pageURL = null;
        try {
            pageURL = new File("bug4284162.html").toURL();
        } catch (MalformedURLException excep) {
            System.out.println("MalformedURL file:bug4284162.html");
        }
        // Assign the page to the editor pane so that the
        // page is displayed
        try {
            editorPane.setPage(pageURL);
        } catch (java.io.IOException excep) {
            System.out.println("setPage" + excep.toString());
        }
    }

    /**
     * Block the calling thread until given <code>Component</code> is
     * displayed on screen. This can be useful for Robot testing.
     * After <code>blockTillDisplayed</code> returns, the
     * <code>Component</code> is laid out and displayed on screen,
     * so <code>Robot</code> can be used to interact with it.
     * <p>Example:
     * <pre>
     *         JFrame f = new JFrame();
     *         f.getContentPane().add(comp);
     *         f.setVisible(true);
     *         Util.blockTillDisplayed(comp);
     *         // comp is now visible on screen
     * </pre>
     *
     * @param comp the <code>Component</code> to be displayed on screen
     * @return the location of the passed in component
     */
    private static Point blockTillDisplayed(Component comp) {
        Point p = null;
        while (p == null) {
            try {
                p = comp.getLocationOnScreen();
            } catch (IllegalStateException e) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ie) {
                }
            }
        }
        return p;
    }

    /**
     * Method used for deleting the generated files
     * after test is finished.
     */
    private void deleteHTMLFile() {
        File file = new File(".", "bug4284162.html");
        if (file.exists()) {
            file.delete();
        }
    }

    /**
     * Generates the html file which
     */
    private void generateHTMLFile() {
        File file = new File(".", "bug4284162.html");
        if (file.exists()) {
            file.delete();
        }
        try {
            PrintStream out = new PrintStream(new FileOutputStream(file));
            out.println("<html>");
            out.println("<head>");
            out.println("<title>XXXXX</title>");
            out.println("<STYLE TYPE=\"text/css\">");
            out.println("A:link {");
            out.println("color: blue;");
            out.println("text-decoration: underline;");
            out.println("}");
            out.println("A:visited {");
            out.println("    color: purple;");
            out.println("text-decoration: underline;");
            out.println("}");
            out.println("A:active {");
            out.println("    color: red;");
            out.println("    text-decoration: underline;");
            out.println("}");
            out.println("html {");
            out.println("background-color: #cccccc;");
            out.println("}");
            out.println("body {");
            out.println("background-color: #cccccc;");
            out.println("text-indent: -36.000000pt;");
            out.println("margin-left: 36.000000pt;");
            out.println("}");
            out.println("blockquote {");
            out.println("text-indent: 0.000000pt;");
            out.println("margin-left: 0.000000pt;");
            out.println("}");
            out.println("table {");
            out.println("text-indent: 0.000000pt;");
            out.println("margin-left: -10.000000pt;");
            out.println("}");
            out.println("tr th {");
            out.println("text-align: center;");
            out.println("padding-left: 10.000000pt;");
            out.println("padding-right: 10.000000pt;");
            out.println("}");
            out.println("tr td {");
            out.println("padding-left: 10.000000pt;");
            out.println("padding-right: 10.000000pt;");
            out.println("margin-top: -3.000000pt;");
            out.println("margin-bottom: -3.000000pt;");
            out.println("}");
            out.println("</style>");
            out.println("</head>");
            out.println("<body>");
            out.println("<BASEFONT SIZE=2>");
            out.println("<H2 ALIGN=center>xxxxxxx xxx  xxxxx</H2>");
            out.println("<B>xxxxxxxx: </B>xxxxxxx xxxx, xxxxxxxxx xx xxxxxx xx xxxxxxx xx xxxxxxx xx");
            out.println("xxxxxxx xx xxxxxxxxxx xx xxxxxxx xx xxxxxxxxxxx xx xxxxxxxxxx xx xxxxxx xx xxxxxxxxxx xx");
            out.println("xxxxxxxxxxx xx xxxxxxxxxx xx xxxxxxxxxxxx<DIV HEIGHT=18><B>xxxxxxxxxx");
            out.println("xxxx:</B></DIV>");
            out.println("<BLOCKQUOTE>");
            out.println("xx xxxxxxxxxx xxxx xxxxx</BLOCKQUOTE>");
            out.println("<DIV HEIGHT=18><B>xxxxxxxxxxx:</B></DIV><BLOCKQUOTE>");
            out.println("xxxx</BLOCKQUOTE>");
            out.println("<DIV><B>xxxxx xxxx:</B></DIV><TABLE");
            out.println("BORDER=0><TR><TH>xxxxx xxxxxx</TH><TH>xx");
            out.println("xxx</TH><TH>xx xxxx</TH><TH>xx");
            out.println("xxxxx</TH><TH>xxxxxxxx xxxxxxxxxxxxxx</TH></TR><TR><TD");
            out.println("ALIGN=center>A</TD><TD ALIGN=center>B</TD><TD");
            out.println("ALIGN=center>C</TD><TD ALIGN=center>D</TD><TD");
            out.println("ALIGN=center>E</TD></TR>");
            out.println("</TABLE><DIV><B>xxx xxxxxxxxxxxxxx:</B></DIV>");
            out.println("<TABLE BORDER=0><TR><TH>xxxxxxxxxxxxx</TH><TH>xxxxx</TH><TH>xxx</TH><TH>xxx</TH><TH>xxx</TH></TR><TR");
            out.println("valign=baseline><TD>xxxxx</TD><TD ALIGN=right>Z</TD><TD");
            out.println("ALIGN=right>xxxxxxxx</TD><TD ALIGN=right>xxxxxxxx</TD><TD");
            out.println("ALIGN=right>yyyyyyyy</TD></TR>");
            out.println("<TR valign=baseline><TD>xxxx</TD><TD");
            out.println("ALIGN=right>Z</TD><TD ALIGN=right>xxxxxxxx</TD><TD");
            out.println("ALIGN=right>xxxxxxxx</TD><TD ALIGN=right>yyyyyyyy</TD></TR>");
            out.println("</TABLE><DIV><B>xxxxxxx xxxxxxxxxxx:</B></DIV><TABLE");
            out.println("BORDER=0><TR><TH width=75>xxxx</TH><TH");
            out.println("width=60>xxxx</TH><TH width=60>xxxxxx</TH><TH");
            out.println(">xxxxxx</TH><TH >xxxxxxxxxxx</TH></TR>");
            out.println("<TR VALIGN=BASELINE><TD ALIGN=\"left\">xxxxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxxxxx</TD><TD ALIGN=\"right\">xxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxx</TD><TD ALIGN=\"left\">xxxxx</TD></TR>");
            out.println("<TR VALIGN=BASELINE><TD ALIGN=\"left\">xxxxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxxxxx</TD><TD ALIGN=\"right\">xxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxx<BR>xxxxx<BR>xxxxx</TD></TR>");
            out.println("<TR VALIGN=BASELINE><TD ALIGN=\"left\">xxxxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxxxxx</TD><TD ALIGN=\"right\">xxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxx</TD><TD ALIGN=\"left\">xxxxx</TD></TR>");
            out.println("<TR VALIGN=BASELINE><TD ALIGN=\"left\">xxxxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxxxxx</TD><TD ALIGN=\"right\">xxxxxxxx</TD><TD");
            out.println("ALIGN=\"left\">xxxxx</TD><TD ALIGN=\"left\">xxxxx</TD></TR>");
            out.println("</TABLE>");
            out.println("</body>");
            out.println("</html>");
            out.flush();
            out.close();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Exit the VM with specific information.
     * @param status status to be used for exit
     */
    private static void exit(int status) {
        if (status == 0 && DEBUG) {
            System.out.println("Test Passed.");
        } else if (DEBUG){
            System.out.println("Test Failed.");
        }

        //Exit the VM with the specified status code.
        System.exit(status);
    }
}
