package CookieCutter.g5;

import CookieCutter.CookieCutter;
import CookieCutter.Vertex;
import CookieCutter.IFCPlayer;
import CookieCutter.Move;
import java.io.Serializable;
import java.util.Vector;
import java.util.Enumeration;
import java.util.Random;
import java.awt.Shape;
import java.awt.Rectangle;
import java.awt.geom.PathIterator;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;

/** 
 * Group 5 Player (Iteration 3)
 *
 * Cookie Corner Clustering Player.  This player attempts to cluster 
 * cookies into one "Amoeba Cookie" which absorbs each subsequent copy.  
 * The Amoeba Cookie looks for ideal corners b/w itself and the cookie 
 * copy.  Amoeba Cookies can also be cloned and merged together.
 *
 * Currently, the way Amoeba Cookie picks an ideal pair of corners to 
 * match is by checking to see if two corners' outside angles sum to 
 * something close to 360 degrees.  Amoeba Cookie checks every pairwise 
 * combination for the smallest difference from 360 degrees.
 *
 * If the cookie shape is convex, the Amoeba Cookie tries to match 
 * edges of similar length, with a preference for longer edges.
 *
 * @author Prakash Gowri Shankor
 * @author Stephen Lee
 * @author Ludvig Ungewitter
 */

public class Group5Player3 implements IFCPlayer {
	private static final String _CNAME = "Famous Frugal Amos";
	private static Random _random;

	private CookieCutter _cookiecutter;
	private Vertex[][] _cookies;
	private int _copies;
	private AmoebaCookie[] _mergedCopies;

	public void register( CookieCutter __cookiecutter ) throws Exception {
		_cookiecutter = __cookiecutter;
		_cookies = _cookiecutter.cookieshapes();
		_copies = _cookiecutter.cookieCopies();
		_random = new Random();
		_mergedCopies = new AmoebaCookie[_cookies.length];

		for( int i = 0; i < _cookies.length; i++ ) {
			for( int j = 0; j < _copies; j++ ) {
				Cookie cookie = new Cookie( j, _cookies[i] );

				// initialize amoeba cookie
				if( j == 0 ) {
					_mergedCopies[i] = new AmoebaCookie( cookie );
					continue;
				}

				// join shapes that are convex hulls
				//if( _mergedCopies[i].isConvexHull() && cookie.isConvexHull() ) {
				if( cookie.isConvexHull() ) {
					Edge[] bestMatch = _mergedCopies[i].getBestEdgeComplement( cookie );

					if( bestMatch != null ) {
						while( bestMatch != null && !_mergedCopies[i].transformCookie( cookie, bestMatch ) ) {
							System.out.println( "[" + i + "." + j + "] rejected edge " + 
								bestMatch[0].ID() + " -> edge " + bestMatch[1].ID() 
							);

							bestMatch = _mergedCopies[i].getBestEdgeComplement( cookie );

							// the only difference b/w the current cookie and a new one is the 
							// state of the corners, but for some reason, untranslating and 
							// unrotating the original cookie object isn't enough to prevent 
							// an invalid cookie placement
							Vector oldEdges = cookie.getEdges();
							cookie = new Cookie( j, _cookies[i] );
							Vector newEdges = cookie.getEdges();

							for( int k = 0; k < oldEdges.size(); k++ ) {
								Edge edge = ( Edge )oldEdges.elementAt( k );

								if( edge.isUsed() ) {
									Edge newEdge = ( Edge )newEdges.elementAt( k );
									newEdge.use();
								}
							}
						}

						System.out.println( "[" + i + "." + j + "] edge " + bestMatch[0].Owner() + "." + 
							bestMatch[0].ID() + " matches with edge " + bestMatch[1].Owner() + "." + 
							bestMatch[1].ID() 
						);
				
						_mergedCopies[i].assimilate( cookie, bestMatch );
					}
					else {
						throw new Exception( "edges best match is null" );
					}

					continue;
				}

				// join shapes that have concave and convex corners
				Corner[] bestMatch = _mergedCopies[i].getBestCornerComplement( cookie );

				if( bestMatch != null ) {
					while( bestMatch != null && !_mergedCopies[i].transformCookie( cookie, bestMatch ) ) {
						System.out.println( "[" + i + "." + j + "] rejected corner " + bestMatch[0].Owner() + "." + 
							bestMatch[0].ID() + " -> corner " + bestMatch[1].Owner() + "." + 
							bestMatch[1].ID() 
						);
						bestMatch = _mergedCopies[i].getBestCornerComplement( cookie );

						// the only difference b/w the current cookie and a new one is the 
						// state of the corners, but for some reason, untranslating and 
						// unrotating the original cookie object isn't enough to prevent 
						// an invalid cookie placement
						Vector oldCorners = cookie.getCorners();
						cookie = new Cookie( j, _cookies[i] );
						Vector newCorners = cookie.getCorners();

						for( int k = 0; k < oldCorners.size(); k++ ) {
							Corner corner = ( Corner )oldCorners.elementAt( k );

							if( corner.isUsed() ) {
								Corner newCorner = ( Corner )newCorners.elementAt( k );
								newCorner.use();
							}
						}
					}

					System.out.println( "[" + i + "." + j + "] corner " + bestMatch[0].Owner() + "." + 
						bestMatch[0].ID() + " matches with corner " + bestMatch[1].Owner() + "." + 
						bestMatch[1].ID() 
					);

					_mergedCopies[i].assimilate( cookie, bestMatch );
				}
				else {
					throw new Exception( "corners best match is null" );
				} 
			}
		}
	}

	public Move[] moves() throws Exception {
		Move[] RET = new Move[_cookies.length];

		for( int i = 0; i < _cookies.length; i++ ) {
			RET[i] = new Move( _copies );

			Vector cookieCopies = _mergedCopies[i].getCookies();
			Rectangle2D amoebaBounds = _mergedCopies[i].getBounds2D();
			Point2D.Double amoebaCent = _mergedCopies[i].centroid();

			/*
			System.out.println( "before" );
			for( int a = 0; a < _mergedCopies[i].getVertexCount(); a++ ) {
				System.out.println( ( _mergedCopies[i].getX( a ) + 2.0 ) + " " + 
					( _mergedCopies[i].getY( a ) + 1.0 ) 
				);
			}
			System.out.println( "after" );
			*/

			/*
			System.out.println( amoebaBounds.getX() + " " + amoebaBounds.getY() + " " + 
				amoebaBounds.getWidth() + " " + amoebaBounds.getHeight() 
			);
			*/
			
			for( int j = 0; j < cookieCopies.size(); j++ ) {
				Cookie cookie = ( Cookie )( cookieCopies.elementAt( j ) );
				Point2D.Double cent = cookie.centroid();
				Point2D.Double transl = cookie.getTranslation();

				/*
				System.out.println( "[" + i + "." + j + "] rotation = " + 
					( cookie.getRotation() * 180 / Math.PI ) + " translation = [" + 
					transl.getX() + ", " + transl.getY() + "]"
				);
				*/

				RET[i].setCookiePosition( j, new Vertex( cent.getX() - amoebaBounds.getX() + .0000001, 
					cent.getY() - amoebaBounds.getY() ), 
					cookie.getRotation() 
				);
			}

			RET[i].setRightBoundary( amoebaBounds.getWidth() + ( _copies * .0000001 ) );
		}

		return( RET );
	}

	public String name() throws Exception {
		return( _CNAME );
	}

	public boolean interactive() throws Exception {
		return( false );
	}
}
