/**
 * parser for resistor structure strings
 *
 * @author Peter Sch&uuml;ller <mailto:e0125596@student.tuwien.ac.at>
 */
public class WiderstParser extends Object {	
	//static member to record number of resistors
	// (unlimited resistors _could_ be calculated)
	public static int iEprogLimit = 0;
	
	/**
	 * generic exception for this parser
	 */
	public static class WiderstParserException extends Exception {
	}

	/**
	 * structure which can record
	 * *) a single resistor
	 * *) a parallel resistor-circuit
	 * *) a serial resistor-circuit
	 */
	public static class Structure extends Object {
		/**
		 * generic exception for structure operations
		 */
		public static class StructureException extends Exception {
		}

			//"no structure"
		public static final int ERROR = 0;
			//parallel circuit
		public static final int PARALLEL = 1;
			//serial circuit
		public static final int SERIAL = 2;
			//simple resistor
		public static final int RESISTOR = 3;

			//one of the above defined types
		public int iType;

			//array of structures below this one
		public Structure[] acSubStructures;

			//value if this is a simple resistor
		public double dResistorValue;

		/**
		 * constructor
		 * error is standard, so we know if we forgot to initialize
		 */
		Structure() {
			iType = ERROR;
			acSubStructures = null;
		}

		/**
		 * add a (parsed) substructure into this
		 * this function manages the array magic in this object
		 */
		public void addSubStructure( Structure s ) {
			Structure[] acNew;
			
			if( acSubStructures == null ) {
				acNew = new Structure[1];
			}
			else {
				acNew = new Structure[1 + acSubStructures.length];
				int i;
				for( i = 0; i < acSubStructures.length; i++ ) {
					acNew[i] = acSubStructures[i];
				}
			}
			acNew[ acNew.length - 1 ] = s;
			acSubStructures = acNew;
		}

		/**
		 * calculate the resistance of this structure
		 * *) resistor: return value
		 * *) parallel: return 1/( sum( 1/substructure_values ) )
		 * *) serial: return sum( substructure_values )
		 */
		public double calculateResistance() throws StructureException {
			double d;
			int i;

			switch( iType ) {
			case ERROR:
				throw new StructureException();

			case PARALLEL:
				d = 0.0;
				for( i = 0; i < acSubStructures.length; i++ ) {
					d += 1.0 / acSubStructures[i].calculateResistance();
				}
				d = 1.0 / d;
				break;
				
			case SERIAL:
				d = 0.0;
				for( i = 0; i < acSubStructures.length; i++ ) {
					d += acSubStructures[i].calculateResistance();
				}
				break;
				
			case RESISTOR:
				d = dResistorValue;
				break;
				
			default:
				throw new StructureException();
			}
			return d;
		}
	} //end of structure class definition

	/**
	 * parses a whole resistor structure from a string into the Structure
	 */
	public static Structure parseString( String s ) throws WiderstParserException {
		Structure sReturn = new Structure();

			//this is a structure specification
		if( s.charAt(0) == '(' && s.charAt(s.length()-1) == ')' ) {
			//remove brackets
			s = s.substring( 1, s.length() - 1 );

			//get type from last character
			switch( s.charAt( s.length() - 1 ) ) {
			case 'P':
				sReturn.iType = Structure.PARALLEL;
				break;
			case 'S':
				sReturn.iType = Structure.SERIAL;
				break;
			default:
				throw new WiderstParserException();
			}
			//remove last character and ',' before
			if( s.charAt( s.length() - 2 ) == ',' )
				s = s.substring( 0, s.length() - 2 );
			else
				throw new WiderstParserException();
			
			//find end of first substructure
			int iEnd = -1; //-1 = to allow the first substring operation to work
			do {
				s = s.substring( iEnd + 1, s.length() );
				iEnd = findEndOfNextStructureSpecification( s );
				sReturn.addSubStructure( parseString( s.substring( 0, iEnd ) ) );
			}
			while( iEnd != s.length() );			
		}
			//this is a resistor specification
		else {
			iEprogLimit++;
			
			sReturn.iType = Structure.RESISTOR;
			try {
				sReturn.dResistorValue = ResistorCodes.decodeString( s );			
			}
			catch( ResistorCodes.ResistorCodesException e ) {
				throw new WiderstParserException();
			}
		}
		return sReturn;
	}

	/**
	 * this function finds the end of the first structure specification in the string s
	 */
	protected static int findEndOfNextStructureSpecification( String s ) throws WiderstParserException {
		int i;
		int iDepth = 0;
		for( i = 0; i < s.length(); i++ ) {
			switch( s.charAt( i ) ) {
			case '(':
				iDepth ++;
				break;
			case ')':
				iDepth --;
					//not allowed here
				if( iDepth == -1 )
					throw new WiderstParserException();
				break;
			case ',':
				if( iDepth == 0 ) {
					return i;
				}
				break;
			}	
		}
		
		if( iDepth != 0 )
			throw new WiderstParserException();
		else
			return s.length();
	}
}