import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.Date;

public class Slider extends Applet implements Runnable
{
	static int[] clonecount = { 0, 0 };	// [1] is solved flag
	final String NAME = "Slider";
	final String VERSION = "Version 1.0";
	final String COPYWRITE = "\u00A9 1997 wcb@lucent.com";

	// default dimensions & resize detection for stand-alone
	int m_width = 120;
	int m_height = 150;

	// PARAMETER SUPPORT:
	int m_tilecolor = 0x808080;
	private final String PARAM_tilecolor = "tilecolor";
	int m_boardcolor = 0;
	private final String PARAM_boardcolor = "boardcolor";
	int m_shimcolor = 0xc0c0c0;
	private final String PARAM_shimcolor = "shimcolor";

	private Thread m_Thread = null;
	boolean m_fStandAlone = false;

	Panel buttons;			// reset & about
	SliderBox puzzle;		// model of the physical puzzle
	SliderAbout about;		// about dialog
	Point aboutloc;			//   & its location
	int moves;				// since last reset
	int timer;				// seconds since last reset
	boolean winner;			// solved since last reset
	boolean bigwinner;		// big tile centered on bottom
	boolean solving;		// busy showing solution
	boolean solved;			// solution revealed

	public static void main(String args[])	// iff stand-alone
	{
		Slider slider = new Slider();
		slider.m_fStandAlone = true;
		slider.GetParameters(args);
		slider.init();

		AppletFrame frame = new AppletFrame("Slider", slider, clonecount);
		// Must show Frame before we size it so insets() will return valid values
		frame.show();
		frame.hide();
		frame.setBackground(new Color(slider.m_shimcolor));
//		frame.setIconImage(slider.createIcon());	// WHY doesn't this work!?!?
		frame.resize(frame.insets().left + frame.insets().right + slider.m_width,
					 frame.insets().top + frame.insets().bottom + slider.m_height);
		frame.add("Center", slider);
		slider.start();
		frame.show();
	}

	public Slider()
	{
		about = null;
		aboutloc = new Point(0,0);
		winner = bigwinner = false;
		solved = solving = false;
	}

	public void init()
	{
		if (!m_fStandAlone)	// otherwise done in main()
			GetParameters(null);
		setFont(new Font("Helvetica", Font.PLAIN, 12));
		buttons = new Panel();
		buttons.setLayout(new GridLayout(1,2));
		buttons.add(new Button("Reset"));
		buttons.add(new Button("About"));
		puzzle = new SliderBox(this);
		setLayout(new BorderLayout());
		add("North",buttons);
		add("Center",puzzle);
		moves = 0;
	}

	public void start() {
		if (moves!=0 && m_Thread == null) {
			m_Thread = new Thread(this);
			m_Thread.start();
		}
	}
	
	public void stop() {
		if (m_Thread != null) {
			m_Thread.stop();
			m_Thread = null;
		}
		if (about!=null) {
			about.dispose();
			about = null;
		}
	}

	public void destroy() {
		// TODO: Place applet cleanup code here
	}

	public void run() {	// what m_Thread executes
		while (true) {
			try {
				if (winner) {
					if (bigwinner) puzzle.repaint();
					Thread.sleep(200);
				}
				else if (solving) {
					for (int i=0; i<solution.length; i++) {
						Thread.sleep(50);
						puzzle.movetile(solution[i]&0x0f,solution[i]>>4,2,false);
						puzzle.repaint();
						Thread.sleep(50);
						puzzle.movetile(solution[i]&0x0f,solution[i]>>4,2,true);
						puzzle.repaint();
					}
					solving = false;
					if (about != null) about.clonebutton.enable();
					m_Thread = null;
					return;	// (terminates thread)
				}
				else {
					if (about!=null) about.displaytime(timer);
					Thread.sleep(1000);
					timer++;
				}
			}
			catch (InterruptedException e) {
				// TODO: Place exception-handling code here in case an
				//       InterruptedException is thrown by Thread.sleep(),
				//		 meaning that another thread has interrupted this one
				stop();
			}
		}
	}

	void reset() {
		if (m_Thread != null) {
			m_Thread.stop();
			m_Thread = null;
		}
		winner = bigwinner = false;
		solved = solving = false;
		timer = 0;
		moves = 0;
		puzzle.reset();
		puzzle.repaint();
		if (about!=null) {
			about.displaywipe();
			about.clonebutton.enable();
		}
	}

	public boolean action(Event evt, Object arg) {
		if (arg.equals("Reset")) {
			reset();
			return true;
		}
		else if (arg.equals("About")) {
			if (about == null) {
				about = new SliderAbout(this);
				if (moves != 0) about.displaymoves(moves);
			}
			else about.next();
			return true;
			}
		return false;
	}

	void addmove() {
		if (m_Thread == null)
		{
			m_Thread = new Thread(this);
			m_Thread.start();
		}
		if (moves >= 0) moves++;
		if (about!=null) about.displaymoves(moves);
	}

