/*
 * $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_MapAttributeDeclaration.java */

package jsdai.expressCompiler;

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

public class X_MapAttributeDeclaration extends SimpleNode {

	jsdai.SExtended_dictionary_schema.ETarget_parameter target_parameter = null;
//	jsdai.SExtended_dictionary_schema.EMap_partition partition = null;
	jsdai.SExtended_dictionary_schema.EMap_or_view_partition partition = null;
  Vector qualifiers = null;
	static HashSet targets = null; // target instance should be created only once - when first encountered target_parameter 

  public X_MapAttributeDeclaration(int id) {
    super(id);
    qualifiers = new Vector();
		targets = new HashSet();
  }

  public X_MapAttributeDeclaration(Compiler2 p, int id) {
    super(p, id);
    qualifiers = new Vector();
		targets = new HashSet();
  }


  /** 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 jsdai.lang.SdaiException {

// System.out.println("map attribute, target parameter: " + target_parameter);

    JavaClass jc = ( JavaClass )data;
		java.io.PrintWriter pw = jc.pw;

		Vector src_par_names = new Vector();
		Vector src_par_orders = new Vector();
		String generated_expression = "";
		String gen_target_attr = "";
		String q_name = "";
		boolean expression_part = false;
		
		//String tar_par_name = ((EMap_definition)jc.entity).getName(null).toLowerCase() + "_" + target_parameter.getName(null);
		String tar_par_name = target_parameter.getName(null);
		String plain_target_name = tar_par_name;
		tar_par_name += "_" +jc.target_par_count;
		// experiment
		tar_par_name = 	((EMap_definition)jc.entity).getName(null).toLowerCase() + "_" + tar_par_name;
			
		
		
		jc.target_par_count++;

		String left_str = "";
		String right_str = "";

		String left_str2 = "";

		String my_variable_declarations = "";
		String my_statements = "";

		if (children != null) {


      // for contained statements
      variable_names = new Vector();
      variable_declarations = new Vector();
      statements = new Vector();
      initializing_code = new Vector();
      variable_names_tmp = new Vector();
      variable_declarations_tmp = new Vector();
      statements_tmp = new Vector();
      initializing_code_tmp = new Vector();

			my_variable_declarations = "";
			my_statements = "";


//					pw.println("---START----MapAttributeDeclaration, generated in children: ");
			

			for (int l = 0; l < children.length; ++l) {


				//				System.out.println("el: " +l + " ql size: " +qualifiers.size());
				if((children[l] instanceof X_AttributeQualifier) && (l == qualifiers.size())){
					jc.last_left_qualifier = true;
				}else{
					jc.last_left_qualifier = false;
				}

//				pw.println("<OOO> BEFORE last_left_qualifier: " + jc.last_left_qualifier);

				children[l].jjtAccept(visitor, data);

//				pw.println("<OOO> AFTER last_left_qualifier: " + jc.last_left_qualifier);

/*

				if(!(children[l] instanceof X_TargetParameterRef) && !(children[l] instanceof X_SourceParameterRef)){
					if(expression_part) {
						generated_expression += jc.generated_java;
					} else if (l == qualifiers.size()) {
						gen_target_attr = jc.generated_java;
					} else {
						gen_target_attr += jc.generated_java;
				  }
				} else if(children[l] instanceof X_SourceParameterRef){ // multiple X_SourceParameterRef possible !!!
					expression_part = true;
					//					System.out.println("Source parameter" +((X_SourceParameterRef)children[l]).name)
					//					src_par_names.add(((X_SourceParameterRef)children[l]).name);
				}

*/

//					pw.println("-----MapAttributeDeclaration, generated in children, child:  " + children[l] + ", expression: " + jc.generated_java);


