import java.awt.Color;
import java.io.*;

/**
 * Unit test of the Picture class. Requires colors.ppm and badp3.ppm
 * to operate.
 *
 * @version 1.3 4/30/09
 * @author Ed Parrish
 */
// NTR: should use test file with color depth < 255
public class PictureTester {
    private static int numErrors;
    private static final int COLOR_WIDTH = 3;
    private static final int COLOR_HEIGHT = 2;
    private static final int COLOR_DEPTH_MAX = 255;
    private static final int COLORS_NUM = 6;
    private static final int THIRD_NUM = 3;
    private static final int NUMS_PER_PIXEL = 3;
    private static final int[] COLORS = {
        255, 0, 0,
        0, 255, 0,
        0, 0, 255,
        255, 255, 0,
        255, 255, 255,
        0, 0, 0
    };

    /**
     * The main method begins execution of the tests.
     *
     * @param args not used
     */
    public static void main(final String[] args) {
        testPicture();
        testLoadPPM();
        testSavePPM();
        testAddRGB();
        testToString();
        System.out.println("PictureTester completed");
        if (numErrors == 0) {
            System.out.println("*** All tests passed ***");
        } else {
            System.out.println("*** Some tests failed ***");
        }
        System.exit(0);
    }

    /**
     * Convenience method to test for assertions.
     *
     * @param condition The test condition that must be true to pass.
     * @param message The reason for the failure.
     */
    public static void assertTrue(boolean condition, String message) {
        if (!condition) {
            System.out.println("Error: " + message);
            numErrors++;
        }
    }

    /**
     * Test method: testPicture()
     */
    public static void testPicture() {
        System.out.println("Testing the default constructor");
        Picture p = new Picture();
        assertTrue(p.getWidth() == 0,
            "Constructor returns width != 0");
        assertTrue(p.getHeight() == 0,
            "Constructor returns height != 0");
        assertTrue(p.getColorDepth() == 0,
            "Constructor returns color depth != 0");
        assertTrue(p.getColors() == null,
            "Constructor returns colors[] != null");
    }

    /**
     * Test method: testLoadPPM()
     */
    public static void testLoadPPM() {
        System.out.println("Testing loadPPM()");
        File badp3PPM = new File("badp3.ppm");
        File colorsPPM = new File("colors.ppm");
        if (!colorsPPM.exists() || !badp3PPM.exists()) {
            System.out.println(
                "Both badp3.ppm and colors.ppm needed to run this test");
            System.exit(-1);
        }
        Picture p = new Picture();
        try {
            p.loadPPM("badp3.ppm");
            assertTrue(false,
                "Did not throw IOException when loading badp3.ppm");
        } catch (IOException ioe) {
            //ioe.printStackTrace();
            int x = 0; // nonsense line for CheckStyle
        }
        final String FILE_NAME = "colors.ppm";
        try {
            p.loadPPM(FILE_NAME);
        } catch (IOException ioe) {
            assertTrue(false, "Got an unexpected IOException");
            ioe.printStackTrace();
        }
        assertTrue(p.getWidth() == COLOR_WIDTH, "Wrong width ("
            + p.getWidth() + ") from:" + FILE_NAME);
        assertTrue(p.getHeight() == COLOR_HEIGHT, "Wrong height ("
            + p.getHeight() + ") from:" + FILE_NAME);
        assertTrue(p.getColorDepth() == COLOR_DEPTH_MAX,
            "Wrong color depth (" + p.getColorDepth() + ") from:"
            + FILE_NAME);
        Color[] colors = p.getColors();
        assertTrue(colors != null,
            "After calling loadPPM(), getColors() returned null");
        if (colors == null) return;
        assertTrue(colors.length == COLORS_NUM,
            "Wrong number of colors loaded (" + colors.length + ") from:"
            + FILE_NAME);
        for (int i = 0; i < colors.length; i++) {
            Color c = colors[i];
            assertTrue(c != null,
                "After loadPPM(), found null in color array[" + i + "]");
            if (c != null) {
                int r = c.getRed();
                int g = c.getGreen();
                int b = c.getBlue();
                assertTrue(COLORS[i * NUMS_PER_PIXEL] == r,
                    "Wrong red value: " + r
                    + "s/b" + COLORS[i * NUMS_PER_PIXEL]);
                assertTrue(COLORS[i * NUMS_PER_PIXEL + 1] == g,
                    "Wrong green value: " + g
                    + "s/b" + COLORS[i * COLOR_WIDTH + 1]);
                assertTrue(COLORS[i * NUMS_PER_PIXEL + 2] == b,
                    "Wrong blue value: " + b
                    + "s/b" + COLORS[i * NUMS_PER_PIXEL + 2]);
            }
        }
    }

    /**
     * Test method: testSavePPM()
     */
    public static void testSavePPM() {
        System.out.println("Testing savePPM()");
        Picture p = new Picture();
        try {
            p.loadPPM("colors.ppm");
            p.savePPM("colors-save.ppm");
            File savedPPM = new File("colors-save.ppm");
            assertTrue(savedPPM.exists(),
                "Did not save the test file");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    /**
     * Test method: testAddRGB()
     */
    public static void testAddRGB() {
        System.out.println("Testing addRGB()");
        int startErrors = numErrors;
        Picture p = new Picture();
        try {
            p.loadPPM("colors.ppm");
            p.addRGB(1, 2, THIRD_NUM);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        Color[] colors = p.getColors();
        int max = p.getColorDepth();
        for (int i = 0; i < colors.length; i++) {
            Color c = colors[i];
            assertTrue(c != null,
                "After addRGB(), found null in color array[" + i + "]");
            if (c == null) return;
            int r = c.getRed();
            int g = c.getGreen();
            int b = c.getBlue();
            assertTrue(r <= max, "Red value > max color depth of " + max);
            assertTrue(g <= max, "Green value > max color depth of " + max);
            assertTrue(b <= max, "Blue value > max color depth of " + max);
            assertTrue(r >= 0, "Red value < 0: " + r);
            assertTrue(g >= 0, "Green value < 0: " + g);
            assertTrue(b >= 0, "Blue value < 0: " + b);
            int red = COLORS[i * NUMS_PER_PIXEL] + 1;
            if (red > max) red = max;
            int green = COLORS[i * NUMS_PER_PIXEL + 1] + 2;
            if (green > max) green = max;
            int blue =  COLORS[i * NUMS_PER_PIXEL + 2] + THIRD_NUM;
            if (blue > max) blue = max;
            assertTrue(red == r, "Element " + (i * NUMS_PER_PIXEL)
                + " has wrong red value of " + r + ", should be: " + red);
            assertTrue(green == g, "Element " + (i * NUMS_PER_PIXEL + 1)
                + " has wrong green value: " + g + " should be: " + green);
            assertTrue(blue == b, "Element " + (i * NUMS_PER_PIXEL + 2)
                + " has wrong blue value: " + b + " should be: " + blue);
        }
        if (numErrors - startErrors > 0) {
            String fileName = "colors-error.ppm";
            System.out.println("Saving your picture with errors as: "
                + fileName);
            try {
                p.savePPM(fileName);
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    }

    /**
     * Test method: testToString()
     */
    public static void testToString() {
        System.out.println("Testing toString()");
        Picture p = new Picture();
        String str = p.toString();
        assertTrue(str != null, "toString() returns null");
        assertTrue(str.length() > 0, "toString() returns 0 length string");
    }
}

