/*
 *   Copyright (c) 2005, Richard Koolish 
 *   All Rights Reserved.
 *
 */


/*********************************************************************
*                                                                    * 
*  ScatterPlot - Create a JPG image of a scatter plot                * 
*                                                                    * 
*********************************************************************/  

import java.util.*;
import java.io.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.font.*;


public class ScatterPlot  {

    private static boolean verbose = false;
    private static String source = null;
    private static String dest = null;
    private static String indir = null;
    private static String outdir = null;
    private static String usage = "usage: java ScatterPlot -h <height> -w <width> -s <source> -d <dest> -indir <dir> -outdir <dir>";
    private static int canvas_w = 1024;
    private static int canvas_h = 768;

    private Hashtable colors = new Hashtable ();
    private Vector points = new Vector ();
    private double x_min = Double.MAX_VALUE;
    private double x_max = Double.MIN_VALUE;
    private double y_min = Double.MAX_VALUE;
    private double y_max = Double.MIN_VALUE;
    private String plot_title = "";
    private String x_axis_title = "";
    private String y_axis_title = "";


    public ScatterPlot () {

        colors = new Hashtable ();
        colors.put ("black", Color.black);
        colors.put ("red", Color.red);
        colors.put ("blue", Color.blue);
        colors.put ("green", Color.green);
    }


    private void process_file () {

        BufferedReader in;
        String line;
        String new_line;
        int line_cnt = 0;

        // open the file

        System.err.println ("processing '" + source + "'");

        try {
            in = new BufferedReader (new FileReader (indir + "/" + source));
        } catch (Exception e) {
            System.err.println ("Can't open input file '" + indir + "/" + source + "'");
            e.toString ();
            return;
        }

        // read file, compute min, max, save points

        while (true) {
            try {
                line = in.readLine ();
                if (line == null)
                    break;
                line_cnt++;
                if (line.trim().length() == 0)
                    continue;
                if (line.startsWith ("#"))
                    continue;
                if (line_cnt == 1) {
                    plot_title = line;
                    continue;
                }
                if (line_cnt == 2) {
                    x_axis_title = line;
                    continue;
                }
                if (line_cnt == 3) {
                    y_axis_title = line;
                    continue;
                }
                if (line_cnt < 6)
                    continue;
                Vector v = tokenize (line, "\t");
                if (v.size() < 2)
                    continue;
                double x1 = Double.parseDouble ((String)v.elementAt (0));
                double y1 = Double.parseDouble ((String)v.elementAt (1));
                Point2D.Double p = new Point2D.Double (x1, y1);
                points.add (p);
                if (x1 < x_min)
                    x_min = x1;
                if (x1 > x_max)
                    x_max = x1;
                if (y1 < y_min)
                    y_min = y1;
                if (y1 > y_max)
                    y_max = y1;
            } catch (Exception e) {
                e.printStackTrace ();
                break;
            }
        }

        try {
            in.close ();
        } catch (Exception e) {
        }

        BufferedImageCanvas canvas = new BufferedImageCanvas (canvas_w, canvas_h);

        // compute grid

        double dx = x_max - x_min;
        double dy = y_max - y_min;

        int i = 0;
        double n = 5.0;

        while (true) {
            i++;
            if ((dx / (i * n)) <= 12.0)
                break;
        }

        double x_incr = i * n;

        i = 0;
        while (true) {
            i++;
            if ((dy / (i * n)) <= 12.0)
                break;
        }

        double y_incr = i * n;

        x_min = Math.floor (x_min - x_incr);
        x_max = Math.ceil (x_max + x_incr);
        y_min = Math.floor (y_min - y_incr);
        y_max = Math.ceil (y_max + y_incr);

        // draw grid and labels

        int x_org = 100;
        int y_org = 100;
        int x_width = canvas_w - 200;
        int y_height = canvas_h - 200;
        double x_scale = (canvas_w - 200) / (x_max - x_min);
        double y_scale = (canvas_h - 200) / (y_max - y_min);

        int x1 = 0;
        int y1 = 0;
        int x2 = 0;
        int y2 = 0;
        int lw = 0;
        Color c = Color.black;

        //canvas.drawLine (x_org, y_org, x_org + x_width, y_org, 1, c);
        //canvas.drawLine (x_org, y_org, x_org, y_org + y_height, 1, c);
        //canvas.drawLine (x_org + x_width, y_org + y_height, x_org + x_width, y_org, 1, c);
        //canvas.drawLine (x_org + x_width, y_org + y_height, x_org, y_org + y_height, 1, c);

        canvas.setFontStyle (Font.BOLD);
        int sl = canvas.stringLength (plot_title);
        canvas.drawString (plot_title, x_org + (x_width / 2) - (sl / 2), y_org - 50, c);
        sl = canvas.stringLength (x_axis_title);
        canvas.drawString (x_axis_title, x_org + (x_width / 2) - (sl / 2), y_org + y_height + 50, c);
        sl = canvas.stringLength (y_axis_title);
        canvas.drawVertString (y_axis_title, 50, y_org + (y_height / 2) + (sl / 2), c);
        canvas.restoreFont ();

        for (double xx = x_min; xx <= x_max; xx += x_incr) {
            int xx1 = (int)(((xx - x_min) * x_scale) + x_org);
            canvas.drawLine (xx1, y_org, xx1, y_org + y_height, 1, c);
            String s = "" + xx;
            int len = canvas.stringLength (s);
            canvas.drawString (s, xx1 - len / 2, y_org + y_height + 15, c);
        }

        for (double yy = y_min; yy <= y_max; yy += y_incr) {
            int yy1 = (int)(((yy - y_min) * y_scale) + y_org);
            canvas.drawLine (x_org, yy1, x_org + x_width, yy1, 1, c);
            String s = "" + yy;
            int len = canvas.stringLength (s);
            canvas.drawString ("" + yy, x_org - len - 5, yy1 + 3, c);
        }

        // plot the points

        for (int pi = 0; pi < points.size(); pi++) {
            Point2D.Double p = (Point2D.Double)points.elementAt (pi);
            double x = p.getX ();
            double y = p.getY ();
            x1 = (int)(((x - x_min) * x_scale) + x_org);
            y1 = (int)(((y_max - y) * y_scale) + x_org);
            canvas.drawRect (x1, y1, 4, 4, 1, c);
        }

        // write the image

        canvas.write (outdir + "/" + dest);
    }


