public class DrawGaussian {

    public static final int PLOT_LITTLE_PHI = 1;
    public static final int PLOT_BIG_PHI = PLOT_LITTLE_PHI << 1;
    public static final int PLOT_SAMPLE = PLOT_BIG_PHI << 1;

    public static void plotCoordinates (double xmin, double xmax,
            double ymin, double ymax) {

        StdDraw.setPenColor (StdDraw.GRAY);
        StdDraw.setXscale(xmin, xmax);
        StdDraw.line (xmin, 0, xmax, 0);

        for (double x = xmin; x <= xmax; x += 1.0) {
            StdDraw.line (x, ymin, x, ymin + 0.02);
        }

        StdDraw.setYscale(ymin, ymax);
        StdDraw.line (0, ymin, 0, ymax);

        for (double y = ymin; y <= ymax; y += 1.0) {
            StdDraw.line (-.1, y, .1, y);
        }
    }

    public static void plotphi (double mu, double sigma,
            double xmin, double xmax, int nsteps) {

        StdDraw.setPenColor (StdDraw.BLACK);

        double dx = (xmax - xmin) / nsteps;
        double x = xmin;
        double y = Gaussian.phi (x, mu, sigma);

        for (int n = 0; n < nsteps; n++) {
            double xnext = x + dx;
            double ynext = Gaussian.phi (xnext, mu, sigma);
            StdDraw.line(x, y, xnext, ynext);
            x = xnext;
            y = ynext;
        }
    }

    public static void plotPhi (double mu, double sigma,
            double xmin, double xmax, int nsteps) {

        StdDraw.setPenColor (StdDraw.BLUE);

        double dx = (xmax - xmin) / nsteps;
        double x = xmin;
        double y = Gaussian.Phi (x, mu, sigma);

        for (int n = 0; n < nsteps; n++) {
//            StdDraw.setPenColor (StdDraw.LIGHT_GRAY);
//            StdDraw.line(x, 0, x, Gaussian.phi(x, mu, sigma));
//            StdDraw.setPenColor (StdDraw.BLUE);

            double xnext = x + dx;
            double ynext = Gaussian.Phi (xnext, mu, sigma);
            StdDraw.line(x, y, xnext, ynext);
            x = xnext;
            y = ynext;

            // Insert delay loop to slow down the action...
//            for (int delay = 0; delay < 50000000; delay++)
//                ;
        }
    }

    public static void plotHistogram (double [] histogram,
            double xmin, double xmax) {

        StdDraw.setXscale(xmin, xmax);
        StdDraw.setYscale(0.0, 1.0);

        double x = xmin;
        double dx = (xmax - xmin) / histogram.length;
        double y = 0;

        for (int i = 0; i < histogram.length; i++) {
            StdDraw.line(x, y, x, histogram[i]);
            y = histogram[i];
            StdDraw.line (x, y, x+dx, y);
            x += dx;
        }
    }

    public static void main(String[] args) {
        // Set defaults for optional command-line arguments
        // (use these values if corresponding arguments are omitted)
        double mu = 0.0;
        double sigma = 1.0;
        int plotCode = 1;

        // Look for optional arguments...
        if (args.length > 0) {
            mu = Double.parseDouble (args[0]);
        }
        if (args.length > 1) {
            sigma = Double.parseDouble (args[1]);
        }
        if (args.length > 2) {
            plotCode = Integer.parseInt (args[2]);
        }

        double xmin = -3.0;
        double xmax = 3.0;
        double ymin = 0.0;
        double ymax = 1.0;

        plotCoordinates (xmin, xmax, ymin, ymax);

        int nsteps = (int) (300 / sigma);

        if ((plotCode & PLOT_LITTLE_PHI) != 0) {
            plotphi (mu, sigma, xmin, xmax, nsteps);
        }
        if ((plotCode & PLOT_BIG_PHI) != 0) {
            plotPhi (mu, sigma, xmin, xmax, nsteps);
        }
        if ((plotCode & PLOT_SAMPLE) != 0) {
            double [] histogram =
                    SampleGaussian.getHistogram (mu, sigma, 100000, 51, xmin, xmax);
            plotHistogram (histogram, xmin, xmax);
        }
    }
}
