/** 
 *  BlackHole Source File
 *
 *  GNU Copyright (C) 2008  Gaspar Sinai gaspar(at)adys.org 
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License, version 2,
 *  dated June 1991. See file COPYYING for details.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package sinai.gaspar.blackhole;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

/**
 * Create an prime patterns.
 * Currently type 0 and type 1 is supported.
 * This program depends on javax, so don't run it in a browser.
 *
 * The spiral pattern was discovered by Stanislaw Ulam (1909-1986) in 1963 
 * while doodling during a boring talk at a scientific meeting. 
 *
 * @author Gaspar Sinai
 * @version 2008-04-28
 */
public class PrimeImage {

    int width = 1024;
    int height = 800;
    Color foreground = getColor ("000000");
    Color background = getColor ("ffffff");
    File out = new File ("prime.png");
    long start = 1;
    int cellSize=1;
    int type = IOptions.TYPE_SPIRAL;
    boolean showNumber = false;

    /**
     * This is called from java main.
     */
    public static void main (String args[]) throws Exception {
        PrimeImage prim =  new PrimeImage ();

        if (args.length == 0) {
            usage ();
            System.exit (1);
        }
        boolean hasExample = false; 
        boolean hasImage = false; 
 
        for (int i=0; i<args.length; i++) {
            if ("--width".equals (args[i])) {
                prim.setWidth (Integer.parseInt(args[++i]));
            } else if ("--height".equals (args[i])) {
                prim.setHeight (Integer.parseInt(args[++i]));
            } else if ("--cellSize".equals (args[i])) {
                prim.setCellSize (Integer.parseInt(args[++i]));
            } else if ("--type".equals (args[i])) {
                prim.setType (Integer.parseInt(args[++i]));
            } else if ("--foreground".equals (args[i])) {
                prim.setForeground (getColor (args[++i]));
            } else if ("--background".equals (args[i])) {
                prim.setBackground (getColor (args[++i]));
            } else if ("--out".equals (args[i])) {
                prim.setOut (new File (args[++i]));
                hasImage = true;
            } else if ("--showNumber".equals (args[i])) {
                prim.setShowNumber (true);
            } else if ("--start".equals (args[i])) {
                prim.setStart (Long.parseLong(args[++i]));
            } else {
                System.err.println ("Unknow option: " + args[i]);
                usage ();
                System.exit (1);
            }
        }
        if (!hasImage) {
            usage ();
            System.exit (1);
        }
        prim.writeImage ();
        System.exit (0);
    }

    /**
     * Construct a default object.
     */
    public PrimeImage() throws Exception {
    }

    /**
     * @param color is RRGGBB where RR GG and BB are hexadecimal numbers.
     */
    public static Color getColor (String color) throws Exception {
        String r = color.substring(0,2);
        String g = color.substring(2,4);
        String b = color.substring(4,6);
        return new Color (Integer.parseInt(r, 16), 
            Integer.parseInt(g, 16), Integer.parseInt (b, 16));
    }

    public static void usage () {
       System.err.println ("PrimeImage creates a png image where prime numbers are marked.");
       System.err.println ("usage: PrimeImage [--type 0] [--start 1] [--width 1024 ] [--height 800] [--background ffffff] [--foreground 000000] [--cellSize 40] [--showNumber] [-out prime.png]");
       System.err.println ("       Currently type 0 and 1 is supported.");
    }
    public void setWidth (int width) {
        this.width = width;
    }
    public void setHeight (int height) {
        this.height = height;
    }
    public void setCellSize (int cellSize) {
        this.cellSize = cellSize;
    }
    public void setType (int type) {
        this.type = type;
    }
    public void setBackground (Color background) {
        this.background = background;
    }
    public void setForeground (Color foreground) {
        this.foreground = foreground;
    }
    public void setOut (File out) {
        this.out = out;
    }
    public void setShowNumber (boolean showNumber) {
        this.showNumber = showNumber;
    }
    public void setStart (long start) {
        this.start = start;
    }

    /**
     * Print the image.
     * If cellSize == 40, then print a number in the area too.
     */
    private void writeImage () throws Exception {
        CoordConverter converter = new CoordConverter (type, width, height);

        BufferedImage image = new BufferedImage (width*cellSize, 
            height*cellSize, BufferedImage.TYPE_INT_ARGB);

        Graphics graphics = image.getGraphics();         
        graphics.setColor (background);
        graphics.fillRect(0, 0, width*cellSize, height*cellSize);
        graphics.setColor (foreground);

        for (int i=0; i<width; i++) {
            for (int j=0; j<height; j++) {
                long p = converter.convert (i, j);
                if (p < 0) continue;
                if (PrimeStack.isPrime (p + start)) {
                    graphics.setColor (foreground);
                    graphics.fillRect (cellSize*(int)i, 
                        cellSize*(int)j, cellSize, cellSize);
                    graphics.setColor (background);
                } else {
                    graphics.setColor (foreground);
                }
                if (showNumber) {
                    printNum (graphics, cellSize*i+cellSize/2+4, 
                        cellSize*j+cellSize/2-10, p + start);
                }
            }
        }
        image.flush ();
        ImageIO.write (image, "PNG", out);
        System.out.println ("Wrote PNG file: " + out.getName() + ".");
    }

    /**
     * From GNU Unifont. 0..9
     * http://en.wikipedia.org/wiki/GNU_Unifont
     */
    static String FONT[] = { 
            "00000000182442424242424224180000",
            "000000001030501010101010107C0000",
            "000000003C4242020C102040407E0000",
            "000000003C4242021C020242423C0000",
            "00000000040C142444447E0404040000",
            "000000007E4040407C020202423C0000",
            "000000001C2040407C424242423C0000",
            "000000007E0202040404080808080000",
            "000000003C4242423C424242423C0000",
            "000000003C4242423E02020204380000"
    };
    public void printNum (Graphics graphics, int x, int y, long num) {
        if (num >= 10) printNum (graphics, x-8, y, num/10);
        num = num%10;
        String f = FONT[(int)num];
        for (int row=0; row<16; row++) {
           int b = Integer.parseInt (f.substring(row*2, row*2+2), 16);
           for (int column=0; column<8; column++) {
               if ((b & 0x80) == 0x80) {
                   graphics.fillRect (x+column, y+row, 1, 1);
               }
               b = b << 1;
            }
        }
    }
}