				if (children[l] instanceof X_TargetParameterRef) {
					// we already know what it is from target_parameter field
					left_str = "expr_" + tar_par_name;
					left_str2 = jc.generated_java;
//					pw.println("<1> TargetParameterRef: " + tar_par_name + ", generated: " + jc.generated_java);
				} else
				if (children[l] instanceof X_AttributeQualifier) {
	        if (l <= qualifiers.size()) {
          	// left side

					if (jc.in_entity_instantiation_loop) {
						left_str += left_str2;
						gen_target_attr += left_str2;
					}

						left_str += jc.generated_java;
						gen_target_attr += jc.generated_java;
//						pw.println("<2> AttributeQualifier-LEFT: "  + jc.generated_java);
          } else {
          	// right side
          	// actually, because we now have expression node, it should not happen on the right side
//						pw.println("<3> AttributeQualifier-RIGHT: "  + jc.generated_java);
            right_str += jc.generated_java;
          }
				} else
//				if ((children[l] instanceof X_IndexQualifier) && (jc.in_entity_instantiation_loop) && (l <= qualifiers.size())) {
				if (children[l] instanceof X_IndexQualifier) {
					//  one-to-many mapping with Entity instantiation loop, left side index on target, just remove (ignore) it altogether
					// ok, not checking if entity instantiation loop, unlikely that left side indexing may occur if not
					// and if it can occur, then it can occur also with entity instantiation loop as well (double indexing?), 
					// in which case should not be ignored
					
					// this indexing gets stuck to something else later on.
					
					/*
							 actually, generated string:
							 
							 tar.indexing(_implicit_2_i, null)
							 
							 so "tar" part should not be lost, but what about TargetParameterRef ?
					
					*/

						if (l <= qualifiers.size()) {
							// left side
//							pw.println("<4> index on LEFT side: " + jc.generated_java);
							// left_str += left_str2;
							// gen_target_attr += left_str2; // ?
						  jc.generated_java = left_str2;
				
						} else {
							// right side
//							pw.println("<5> index on RIGHT side: " + jc.generated_java);
	            right_str += jc.generated_java;
						  jc.generated_java = "";
						}

					jc.generated_java = "";
				} else	 
				if (children[l] instanceof X_Expression) {

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

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

// System.out.println(">-- 1 --< : " + (( SimpleNode )children[l]).variable_names.elementAt(j));
                }

                for (int j = 0; j < (( SimpleNode )children[l]).variable_declarations.size(); j++) {
//                  variable_declarations.add((( SimpleNode )children[l]).variable_declarations.elementAt(j));
// System.out.println(">-- 2 --< : " + (( SimpleNode )children[l]).variable_declarations.elementAt(j));

my_variable_declarations += (( SimpleNode )children[l]).variable_declarations.elementAt(j) + "\n";
                }

                for (int j = 0; j < (( SimpleNode )children[l]).statements.size(); j++) {
//                  statements.add((( SimpleNode )children[l]).statements.elementAt(j));
// System.out.println(">-- 3 --< : " + (( SimpleNode )children[l]).statements.elementAt(j));
my_statements += (( SimpleNode )children[l]).statements.elementAt(j) + "\n";
                }

                // initializing_code += "\n" + ((SimpleNode)children[i]).initializing_code;
                for (int j = 0; j < (( SimpleNode )children[l]).initializing_code.size(); j++) {
                  initializing_code.add((( SimpleNode )children[l]).initializing_code.elementAt(j));
// System.out.println(">-- 4 --< : " + (( SimpleNode )children[l]).initializing_code.elementAt(j));
                }
	              }



//					pw.println("<6> Expression: "  + jc.generated_java);

          right_str += jc.generated_java;
				  jc.generated_java = "";
				} else {
					// everything is covered above?
//					pw.println("<7> everything else: "  + jc.generated_java);
           right_str += jc.generated_java;
				  jc.generated_java = "";
				} 
				

			}
		}


		generated_expression = right_str;



		SdaiIterator spi = jc.asp.createIterator();
		while (spi.next()) {
			ESource_parameter sp = (ESource_parameter)jc.asp.getCurrentMemberObject(spi);
			String sp_name = sp.getName(null);
			src_par_names.add(sp_name);
		}

