/**
* @(#)UnrollTransition.java
* @version 1.51 04/06/97
* @author Robert Temple (robertt@starwave.com)
*/

import java.awt.image.MemoryImageSource;
import java.awt.*;
import java.util.Hashtable;

/**
* The UnrollTransition class changes one image into another by setting a roll
* which is the new image on top of the old image, and then unrolling the new
* image until it covers the old image.
*/
public class UnrollTransition extends BillTransition {
// Static Members
	/**
	* The total number of CELLS this transition will show on the screen before
	* the new image is shown in its entirety
	*/
	final static int CELLS = 9;

	/** array of three pixels used to fill in the right hand side of the roll */
	static int fill_pixels[] = { 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF };

	/**
	 * Creates a unroll array used later to create cells.
	 * This array is used to determine how many verticle pixels to unroll
	 * the image for each cell.
	 */
	private static int[] createUnrollAmountArray(int cell_h) {
		

		// The First line of the statement below determines that average
		// amount each cell must unroll the image in order to completely
		// unroll the image during the transition.  Note that we add one
		// to the CELLS count because the drawing of the whole next
		// image to the screen is part of the unrolling process too.
		// the second line determines the location the across the x-axis
		// that this average will fall if the first cell starts at a
		// x point of 1.  This is why one more is added to cells
		// then the top.
		// The divide determines the slope of the line from (0,0) to
		// (x_avg, y_avg)
		// if you are confused here, don't worry, so was I...  but
		// it works...
		float unroll_increment = ((float)cell_h / (float)(CELLS + 1)) /
					((float)(CELLS + 2) / 2.0f);

		int total = 0;
		int unroll_amount[] = new int[CELLS + 1];
		for(int u = 0; u <= CELLS; ++u) {
			unroll_amount[u] = (int)(unroll_increment * (CELLS - u + 1));
			total += unroll_amount[u];
		}

		// make sure we did not round our way to unrolling more of the
		// image then there is to unroll
		if(total < 0) {
			unroll_amount[0] -= 1;
		}

		return unroll_amount;
	}

	/**
	* An array which holds the amount of verticle pixels to unroll the image
	* each cell.
	*/
	int[] unroll_amount;

// Instance Members
	/** The index into the work_pixel array that the start of the roll is at */
	int location;

	/**
	* Used to initialize the transition right after it is created.
	* creates cells
	* @param owner the component to be used to create images from cells
	*/
	public void init(Component owner, int[] current, int[] next) {
		init(owner, current, next, CELLS, 220);

		location = pixels_per_cell;

		System.arraycopy((Object)current_pixels, 0, (Object)work_pixels, 
					0, pixels_per_cell);
		
		// get the random array for an applet of this height from the object table.
		unroll_amount = (int[])object_table.get(getClass().getName() + cell_h);

		// if the random array is not found, create it and put it in the 
		// object table.
		if(unroll_amount == null) {
			unroll_amount = createUnrollAmountArray(cell_h);
			object_table.put(getClass().getName() + cell_h, unroll_amount);
		}

		for(int c = 0; c < CELLS; ++c) {

			// unroll the image
			location -= unroll_amount[c] * cell_w;

			// give other threads a shot at the CPU
			try { Thread.sleep(150); } catch (InterruptedException e) {}

			// create the next cell
			Unroll(c);

			// give other threads a shot at the CPU
			try { Thread.sleep(100); } catch (InterruptedException e) {}

			// create the new cell image from the work pixels
			createCellFromWorkPixels(c);

			// copy over the new image onto where the roll last appeared
			System.arraycopy((Object)next_pixels, location,
						(Object)work_pixels, location, unroll_amount[c] * cell_w);
		}

		// we don't need the work pixels anymore
		work_pixels = null;
	}

	/** 
	* Create the next cell in the work pixel array 
	*/
	void Unroll(int c) {

		int y_flip = cell_w;

		// the offset is what makes the roll appear to be raised up
		int offset[] = new int[unroll_amount[c]];
		for(int o = 0; o < unroll_amount[c]; ++o) {
			offset[o] = 4;
		}
		offset[0] = 2;

		if(unroll_amount[c] > 1) {
			offset[1] = 3;
		}
		if(unroll_amount[c] > 2) {
			offset[unroll_amount[c] - 1] = 2;
		}
		if(unroll_amount[c] > 3) {
			offset[unroll_amount[c] - 2] = 3;
		}

		int offset_index = 0;
		int end_location = location + unroll_amount[c] * cell_w;
		for(int p = location; p < end_location; p += cell_w) {

			System.arraycopy((Object)next_pixels, 
						p - y_flip + offset[offset_index], (Object)work_pixels,
						p, cell_w - offset[offset_index]);

			// draw in the right side of the roll
			System.arraycopy((Object)fill_pixels, 0, (Object)work_pixels,
						p + cell_w - offset[offset_index], offset[offset_index]);

			++offset_index;

			y_flip += cell_w + cell_w;

		}

		// cheesy way but kinda fast to make the roll appear more 3D.
		for(int x = location + cell_w - 1; x > location; --x) {
			work_pixels[x] |= 0xFFAAAAAA;
			work_pixels[x + unroll_amount[c]] &= 0xFF555555;
		}

	}
}