	static final byte[] solution = {

		0x11, 0x06, 0x36, 0x08, 0x08, 0x14, 0x26, 0x26, 0x38, 0x28,
		0x31, 0x31, 0x07, 0x17, 0x09, 0x09, 0x14, 0x18, 0x28, 0x21,
		0x39, 0x39, 0x37, 0x37, 0x04, 0x05, 0x18, 0x18, 0x16, 0x16,
		0x21, 0x27, 0x37, 0x34, 0x35, 0x23, 0x23, 0x10, 0x04, 0x04,
		0x35, 0x33, 0x08, 0x08, 0x16, 0x06, 0x11, 0x11, 0x27, 0x17,
		0x29, 0x29, 0x35, 0x33, 0x36, 0x06, 0x01, 0x17, 0x17, 0x19,
		0x19, 0x25, 0x23, 0x36, 0x36, 0x38, 0x38, 0x01, 0x09, 0x19,
		0x13, 0x28, 0x28, 0x24, 0x24, 0x12, 0x06, 0x06, 0x05, 0x05,
		0x38, 0x08, 0x24, 0x22, 0x16, 0x05, 0x08, 0x34, 0x22, 0x22,
		0x18, 0x25, 0x36, 0x08, 0x08, 0x02, 0x02, 0x33, 0x39, 0x29,
		0x21, 0x20, 0x18, 0x18, 0x16, 0x16, 0x05, 0x04, 0x02, 0x03,
		0x39, 0x39, 0x37, 0x37, 0x21, 0x20, 0x26, 0x16, 0x12, 0x03,
		0x03, 0x30, 0x26, 0x26, 0x28, 0x28, 0x12, 0x13, 0x15, 0x04,
		0x04, 0x30, 0x36, 0x06, 0x01, 0x17, 0x17, 0x19, 0x19, 0x20,
		0x36, 0x36, 0x38, 0x38, 0x01, 0x09, 0x19, 0x10

		};

	void showsolution() {
		if (clonecount[1]++ != 0) return;
		int width =puzzle.width;
		int height = puzzle.height;
		reset();
		puzzle.resize(width,height);
		if (about!=null) {
			about.clonebutton.disable();
			about.displaymoves(moves = -1);
			about.displaytime(timer);
		}
		solved = solving = true;
		start();	// start solution (in run())
	}



	public String getAppletInfo() {
		return NAME + "\r\n" + VERSION + "\r\n" + COPYWRITE;
	}

	public String[][] getParameterInfo() {
		String[][] info =
		{
			{ PARAM_tilecolor, "int", "RGB value, default=0,128,192" },
			{ PARAM_boardcolor, "int", "RGB value, default=192,192,192" },
			{ PARAM_shimcolor, "int", "RGB value, default=0,0,0" },
		};
		return info;		
	}

	void GetParameters(String args[]) {
		String param;
		int i;

		param = GetParameter(PARAM_tilecolor, args);
		if (param != null)
			if ((i = rgb2int(param)) != -1)
				m_tilecolor = i;

		param = GetParameter(PARAM_boardcolor, args);
		if (param != null)
			if ((i = rgb2int(param)) != -1)
			m_boardcolor = i;

		param = GetParameter(PARAM_shimcolor, args);
		if (param != null)
			if ((i = rgb2int(param)) != -1)
			m_shimcolor = i;
	}

	static int rgb2int(String s) {
		int rgb[] = { 0,0,0 };
		int i = 0;
		try {
			for (int j=0; j<s.length(); j++) {
				char c = s.charAt(j);
				if (c==' ') continue;
				if (c==',') {
					i++;
					continue;
				}
				int x = c - '0';
				if (x<0 || x>9) return -1;
				if ((rgb[i] = 10*rgb[i]+x) > 255) return -1;
			}
			if (i != 2) return -1;
			return (rgb[0]<<16) + (rgb[1]<<8) + rgb[2];
		}
		catch (Exception e) {
			return -1;
		}
	}
	
	String GetParameter(String strName, String args[]) {
		if (args == null)
		{
			// Running within an HTML page, so call original getParameter().
			return getParameter(strName);
		}

		// Running as standalone application, so parameter values are obtained from
		// the command line. The user specifies them as follows:
		//
		//	JView Slider param1=<val> param2="<val with spaces>" ...
		//-----------------------------------------------------------------------
		int    i;
		String strArg	= strName + "=";
		String strValue = null;
		int    nLength  = strArg.length();

//		try
//		{
			for (i = 0; i < args.length; i++)
			{
				String strParam = args[i].substring(0, nLength);

				if (strArg.equalsIgnoreCase(strParam))
				{
					strValue = args[i].substring(nLength);
					if (strValue.startsWith("\""))			// remove surrounding quotes
					{
						strValue = strValue.substring(1);
						if (strValue.endsWith("\""))
							strValue = strValue.substring(0, strValue.length() - 1);
					}
					break;
				}
			}
//		}
//		catch (Exception e)
//		{
			// TODO: Place exception-handling code here in case an
//		}

		return strValue;
	}

	Image createIcon() {

		byte pattern[] = {	0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							0,1,2,2,1,2,2,2,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,2,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,2,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,2,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,2,2,2,1,2,2,1,0,0,
							0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							0,1,1,1,1,2,2,2,2,2,1,1,1,1,0,0,
							0,1,1,1,1,2,2,2,2,2,1,1,1,1,0,0,
							0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
							0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
							0,1,2,2,1,1,1,1,1,1,1,2,2,1,0,0,
							0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
							0,1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
							0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0		};

		int color[] = new int[3];
		color[0] = 0;	// transparent!
		color[1] = 255<<24 | m_boardcolor;
		color[2] = 255<<24 | m_tilecolor;

		int[] icon = new int[1024];
		for (int i = 0; i < 256; i++) {
			int j = ((i/16)*64) + ((i%16)*2);
			icon[j] = icon[j+1] = icon[j+32] = icon[j+33] = color[pattern[i]];
		}
		return createImage(new MemoryImageSource(32,32,icon,0,32));
	}

}

