package CookieCutter.g1;

import java.text.NumberFormat;
import java.util.*;
import CookieCutter.*;

/**
 * Pillsbury Doughboy
 * 
 * @author Mark Ayzenshtat
 * @author Vlad Shchogolev
 * @author David Vespe
 */
public class Group1Player1 implements IFCPlayer {

	private String kName = "Pillsbury Doughboy";
	private CookieCutter mCC;
	private Cookie[] mCookieShapes;
	private int mNumCookieCopies;
	private Move[] mMoves;

	public void register(CookieCutter iCC) throws Exception {
		mCC = iCC;		
		Vertex[][] shapes = mCC.cookieshapes();
		mCookieShapes = new Cookie[shapes.length];
		for (int i = 0; i < shapes.length; i++) {
			mCookieShapes[i] = new Cookie(shapes[i], mCC);
		}
		
		mNumCookieCopies = mCC.cookieCopies();
	}

	public Move[] moves() throws Exception {						
		if (mMoves == null) {		
			mMoves = new Move[mCookieShapes.length];
			for (int i = 0; i < mMoves.length; i++) {
				mMoves[i] = new Move(mNumCookieCopies);
				computeMove(mMoves[i], mCookieShapes[i]);
								
				// print % of available space utilized
				NumberFormat nf = NumberFormat.getPercentInstance();
				String pctUtilized = nf.format(
					getSpaceUtility(mCookieShapes[i], mMoves[i].GetRightBoundary()));			
			}
		}		
		
		return mMoves;
	}
	
	/**
	 * This method packs and orients N copies of the given cookie shape and
	 * stores this information in the given move object.   
	 */
	private void computeMove(Move iMove, Cookie iShape) {		
		double minScore = Double.MAX_VALUE;
		Cookie[] bestPattern = cutCookies(iShape);
		CookiePlacer[] placers = getBestCookiePlacers(iShape);
		String bestPlacerName = null;		

		// run the given cookie shape through each cookie placer
		// keep the configuration that yields the minimum score		
		for (int i = 0; i < placers.length; i++) {
			Cookie[] cookies = cutCookies(iShape);
			placers[i].placeCookies(cookies);
			
			// make sure cookies don't intersect each other or dough borders
			if (!isLegal(cookies)) {
//				System.out.println("WARNING: CookiePlacer " + placers[i].getClass().getName()
//					+ " created a bad cookie arrangement, ignoring");
			} else {
				double score = Cookie.computeRightBoundary(cookies);
				if (score < minScore) {
					minScore = score;
					bestPattern = cookies;
					bestPlacerName = placers[i].getClass().getName();
				}
			}
		}		
		
		// write our final cookies to the move object
		storeInMove(bestPattern, iMove);
	}
	
	/**
	 * Return true if this is a legal cookie arrangement
	 */
	private boolean isLegal(Cookie[] iCookies) {		
		for (int i = 0; i < iCookies.length; i++) {
			if (!iCookies[i].isInBound()) {
				return false;
			}
			
			for (int j = i+1; j < iCookies.length; j++) {
				if (iCookies[i].intersects(iCookies[j])) {
					return false;
				}
			}
		}
				
		return true;
	}
	
	private Cookie[] cutCookies(Cookie iTemplate) {
		// we create an array of N clones of this Cookie
		Cookie[] cookies = new Cookie[mNumCookieCopies];
		for (int i = 0; i < cookies.length; i++) {
			cookies[i] = iTemplate.copy();
		}
		
		return cookies;
	}
	
	/**
	 * For the given cookie template, this method identifies the cookie placers
	 * to use.  For example, we might want to use a specialized placer for
	 * triangles and a generic placer for all other shapes.
	 */
	private CookiePlacer[] getBestCookiePlacers(Cookie iTemplate) {
		return new CookiePlacer[] {
			new SafeCookiePlacer(),
			//new ValueCorrectionPlacer(),
			new TrianglePlacer(),
			new StateSpacePlacer(),
			new PixelPlacer(),
		};
	}
	
	/**
	 * Stores cookies' positions and orientations in the move object.  Also,
	 * computes the rightmost boundary of the cookie set stores it in the move
	 * object.
	 */
	private void storeInMove(Cookie[] iCookies, Move iMove) {
		// compute the rightmost boundary
		double rightBoundary = Cookie.computeRightBoundary(iCookies);
		iMove.setRightBoundary(rightBoundary);
		
		try {		
			for (int i = 0; i < iCookies.length; i++) {
				iMove.setCookiePosition(i, iCookies[i].getCentroid(),
					iCookies[i].getRotation());
			}
		} catch (Exception ex) {
			System.err.println(ex);			
		}
	}
	
	private double getSpaceUtility(Cookie iTemplate, double iRightBoundary) {
		return (iTemplate.getArea() * mNumCookieCopies) / iRightBoundary;
	}

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

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