/**	
	Company:		Shout Interactive
	Project:		Shout3D Core Implementation
	Class:			Shout3DWriter
	Date:			Sep 21, 1999
	Description:	Class that writes out a node and its subgraph in pseudo-vrml style.
	(C) Copyright Shout Interactive, Inc. - 1997/1998/1999 - All rights reserved
 */

package applets;

import java.io.PrintStream;
import java.util.Enumeration;
import shout3d.core.*;


/**
 * Class that writes out a node and its subgraph in pseudo-vrml style.
 * 
 * @author Paul Isaacs
 * @author Dave Westwood
 * @author Jim Stewartson
 */

class Shout3DWriter {
	
	/**
	 * Constructs a new Shout3DWriter
	 * 
	 */
	public Shout3DWriter(){
	}
	
    /**
	 * Writes a description of the node, its subgraph and its fields, vrml-style 
	 * to the given PrintStream
	 * 
	 * @param root the root of the scene to write
	 * @param the PrintStream in which to write.	 
	 */
	public void write(Node root, PrintStream ps){
		writeNode(root, 0, ps);
	}
	
    /**
	 * Writes a description of the node, its subgraph and its fields, vrml-style 
	 * to the given PrintStream
	 * 
	 * @param root the root of the scene to write
	 * @param the number of indent levels
	 * @param the PrintStream in which to write.	 
	 */
	private void writeNode(Node root, int indent, PrintStream ps){
		String outStr = new String();
		for (int i = 0; i < indent; i++)
			outStr += "    ";
		if (root.getDEFName() != null)
			outStr += root.getDEFName() + " ";
		outStr += root.getTypeName() + "{\n";
		ps.print(outStr);
		Field curField;
		for (int i = 0; i < root.getNumFields(); i++){
			curField = root.getFieldByIndex(i);
			if (curField != null) {
				writeField(curField, indent+1, ps);
			}
		}
		outStr = "";
		for (int i = 0; i < indent; i++)
			outStr += "    ";
		outStr += "}\n";
		ps.print(outStr);
	}
	
    /**
	 * Writes a given field 
	 * to the given PrintStream
	 * 
	 * @param field the field to write
	 * @param the number of indent levels
	 * @param the PrintStream in which to write.	 
	 */
	private void writeField(Field field, int indent, PrintStream ps){
		if (field instanceof ArrayField)
			writeArrayField(field, indent, ps);
		else
			writeNonArrayField(field, indent, ps);
	}
	
	private void writeNonArrayField(Field field, int indent, PrintStream ps){
		writeFieldIntro(field, indent, ps, false);
		
		if (field instanceof BooleanField){
			ps.print(""+((BooleanField)field).getValue()+"\n");
		}
		else if (field instanceof DoubleField){
			ps.print(""+((DoubleField)field).getValue()+"\n");
		}
		else if (field instanceof FloatField){
			ps.print(""+((FloatField)field).getValue()+"\n");
		}
		else if (field instanceof IntField){
			ps.print(""+((IntField)field).getValue()+"\n");
		}
		else if (field instanceof NodeField){
			Node value = ((NodeField)field).getValue();
			if (value != null) 
				writeNode(value, indent, ps);
			else
				ps.print("NULL\n");
		}
		else if (field instanceof StringField){
			ps.print(((StringField)field).getValue()+"\n");
		}
	}
	
	private void writeArrayField(Field field, int indent, PrintStream ps){
		writeFieldIntro(field, indent, ps, true);
		
		if (field instanceof BooleanArrayField){
			boolean[] value = ((BooleanArrayField)field).getValue();
			if (value != null) {
				String outStr = new String();
				for (int i=0; i<value.length; i++) {
					outStr += ""+value[i]+" ";
					outStr = makePrettyForIndex(12, i, value.length, indent+2, outStr);
				}
				ps.print(""+outStr);
			}
		}
		else if (field instanceof DoubleArrayField){
			double[] value = ((DoubleArrayField)field).getValue();
			if (value != null) {
				String outStr = new String();
				for (int i=0; i<value.length; i++) {
					outStr += ""+value[i]+" ";
					outStr = makePrettyForIndex(12, i, value.length, indent+2, outStr);
				}
				ps.print(""+outStr);
			}			
		}
		else if (field instanceof FloatArrayField){
			float[] value = ((FloatArrayField)field).getValue();
			if (value != null) {
				String outStr = new String();
				for (int i=0; i<value.length; i++) {
					outStr += ""+value[i]+" ";
					outStr = makePrettyForIndex(12, i, value.length, indent+2, outStr);
				}
				ps.print(""+outStr);
			}			
		}
		else if (field instanceof IntArrayField){
			int[] value = ((IntArrayField)field).getValue();
			if (value != null) {
				String outStr = new String();
				for (int i=0; i<value.length; i++) {
					outStr += ""+value[i]+" ";
					outStr = makePrettyForIndex(12, i, value.length, indent+2, outStr);
				}
				ps.print(""+outStr);
			}			
		}
		else if (field instanceof NodeArrayField){
			Node[] value = ((NodeArrayField)field).getValue();
			if (value != null) {
				ps.print("\n");
				for (int i=0; i<value.length; i++) {
					if (value[i] == null)
						ps.print("NULL\n");
					else
						writeNode(value[i], indent, ps);
				}
			}
			writeIndent(indent, ps);
		}
		else if (field instanceof StringArrayField){
			String[] value = ((StringArrayField)field).getValue();
			if (value != null) {
				String outStr = new String();
				for (int i=0; i<value.length; i++) {
					outStr += ""+value[i]+" ";
					outStr = makePrettyForIndex(12, i, value.length, indent+2, outStr);
				}
				ps.print(""+outStr);
			}
		}
	
		ps.print("]\n");
	}
	

	String indentStr = new String();
	private void writeIndent(int indent, PrintStream ps){
		indentStr = "";
		for (int i = 0; i < indent; i++)
			indentStr +="    ";
		ps.print(indentStr);
	}
	
	/**
	 * Writes a description of this field, vrml-style
	 * the given PrintStream
	 * 
	 * @param the number of indent levels
	 * @param the PrintStream in which to write.
	 * 
	 */
	private void writeFieldIntro(Field field, int indent, PrintStream ps, boolean isArray) {
		writeIndent(indent,ps);
		
		// Now the name and if needed, array opener
		ps.print(field.getName() + "    ");
		if (isArray)
			ps.print(field.getName() + "\t[");
	}	
	
	static final protected int NUM_PER_ROW = 8;

	/**
	 * For writing, indents if this is the numPerRow'th value in the row
	 */
	protected  String makePrettyForIndex(int numPerRow, int i, int total, int indent, String outStr) {
		if (((i+1) % numPerRow == 0) && (i != total -1)) {
			outStr += "\n";
			for (int j = 0; j < indent; j++)
				outStr += "    ";
		}
		return outStr;
	}	
}
