/*
	modernca.js - Javascript support for Modern Cellular Automata

	Written by George Maydwell
	Copyright (c) 2001, 2002 by Software Collidoscope Foundry.
	May be freely reproduced and modified.

Updates:
05/27/02 - Added support for synchronized experiments.
05/17/01 - Added stringRepeat function for making formations.
*/


/*								General Note

	A writerObject provides write(string) and writeln(string) methods.
	A document object is thus a writerObject. Writer objects are passed
	into Ca write methods, to give the Ca a place to write html strings. 
*/


// Helper function which writes an applet parameter to a writer object:
function Ca_writeParam(writerObject, paramNameString, paramValueString) {
	if (paramValueString) {
		writerObject.writeln(
			' <param name="' + paramNameString + '" value="' + paramValueString + '">')
	}
}


// Implement a Ca object's write method:
function Ca_write(writerObject, defaultCa) {

	// Don't worry about defaultCa == null:
	if (defaultCa == null) {
		defaultCa = this
	}

	var appletWidth = 256
	var appletHeight = 256

	var appletSize = this.appletSize ? this.appletSize : defaultCa.appletSize
	var zoom = this.zoom ? this.zoom : (defaultCa.zoom ? defaultCa.zoom : 2)
	var universeSize = this.universeSize ? this.universeSize
										 : (defaultCa.universeSize ? defaultCa.universeSize : '128,128')
	var dimensions
	if (appletSize == null) {
		dimensions = universeSize.split(',')
		if (dimensions.length > 1) {
			appletWidth = zoom * dimensions[0]
			appletHeight = zoom * dimensions[1]
		}
	} else {
		dimensions = appletSize.split(',')
		if (dimensions.length > 1) {
			appletWidth = dimensions[0]
			appletHeight = dimensions[1]
		}
	}

	if (this.caption) {
		// Use a table so that things line up correctly
		writerObject.writeln('<TABLE>')
		writerObject.writeln('<TR ALIGN="CENTER"><TD ALIGN="CENTER">')
	}

	writerObject.writeln('<APPLET' + (this.name ? (' NAME="' + this.name + '"') : ''))
	if (this.hexagonal) {
		writerObject.writeln(' CODEBASE="." ARCHIVE="modernca.jar" CODE="modernca.HexCa.class" ')
	} else {
		writerObject.writeln(' CODEBASE="." ARCHIVE="modernca.jar" CODE="modernca.Ca.class" ')
	}
	writerObject.writeln(' WIDTH="' + appletWidth + '" HEIGHT="' + appletHeight + '" ALIGN="middle">')
		
	
	Ca_writeParam(writerObject, "Ca", this.ca)
	Ca_writeParam(writerObject, "maximum Rate", this.maximumRate ? this.maximumRate : defaultCa.maximumRate)
	Ca_writeParam(writerObject, "Reset Bounds", this.resetBounds ? this.resetBounds : defaultCa.resetBounds)
	Ca_writeParam(writerObject, "Reset Formation", this.resetFormation ? this.resetFormation : defaultCa.resetFormation)
	Ca_writeParam(writerObject, "Reset Generation", this.resetGeneration ? this.resetGeneration : defaultCa.resetGeneration)
	Ca_writeParam(writerObject, "Reset Interval", this.resetInterval ? this.resetInterval : defaultCa.resetInterval)
	Ca_writeParam(writerObject, "Rule", this.rule ? this.rule : defaultCa.rule)
	Ca_writeParam(writerObject, "Rule Mutation Rate", this.ruleMutationRate ? this.ruleMutationRate : defaultCa.ruleMutationRate)
	Ca_writeParam(writerObject, "Universe Size", this.universeSize ? this.universeSize : defaultCa.universeSize)
	Ca_writeParam(writerObject, "Slave", this.slave)
	Ca_writeParam(writerObject, "Zoom", zoom != 2 ? zoom : null)

	writerObject.writeln('</APPLET>')

	if (this.caption) {
		writerObject.writeln('</TD></TR>')
		writerObject.writeln('<TR ALIGN="CENTER"><TD ALIGN="CENTER">' + this.caption)
		writerObject.writeln('</TD></TR>')
		writerObject.writeln('</TABLE>')
	}
	writerObject.writeln('')
}


// mcaSynchronize - Synchronizes a collection of ca for running
//	and resetting in lockstep.
function mcaSynchronize(caArray, masterIndex)
{
	// Default master index to the first ca in the input array
	if (!masterIndex) {
		masterIndex = 0
	}

	var caNames = new Array(caArray.length - 1)
	var currName = 0
	for (i = 0; i < caArray.length; i++) {
		if (i != masterIndex) {
			caArray[i].name = 'slave' + (currName + 1)
			caArray[i].slave = 'true'
			caNames[currName++] = caArray[i].name
		}
	}
	caArray[masterIndex].ca = caNames.join(' ')
}


// mcaMutationExperiment - Sets up a rule mutation experiment on a
//	collection of ca.
function mcaMutationExperiment(caArray, masterIndex)
{
	// Default master index to the first ca in the input array
	if (!masterIndex) {
		masterIndex = 0
	}

	for (i = 0; i < caArray.length; i++) {
		if (i != masterIndex) {
			caArray[i].rule = 'master'
		}
	}
	caArray[masterIndex].ruleMutationRate = '0.0' // use a string not a number!
}


// mcaWriteTable - Writes a table using a collection of ca.
function mcaWriteTable(writerObject, caArray, defaultCa, columns, rows)
{
	if (!rows) {
		rows = caArray.length / columns
	}

	writerObject.writeln('<TABLE>')

	for (row = 0; row < rows; row++) {
		writerObject.writeln('<TR>')
		for (col = 0; col < columns; col++) {
			writerObject.writeln('<TD>')
			caArray[row * columns + col].write(writerObject, defaultCa)
			writerObject.writeln('</TD>')
		}
		writerObject.writeln('</TR>')
	}

	writerObject.writeln('</TABLE>')
}


// A Ca object provides the means to create an applet with an
//	associated caption.
function Ca()
{
	// ca.write(writerObject, defaultCA) generates HTML for the CA applet
	this.write = Ca_write

// public: (these all correspond to applet parameters)
	this.appletSize = null
	this.maximumRate = null
	this.resetBounds = null
	this.resetFormation = null
	this.resetGeneration = null
	this.resetInterval = null
	this.rule = null
	this.ruleMutationRate = null
	this.universeSize = null
	this.caption = null
	this.zoom = null
	this.hexagonal = false

// private: (use mcaSynchronize and mcaMutationExperiment to set these up)
	this.name = null
	this.slave = null
	this.ca = null
}

