import java.awt.*;
import java.lang.*;

// class definitions
// version 0.3 (21-05-08) - fixed multi and random colours

class SGUnit {
	private double radius;
	private double factor;
	private double offset;

	SGUnit() {
		radius = 0.0;
		factor = 0.0;
		offset = 0.0;
	}

	SGUnit(double theRadius, double theFactor, double theOffset) {
		radius = theRadius;
		factor = theFactor;
		offset = theOffset;
	}

	public double radius() { return this.radius; }
	public double factor() { return this.factor; }
	public double offset() { return this.offset; }

	public void setRadius(double value) { this.radius = value; }
	public void setFactor(double value) { this.factor = value; }
	public void setOffset(double value) { this.offset = value; }
}

class SGPair {
	private SGUnit X, Y;

	SGPair() {
		X = new SGUnit();
		Y = new SGUnit();
	}

	SGPair(double xRadius, double yRadius, double xFactor, double yFactor,
			double xOffset, double yOffset) {
		X = new SGUnit(xRadius, xFactor, xOffset);
		Y = new SGUnit(yRadius, yFactor, yOffset);
		/* this();
		X.setRadius(xRadius);
		X.setFactor(xFactor);
		X.setOffset(xOffset)
		Y.setRadius(yRadius);
		Y.setFactor(yFactor);
		Y.setOffset(yOffset); */
	}

	public double XRadius() { return X.radius(); }
	public double XFactor() { return X.factor(); }
	public double XOffset() { return X.offset(); }
	public double YRadius() { return Y.radius(); }
	public double YFactor() { return Y.factor(); }
	public double YOffset() { return Y.offset(); }

	public void setXRadius(double value) { X.setRadius(value); }
	public void setXFactor(double value) { X.setFactor(value); }
	public void setXOffset(double value) { X.setOffset(value); }
	public void setYRadius(double value) { Y.setRadius(value); }
	public void setYFactor(double value) { Y.setFactor(value); }
	public void setYOffset(double value) { Y.setOffset(value); }

	public void setX(double rad, double fac, double off)
	{
		setXRadius(rad);
		setXFactor(fac);
		setXOffset(off);
	}

	public void setY(double rad, double fac, double off)
	{
		setYRadius(rad);
		setYFactor(fac);
		setYOffset(off);
	}
}

class SGParameters {
	// Class variables
	final static double pi = Math.PI;

	static int totalColours;
	static Color c[] =	{Color.blue, Color.red, Color.green, Color.yellow, Color.cyan,
						 Color.magenta, Color.orange, Color.pink};

	static boolean randomColrs = false;
	static boolean multiColrs = true;

	// Instance variables - S_Grapher parameters
	private double startingAngle;	// starting angle
	private double endingAngle;		// ending angle
	private double interval;		// draw every ... degrees
	private SGPair A;				// point A's attributes
	private SGPair B;				// point B's attributes
	private int numOfColours;		// how many colours to use
	private double xOrigin;			// x coord of graph origin
	private double yOrigin;			// y coord of graph origin

	// Constructors
	SGParameters() {
		startingAngle = 0.0;
		endingAngle = 360.0;
		interval = 1.0;
		A = new SGPair(100.0, 100.0, 1.0, 1.0, 0.0, 0.0);
		B = new SGPair(100.0, 100.0, 2.0, 3.0, 0.0, 0.0);
		numOfColours = 1;
		xOrigin = 180.0;
		yOrigin = 150.0;
	}

	SGParameters(double bxfactor, double byfactor, int rad1, int rad2, int numOfColrs,
				 double bxoffset, double byoffset) {
		this();
		A.setXRadius((float) rad1);
		A.setYRadius((float) rad1);
		B.setXRadius((float) rad2);
		B.setYRadius((float) rad2);
		numOfColours = numOfColrs;
		B.setXFactor(bxfactor);
		B.setYFactor(byfactor);
		B.setXOffset(bxoffset);
		B.setYOffset(byoffset);
	}

	SGParameters(double bxfactor, double byfactor, int rad1, int rad2, int numOfColrs,
				 double bxoffset, double byoffset, double xmid, double ymid) {
		this(bxfactor, byfactor, rad1, rad2, numOfColrs, bxoffset, byoffset);
		xOrigin = xmid;
		yOrigin = ymid;
	}

	// Class methods
	public static void initialise()
	{
		totalColours = c.length;
		randomColrs = false;
		multiColrs = true;
	}

	public static boolean randomColrs()
	{
		return randomColrs;
	}

	public static boolean multiColrs()
	{
		return multiColrs;
	}

	public static void setRandomColrs(boolean flag)
	{
		randomColrs = flag;
	}

	public static void setMultiColrs(boolean flag)
	{
		multiColrs = flag;
	}

	// Instance method
	public void draw( Graphics g )
	{
		double ax;						// point A, X coordinate
		double ay;						// point A, Y coordinate
		double bx;						// point B, X coordinate
		double by;						// point B, Y coordinate

		int currentColour = 0;

		int lineColour;
		int lineColourRed, lineColourGreen, lineColourBlue;
		int random_hue;

		totalColours = c.length;	// jic

		// draw the s-graph
		for (double angle = this.startingAngle; angle < this.endingAngle; angle += this.interval)
		{
			// calculate coordinate a
			ax = this.A.XRadius() * Math.cos(this.A.XFactor() * (angle + this.A.XOffset())/180*pi) + this.xOrigin;
			ay = this.A.YRadius() * Math.sin(this.A.YFactor() * (angle + this.A.YOffset())/180*pi) + this.yOrigin;

			// calculate coordinate b
			bx = this.B.XRadius() * Math.cos((this.B.XFactor() * angle + this.B.XOffset())/180*pi) + this.xOrigin;
			by = this.B.YRadius() * Math.sin((this.B.YFactor() * angle + this.B.YOffset())/180*pi) + this.yOrigin;

			// check if it's time to change colour
			if (angle != 0)
			{
				if (angle % ((this.endingAngle - this.startingAngle) / this.numOfColours) == 0)
					currentColour = (currentColour + 1) % totalColours;
			}

			// set line colour
			if (multiColrs)
			{
				lineColour = Math.abs(Color.HSBtoRGB(( (float) angle / 360.0f), 0.92f, 0.8f));
				lineColourRed   = lineColour / (256 * 256);
				lineColourGreen = (lineColour % (256 * 256)) / 256;
				lineColourBlue  = lineColour % 256;
				g.setColor( new Color(lineColourRed, lineColourGreen, lineColourBlue).darker() );
			}
			else if (randomColrs)
			{
				// alt 1: use separate, random, red green and blue values
				// lineColourRed   = 1 + (int) (Math.random() * 255);
				// lineColourGreen = 1 + (int) (Math.random() * 255);
				// lineColourBlue  = 1 + (int) (Math.random() * 255);

				// alt 2: use single, random, hue value
				random_hue = 1 + (int) (Math.random() * 360);
				lineColour = Math.abs(Color.HSBtoRGB(( (float) random_hue / 360.0f), 0.92f, 0.8f));
				lineColourRed   = lineColour / (256 * 256);
				lineColourGreen = (lineColour % (256 * 256)) / 256;
				lineColourBlue  = lineColour % 256;
				// set the color
				g.setColor( new Color(lineColourRed, lineColourGreen, lineColourBlue).darker() );
			}
			else
			{
				g.setColor(c[currentColour].darker());
			}

			// now just have to plot the line!
			g.drawLine((int) ax, (int) ay, (int) bx, (int) by);
		}

	}

}
