/*
 * $Id$
 *
 * JSDAI(TM), a way to implement STEP, ISO 10303
 * Copyright (C) 1997-2008, LKSoftWare GmbH, Germany
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License
 * version 3 as published by the Free Software Foundation (AGPL v3).
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * JSDAI is a registered trademark of LKSoftWare GmbH, Germany
 * This software is also available under commercial licenses.
 * See also http://www.jsdai.net/
 */

/* Generated By:JJTree: Do not edit this line. X_CaseExpr.java */

package jsdai.expressCompiler;

import java.util.*;
import jsdai.lang.*;
import jsdai.SExtended_dictionary_schema.*;

public class X_CaseExpr extends SimpleNode {


	int case_count = 0;
	boolean otherwise_present = false;


	String selector_expression = "";
 	String otherwise_expression = "";
	Vector action_labels = null;
	Vector action_values = null; 
  int current_case_count = 0;
  Vector processed_labels = null;

	String if_expression = "";
	String then_expression = "";
	String else_expression = "";
	Vector elsif_conditions = null;
	Vector elsif_expressions = null;

	boolean elsif_condition = true;
	int elsif_current_count = 0;



  public X_CaseExpr(int id) {
    super(id);
		case_count = 0;
		otherwise_present = false;
  }

  public X_CaseExpr(Compiler2 p, int id) {
    super(p, id);
		case_count = 0;
		otherwise_present = false;
  }


  /** Accept the visitor. **/
  public Object jjtAccept(Compiler2Visitor visitor, Object data) throws jsdai.lang.SdaiException {
    return visitor.visit(this, data);
  }