/*
		if (jc.secondary == 2) {
			// this is a temporary solution, probably will have to do better than that (what if the main subclass has no attributes mapped for this target?
			pw.println("\t\t\texpr_" +tar_par_name +" = Value.alloc().unset();");
			pw.println("\t\t\tlast_expr_" +tar_par_name +" = Value.alloc().unset();");
		} else {
			pw.println("\t\t\tValue expr_" +tar_par_name +" = Value.alloc().unset();");
			pw.println("\t\t\tValue last_expr_" +tar_par_name +" = Value.alloc().unset();");
		}
*/
			pw.println("\t\t\tValue expr_" +tar_par_name +" = Value.alloc().unset();");
			pw.println("\t\t\tValue last_expr_" +tar_par_name +" = Value.alloc().unset();");


		pw.println("");

		if(jc.identified_by){
			pw.println("\t\t\tboolean indeterminate_" +tar_par_name +" = false;");
			pw.println("");
			pw.println("\t\t\tfor(int j=0; j < eq_class.size(); j++){ ");
			pw.println("\t\t\t\tinst_num = ((Integer)eq_class.get(j)).intValue();");
			pw.println("\t\t\t\tif(!indeterminate_" +tar_par_name +"){");

			for(int si=0; si < src_par_names.size(); si++){
				pw.println("\t\t\t\t\tsrc_par_id_" +(String)src_par_names.get(si)+" = ((Integer)src_id_map.get(\""+(String)src_par_names.get(si)+"\")).intValue();");
				pw.println("\t\t\t\t\tValue " +(String)src_par_names.get(si) +" = (Value)((Vector)binding_inst_extent.elementAt(inst_num)).elementAt(src_par_id_" +(String)src_par_names.get(si) +");");
			}
//			pw.println("\t\t\t\t\texpr_" +tar_par_name +" = " +generated_expression +";");
//			pw.println("\t\t\t\t\t" + left_str +".set(_context, " +generated_expression +");");

			pw.println("\t\t\t\t\t" + my_variable_declarations);
			pw.println("\t\t\t\t\t" + my_statements);
			pw.println("\t\t\t\t\texpr_" +tar_par_name +" = " +generated_expression +";");
			pw.println("\t\t\t\t\tif(expr_" +tar_par_name +".isIndeterminate()) { ");
			pw.println("\t\t\t\t\t\tindeterminate_" +tar_par_name +" = true;");
			pw.println("\t\t\t\t\t}else");
			pw.println("\t\t\t\t\t\tif(j>0){ ");
			pw.println("\t\t\t\t\t\t\tif(Value.alloc(ExpressTypes.BOOLEAN_TYPE).nequal(_context, expr_" +tar_par_name +", last_expr_" +tar_par_name +").getAsBoolean())");
			pw.println("\t\t\t\t\t\t\t\tindeterminate_" +tar_par_name +" = true;");
			pw.println("\t\t\t\t\t\t}");
			pw.println("\t\t\t\t}");
			pw.println("\t\t\t\tif(!indeterminate_" +tar_par_name +")");
			pw.println("\t\t\t\t\tlast_expr_" +tar_par_name +" = expr_" +tar_par_name +"; ");
			pw.println("\t\t\t\tif(indeterminate_" +tar_par_name +") { ");
			pw.println("\t\t\t\t\texpr_" +tar_par_name +".unset();");
			pw.println("\t\t\t\t\tbreak;");
			pw.println("\t\t\t\t}");
			pw.println("\t\t\t}");
			pw.println("");
		} else {
			//			pw.println("\t\t\tfor(int j=0; j < binding_inst_extent.size(); j++){ ");

			if(jc.first_pass){
				for(int si=0; si < src_par_names.size(); si++){
					jc.first_pass = false;
					pw.println("\t\tint src_par_id_" +(String)src_par_names.get(si) +";");
					pw.println("\t\t\tValue " +(String)src_par_names.get(si) +";");
				}
			}

			for(int si=0; si < src_par_names.size(); si++){
				pw.println("\t\t\tsrc_par_id_" +(String)src_par_names.get(si)+" = ((Integer)src_id_map.get(\""+(String)src_par_names.get(si)+"\")).intValue();");
				pw.println("\t\t\t" +(String)src_par_names.get(si) +" = (Value)((Vector)binding_inst_extent.elementAt(j)).elementAt(src_par_id_" +(String)src_par_names.get(si) +");");
			}
			
			if (jc.in_entity_instantiation_loop_first) {
				jc.in_entity_instantiation_loop_first = false; // only once
				pw.println(jc.java_str5);
				jc.java_str5 = "";
			}
			
			
			pw.println("\t\t\t\t\t" + my_variable_declarations);
			pw.println("\t\t\t\t\t" + my_statements);
			pw.println("\t\t\texpr_" +tar_par_name +" = " +generated_expression +";");
		}

		if(!targets.contains(plain_target_name)){
        EEntity_definition target_type = target_parameter.getExtent(null);
				String tar_extent_name  = target_type.getName(null);
				String normalized_name = tar_extent_name.substring(0, 1).toUpperCase() + tar_extent_name.substring(1).toLowerCase();
				String tar_package = getEntityPackage(target_type);
				String etar_type = tar_package + "E" + normalized_name;
				String ctar_type = tar_package + "C" + normalized_name;
				pw.println("\t\t\t" +etar_type +" " +plain_target_name +"_inst = (" +etar_type +")tar_model.createEntityInstance(" +etar_type +".class);");		
				pw.println("\t\t\tValue " +plain_target_name +" = Value.alloc(" +ctar_type +".definition).set(_context, " +plain_target_name +"_inst);");
				if (jc.single_map_call) {
					if (jc.current_target == null) {
						pw.println("\t\t\tresult = " + plain_target_name + ";");
						jc.x_target_type = etar_type;
					} else {
						if (target_parameter == jc.current_target){
							// pw.println("\t\t\t//jc.target = jc.current_target: " + jc.current_target);
							pw.println("\t\t\tresult = " + plain_target_name + ";");
							jc.x_target_type = etar_type;
//							pw.println("\t\t\t//jc.x_target_type = " + etar_type);
						} else {
							// pw.println("\t\t\t//jc.target NOT = jc.current_target: " + jc.current_target);
						}
					}
				}
				targets.add(plain_target_name);
		}

		//		pw.println("\t\t\tif(!indeterminate_" +tar_par_name +")");

		if (jc.attribute_mappings != null) {

			if (jc.attribute_mappings.add(gen_target_attr)) {
				pw.println("\t\t\t" +gen_target_attr +" expr_" +tar_par_name +");"); //  d.setName();
			}
		} else  {
			pw.println("\t\t\t" +gen_target_attr +" expr_" +tar_par_name +");"); //  d.setName();
		}
		//		pw.println("\t\t\t// else INDETERMINATE");

		return data;
	}

  String getEntityPackage(EEntity_definition eds) throws SdaiException {
    // return an empty string if ed and eds in the same schema, and the package of eds otherwise
    String entity_package = "";
    SdaiModel entity_model = eds.findEntityInstanceSdaiModel();

    //    if (entity_model != current_model) {
    String entity_schema_name = getSchema_definitionFromModel(entity_model).getName(null);

    if (entity_schema_name.equalsIgnoreCase("Sdai_dictionary_schema")) {
      entity_package = "jsdai.dictionary.";
    } else {
      entity_package = "jsdai.S" + entity_schema_name.substring(0, 1).toUpperCase() + 
                       entity_schema_name.substring(1).toLowerCase() + ".";
    }

    //    }
    return entity_package;
  }

  ESchema_definition getSchema_definitionFromModel(SdaiModel sm)
                                            throws SdaiException {
    Aggregate ia = sm.getEntityExtentInstances(ESchema_definition.class);
    SdaiIterator iter_inst = ia.createIterator();

    while (iter_inst.next()) {
      ESchema_definition inst = (ESchema_definition) ia.getCurrentMemberObject(iter_inst);

      return inst;
    }

    return null;
  }

}
