var 	JO_VMM_OUTPUTFILE_SEPARATOR_LINE		= "######################################################################";
var	JO_VMM_OUTPUTFILE_COMMENT_PREFIX		= "# ";
var	JO_VMM_OUTPUTFILE_TXT_TAB					= "\t"; // "<span style='white-space:pre'>&#9;</span>";


/* ********************************************************************************************************** */
/* Object Class */
/* ********************************************************************************************************** */

function joVMMDataSimulatorClass (id, gui_parent_node_name, data_collection_name, data_name)
{
	this.id								= id;
	this.gui_type						= "tasks";
	this.gui_title_node				= null;
	this.data							= null;	

	this.data_collection_name		= data_collection_name;
	this.data_name						= data_name;
	this.data_id						= "";

	this.data_ok						= false;
	
	this.data_entity_id				= "";
	this.data_entity					= null;

	this.simulation_data			= null;
	this.task_data						= null;

	this.gui_list_node				= null;
	this.form_node						= null;
	this.task_edit_node				= null;
	
	this.preview_node					= null;
	
	this.zlayers						= null;
	this.zlayers_maxheight			= 0;
	this.zlayers_bottom				= null;
	this.zlayers_top					= null;

	this.gui_container_node_name	=
	this.gui_parent_node_name		= gui_parent_node_name;
	
	this.gui_container_node		=
	this.gui_parent_node			= joFIND (gui_parent_node_name);
	
	this.gui_body_node				= null;
	
	this.ResetData						= _joVMMDataSimulator_ResetData;
	this.ResetTaskForm				= _joVMMDataSimulator_ResetTaskForm;
	this.InitGui							= _joVMMDataSimulator_InitGui;
	this.ShowData						= _joVMMDataSimulator_ShowData;
	this.ShowDataEntity				= _joVMMDataSimulator_ShowDataEntity;
	this.SetActiveEntity			= _joVMMDataSimulator_SetActiveEntity;
	this.SaveData						= _joVMMDataSimulator_SaveData;

	this.AddButton						= _joVMMDataSimulator_AddButton;
	this.ActivateButtons			= _joVMMDataSimulator_ActivateButtons;
	this.SetButtonState				= _joVMMDataSimulator_SetButtonState;
	this.EditTask						= _joVMMDataSimulator_EditTask;
	this.SaveTaskData					= _joVMMDataSimulator_SaveTaskData;

	this.BuildTextFileData			= _joVMMDataSimulator_BuildTextFileData;
	this.Comment							= _joVMMDataSimulator_Comment;
	this.GetMaterialInfo			= _joVMMDataSimulator_GetMaterialInfo;
	
	this.ShowTextFileData			= _joVMMDataSimulator_ShowTextFileData;
	this.GetBoolStr					= _joVMMDataSimulator_GetBoolStr;
	this.AddVertFrameLayers		= _joVMMDataSimulator_AddVertFrameLayers;
	
	this.output_filename			= "";
	this.UploadTextFileData		= _joVMMDataSimulator_UploadTextFileData;

	this.GetObjectNr					= _joVMMDataSimulator_GetObjectNr;

	// events
	this.Action							= _joVMMDataSimulator_Action;
	this.OnEvent		 					= _joVMMDataSimulator_OnEvent;
	this.OnUpdateFormStatus		= _joVMMDataSimulator_OnUpdateFormStatus;

	this.StartSimulation			= _joVMMDataSimulator_StartSimulation;

	// do now
	this.InitGui();
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_InitGui()
{
	var list_node, title_node, footer_node, table_node, tr_node, td_node;
	
	this.form_node 												= joAddHTMLChildNode (this.gui_parent_node, "FORM");
		joDOM.SetAttribute 										(this.form_node, "vmm_gui_name", this.id);
		joAddEvent 													(this.form_node, "submit", function (event) { void(0); });
			
		table_node		 											= joAddTableChildNode (this.form_node, "simulator_main");
			tr_node													= joAddHTMLChildNode (table_node, "TR");
				td_node												= joAddHTMLChildNode (tr_node, "TD", "simulator");
					list_node										= joAddHTMLChildNode (td_node, "DIV", "vmm_simulator");
						title_node									= joAddHTMLChildNode (list_node, "DIV", "title");
							joVMMApp.AddTitle 					(title_node, "tasks");
							
						this.gui_list_node						= joAddHTMLChildNode (list_node, "DIV", "content", "task_list");
						footer_node									= joAddHTMLChildNode (list_node, "DIV", "footer");
							this.AddButton 						(footer_node, "genfile");
							this.AddButton 						(footer_node, "start");
							
				td_node												= joAddHTMLChildNode (tr_node, "TD", "simulator_task");
					td_node.rowSpan 								= 3;
					this.task_edit_node							= joAddHTMLChildNode (td_node, "DIV", "vmm_simulator vmm_task_params");
						this.task_edit_node.style.display	= "none";
		
			tr_node													= joAddHTMLChildNode (table_node, "TR");
				td_node												= joAddHTMLChildNode (tr_node, "TD", "simulator");
					list_node										= joAddHTMLChildNode (td_node, "DIV", "vmm_simulator");
						title_node									= joAddHTMLChildNode (list_node, "DIV", "title");
							joVMMApp.AddTitle 					(title_node, "simulation_params");
							
						joGUI.BuildForm 							("simulator_simulation_form", list_node);
		
			tr_node													= joAddHTMLChildNode (table_node, "TR");
				td_node												= joAddHTMLChildNode (tr_node, "TD", "simulator");
					list_node										= joAddHTMLChildNode (td_node, "DIV", "vmm_simulator");
						title_node									= joAddHTMLChildNode (list_node, "DIV", "title");
							joVMMApp.AddTitle 					(title_node, "fieldplot_params");

						joGUI.BuildForm 							("simulator_window_form", list_node);

	this.ShowData();
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ResetTaskForm()
{
	if (this.task_data) this.task_data = null;
	this.task_edit_node.style.display	= "none";
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ResetData()
{
	this.data 					= null;
	this.zlayers				= null;
	this.zlayers_maxheight	= 0;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ShowData (data_id)
{
	if (joVMM.xmlData)
	{
		var list_node 	= joVMM.xmlData.FindNode ("tasks");
		
		if (list_node)
		{
			var elements = list_node.childNodes;
			var element = elements.element_first;
			var element_id;
			
			// init
			joDOM.RemoveChildNodes (this.gui_list_node);
			this.data_entity_id = "";
		
			// fill
			while (element)
			{
				this.ShowDataEntity (element);
				element = element.element_next;
			}
		}

		this.simulation_data		= joVMM.xmlData.FindNode ("simulation");
		if (this.simulation_data)
		{
			joGUI.FillForm (this.form_node, this.simulation_data, "simulator_simulation_form");
			joGUI.FillForm (this.form_node, this.simulation_data, "simulator_window_form");
			joGUI.ShowFormValidState (this.form_node);
		}		 
		this.ActivateButtons();
	}	
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ShowDataEntity (element)
{
	var element_id, element_node, color_node, info_node, text_node;
	
	element_id									= element.name;

	element_node 								= joAddHTMLChildNode (this.gui_list_node, "DIV", "vmm_list_" + this.data_name, this.id + "_" + element_id);
	element_node.ondblclick 				= function() 
														{ 
															var curr_list_obj = joVMMApp.GetGuiObject (this.getAttribute ("vmm_data_obj"));
															if (!joDOM.GetFormElement (curr_list_obj.form_node, "button_add").disabled)
															{
																joVMMApp.gui_current_modeller.AddEntity (joVMMApp.GetGuiObject (this.getAttribute ("vmm_data_obj"))); 
															}
															return false; 
														};
	element_node.onclick 					= function() { joVMMApp.GetGuiObject (this.getAttribute ("vmm_data_obj")).SetActiveEntity (this); return false; };
	element_node.title 						= element.GetAttribute ("description");
	joDOM.SetAttribute (element_node, "vmm_data_obj", this.id);

	info_node 									= joAddHTMLChildNode (element_node, "DIV", "vmm_info");
	text_node									= joAddHTMLChildNode (info_node, "SPAN");

	text_node.innerHTML 					= element.name;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_SaveData()
{
	this.SaveTaskData();
	joGUI.SaveForm (this.form_node, this.data_collection_node, this.data_name, this.simulation_data, "simulator_simulation_form");
	joGUI.SaveForm (this.form_node, this.data_collection_node, this.data_name, this.simulation_data, "simulator_window_form");
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_SaveTaskData()
{
	if (this.task_data) joGUI.SaveForm (this.form_node, this.data_collection, this.data_name, this.task_data, this.data_entity_id + "_form");
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_SetActiveEntity (gui_node)
{
	this.SaveTaskData();

	if (this.data_entity_id != "")
	{
		var old_gui_node = joFIND (this.id + "_" + this.data_entity_id);
		old_gui_node.getElementsByTagName ("DIV")[0].className = "vmm_info";
		old_gui_node.style.backgroundColor = "";
	}
	
	gui_node.getElementsByTagName ("DIV")[0].className = "vmm_info active_txt";
	
	gui_node.style.backgroundColor 	= "#F5F2E1";
	
	this.data_entity						= null;
	this.data_entity_id 				= gui_node.id.substr (this.id.length + 1);
	var tasks 								= this.simulation_data.FindNodeByAttribute ("tasks" ,"","", true);
	if (tasks) this.data_entity 		= tasks.FindNode (this.data_entity_id);
	
	this.EditTask();
	this.ActivateButtons();
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_EditTask()
{	
	joDOM.RemoveChildNodes 	(this.task_edit_node);
	var title_node					= joAddHTMLChildNode (this.task_edit_node, "DIV", "title");
		joVMMApp.AddTitle 		(title_node, "task_" + this.data_entity_id, joGUI.GetLocaleText ("task") + ": " + this.data_entity_id);
	
	this.task_data					= this.simulation_data.FindNodeByAttribute (this.data_entity_id ,"","", true);
	
	joGUI.BuildForm 				(this.data_entity_id + "_form", this.task_edit_node);
	joGUI.FillForm 				(this.form_node, this.task_data, this.data_entity_id + "_form");
	
	this.task_edit_node.style.display 	= "block";
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_OnEvent (event_type, event_data_type)
{
	switch (event_type)
	{
		case JO_VMM_GUI_ON_GET_FOCUS:
			if (joVMM.xmlData)
			{
			}
		break;
	}
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_AddButton (parent_node, button_type)
{
	button_node						= joAddHTMLChildNode (parent_node, "BUTTON", "joGfxButton");
	button_node.name				= "button_" + button_type;
	button_node.title				= joGUI.GetLocaleText (button_type);
	button_node.onclick			= function() { joVMMApp.GetGuiObject (this.getAttribute ("vmm_data_obj")).Action (this.getAttribute ("name").substr ("button_".length)); return false; };
	joDOM.SetAttribute (button_node, "vmm_data_obj", this.id);
	
	joAddImageChildNode (button_node, 	"images/button_" + button_type + ".gif");
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ActivateButtons()
{
	var active_entity	 = this.data_entity_id == "" ? false : true;

	this.SetButtonState ("button_genfile", active_entity && this.data_ok);
	this.SetButtonState ("button_start", active_entity && this.data_ok);
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_SetButtonState (button_name, state)
{
	var button_node = joDOM.GetFormElement (this.form_node, button_name);
	if (button_node)
	{
		button_node.style.cursor = state ? "pointer" : "auto";
		button_node.disabled = state ? "" : "disabled";
		button_node.style.backgroundColor = state ? "" : "#ECE9D8";
		
		var image = joDOM.GetSubNode (button_node, "IMG");
		if (image)
		{
			image.style.visibility = state ? "visible" : "hidden";
		}
	}
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_Action (action_type)
{
	joVMMApp.GuiObjectAction (action_type, this); 
	return false;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_Comment (comment)
{
	return (JO_VMM_OUTPUTFILE_COMMENT_PREFIX + comment);
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_ShowTextFileData (with_upload)
{
	if (JO_DEBUG || !with_upload)
	{
		var outputfile_content = "";
		
		for (var i = 0; i < this.data.length; i++)
		{
			var data_line	= this.data[i];
			
			var comment_start = data_line.indexOf (JO_VMM_OUTPUTFILE_COMMENT_PREFIX);
			
			if (data_line == JO_VMM_OUTPUTFILE_SEPARATOR_LINE)
			{
				outputfile_content += "<span class='comment'>" + data_line + "</span><br />";
			}
			else if (comment_start == -1)
			{
				outputfile_content += data_line + "<br />";
			}
			else
			{
				outputfile_content += data_line.substr (0, comment_start);
				outputfile_content += "<span class='comment'>" + data_line.substr (comment_start) + "</span><br />";
			}	
		}
		
		joDEBUG_SHOW_OUTPUTFILE (outputfile_content);
	}
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_UploadTextFileData()
{
	var outputfile_content = "";
	
	for (var i = 0; i < this.data.length; i++)
	{
		outputfile_content += this.data[i] + "\n";
	}
	
	var upload_filename = joGUI.GetLocaleText ("file_path") + "/spool/" + joVMM.UserDir + this.output_filename + ".in.txt";
	ajax_upload (joGUI.GetLocaleText('php_path') + '/file_save.php', upload_filename, outputfile_content, OnStartJob);
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_AddVertFrameLayers (frame, show_mode, count_offset)
{
	// show mode 0: just count
	// show mode 1: frame object
	// show mode 2: normal object

	var result = 0;
	var frame_body			= frame.FindNode ("body", false);
	
	if (frame_body && frame_body.childNodes && frame_body.childNodes.element_first)
	{
		var curr_object		= frame_body.childNodes.element_first;
		var object_entity		= joVMM.entities["object"].FindNodeByAttribute ("", "id", curr_object.GetAttribute ("id", ""))
		
		if (object_entity)
		{
			var object_body	= object_entity.FindNode ("body", false);
			if (object_body && object_body.childNodes && object_body.childNodes.element_first)
			{
				var curr_element = object_body.childNodes.element_first;
				while (curr_element)
				{
					result++;
					var layerthickness 	= curr_element.GetAttribute ("thickness");
					switch (show_mode)
					{
						case 1: 
						{
							this.data.push ((count_offset + result) + JO_VMM_OUTPUTFILE_TXT_TAB + layerthickness);
							break;
						}
						case 2:
						{
							material_infos 	= this.GetMaterialInfo (curr_element.GetAttribute ("id"), layerthickness + ", frame");
							this.data.push ((count_offset + result) + JO_VMM_OUTPUTFILE_TXT_TAB + material_infos);
						}
					}
					curr_element = curr_element.element_next;
				}
			}
		}
	}
	
	
	return result;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_BuildTextFileData()
{
	this.ResetData();
	this.data = [];
	
	if (joVMM.entities["object"].childNodes && joVMM.entities["object"].childNodes.element_first)
	{
		var object_list	= joVMMApp.GetGuiObject ("vmm_object_list");
		var object 			= joVMM.entities["object"].childNodes.element_first;
		var object_count	= 0;
		var my_objects		= [];
		var curr_zlayers;
		var task_mode;
	
		//.........................................................................................get "spacer"
		var spacer 					= joVMM.entities["device"].FindNodeByAttribute ("", "id", "Spacer"); 
		var spacer_body			= spacer.FindNode ("body", false);
		var spacer_name			= "";
		var spacer_thickness	= new joVirtNumber (spacer.GetAttribute ("thickness"));
		var spacer_with_volume	= 0;

		if (spacer_body && spacer_body.childNodes && spacer_body.childNodes.element_first)
		{
			spacer_name				= spacer_body.childNodes.element_first.GetAttribute ("id");
			var zero 				= new joVirtNumber ("0");
			if (zero.IsSmallerThan (spacer_thickness)) spacer_with_volume = 1;
		}	

		while (object)
		{
			if (	!joNumCheck (object.GetAttribute ("is_virtual"), "boolean") && 
					joVMM.EntityIsInDevice ("object", object.GetAttribute ("id")))
			{
				object_count++;
				if (object_count == 1)
				{
					this.zlayers 	= joVMM.GetObjectLayerArray (object);
				}
				else
				{
					curr_zlayers	= joVMM.GetObjectLayerArray (object);
					this.zlayers	= joVMM.CombineObjectLayerArrays (this.zlayers, curr_zlayers);
				}
			}
			
			object = object.element_next;
		}
		this.zlayers = joVMM.ObjectCalcLayerHeightsArray (this.zlayers);

		//............................................................................................task mode
		if (this.data_entity)
		{
			task_mode = this.data_entity.GetAttribute ("mode");
			this.data.push ("#!" + task_mode);
			this.data.push (this.Comment ("(task mode)"));
			this.data.push (this.Comment (""));
		}

		this.data.push (JO_VMM_OUTPUTFILE_SEPARATOR_LINE);
		this.data.push (this.Comment ("input file generated by " + VMM_APP_NAME + " " + VMM_APP_VERSION));
		this.data.push (this.Comment ("at " + new Date()));

		this.data.push (JO_VMM_OUTPUTFILE_SEPARATOR_LINE);
		this.data.push (this.Comment (""));

		//...............................................................................nz (number of zlayers)
		var frame_top					= joVMM.entities["device"].FindNodeByAttribute ("", "id", "FrameTop"); 
		var frame_bottom				= joVMM.entities["device"].FindNodeByAttribute ("", "id", "FrameBottom"); 
		var count_frame_bottom		= this.AddVertFrameLayers (frame_bottom, 0, 0);
		var count_frame_top			= this.AddVertFrameLayers (frame_top, 0, 0);
		var count_all_layers		= count_frame_bottom + (this.zlayers ? this.zlayers.length : 0) + spacer_with_volume + count_frame_top;
		this.data.push 		(this.Comment ("nz --- number of z-layers (growth direction)"));
		this.data.push 		(count_all_layers + "");

		//................................................................................................dzmax
		var sim_input 	= this.simulation_data.FindNode ("input");
		if (sim_input)
		{
			this.data.push (this.Comment ("dzmax(REAL) pz(INT) --- mesh parameters"));
			
			var dzmax 	= sim_input.GetAttribute ("grid_size_z");
			var pz		= sim_input.GetAttribute ("max_degree_z");
			
			this.data.push (dzmax + JO_VMM_OUTPUTFILE_TXT_TAB + pz);
		}
		
		//...............................................................................................layers
		this.data.push (this.Comment ("layers"));
		
		var device_offset		= this.AddVertFrameLayers (frame_bottom, 1, 0);
		
		for (var i = 0; this.zlayers && i < this.zlayers.length; i++)
		{
			this.data.push ((i + device_offset + 1) + JO_VMM_OUTPUTFILE_TXT_TAB + this.zlayers[i].Normalize());	
		}
		
		if (spacer_with_volume)
		{
			this.data.push ((i + device_offset + 1) + JO_VMM_OUTPUTFILE_TXT_TAB + spacer_thickness.Normalize());	
			i++;
		}
		
		this.AddVertFrameLayers (frame_top, 1, i + device_offset);
		
		//.........................................................................................object count
		this.data.push (this.Comment ("count of different waveguides"));
		this.data.push (object_count + "");
	
		//...................................................................................object definitions
		object = joVMM.entities["object"].childNodes.element_first;
		object_count = 0;
		while (object)
		{
			
			if (!joNumCheck (object.GetAttribute ("is_virtual"), "boolean") && joVMM.EntityIsInDevice ("object", object.GetAttribute ("id")))
			{
				object_count++;
				my_objects.push (object.GetAttribute ("id"))
				this.data.push (this.Comment ("waveguide " + object_count + ": " + object.GetAttribute ("id")));
				var object_body 	= object.FindNode ("body");
				
				this.AddVertFrameLayers (frame_bottom, 2, 0);
				if (object_body && object_body.childNodes.element_first)
				{
					var layer			= object_body.childNodes.element_first;
					var zlayeridx		= 0;
					var layercount	 	= 1;
					var cumzlayer 		= new joVirtNumber();
					var layerthickness;
					var material_info;
					var material_infos;
					var material_name;

					while (layer)
					{			
						material_infos 	= "";
						material_name		= layer.GetAttribute ("id", "");
						layerthickness 	= new joVirtNumber (joGetRealPartAsFloat (layer.GetAttribute ("thickness")) + "");
						material_infos 	= this.GetMaterialInfo (material_name, layerthickness.Normalize());
						
						cumzlayer.Clone (this.zlayers [zlayeridx]);
						while (!layerthickness.IsSmallerThan (cumzlayer) && zlayeridx < this.zlayers.length)
						{
							this.data.push ((layercount + count_frame_bottom) + JO_VMM_OUTPUTFILE_TXT_TAB + material_infos);
	
							zlayeridx++;
							if (zlayeridx < this.zlayers.length)
							{
								cumzlayer.Add (this.zlayers [zlayeridx]);
							}
							layercount++;
						}
						layer = layer.element_next;
					}			
					
				}
				
				//................................................................................spacer material
				
				while (zlayeridx < this.zlayers.length)
				{
					material_infos 	= this.GetMaterialInfo (spacer_name, "spacer");
					this.data.push (layercount + count_frame_bottom + JO_VMM_OUTPUTFILE_TXT_TAB + material_infos);
					zlayeridx++;
					layercount++;
				}
				
				//..................................................................................spacer thickness
				
				if (spacer_with_volume)
				{
					material_infos 	= this.GetMaterialInfo (spacer_name, spacer_thickness.Normalize());
					this.data.push (layercount + count_frame_bottom + JO_VMM_OUTPUTFILE_TXT_TAB + material_infos);
					layercount++;
				}
	
				this.AddVertFrameLayers (frame_top, 2, layercount - 1 + count_frame_bottom);
			}
			
			object = object.element_next;
		}
		
		//..............................................................................count objects in device
		this.data.push (JO_VMM_OUTPUTFILE_SEPARATOR_LINE);
		this.data.push (this.Comment ("count objects in device (nx --- number of x-layers)"));
		
		var count_obj = joVMM.GetCountSubObjects (joVMM.entities["device"]);
		this.data.push (count_obj + "");
		
		//..........................................................................................device body
		this.data.push (this.Comment ("device setup (w(:), dx(:), lw(:))"));

		var device_part = joVMM.entities["device"].childNodes.element_first;
		var device_part_count = 1;
		while (device_part)
		{
			if (device_part.GetAttribute ("type") == "device")
			{
				var elements = device_part.FindNode ("body");
				if (elements)
				{
					this.data.push (this.Comment ("device part " + device_part.GetAttribute ("id")));
					var curr_element = elements.childNodes.element_first;
					while (curr_element)
					{
						if (curr_element.name == "object") 
						{
							this.data.push (device_part_count + JO_VMM_OUTPUTFILE_TXT_TAB + curr_element.GetAttribute ("width") + JO_VMM_OUTPUTFILE_TXT_TAB + this.GetObjectNr (curr_element.GetAttribute ("id"), my_objects) + JO_VMM_OUTPUTFILE_TXT_TAB + this.Comment ("object " + curr_element.GetAttribute ("id")));
							device_part_count++;
						}
						else 
						{
							var macro = joVMM.entities["macro"].FindNodeByAttribute ("macro", "id", curr_element.GetAttribute ("id", ""));
							this.data.push (this.Comment ("macro " + curr_element.GetAttribute ("id")));
							
							var macro_count = parseInt (curr_element.GetAttribute ("count"));
							for (var i = 0; macro && i < macro_count; i++)
							{
								var subelements = macro.FindNode ("body");
								if (subelements)
								{
									var subelement = subelements.childNodes.element_first;
									while (subelement)
									{
										this.data.push (device_part_count + JO_VMM_OUTPUTFILE_TXT_TAB + subelement.GetAttribute ("width") + JO_VMM_OUTPUTFILE_TXT_TAB + this.GetObjectNr (subelement.GetAttribute ("id"), my_objects) + JO_VMM_OUTPUTFILE_TXT_TAB + this.Comment ("object " + subelement.GetAttribute ("id")));
										subelement = subelement.element_next;
										device_part_count++;
									}
								}
							}						
						}
						curr_element = curr_element.element_next;
					}
				}
			}
		
			device_part = device_part.element_next;
		}

		//...........................................................................................task infos
		if (this.data_entity)
		{
		
			//........................................................................................boundaries
			var boundaries 	= this.data_entity.FindNode ("boundaries");
			var b_bottom 		= boundaries.FindNode ("bottom").GetAttribute ("boundary_condition_vert");
			var b_top 			= boundaries.FindNode ("top").GetAttribute ("boundary_condition_vert");
			this.data.push 	(this.Comment ("lower_bc(PEC/PMC) upper_bc(PEC/PMC) --- lower and upper boundary condition"));
			this.data.push 	(b_bottom + JO_VMM_OUTPUTFILE_TXT_TAB + b_top);
			
			var b_left = boundaries.FindNode ("left");
			if (b_left)
			{
				b_left 			= b_left.GetAttribute ("boundary_condition_horz");
				var b_right 	= boundaries.FindNode ("right").GetAttribute ("boundary_condition_horz");
				this.data.push 	(this.Comment ("left_bc(PEC/PMC/OPEN) right_bc(PEC/PMC/OPEN) --- left and right boundary condition"));
				this.data.push 	(b_left + JO_VMM_OUTPUTFILE_TXT_TAB + b_right);
			}
			
			//.......................................................................................polarization
			var polarization = this.data_entity.GetAttribute ("polarization");
			if (polarization != "" && this.data_entity_id.substr (0, 5) != "cross")
			{
				this.data.push (this.Comment ("polarization(TE/TM) --- polarization"));
				this.data.push (polarization);
			}			
			
			//..........................................................................................task info
			if (task_mode == "VMM2D")
			{
				this.data.push (this.Comment ("task(MODE_RT/RAD_EXC_ANGLE_SWEEP/RAD_EXC_WAVELENGTH_SWEEP) --- vmm model"));
				this.data.push (this.data_entity.name.toUpperCase());
			}
			else
			{
				this.data.push (this.Comment ("model(VECTORIAL/SCALAR_TE/SCALAR_TM)"));
				var model_value = this.data_entity.name.substr ("cross_sec_".length).toUpperCase();
				if (model_value == "SCALAR") model_value += "_" + polarization;
				this.data.push (model_value);
			}
		
			//...................................................................................wavelength/angle
			var wa_data 	= this.data_entity.FindNode ("wavelength");
			if (!wa_data)
			{
				wa_data 		= this.data_entity.FindNode ("angle");
			}
			if (wa_data)
			{
				this.data.push (this.Comment ("sweep: start / end /points (wavelength or angle)"));
				var start	= wa_data.GetAttribute ("start");
				var end		= wa_data.GetAttribute ("end");
				var count	= wa_data.GetAttribute ("count");
				this.data.push 	(start + JO_VMM_OUTPUTFILE_TXT_TAB + end + JO_VMM_OUTPUTFILE_TXT_TAB + count);
			}
			
			//..........................................................................................direction
			var direction = this.data_entity.GetAttribute ("direction");
			if (direction != "")
			{
				this.data.push (this.Comment ("excitation_direction"));
				this.data.push (("FROM_" + direction.substr (0, direction.indexOf ("to") - 1)).toUpperCase());
			}			
			
			//............................................................................................n modes
			var n_modes = this.data_entity.GetAttribute ("n_modes");
			if (n_modes != "")
			{
				this.data.push (this.Comment ("num_modes(INT) --- number of incident waveguide modes"));
				this.data.push (n_modes);
			}			

			//................................................................wave length and root_solver_options
			if (task_mode == "CROSSSECWG")
			{
				var wavelength = this.data_entity.GetAttribute ("wavelength");
				if (wavelength != "")
				{
					this.data.push (this.Comment ("wavelength"));
					this.data.push (wavelength);
				}
				
				var root_solver 	= this.data_entity.FindNode ("root_solver_options");
				if (root_solver)
				{
					var neff_guess			= root_solver.GetAttribute ("neff_guess", "");
					var tolerance			= root_solver.GetAttribute ("tolerance", "");
					var initstep 			= root_solver.GetAttribute ("initstep", "");
					var max_iteration 	= root_solver.GetAttribute ("max_iteration", "");
	/*				var max_iteration_2	= root_solver.GetAttribute ("max_iteration_2", ""); */
					
					var root_info										= neff_guess;
					if (tolerance != "")			root_info += JO_VMM_OUTPUTFILE_TXT_TAB + tolerance;
					if (initstep != "")				root_info += JO_VMM_OUTPUTFILE_TXT_TAB + initstep;
					if (max_iteration != "")		root_info += JO_VMM_OUTPUTFILE_TXT_TAB + max_iteration;
	/*				if (max_iteration_2 != "")	root_info += JO_VMM_OUTPUTFILE_TXT_TAB + max_iteration_2; */

					this.data.push (this.Comment ("neff_guess [tol initstep maxitn] --- parameters for root solver"));
					this.data.push (root_info);
				}
			}
			
			//....................................................................................sweep parameter
			else if (task_mode == "VMM2D" && this.data_entity.name.toUpperCase() != "MODE_RT")
			{
				var info1 = this.data_entity.GetAttribute ("wavelength");
				if (info1 == "")
				{
					info1 = this.data_entity.GetAttribute ("angle", "0");
				}
				this.data.push (this.Comment ("angle or wavelength"));
				this.data.push (info1);
				
				//......................................................................................wavesource
				var wavesource		= this.data_entity.FindNode ("wavesource");
				if (wavesource)
				{
					var zsource 			= wavesource.GetAttribute ("zsource");
					var excitation_type	= wavesource.GetAttribute ("excitation_type").toUpperCase();
					var xstart 				= wavesource.GetAttribute ("xstart");
					var xend					= wavesource.GetAttribute ("xend");
					var xcenter				= wavesource.GetAttribute ("xcenter");
					var xsigma				= wavesource.GetAttribute ("xsigma");
					
					this.data.push (this.Comment ("z-position of source"));
					this.data.push (zsource);
				
					this.data.push (this.Comment ("excitation_type(PLANE/GAUSS)"));
					this.data.push (excitation_type);
				
					this.data.push (this.Comment ("xstart xend [xcenter xsigma]"));
					var info2				= xstart + JO_VMM_OUTPUTFILE_TXT_TAB + xend;
					if (excitation_type == "GAUSS")
						info2					+= JO_VMM_OUTPUTFILE_TXT_TAB + xcenter + JO_VMM_OUTPUTFILE_TXT_TAB + xsigma;
					this.data.push (info2);
				}
			}
			
			//..........................................................................................save data
			var out_data 	= this.data_entity.FindNode ("output");
			if (out_data)
			{
				var save_local_wg_fields = out_data.GetAttribute ("save_local_wg_fields");
				if (save_local_wg_fields != "")
				{
					this.data.push (this.Comment ("save_local_waveguide_fields"));
					this.data.push (save_local_wg_fields.toUpperCase());
				}
				
				var save_global_Fx = out_data.GetAttribute ("save_global_Fx");
				if (save_global_Fx != "")
				{
					var save_global_Fy 	= out_data.GetAttribute ("save_global_Fy", "FALSE");
					var save_global_Fz 	= out_data.GetAttribute ("save_global_Fz", "FALSE");
					this.data.push 		(this.Comment ("save_global_Fy save_global_Fz save_global_Fx"));
					this.data.push 		(this.GetBoolStr (save_global_Fy) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Fz) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Fx));
				}
				
				var save_global_Ex = out_data.GetAttribute ("save_global_Ex");
				if (save_global_Ex != "")
				{
					var save_global_Ey 	= out_data.GetAttribute ("save_global_Ey", "FALSE");
					var save_global_Ez 	= out_data.GetAttribute ("save_global_Ez", "FALSE");
					this.data.push 		(this.Comment ("save_global_Ey save_global_Ez save_global_Ex"));
					this.data.push 		(this.GetBoolStr (save_global_Ey) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Ez) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Ex));
				}
				
				var save_global_Hx = out_data.GetAttribute ("save_global_Hx");
				if (save_global_Hx != "")
				{
					var save_global_Hy 	= out_data.GetAttribute ("save_global_Hy", "FALSE");
					var save_global_Hz 	= out_data.GetAttribute ("save_global_Hz", "FALSE");
					this.data.push 		(this.Comment ("save_global_Hy save_global_Hz save_global_Hx"));
					this.data.push 		(this.GetBoolStr (save_global_Hy) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Hz) + JO_VMM_OUTPUTFILE_TXT_TAB 
												+ this.GetBoolStr (save_global_Hx));
				}
			}
			
			//............................................................................................window
			if (sim_input)
			{
				var in_window 	= sim_input.FindNode ("window");
				if (in_window)
				{
					var meshsize	 	= in_window.GetAttribute ("meshsize");
					var dots 			= in_window.GetAttribute ("dots_per_mesh");
					var left	 			= in_window.GetAttribute ("left");
					var bottom 			= in_window.GetAttribute ("bottom");
					var right 			= in_window.GetAttribute ("right");
					var top 				= in_window.GetAttribute ("top");

					this.data.push	 	(this.Comment ("meshsize dots_per_mesh xleft zbottom xright ztop"));
					this.data.push 	(meshsize + JO_VMM_OUTPUTFILE_TXT_TAB
											+ dots + JO_VMM_OUTPUTFILE_TXT_TAB
											+ left + JO_VMM_OUTPUTFILE_TXT_TAB
											+ bottom + JO_VMM_OUTPUTFILE_TXT_TAB
											+ right + JO_VMM_OUTPUTFILE_TXT_TAB
											+ top);
				}
			}
			
			//............................................................................................output
			var sim_output = this.simulation_data.FindNode ("output");
			if (sim_output)
			{
				this.output_filename	= joVMM.project_name + "_" + this.data_entity.name + "_" + sim_output.GetAttribute ("file_name", "");
				this.data.push	 			(this.Comment ("output_filename --- base output filename without path specification"));
				this.data.push 			(this.output_filename);
				
				var fileformat				= sim_output.GetAttribute ("file_format", "").toUpperCase();
				this.data.push	 			(this.Comment ("output_format"));
				this.data.push 			(fileformat);
				
			}
		}
	}
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_GetBoolStr (value)
{
	var istrue = joNumCheck (value, "boolean");
	return (istrue ? "TRUE" : "FALSE");
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_GetMaterialInfo (material_name, layerthickness)
{
	var material_infos		= "";

	var material 				= joVMM.entities["material"].FindNodeByAttribute ("material", "id", material_name);
	if (material)
	{
		var parameters 		= material.FindNode ("parameters");
		var parameter			= parameters.childNodes.element_first;
		material_infos			= parameter.GetAttribute ("xx");
		material_info			= parameter.GetAttribute ("zz");
		if (material_info != "")
		{
			material_infos 	= material_infos + JO_VMM_OUTPUTFILE_TXT_TAB + material_infos + JO_VMM_OUTPUTFILE_TXT_TAB + material_info;
		}
		material_infos			+= JO_VMM_OUTPUTFILE_TXT_TAB + JO_VMM_OUTPUTFILE_COMMENT_PREFIX + material_name + " (" + layerthickness + ")";
	}

	return material_infos;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_GetObjectNr (object_name, object_array)
{
	var result = 0;
	for (var i = 0; i < object_array.length && !result; i++)
	{
		if (object_array[i] == object_name) result = i+1;
	}
	return result;
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_OnUpdateFormStatus (form_node, form_status, field_node) 
{ 
	this.data_ok = form_status;
	this.ActivateButtons();
}

/* ********************************************************************************************************** */

function _joVMMDataSimulator_StartSimulation (with_upload) 
{ 
	if (this.task_data) 
	{
		joGUI.SaveForm (this.form_node, this.data_collection, this.data_name, this.task_data, this.data_entity_id + "_form");
		joVMM.SaveTaskFormData();
	}
	
	var checkdata = joVMM.ValidateDataForSimulation();
	if (checkdata == "ok")
	{
		this.BuildTextFileData();
		this.ShowTextFileData (with_upload);
		if (with_upload) this.UploadTextFileData();
	}
	else
	{
		joGUI.Alert (joGUI.GetLocaleText (checkdata) + "<br />" + joGUI.GetLocaleText ("warning_cannot_start_simulation"), joGUI_ALERT_TYPE_WARNING, joGUI_ALERT_BUTTON_OK);
	}
}