  public Object childrenAccept(Compiler2Visitor visitor, Object data) throws SdaiException {


//	 System.out.println("---<CaseExpr> ------------");


    JavaClass jc = (JavaClass) data;

    if (children != null) {

			// these initializations are from SimpleNode, perhaps needed or not
      variable_names = new Vector();
      variable_declarations = new Vector();
      statements = new Vector();
      initializing_code = new Vector();


			action_labels = new Vector();
			action_values = new Vector();
			current_case_count = 0;

      for (int i = 0; i < children.length; ++i) {
        children[i].jjtAccept(visitor, data);

        if (jc != null) {

          if (jc.active) {

              if (((SimpleNode) children[i]).java_contains_statements) {
                java_contains_statements = true;

                // variable_declaration += "\n" + ((SimpleNode)children[i]).variable_declaration;
                for (int j = 0; j < ((SimpleNode) children[i]).variable_names.size(); j++) {
                  variable_names.add(((SimpleNode) children[i]).variable_names.elementAt(j));
                }

                for (int j = 0; j < ((SimpleNode) children[i]).variable_declarations.size(); j++) {
                  variable_declarations.add(((SimpleNode) children[i]).variable_declarations.elementAt(j));
                }

                for (int j = 0; j < ((SimpleNode) children[i]).statements.size(); j++) {
                  statements.add(((SimpleNode) children[i]).statements.elementAt(j));
                }

                // initializing_code += "\n" + ((SimpleNode)children[i]).initializing_code;
                for (int j = 0; j < ((SimpleNode) children[i]).initializing_code.size(); j++) {
                  initializing_code.add(((SimpleNode) children[i]).initializing_code.elementAt(j));
                }
              } // if contains statements

	//						System.out.println("<CaseExpr> child: " +  children[i] + ", jc.generated_java: " + jc.generated_java);

							/*

									 the children nodes are as follows, for example:
									 
									 a := CASE b OF 'one', 'two', 'three' : 'first'; 'four' :'second'; 'five', 'six' : 'third'; OTHERWISE : 'fourth' END_CASE;
									 
									 		b - expression
									 
									 		'one', 'two', 'three' :  'first'  - CaseExprAction
									 					'one'   - CaseLabel -> expression
									 					'two'   - CaseLabel -> expresion
									 					'three' - CaseLabel -> expression
                            'first' - expression
						  				'four' : second - CaseExpression
						  							'four' - CaseLabel -> expression
						  							'second' - expression
						  				. . .
						  				OTHERWISE - expression			
						  
						  		So, on this level, possible nodes are:
						  		expression - for the case selector
						  		CaseExpression - for each case condition value, including with multiple labels
						  		expression - for optional OTHERWISE, if OTHERWISE is not present, then indeterminate value assigned
						  
						  		So need to implement CaseExprAction to return the correctly generated java for the whole that part, instead of for only the value  
						  
						  */

							if (children[i] instanceof X_Expression) {
								// the first child - the case selector expression
								// the last child, if present - the value expression for OTHERWISE
								if (i == 0) {
									// the case selector expression - has to be used in multiple places, perhaps it would be more optimal not to calculate this expression each time,
									// but then some temp variable initialization has to be moved in front of java ternary, using the whole expression for now
								
									selector_expression = jc.generated_java;
									jc.generated_java = "";
								} else {
									// the last node only - optional OTHERWISE expression, may check the index to catch an internal error
									
									if ((i == (children.length - 1)) && (otherwise_present)) {
										otherwise_expression = jc.generated_java;
										jc.generated_java = "";
									} else {
										// should not occur
//										System.out.println("Express-X compiler INTERNAL ERROR - CaseExpr 02, node: " + children[i] + ", generated: " + jc.generated_java);
									}
								}
							} else
							if (children[i] instanceof X_CaseExprAction) {
								// one or more CaseExprAction nodes, each return the value expression, but also has Vector with one or more label expressions
								// we don't want to generate java right here in this loop, we would prefer to do it after all the data is collected
								// we want pairs  all labels - value perhaps put inside another Vector
								// or inside two other vectors: action_labels and action_values
								
								action_labels.addElement(((X_CaseExprAction)children[i]).label_expressions);
								action_values.addElement(jc.generated_java);
								jc.generated_java = "";
								current_case_count++;	
							
							} else {
								// should not occur
//								System.out.println("Express-X compiler INTERNAL ERROR - CaseExpr 01, node: " + children[i] + ", generated: " + jc.generated_java);
							}


					} // if jc.active

				} //  if jc not null

			} // loop through all the children

			if (current_case_count != case_count) {
//				System.out.println("Express-X compiler INTERNAL ERROR - CaseExpr 03: from parser: " + case_count + ", current: "  + current_case_count);
			}

			/*
					ok, all the work goes here
					
					for something like this:
					
					a := CASE b OF b1, b2, b3 : bv1; b4 : bv2; b5, b6 : bv3; OTHERWISE : bv4; END_CASE;
		
					we need to generate java ternary equivalent of something like this:
					
					if ((b == b1) || (b == b2) || (b == b3)) {
						bv1
					} else {
						if ((b == b4)) {
							bv2
						} else {
							if ((b == b5) || (b == b6)) {
								bv3
							} else {
								bv4
							}
						}
					}

					a = ((b == b1) || (b == b2) || (b == b3))  ?  bv1  : ((b == b4) ? bv2 : (((b == b5) || (b == b6)) ? bv3 : bv4)) 



		##############  example: #################################################
				
		EXPRESS CASE expression: -------------------------------------------------

			CASE s OF 
				'one', 'two', 'three' : 'first'; 
				'four'                : 'second'; 
				'five', 'six'         : 'third'; 
				OTHERWISE             : 'fourth' 
			END_CASE;					
			
		equivalent to EXPRESS IF expression: -------------------------------------

			IF ((s = 'one') OR (s = 'two') OR (s = 'three')) 
				THEN 'first' 
				ELSIF (s = 'four') 'second' 
				ELSIF ((s = 'five') OR (s ='six')) 'third' 
				ELSE 'fourth' 
			END_IF;		
			
		
		java pseudo-code: --------------------------------------------------------
		
			if ((s == "one") || (s == "two") || (s == "three")) {
				... "first" ...
			} else
			if (s == "four") {
				... "second" ...
			} else
			if ((s == "five") || (s == "six")) {
				... "third" ...
			} else {
				... "fourth" ...
			}
 	
		java pseudo-code transformed to match ternary operator: ------------------
	

			if ((s == "one") || (s == "two") || (s == "three")) {
				... "first" ...
			} else {
				if (s == "four") {
					... "second" ...
				} else {
					if ((s == "five") || (s == "six")) {
						... "third" ...
					} else {
						... "fourth" ...
					}
				}
			}
	
		java ternary operator (nested): ------------------------------------------
	
		  ((s == "one") || (s == "two") || (s == "three")) 
		  ? 
		  "first" 
		  :  		
			(
				(s == "four")
				?
				"second"
				:
				{
					((s == "five") || (s == "six"))
					?
					"third"
					:
					"fourth"
				)
			)
			
		--------------------------------------------------------------------------			
	 	need to generate in java (when inside function, that's why _e_ prefices) :
					
			( (Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
				_context, 
				Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
					_context, 
					Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
						_context, 
						_e_s, 
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "one")
					), 
					Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
						_context, 
						_e_s, 
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "two")
					)	
				), 
				Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
					_context, 
					_e_s, 
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "three")
				)
			).getBoolean() == 2) ? true : false ) 
			? 
			(
				Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "first")
			) 
			: 
			(
				( (Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
					_context, 
					_e_s, 
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "four")
				).getBoolean() == 2) ? true : false ) 
				? 
				(
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "second")
				) 
				: 
				(
					( (Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
						_context, 
						Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
							_context, 
							_e_s, 
							Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "five")
						), 
						Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
							_context, 
							_e_s, 
							Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "six")
						)
					).getBoolean() == 2) ? true : false ) 
					? 
					(
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "third")
					) 
					: 
					(
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "fourth")
					)
				)
			)
					
				
			available pre-generated java pieces: -----------------------------------

							
				selector_expression: _e_s
	
				Vector action_labels, index 0:
					Vector with 3 elements:
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "one")
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "two")
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "three")
				Vector action_values, index 0:	
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "first")
			
				Vector action_labels, index 1:
					Vector with 1 element:
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "four")			

				Vector action_values, index 1:	
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "second")
								
				Vector action_labels, index 2:
					Vector with 2 elements:
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "five")
						Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "six")
				
				Vector action_values, index 2:	
					Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "third")
				
				otherwise_expression:  Value.alloc(ExpressTypes.STRING_TYPE).set(_context, "fourth")


			let's use generic markings for the pieces: -----------------------------
			
				selector_expression: SELECTOR   ( _e_s )
	
				Vector action_labels, index 0:
					Vector with 3 elements:
						LABEL_0_0                    ( "one" )
						LABEL_0_1                    ( "two" )
						LABEL_0_2                    ( "three")
				Vector action_values, index 0:	
						VALUE_0                      ( "first")
			
				Vector action_labels, index 1:
					Vector with 1 element:
						LABEL_1_0			               ( "four" )

				Vector action_values, index 1:	
					VALUE_1                        ( "second" )
								
				Vector action_labels, index 2:
					Vector with 2 elements:
				    LABEL_2_0                    ( "five" )
						LABEL_2_1                    ( "six" )
				
				Vector action_values, index 2:	
					VALUE_2                        ( "third" )
				
				otherwise_expression:  OTHERWISE ( "fourth" )


			the java to generate re-written with generic pieces: -------------------


			( (Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
				_context, 
				Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
					_context, 
					Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
						_context, 
						SELECTOR, 
						LABEL_0_0
					), 
					Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
						_context, 
						SELECTOR, 
						LABEL_0_1
					)	
				), 
				Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
					_context, 
					SELECTOR, 
					LABEL_0_2
				)
			).getBoolean() == 2) ? true : false ) 
			? 
			(
				VALUE_0
			) 
			: 
			(
				( (Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
					_context, 
					SELECTOR, 
					LABEL_1_0
				).getBoolean() == 2) ? true : false ) 
				? 
				(
					VALUE_1
				) 
				: 
				(
					( (Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(
						_context, 
						Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
							_context, 
							SELECTOR, 
							LABEL_2_0
						), 
						Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(
							_context, 
							SELECTOR, 
							LABEL_2_1
						)
					).getBoolean() == 2) ? true : false ) 
					? 
					(
						VALUE_2
					) 
					: 
					(
						OTHERWISE
					)
				)
			)

			let's re-write for better clarity in pseudo-code: ----------------------
		

			(  (OR(
				OR(
					equal(
						SELECTOR, 
						LABEL_0_0
					), 
					equal(
						SELECTOR, 
						LABEL_0_1
					)	
				), 
				equal(
					SELECTOR, 
					LABEL_0_2
				)
			).getBoolean() == 2) ? true : false ) 
			? 
			(
				VALUE_0
			) 
			: 
			(
				( (equal(
					SELECTOR, 
					LABEL_1_0
				).getBoolean() == 2) ? true : false ) 
				? 
				(
					VALUE_1
				) 
				: 
				(
					( (OR(
						equal(
							SELECTOR, 
							LABEL_2_0
						), 
						equal(
							SELECTOR, 
							LABEL_2_1
						)
					).getBoolean() == 2) ? true : false ) 
					? 
					(
						VALUE_2
					) 
					: 
					(
						OTHERWISE
					)
				)
			)

		// re-writing again: 

			(
				(
					OR(
						OR(
							equal(SELECTOR, LABEL_0_0), 
							equal(SELECTOR, LABEL_0_1)	
						), 
						equal(SELECTOR, LABEL_0_2)
				).getBoolean() == 2) ? true : false ) 
			? 
			(
				VALUE_0
			) 
			: 
			(
				( (equal(SELECTOR, LABEL_1_0).getBoolean() == 2) ? true : false ) 
				? 
				(
					VALUE_1
				) 
				: 
				(
					( (OR(
						equal(SELECTOR, LABEL_2_0), 
						equal(SELECTOR, LABEL_2_1)
					).getBoolean() == 2) ? true : false ) 
					? 
					(
						VALUE_2
					) 
					: 
					(
						OTHERWISE
					)
				)
			)

			// and again -------------------			

			((one-two-three).getBoolean() == 2) ? true : false )
			?
			VALUE_0
			:
			(
				((four).getBoolean() == 2) ? true : false )
				?
				VALUE_1
				:
				(
					((five-six).getBoolean() == 2) ? true : false )
					?
					VALUE_2
					: 
					OTHERWISE
				}
			)

			// for simplicity, we could say that we have condition expression generated for each case label group	

			((LABELS_0).getBoolean() == 2) ? true : false )
			?
			VALUE_0
			:
			(
				((LABELS_1).getBoolean() == 2) ? true : false )
				?
				VALUE_1
				:
				(
					((LABELS_2).getBoolean() == 2) ? true : false )
					?
					VALUE_2
					: 
					OTHERWISE
				}
			)
				
				
			// here LABELS_0 is:
			
					OR(
						OR(
							equal(SELECTOR, LABEL_0_0), 
							equal(SELECTOR, LABEL_0_1)	
						), 
						equal(SELECTOR, LABEL_0_2)
					}
				
			// LABELS_2 is: 	

					( (OR(
						equal(SELECTOR, LABEL_2_0), 
						equal(SELECTOR, LABEL_2_1)
					)

				
			// LABELS_1 is:	
				
				
			(equal(SELECTOR, LABEL_1_0)
			
			
			// so we have two cases:
			with more than one label, and with one label only

			// or forget the cases
			
			possible algorithm:
			
			1. calculate the first operand:
			
							equal(SELECTOR, LABEL_0_1)	
			
			2. save it as "previous"
			
			3. if there are more operands,  generate OR  between previous and the next:
			
						OR(
							equal(SELECTOR, LABEL_0_0), 
							equal(SELECTOR, LABEL_0_1)	
						) 
			
			 4. go to step 2 until there are no more operands
			 
			 So, in our example the next cycle in the loop would generate:
			 
					OR(
						OR(
							equal(SELECTOR, LABEL_0_0), 
							equal(SELECTOR, LABEL_0_1)	
						), 
						equal(SELECTOR, LABEL_0_2)
					}
			 		
				that is exactly what is needed.
				Also the other two cases are OK.
				

				
					
			*/

			// OTHERWISE is optional, let's put there indeterminate value if not present
			if (!otherwise_present) {
				otherwise_expression = "Value.alloc(ExpressTypes.GENERIC_TYPE).unset())";
			}

			// ok, all the work goes here, the result in generated_java
			generated_java = "";  
			
			
			// processing labels - preparing nested OR expressions for the condition parts of the ternary operators 
			
			processed_labels = new Vector();
			
			for (int j = 0; j < case_count; j++) { // loop through all the cases

				Vector current_labels = (Vector)action_labels.elementAt(j);
				
				String previous_operand = "";
				boolean first_time = true;
				
				for (int k = 0; k < current_labels.size(); k++) { // loop through all the labels of one case

					String current_label = (String)current_labels.elementAt(k);
					String current_operand = "Value.alloc(ExpressTypes.LOGICAL_TYPE).equal(_context, " + selector_expression + ", " + current_label + ")";
					if (first_time) {
						previous_operand = current_operand;
						first_time = false;
					} else {
						previous_operand = "Value.alloc(ExpressTypes.LOGICAL_TYPE).OR(_context, " + previous_operand + ", " + current_operand + ")";	
					}						
			
				} // for k - loop through all the labels of one case
				processed_labels.addElement(previous_operand);
				
			} // for j - loop through all the cases

			// now let's generate the whole thing
			
			for (int j = 0; j < case_count; j++) { // loop through all the cases again
				String current_selector_expression = (String)processed_labels.elementAt(j);
				String current_value = (String)action_values.elementAt(j);
			
				generated_java += "(((" + current_selector_expression + ").getBoolean() == 2) ? true : false ) ? (";				
				generated_java += current_value + ") : (";

			} // for j - loop through all the cases again

			generated_java += otherwise_expression;

			for (int j = 0; j < case_count; j++) {
				generated_java += ")";
			}
				
			// generated_java += ")";
			


			jc.generated_java = generated_java;


		} // if children not null


    return data;
  }





}
