package tiongson.intnar;import java.util.*;import java.awt.*;import java.applet.*;import java.net.*;import java.io.*;import java.awt.image.*;import tiongson.util.*;	public class Hindsight extends Applet implements Runnable {	Thread player;		Script[] scripts;		NameDrawer[] drawer;		Image[] images;	Image[] transimages;	public String getAppletInfo() {		return "Hindsight v0.01, coded by Phillip Tiongson (C) 1996 MIT Media Lab";	}	public void start() {		player.start();	} // start		public void stop() {		player.stop();					scripts[0].stop();		scripts[1].stop();		scripts[2].stop();		scripts[3].stop();						thetimeline.stop();	} // stop		public void destroy() {		scripts[0].stop();		scripts[1].stop();		scripts[2].stop();		scripts[3].stop();				thetimeline.stop();				scripts[0] = null;		scripts[1] = null;		scripts[2] = null;		scripts[3] = null;						thetimeline = null;		player.stop();		player = null;	} // destroy	boolean started = false;	Font[] f;	FontMetrics[] fm;	long starttime;	Color grey;	ImageFilter[] trans;		public void init() {			starttime = System.currentTimeMillis();		initme = true;		started = false;		done = false;		credits = null;		theDate = new Date();		lastImage = new Image[3];				Utils.dPrint("Initializing . . . .");			this.setBackground(Color.black);		this.setForeground(Color.white);		this.setFont(new Font("Helvetica", Font.PLAIN, 10));				grey = new Color(0xEEEEEE);				f = new Font[3];				f[0] = new Font("Helvetica", Font.PLAIN, 10);		f[1] = new Font("Helvetica", Font.PLAIN, 40);		f[2] = new Font("Courier", Font.PLAIN, 9);						fm = new FontMetrics[3];		fm[0] = Toolkit.getDefaultToolkit().getFontMetrics(f[0]);		fm[1] = Toolkit.getDefaultToolkit().getFontMetrics(f[1]);		fm[2] = Toolkit.getDefaultToolkit().getFontMetrics(f[2]);				trans = new ImageFilter[256]; 		for (int i = 0; i < 256; i++) {			trans[i] = new genTransFilter(i);		} // for				player = new Thread(this);				drawer = new NameDrawer[4];		scripts = new Script[4];		thetimeline = new TimeLine(this, scripts);		scripts[0] = new Script(17, this, "d");		scripts[0].start();		drawer[0] = new NameDrawer(scripts[0], 340, 40);				scripts[1] = new Script(17, this, "p");		scripts[1].start();		drawer[1] = new NameDrawer(scripts[1], 370, 40);					scripts[2] = new Script(20, this, "b");		scripts[2].start();		drawer[2] = new NameDrawer(scripts[2], 400, 40);				scripts[3] = new Script(21, this, "m");		scripts[3].start();		drawer[3] = new NameDrawer(scripts[3], 430, 40);				showStatus("The actors are ready. . . . .");						// load images returns a Vector, must copy that into an		// array, then the local Vector gets garbage collected.		Vector tempimages = loadImages();				images = new Image[21];				for(int i = 0; i < 21; i++) {			images[i] = (Image) tempimages.elementAt(i);		}			//transimages = makeTransImages(images);		credits = new Credit(this);		initme = false;		tempI = new Image[4][256];		Utils.dPrint("Loaded the Bastard.");		} // init	Image currentImage, prevImage, nextImage;	TimeLine thetimeline;	Date theDate;	public void run() {		Utils.dPrint("Running . . . .");				while(!started) {					try{				repaint();				player.sleep(300);			} catch (Exception e) {}				} // while				thetimeline.start();				} // run	Credit credits;	public void runCredits() {			if (!done) {			done = true;			repaint();			credits.start();						scripts[0].stop();			scripts[1].stop();			scripts[2].stop();			scripts[3].stop();				thetimeline.stop();					}	}	public void update(Graphics g) { 	// to prevent flicker			paint(g);	} // update 			// These are for the offscreen drawing buffer.	Image offscreen;    Dimension offscreensize;    Graphics offgraphics;			/** This method overrides the paint method. It double buffers the drawing by drawing first	to the offscreen buffer, then blasting it to the Graphics g.	*/		boolean done = false;	boolean initme = true;	int myactive;	Image[] lastImage;	int whichImage = 0;	int[] lastState = {0, 0, 0};	int[] cacheState = {0, 0, 0};		int showing = 0;	int shading = 0;	Image tempI[][];	boolean clearwhole = true;		public void paint(Graphics g) {			// temp variable for current screen size.		Dimension d = size();				// if no offscreen buffer image, make a new one		if ((offscreen == null) || (d.width != offscreensize.width) 			|| (d.height != offscreensize.height)) {						offscreen = createImage(d.width, d.height);			offscreensize = d;			offgraphics = offscreen.getGraphics();			offgraphics.setFont(getFont());		}					if (initme) { 			offgraphics.setColor(Color.blue);				offgraphics.fillRect(5, 10, 10*scripts[0].lines.length, 20);			offgraphics.fillRect(5, 60, 10*scripts[1].lines.length, 20);			offgraphics.fillRect(5, 110, 10*scripts[2].lines.length, 20);				offgraphics.fillRect(5, 160, 10*scripts[3].lines.length, 20);									offgraphics.setColor(Color.green);			offgraphics.fillRect(5, 10, 10*scripts[0].i, 20);			offgraphics.fillRect(5, 60, 10*scripts[1].i, 20);			offgraphics.fillRect(5, 110, 10*scripts[2].i, 20);			offgraphics.fillRect(5, 160, 10*scripts[3].i, 20);									offgraphics.setColor(Color.red);			for(int i = 5; i<350 ; i += 20) {				offgraphics.fillRect(i, 0, 2, 150);			}					offgraphics.setColor(getForeground());				drawer[0].paintstatus(offgraphics);			drawer[1].paintstatus(offgraphics);			drawer[2].paintstatus(offgraphics);				drawer[3].paintstatus(offgraphics);							}				// clear the screen		//if (clearwhole) {		offgraphics.setColor(getBackground());		offgraphics.fillRect(0, 0, d.width, d.height);		//	clearwhole = false;		/*} else {			offgraphics.setColor(getBackground());			// offgraphics.clipRect(0, 150, d.width, d.height);			offgraphics.fillRect(0, 150, d.width, d.height);		}*/						if (!done) {			if (!initme) {							//int myactive = thetimeline.getCurrentActiveImage();							Image temp = images[myactive];				int h = images[myactive].getHeight(this);				int w = images[myactive].getWidth(this);									if (temp != lastImage[whichImage]) {					whichImage = (whichImage + 1)%3;					lastImage[whichImage] = temp;					lastState[(whichImage+2)%3] = (int) Math.max(0, lastState[(whichImage+2)%3] * .95);					lastState[whichImage] = 355;					tempI[whichImage] = new Image[256]; 					// Utils.dPrint("0: "+lastState[0]+" 1: "+lastState[1]+ " 2:"+lastState[2]);				}				showing++;				for (int i = 0; i < lastImage.length; i++) {					if (lastImage != null) {												if ((showing%3) == 0) {							lastState[i] = (int) Math.max(0, lastState[i] * .95);						} 																		int index = lastState[i]/70;						//if (cacheState[i] != index) {						//	cacheState[i] = index;							clearwhole = true;													if (lastState[i] > 25) {																			if (lastState[i] < 200) {																										if (tempI[i][index*70] == null) {										ImageProducer producer1 = new FilteredImageSource(lastImage[i].getSource(), trans[index*70]);										tempI[i][index*70] = createImage(producer1);									}									offgraphics.drawImage(tempI[i][index*70], ((i*2 + 1)*(d.width/6)) - w/2, 25, this);									//Utils.dPrint(i+" index: "+index);								} else {									offgraphics.drawImage(lastImage[i], ((i*2 + 1)*(d.width/6)) - w/2, 25, this);								} //else greater than 200							} // less then 25 don't draw							//}											} // not null				} // all images								//Utils.dPrint("0: "+lastState[0]+" 1: "+lastState[1]+ " 2:"+lastState[2]);								drawer[0].playing = false;				drawer[1].playing = false;				drawer[2].playing = false;					drawer[3].playing = false;												drawer[thetimeline.active].playing = true;			}// if								offgraphics.setFont(f[2]);				offgraphics.setColor(grey);			int h = fm[2].getHeight();						theDate = new Date();						offgraphics.drawString(theDate.toString(), 10, 220+h);			theDate = new Date();						theDate.setHours((theDate.getHours() + 2) % 24);			offgraphics.drawString(theDate.toString(), 10, 235+h);			theDate = new Date();				theDate.setYear((theDate.getYear() + 10));					offgraphics.drawString(theDate.toString(), 10, 250+h);							int w = fm[2].stringWidth(theDate.toString());			int width = offscreensize.width - 40 - w;						drawer[0].paint(offgraphics, w+20, 220, width);			drawer[1].paint(offgraphics, w+20, 235, width);			drawer[2].paint(offgraphics, w+20, 250, width);				if (thetimeline.resets > 0) {				drawer[3].paint(offgraphics, w+20, 265, width);							offgraphics.setFont(f[2]);					offgraphics.setColor(grey);						theDate = new Date();								theDate.setMonth((theDate.getMonth() + 2) % 12);				offgraphics.drawString(theDate.toString(), 10, 265+h);					}							}				if (done) {			credits.paint(offgraphics);				}				if (!started) {				offgraphics.setColor(new Color(0xEEEEEE));									offgraphics.setFont(f[1]);			offgraphics.drawString("hindsight", 130, 70);							int col = (int)(127 * Math.sin((System.currentTimeMillis()-starttime)*Math.PI/6000.0));			col += 127;			Color c = new Color(col,col,col);			offgraphics.setColor(c);					offgraphics.drawString("(4)", 140 - fm[1].stringWidth("(4)")/2, 100+fm[1].getHeight() - fm[1].getDescent() + 4);								offgraphics.setFont(f[0]);			offgraphics.drawString("a story in", 140 - fm[0].stringWidth("a story in")/2, 100);			offgraphics.drawString("threads", 140 - fm[0].stringWidth("threads")/2, 100 + fm[1].getHeight()+fm[0].getHeight());						offgraphics.drawString("click to choose a thread", 10, 190);			offgraphics.drawString("click to start. . . . ", 10, 190+fm[0].getHeight());						offgraphics.setColor(new Color(0xEEEEEE));			offgraphics.drawString("(please wait for images below to load)", 300, 190);		} // !started		// Blast image to Graphics g.		g.drawImage(offscreen, 0, 0, null);	} // paint		public void fade() {		//showing++;		//shading = 0;	}		public boolean mouseUp(Event evt, int x, int y) {			if (!started && !initme) {			started = true;		} else if (drawer[TimeLine.DIALOGUE].inside(x, y)) {			thetimeline.switchto(TimeLine.DIALOGUE);		} else if (drawer[TimeLine.PHONE].inside(x, y)) {			thetimeline.switchto(TimeLine.PHONE);		} else if (drawer[TimeLine.BED].inside(x, y)) {			thetimeline.switchto(TimeLine.BED);		} else if ((thetimeline.resets > 0) && (drawer[TimeLine.MATT].inside(x, y))) {			thetimeline.switchto(TimeLine.MATT);		}				if (done) init();				repaint();		return true;	}		public boolean handleEvent(Event event) {					if (event.id == Event.KEY_PRESS) {			// Find out the delete character on the DECS!			// Utils.dPrint("Got a key: "+(char)event.key);					switch((char) event.key){				case '1':					thetimeline.switchto(TimeLine.DIALOGUE);					break;				case '2':					thetimeline.switchto(TimeLine.PHONE);					break;				case '3':					thetimeline.switchto(TimeLine.BED);					break;				case '4':					thetimeline.switchto(TimeLine.MATT);					break;				case 'q':					runCredits();					break;				} // switch			repaint();			return true;		} //if				return super.handleEvent(event);	} // handleEvent 			protected MediaTracker transTracker;		public Image[] makeTransImages(Image[] theImages) {			transTracker = new MediaTracker(this);		Image[] temp = new Image[theImages.length*3];						int i = 0;		for (i = 0; i < theImages.length; i++) {			Utils.dPrint("Made Transparent: " +i);			if (theImages[i] != null) {	        	ImageProducer producer1 = new FilteredImageSource(theImages[i].getSource(), trans[0]);	        	temp[i] = createImage(producer1);	        	transTracker.addImage(temp[i], i);	        		        	ImageProducer producer2 = new FilteredImageSource(theImages[i].getSource(), trans[1]);	        	temp[i+theImages.length] = createImage(producer2);	        	transTracker.addImage(temp[i+theImages.length], i+theImages.length);	        	    	       		ImageProducer producer3 = new FilteredImageSource(theImages[i].getSource(), trans[2]);	        	temp[i+(theImages.length*2)] = createImage(producer3);	        	transTracker.addImage(temp[i+(theImages.length*2)], i+(theImages.length*2));    		        }        }                      // Part Deux. MediaTracker forces the loading of images. . . .		for (i = 0; i < theImages.length*3; i++) {			showStatus("Warming up the Transparent TV. #" + i +"/"+theImages.length);			try { 				transTracker.waitForID(i); 			} // try			catch (InterruptedException e) { 				System.out.println("Got interrupted while waiting.");			} // catch			if (tracker.isErrorID(i)) {				System.out.println("You suck. We can't get image "+ i);			} // if		} // for            		return temp;	}		/*=**********************************************************************************************************************/	protected MediaTracker tracker;		private Vector loadImages() {		// get the images using a MediaTracker		tracker = new MediaTracker(this);		Vector loaded = new Vector();		// Must contain the Parameter names for the images to be loaded.		String IMAGEPATH = "jpeg/";		String[] toLoad = new String[21];				for (int i = 0; i < 17; i++) {			toLoad[i] = (i+1) + ".JPG";		} 				toLoad[17] = "title1.JPG";		toLoad[18] = "title2.JPG";				toLoad[19] = "title3.JPG";		toLoad[20] = "title4.JPG";		/*		for (int i = 0; i < 17; i++) {			toLoad[i+21] = "t" + (i+1) + ".JPG";		} 		*/				// Two stage process. 		// First make URLs, and get the images.			// Next, add them to the Tracker and force loading.		for (int i = 0; i < toLoad.length; i++) {			URL theURL = null;			String theName = toLoad[i];			if (theName != null) { 				try {					theURL = new URL(getDocumentBase(), IMAGEPATH+theName); 				} // try				catch (MalformedURLException e) {					System.out.println("You suck. That was a bad URL: "+e);				} // catch				Image theImage = getImage(theURL);				loaded.addElement(theImage);				tracker.addImage(theImage, i);			} // if		} // for		// Part Deux. MediaTracker forces the loading of images. . . .		for (int i = 0; i < toLoad.length; i++) {			showStatus("Warming up the TV. #" + i +"/"+toLoad.length);			try { 				tracker.waitForID(i); 			} // try			catch (InterruptedException e) { 				System.out.println("Got interrupted while waiting.");			} // catch			if (tracker.isErrorID(i)) {				System.out.println("You suck. We can't get image "+ toLoad[i]);			} // if		} // for					showStatus("The TV is warm.");				return loaded;	} // loadImages} // playerThreadedApplet