/*
Lab 8(28-2-2002 to 6-3-2002)								MM:20
1.Define an abstract class called Shape (models 2-D shapes) that has the following abstract functions for shapes - area, perimeter, draw. Consider the following inheritance hierarchy of shapes: RegularShape extends Shape, IrregularShape extends Shape, Polygon and Circle extends RegularShape, 
Quadrilateral, Triangle extends Polygon, Parallelogram, extends Quadrilateral, Rectangle extends
Parallelogram. EquilateralTriangle, IsocelesTriangle and ScaleneTriangle extends Triangle.
Invent suitable representations for each shape. The representation should be at the highest level
that is appropriate. Similarly, the area, perimeter, draw should be implemented at the highest
level possible. Create a separate Test class, which has an array of shapes whose area, perimeter
are printed out and the shape is drawn. You will have to use the element package for drawing
*/
import element.*;
abstract class Shape
{
	protected abstract int getPerimeter();
	protected abstract int getArea();
	protected abstract void draw(DrawingWindow dw);
}
abstract class regularShape extends Shape
{
}
class irregularShape extends Shape
{
	Pt points[];
	public irregularShape(Pt pnts[])
	{
		points = pnts;
	}
	private int dist(Pt p1, Pt p2)
	{
		int d;
		double x,y;
		x = (p1.x()-p2.x()) * (p1.x()-p2.x());
		y = (p1.y()-p2.y()) * (p1.y()-p2.y());
		d = (int)Math.round(Math.sqrt(x+y));
		return d;
	}
	private int triarea(Pt p1, Pt p2, Pt p3)
	{
		int s,a,b,c;
		a = dist(p1,p2);
		b = dist(p2,p3);
		c = dist(p3,p1);
		s = (int)Math.round(1.0*(a+b+c)/2);
		return (int)Math.round(Math.sqrt((double)(s * (s-a) * (s-b) * (s-c))));
	}
	public int getPerimeter()
	{
		int p=0;
		for(int i=1; i<points.length;i++)
			p = p + dist(points[i-1],points[i]);
		p = p + dist(points[points.length-1],points[0]);
		return p;
	}
	public int getArea()
	{
		int area=0;
		for(int i=2;i<points.length;i++)
			area = area + triarea(points[0],points[i-1],points[i]);
		return area;
	}
	public void draw(DrawingWindow dw)
	{
		dw.moveTo(points[0]);
		for(int i=1;i<points.length;i++)
			dw.lineTo(points[i]);
		dw.lineTo(points[0]);
	}
}
class polygon extends regularShape
{
	Pt points[];
	protected int dist(Pt p1, Pt p2)
	{
		int d;
		double x,y;
		x = (p1.x()-p2.x()) * (p1.x()-p2.x());
		y = (p1.y()-p2.y()) * (p1.y()-p2.y());
		d = (int)Math.round(Math.sqrt(x+y));
		return d;
	}
	protected int triarea(Pt p1, Pt p2, Pt p3)
	{
		int s,a,b,c;
		a = dist(p1,p2);
		b = dist(p2,p3);
		c = dist(p3,p1);
		s = (int)Math.round(1.0*(a+b+c)/2);
		return (int)Math.round(Math.sqrt((double)(s * (s-a) * (s-b) * (s-c))));
	}
	public int getPerimeter()
	{
		int p=0;
		for(int i=1; i<points.length;i++)
			p = p + dist(points[i-1],points[i]);
		p = p + dist(points[points.length-1],points[0]);
		return p;
	}
	public int getArea()
	{
		int area=0;
		for(int i=2;i<points.length;i++)
			area = area + triarea(points[0],points[i-1],points[i]);
		return area;
	}
	public void draw(DrawingWindow dw)
	{
		dw.moveTo(points[0]);
		for(int i=1;i<points.length;i++)
			dw.lineTo(points[i]);
		dw.lineTo(points[0]);
	}
}
class circle extends regularShape
{
	Pt center;
	int radius;
	public circle(Pt p, int r)
	{
		center = p;
		radius = r;
	}
	public int getPerimeter()
	{
		int p;
		p = (int)Math.round(2*3.1416*radius);
		return p;
	}
	public int getArea()
	{
		int a;
		a = (int)Math.round(3.1416*radius*radius);
		return a;
	}
	public void draw(DrawingWindow dw)
	{
		dw.drawCircle(center.x(),center.y(),radius);
	}
}
abstract class triangle extends polygon
{
}
class quadrilateral extends polygon
{
	public quadrilateral(Pt pts[])
	{
		if (pts.length == 4)
			points = pts;
		else
		{
			points = new Pt[4];
			points[0] = pts[0];
			points[1] = pts[1];
			points[2] = pts[2];
			points[3] = pts[3];
		}
	}
}
class parallelogram extends quadrilateral
{
	public parallelogram(Pt pts[])
	{
		super(pts);
		int d1 = dist(pts[0],pts[1]);
		int d2 = dist(pts[1],pts[2]);
		int d3 = dist(pts[2],pts[3]);
		int d4 = dist(pts[3],pts[0]);
		int d5 = dist(pts[0],pts[2]);
		int d6 = dist(pts[1],pts[3]);
		if ( ((d1 == d3) && (d2 == d4)) ||  ((d1 == d3) && (d5 == d6)) ||
		     ((d2 == d4) && (d5 == d6) ) 
		{     
			if (pts.length == 4)
				points = pts;
			else
			{
				points = new Pt[4];
				points[0] = pts[0];
				points[1] = pts[1];
				points[2] = pts[2];
				points[3] = pts[3];
			}
		}	
	}
}
class rectangle extends parallelogram
{
	public rectangle(Pt pts[])
	{
		super(pts);
		int d1 = dist(pts[0],pts[1]);
		int d2 = dist(pts[1],pts[2]);
		int d3 = dist(pts[2],pts[3]);
		int d4 = dist(pts[3],pts[0]);
		int d5 = dist(pts[0],pts[2]);
		int d6 = dist(pts[1],pts[3]);
		if ( (d1 == d3) && (d2 == d4) && (d5 == d6) )
		{     
			if (pts.length == 4)
				points = pts;
			else
			{
				points = new Pt[4];
				points[0] = pts[0];
				points[1] = pts[1];
				points[2] = pts[2];
				points[3] = pts[3];
			}
		}	
	}
}
class isosceles extends triangle
{
	public isosceles(Pt pts[])
	{
		int d1 = dist(pts[0],pts[1]);
		int d2 = dist(pts[1],pts[2]);
		int d3 = dist(pts[2],pts[0]);
		if ((d1 == d2) || (d2 == d3) || (d3 == d1))
		{
			if (pts.length == 3)
				points = pts;
			else
			{
				points = new Pt[3];
				points[0] = pts[0];
				points[1] = pts[1];
				points[2] = pts[2];
			}
		}
		else
		{
			System.out.println("Invalid points");
			points = null;
		}
	}
}
class equilateral extends triangle
{
	public equilateral(Pt pts[])
	{
		int d1 = dist(pts[0],pts[1]);
		int d2 = dist(pts[1],pts[2]);
		int d3 = dist(pts[2],pts[0]);
		if ((d1 == d2) && (d2 == d3))
		{
			if (pts.length == 3)
				points = pts;
			else
			{
				points = new Pt[3];
				points[0] = pts[0];
				points[1] = pts[1];
				points[2] = pts[2];
			}
		}
		else
		{
			System.out.println("Invalid points");
			points = null;
		}
	}
}
class scalene extends triangle
{
	public scalene(Pt pts[])
	{
		if (pts.length == 3)
			points = pts;
		else
		{
			points = new Pt[3];
			points[0] = pts[0];
			points[1] = pts[1];
			points[2] = pts[2];
		}
	}
}
public class Lab8
{
	final static int NO_OF_SHAPES = 20;
	
	public static void main()
	{
		Pt p[] = new Pt[4];
		p[0] = new Pt(30,50);
		p[1] = new Pt(60,45);
		p[2] = new Pt(300,200);
		p[3] = new Pt(90,30);
		Pt c = new Pt(50,40);
		int r = 25;
		Pt ptri[] = new Pt[3];
		ptri[0] = new Pt(80,60);
		ptri[1] = new Pt(40,45);
		ptri[2] = new Pt(100,70);
		
		DrawingWindow dw = new DrawingWindow();
		ConsoleWindow cw = new ConsoleWindow();
		
		Shape s[] = new Shape[NO_OF_SHAPES];
		s[0] = new irregularShape(p);
		s[1] = new circle(c,r);
		s[2] = new scalene(ptri);
		
		for(int i = 0; ((i < NO_OF_SHAPES) && (s[i] != null)); i++){
			cw.out.println("Perimeter = " + s[i].getPerimeter());
			cw.out.println("Perimeter = " + s[i].getArea());
			s[i].draw(dw);
		}	
		
	}
}