/*
 * Graphics.java    2.0 97/06/10
 * Copyright (c) 1997, B. F. Caviness
 *
 * This software may be copied/modified for any non-commercial educational use.
 */

package sg;

/**
 * The <code>class Graphics</code> defines a simple character-oriented
 * graphics device.
 *
 * @version   2.0, 10 June 1997
 * @author    B. F. Caviness
 */

public class Graphics
{
   /**
    * A two dimensional array that is used as the drawing canvas or tablet.
    */
   protected char[][] grid;

   /**
    * The number of rows on the drawing canvas.
    */
   protected int rows; 

   /**
    * The number of columns on the drawing canvas.
    */
   protected int cols;

   /**
    * Default constructor that constructs a 50 x 50 canvas.
    */
    public Graphics()				// Zero-param constructor
    {
       this(50, 50);				// Call 2-param constructor
    }						// to construct grid of
						// default size.
    /**
     * Two-parameter constructor.
     *
     * @param rows the number of rows for the newly constructed canvas
     * @param cols the number of columns for the newly constructed canvas
     */
    public Graphics( int rows, int cols )	// 2-param constructor
    {
       this.rows = rows; this.cols = cols;	// "this" is an object of type
       grid = new char[rows][cols];		// Graphics

       int width = cols, height = rows;
       clearRect( 0,0, width, height );		// Clear the grid
    }

    /** 
     * Clear rectangle on grid by filling with spaces ' '.  Part 
     * (or all) of the rectangle can be off the canvas.
     *
     * @param x x-coordinate of the upper left-hand corner of rectangle
     *          to be cleared.
     * @param y y-coordinate of the upper left-hand corner of rectangle
     *          to be cleared.
     * @param width width of rectangle to be cleared.
     *
     * @param height height of rectangle to be cleared.
     *
     * @return void
     */
    public void clearRect( int x, int y, int width, int height )
    {
       for (int j = x; j < x + width; j++)
          for (int i = y; i < y + height; i++)
             if ( 0 <= i && i < rows && 0 <= j && j < cols )
                 grid[i][j] = ' ';
    }

    /** 
     * Display the grid on the standard output.
     *
     * @return void
     */
    public void show()
    {
      for (int i = 0; i < rows; i++)
       {
         for (int j = 0; j < cols; j++)
            System.out.print(grid[i][j]);
         System.out.println( );
       }
    }

    /**
     * Returns the sign of the parameter where the sign is <br>
     * -1 if the parameter is < 0 <br>
     *  0 if the parameter is == 0 <br>
     * +1 if the parameter is > 0 <br>
     *
     * @param x the integer for which the sign is computed
     *
     * @return int the sign(x)
     */
    private static int sign( int x )             // Compute sign of x
    {
      int s = 0;
      if ( x < 0 ) s = -1;
      if ( x > 0 ) s = 1;
      return s;
    }

    /**
     * Computes the greatest common divisor (gcd) of its two parameters.
     *
     * @param m one of the integers.
     *
     * @param n the other integer.
     *
     * @return int the gcd of m and n.
     */
    private static int gcd( int m, int n )// Compute greatest common divisor of
    {					  // m and n.  Used by drawLine()
       m = Math.abs(m); n = Math.abs(n);

       int r;
       while ( n != 0 )
        {
           r = m%n;
           m = n; n = r;
        }

       return m;
    }

    /** 
     * Draw a line on the grid from point (x1,y1) to (x2,y2)
     *
     * @param x1 the x-coordinate of the starting point
     *
     * @param y1 the pixel (x1,y1) is the starting point for the line.  It
     *           is permissable for this point to be off the canvas, in
     *           which case only the part that is actually on the canvas
     *           will be drawn.
     * @param x2 the x-coordinate of the ending point
     *
     * @param y2 the pixel (x2,y2) is the ending point for the line.  It
     * does not have to be on the canvas either.
     *
     * @return void
     */
    public void drawLine( int x1,int y1, int x2,int y2 )
    {
       int xs = sign(x2 - x1);
       int ys = sign(y2 - y1);

       if ( xs == 0 && ys == 0 && 	// line is a single point
            0 <= x1 && x1 < cols && 0 <= y1 && y1 < rows )
           grid[y1][x1] = '*';

       int g = gcd( x2-x1, y2-y1);
       int xIncr = (x2 - x1)/g;
       int yIncr = (y2 - y1)/g;

       while ( xs*(x2 - x1) >= 0 && ys*(y2 - y1) >= 0 )
       {
          if ( 0 <= y1 && y1 < rows && 0 <= x1 && x1 < cols )
              grid[y1][x1] = '*';
          x1 += xIncr;
          y1 += yIncr;
       }
    }

    /**
     * Draws border around canvas.
     *
     * @return void
     */
    public void drawBorder()
    {
      for ( int i = 0; i < rows; i++ )      // Plot left & right vertical
      {                                     // borders
         grid[i][0] = '+';
         grid[i][cols - 1] = '+';
      }
 
      for ( int j = 0; j < cols; j++ )      // Plot top and bottom
      {                                     // horizontal borders
         grid[0][j] = '+';
         grid[rows - 1][j] = '+';
      }
    }
}	// end of class Graphics