    // tokenize

    private static Vector tokenize (String s, String delim) {

        StringTokenizer st;
        if (delim == null)
            st = new StringTokenizer (s);
        else
            st = new StringTokenizer (s, delim);

        Vector tokens = new Vector ();
        while (st.hasMoreTokens ())        
            tokens.add (st.nextToken ());

        return tokens;
    }


    // parseArgs

    private static void parseArgs(String[] args) {

        for (int i = 0; i < args.length; i++) {
	      String arg = args[i];

	      if (arg.equals("-v")) {
		    verbose = true;
            } else if (arg.equals ("-s")) {
                i++;
                source = args[i];
            } else if (arg.equals ("-d")) {
                i++;
                dest = args[i];
            } else if (arg.equals ("-indir")) {
                i++;
                indir = args[i];
            } else if (arg.equals ("-outdir")) {
                i++;
                outdir = args[i];
            } else if (arg.equals ("-w")) {
                i++;
                canvas_w = Integer.parseInt(args[i]);
            } else if (arg.equals ("-h")) {
                i++;
                canvas_h = Integer.parseInt(args[i]);
            } else {
                System.out.println ("Unknown arg: " + arg);
            }
	  } 

        if (source == null) {
            System.err.println ("No source file specified");
            System.err.println (usage);
            System.exit (-1);
        }

        if (dest == null) {
            System.err.println ("No destination file specified");
            System.err.println (usage);
            System.exit (-1);
        }

        if (indir == null) {
            System.err.println ("No input directory specified");
            System.err.println (usage);
            System.exit (-1);
        }

        if (outdir == null) {
            System.err.println ("No output directory specified");
            System.err.println (usage);
            System.exit (-1);
        }
    }


    // main

    public static void main (String[] args) { 

        parseArgs (args);

        ScatterPlot sp = new ScatterPlot ();
        sp.process_file ();

        System.exit (0);
    }

    


}
   