@SuppressWarnings("unchecked")
	void isosurface(int iShape) throws ScriptException {
		viewer.loadShape(iShape);
		viewer.setShapeProperty(iShape, "init", getCommand());
		viewer.setShapeProperty(iShape, "title", new String[] { script });
		int colorRangeStage = 0;
		int signPt = 0;
		boolean surfaceObjectSeen = false;
		boolean planeSeen = false;
		float[] nlmZ = new float[5];
		String str;
		int modelIndex = viewer.getDisplayModelIndex();
		if (modelIndex < 0)
			evalError(GT._("the {0} command requires that only one model be displayed", "ISOSURFACE"));
		for (int i = 1; i < statementLength; ++i) {
			String propertyName = null;
			Object propertyValue = null;
			Token token = statement[i];
			switch (token.tok) {
			case Token.select:
				propertyName = "select";
				++i;
				propertyValue = expression(statement, i + 1);
				i = pcLastExpressionInstruction;
				break;
			case Token.center:
				propertyName = "center";
				switch (statement[++i].tok) {
				case Token.dollarsign:
					String id = objectNameParameter(++i);
					propertyValue = viewer.getDrawObjectCenter(id);
					if (propertyValue == null)
						drawObjectNotDefined(id);
					break;
				case Token.expressionBegin:
				case Token.leftbrace:
					propertyValue = atomCenterOrCoordinateParameter(i);
					i = pcLastExpressionInstruction;
					break;
				default:
					coordinateOrNameOrExpressionRequired();
				}
				break;
			case Token.color:
				/*
				 * "color" now is just used as an equivalent to "sign" and as an introduction to "absolute" any other
				 * use is superfluous; it has been replaced with MAP for indicating "use the current surface" because
				 * the term COLOR is too general.
				 */
				if (i + 1 == statementLength)
					invalidArgument(i, " COLOR keyword not in context");
				colorRangeStage = 0;
				switch (statement[i + 1].tok) {
				case Token.absolute:
					++i;
					colorRangeStage = 1;
					continue;
				case Token.colorRGB:
					signPt = i + 1;
				}
				continue;
			case Token.file:
				continue;
			case Token.plus:
				if (colorRangeStage == 0) {
					propertyName = "cutoffPositive";
					propertyValue = new Float(floatParameter(++i));
				}
				break;
			case Token.decimal:
			case Token.integer:
				// default is "cutoff"
				propertyName = (colorRangeStage == 1 ? "red" : colorRangeStage == 2 ? "blue" : "cutoff");
				propertyValue = new Float(floatParameter(i));
				if (colorRangeStage > 0)
					++colorRangeStage;
				break;
			case Token.colorRGB:
				if (i != signPt && i != signPt + 1)
					invalidParameterOrder();
				propertyName = "colorRGB";
				propertyValue = new Integer(getArgbParam(i));
				break;
			case Token.ionic:
				propertyName = "ionicRadius";
				propertyValue = new Float(radiusParameter(++i, 0));
				i = pcLastExpressionInstruction;
				break;
			case Token.vanderwaals:
				propertyName = "vdwRadius";
				propertyValue = new Float(radiusParameter(++i, 0));
				i = pcLastExpressionInstruction;
				break;
			case Token.identifier:
				str = (String) token.value;
				if (str.equalsIgnoreCase("REMAPPABLE")) { // testing only
					propertyName = "remappable";
					break;
				}
				if (str.equalsIgnoreCase("IGNORE")) {
					propertyName = "ignore";
					++i;
					propertyValue = expression(statement, i + 1);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("CUTOFF")) {
					if (++i < statementLength && statement[i].tok == Token.plus) {
						propertyName = "cutoffPositive";
						propertyValue = new Float(floatParameter(++i));
					}
					else {
						propertyName = "cutoff";
						propertyValue = new Float(floatParameter(i));
					}
					break;
				}
				if (str.equalsIgnoreCase("SCALE")) {
					propertyName = "scale";
					propertyValue = new Float(floatParameter(++i));
					break;
				}
				if (str.equalsIgnoreCase("ANGSTROMS")) {
					propertyName = "angstroms";
					break;
				}
				if (str.equalsIgnoreCase("RESOLUTION")) {
					propertyName = "resolution";
					propertyValue = new Float(floatParameter(++i));
					break;
				}
				if (str.equalsIgnoreCase("ANISOTROPY")) {
					propertyName = "anisotropy";
					propertyValue = getCoordinate(i + 1, false);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("ECCENTRICITY")) {
					propertyName = "eccentricity";
					propertyValue = getPoint4f(i + 1);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("FIXED")) {
					propertyName = "fixed";
					propertyValue = Boolean.TRUE;
					break;
				}
				if (str.equalsIgnoreCase("MODELBASED")) {
					propertyName = "fixed";
					propertyValue = Boolean.FALSE;
					break;
				}
				if (str.equalsIgnoreCase("SIGN")) {
					signPt = i + 1;
					propertyName = "sign";
					propertyValue = Boolean.TRUE;
					colorRangeStage = 1;
					break;
				}
				if (str.equalsIgnoreCase("INSIDEOUT")) { // no longer of use?
					propertyName = "insideOut";
					break;
				}
				if (str.equalsIgnoreCase("REVERSECOLOR")) {
					propertyName = "reverseColor";
					propertyValue = Boolean.TRUE;
					break;
				}
				if (str.equalsIgnoreCase("ADDHYDROGENS")) {
					propertyName = "addHydrogens";
					propertyValue = Boolean.TRUE;
					break;
				}
				if (str.equalsIgnoreCase("COLORSCHEME")) {
					propertyName = "setColorScheme";
					propertyValue = stringParameter(++i);
					break;
				}
				if (str.equalsIgnoreCase("DEBUG") || str.equalsIgnoreCase("NODEBUG")) {
					propertyName = "debug";
					propertyValue = (str.equalsIgnoreCase("DEBUG") ? Boolean.TRUE : Boolean.FALSE);
					break;
				}
				if (str.equalsIgnoreCase("GRIDPOINTS")) {
					propertyName = "gridPoints";
					break;
				}
				if (str.equalsIgnoreCase("CONTOUR")) {
					propertyName = "contour";
					propertyValue = new Integer(
							i + 1 < statementLength && statement[i + 1].tok == Token.integer ? intParameter(++i) : 0);
					break;
				}
				if (str.equalsIgnoreCase("PHASE")) {
					propertyName = "phase";
					propertyValue = (i + 1 < statementLength && statement[i + 1].tok == Token.string ? stringParameter(++i)
							: "_orb");
					break;
				}
				// surface objects
				if (str.equalsIgnoreCase("MAP")) { // "use current"
					surfaceObjectSeen = true;
					propertyName = "map";
					break;
				}
				if (str.equalsIgnoreCase("plane")) {
					// plane {X, Y, Z, W}
					planeSeen = true;
					propertyName = "plane";
					propertyValue = planeParameter(++i);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("hkl")) {
					// miller indices hkl
					planeSeen = true;
					propertyName = "plane";
					propertyValue = hklParameter(++i);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("sphere")) {
					// sphere [radius]
					surfaceObjectSeen = true;
					propertyName = "sphere";
					propertyValue = new Float(floatParameter(++i));
					break;
				}
				if (str.equalsIgnoreCase("ellipsoid")) {
					// ellipsoid {xc yc zc f} where a = b and f = a/c
					surfaceObjectSeen = true;
					propertyName = "ellipsoid";
					propertyValue = getPoint4f(i + 1);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("lobe")) {
					// lobe {eccentricity}
					surfaceObjectSeen = true;
					propertyName = "lobe";
					propertyValue = getPoint4f(i + 1);
					i = pcLastExpressionInstruction;
					break;
				}
				if (str.equalsIgnoreCase("AtomicOrbital") || str.equalsIgnoreCase("orbital")) {
					surfaceObjectSeen = true;
					nlmZ[0] = intParameter(++i);
					nlmZ[1] = intParameter(++i);
					nlmZ[2] = intParameter(++i);
					nlmZ[3] = (isFloatParameter(i + 1) ? floatParameter(++i) : 6f);
					propertyName = "hydrogenOrbital";
					propertyValue = nlmZ;
					break;
				}
				if (str.equalsIgnoreCase("functionXY")) {
					surfaceObjectSeen = true;
					Vector v = new Vector();
					if (++i == statementLength)
						badArgumentCount();
					if (statement[i].tok != Token.string)
						invalidArgument(i, "function name in quotation marks expected");
					v.add(statement[i++].value);
					v.add(getCoordinate(i, false));
					v.add(getPoint4f(pcLastExpressionInstruction + 1));
					v.add(getPoint4f(pcLastExpressionInstruction + 1));
					v.add(getPoint4f(pcLastExpressionInstruction + 1));
					i = pcLastExpressionInstruction;
					propertyName = "functionXY";
					propertyValue = v;
					break;
				}
				if (str.equalsIgnoreCase("molecular")) {
					surfaceObjectSeen = true;
					propertyName = "molecular";
					propertyValue = new Float(1.4);
					break;
				}
				propertyValue = token.value;
				// fall through for identifiers
			case Token.all:
				propertyName = "thisID";
				break;
			case Token.lcaocartoon:
				surfaceObjectSeen = true;
				String lcaoType = stringParameter(++i);
				viewer.setShapeProperty(iShape, "lcaoType", lcaoType);
				switch (statement[++i].tok) {
				case Token.expressionBegin:
					propertyName = "lcaoCartoon";
					int atomIndex = viewer.firstAtomOf(expression(statement, ++i));
					if (atomIndex < 0)
						expressionExpected();
					viewer.setShapeProperty(iShape, "modelIndex", new Integer(viewer.getAtomModelIndex(atomIndex)));
					Vector3f[] axes = { new Vector3f(), new Vector3f(), new Vector3f(viewer.getAtomPoint3f(atomIndex)) };
					viewer.getPrincipalAxes(atomIndex, axes[0], axes[1], lcaoType, false);
					i = pcLastExpressionInstruction;
					propertyValue = axes;
					break;
				default:
					expressionExpected();
				}
				break;
			case Token.mo:
				// mo 1-based-index
				if (++i == statementLength)
					badArgumentCount();
				int moNumber = intParameter(i);
				setMoData(iShape, moNumber, null);
				surfaceObjectSeen = true;
				continue;
			case Token.mep:
				float[] partialCharges = null;
				try {
					partialCharges = viewer.getFrame().partialCharges;
				}
				catch (Exception e) {
				}
				if (partialCharges == null)
					evalError(GT
							._("No partial charges were read from the file; Jmol needs these to render the MEP data."));
				surfaceObjectSeen = true;
				propertyName = "mep";
				propertyValue = partialCharges;
				break;
			case Token.sasurface:
			case Token.solvent:
				surfaceObjectSeen = true;
				propertyName = (token.tok == Token.sasurface ? "sasurface" : "solvent");
				float radius = (isFloatParameter(i + 1) ? floatParameter(++i) : viewer.getSolventProbeRadius());
				propertyValue = new Float(radius);
				break;
			case Token.string:
				propertyName = surfaceObjectSeen || planeSeen ? "mapColor" : "getSurface";
				/*
				 * a file name, optionally followed by an integer file index. OR empty. In that case, if the model
				 * auxiliary info has the data stored in it, we use that. There are two possible structures:
				 * 
				 * jmolSurfaceInfo jmolMappedDataInfo
				 * 
				 * Both can be present, but if jmolMappedDataInfo is missing, then jmolSurfaceInfo is used by default.
				 */
				String filename = (String) token.value;
				if (filename.length() == 0) {
					if (surfaceObjectSeen || planeSeen)
						propertyValue = viewer.getModelAuxiliaryInfo(modelIndex, "jmolMappedDataInfo");
					if (propertyValue == null)
						propertyValue = viewer.getModelAuxiliaryInfo(modelIndex, "jmolSurfaceInfo");
					surfaceObjectSeen = true;
					if (propertyValue != null)
						break;
					filename = viewer.getFullPathName();
				}
				surfaceObjectSeen = true;
				if (i + 1 < statementLength && statement[i + 1].tok == Token.integer)
					viewer.setShapeProperty(iShape, "fileIndex", new Integer(intParameter(++i)));
				Object t = viewer.getUnzippedBufferedReaderOrErrorMessageFromName(filename);
				if (t instanceof String)
					fileNotFoundException(filename + ":" + t);
				Logger.info("reading isosurface data from " + filename);
				propertyValue = t;
				break;
			default:
				if (!setMeshDisplayProperty(iShape, token.tok))
					invalidArgument(i, statement[i] + " not recognized");
			}
			if (propertyName != null)
				viewer.setShapeProperty(iShape, propertyName, propertyValue);
		}
		if (planeSeen && !surfaceObjectSeen) {
			viewer.setShapeProperty(iShape, "nomap", new Float(0));
		}
	}