/***********************************************************************
*
*       ELMER, A Computational Fluid Dynamics Program.
*
*       Copyright 1st April 1995 - , Center for Scientific Computing,
*                                    Finland.
*
*       All rights reserved. No part of this program may be used,
*       reproduced or transmitted in any form or by any means
*       without the written permission of CSC.
*
*                Address: Center for Scientific Computing
*                         Tietotie 6, P.O. BOX 405
*                         02101 Espoo, Finland
*                         Tel.     +358 0 457 2001
*                         Telefax: +358 0 457 2302
*                         EMail:   Jari.Jarvinen@csc.fi
************************************************************************/

/***********************************************************************
Program:    ELMER Front
Module:     ecif_inputCadi.cpp
Language:   C++
Date:       20.10.98
Version:    1.00
Author(s):  Martti Verho
Revisions:

Abstract:   Implementation (read Elmer Cadinterface model file)

************************************************************************/

#include "ecif_body.h"
#include "ecif_bodyLayer.h"
#include "ecif_bodyElement.h"
#include "ecif_bodyElementGroup.h"
#include "ecif_bodyElement1D.h"
#include "ecif_control.h"
#include "ecif_geometry.h"
#include "ecif_inputFront.h"
#include "ecif_model.h"
#include "ecif_model_aux.h"
#include "ecif_parameter.h"
#include "ecif_userinterface.h"
#include "ecif_timer.h"

extern char read_buffer[];

bool IS_FATAL = true;
bool NOT_FATAL = false;

const int isOk = emf_OK;
const int notOk = emf_ERROR;

// Init static class variables
//
bool InputFront::isChecked = false;
bool InputFront::isEgfInput = false;
bool InputFront::isEmfInput = false;
double InputFront::inputUnit = 1.0;  // By default input is in meters

template <class T> ostream&
output_array(ostream& out, UserInterface* gui, int length, T* array)
{
  ostrstream strm;
  for (int i = 0; i < length; i++) {
    strm << array[i];
  }
  strm << ends;
  gui->showMsg(strm.str());

  return out;
}


InputFront::InputFront(enum ecif_modelDimension m_dim,
                       ifstream& in_file, char* in_filename):
Input(m_dim, in_file, in_filename)
{
  isChecked = false;
  isEgfInput = false;
  isEmfInput = false;
  inputUnit = 1.0; // Default input unit is 1m
}


// Add normal (single) component
//
bool
InputFront::addElementComponent(ecif_Element_X& tx, ecif_geometryType gtype)
{
  // Current and new nof components
  int nof_components = tx.nof_components;
  tx.nof_components++;

  // Allocate new array and copy old components
  ecif_ElementComponent_X** components = new ecif_ElementComponent_X*[tx.nof_components];

  for (int i = 0; i < nof_components; i++) {
    components[i] = tx.components[i];
  }

  // Update tx
  delete[] tx.components;
  tx.components = components;

  // Allocate and store one new component
  ecif_ElementComponent_X* txc = new ecif_ElementComponent_X;
  init_trx_data(*txc);
  txc->gmtr_type = gtype;

  tx.components[tx.nof_components - 1] = txc;

  // Set geometry (union member) by element type
  if ( tx.tplg_type == ECIF_VERTEX) {
    txc->geometry.vertex = new ecif_VertexGeometry_X;
    init_trx_data(*txc->geometry.vertex);

  } else if ( tx.tplg_type == ECIF_EDGE) {
    txc->geometry.edge = new ecif_EdgeGeometry_X;
    init_trx_data(*txc->geometry.edge);

  } else if ( tx.tplg_type == ECIF_FACE ) {
    txc->geometry.face = new ecif_FaceGeometry_X;
    init_trx_data(*txc->geometry.face);
  }

  return true;
}


bool
InputFront::addFunctionComponentData(ecif_DllArg& da ,ecif_ElementComponent_X& tx)
{
  tx.isFunction = true;
  tx.isCpp = da.is_cpp;
  tx.isF95 = da.is_f95;
  tx.isMatc = da.is_matc;

  update_dyna_string(tx.functionName, da.func);
  update_dyna_string(tx.libraryName, da.lib);

  tx.startVertex = da.start_vertex;
  tx.endVertex = da.end_vertex;

  tx.argc = da.argc;

  if ( tx.argc > 0 ) {
    tx.argv = new double[tx.argc];
    for (int i = 0; i < tx.argc; i++) {
      tx.argv[i] = da.argv[i];
    }
  }

  if ( da.has_start_point ) {
    tx.startPoint = new Point3[1];
    (*tx.startPoint)[0] = da.start_point[0];
    (*tx.startPoint)[1] = da.start_point[1];
    (*tx.startPoint)[2] = da.start_point[2];
  }

  if ( da.has_end_point ) {
    tx.endPoint = new Point3[1];
    (*tx.endPoint)[0] = da.end_point[0];
    (*tx.endPoint)[1] = da.end_point[1];
    (*tx.endPoint)[2] = da.end_point[2];
  }

  // Copy any Matc-expression strings into component
  //
  copyMatcValueTable(da.matcTable, tx.matcTable);

  return true;
}


// Find geometry type code
//
ecif_geometryType
InputFront::getElementGeometryType(const char* type_name , ecif_Element_X& tx)
{
  ecif_geometryType gmtr_type;
  char* type = (char*) type_name;

  if ( LibFront::ncEqual(type, "Circle") ) {
    gmtr_type = ECIF_CIRCLE;
  }
  else if ( LibFront::ncEqual(type, "Ellipse") ) {
    gmtr_type = ECIF_ELLIPSE;
  }
  else if ( LibFront::ncEqual(type, "Hyperbola") ) {
    gmtr_type = ECIF_HYPERBOLA;
  }
  else if ( LibFront::ncEqual(type, "Line") ) {
    gmtr_type = ECIF_LINE;
  }
  else if ( LibFront::ncEqual(type, "Parabola") ) {
    gmtr_type = ECIF_PARABOLA;
  }
  else if ( LibFront::ncEqual(type, "PolyLine") ) {
    gmtr_type = ECIF_POLYLINE;
  }
  else if ( LibFront::ncEqual(type, "Spline") ) {
    gmtr_type = ECIF_SPLINE;
  }
  else if ( LibFront::ncEqual(type, "Nurbs") ) {
    gmtr_type = ECIF_NURBS;
  }
  else {
    gmtr_type = ECIF_NODIM;
  }

  return gmtr_type;
}


// Read one field for a body
int
InputFront::readBody(emf_ObjectData_X* od)
{
  static UserInterface* gui = theControlCenter->getGui();
  strstream strm1, strm2;

  static ecif_Body_X tx;
  static ecif_BodyLayer_X tx_layer;

  static int current_layer_tag = NO_INDEX;
  static char* current_layer_name = NULL;

  static IdArray edge_tags;
  static IdArray edge_group_tags;
  static IdArray vertex_groups;
  static IdArray vertex_tags;
  static int vertex_group_id = 0;
  static int layer = 0;
  static bool new_layer = false;

  static Body* body = NULL;
  static BodyLayer* bl = NULL;

  const char* fn = od->field_name;

  // This is the field id (when it make sense!)
  int id;
  LibFront::setNumericData(id, 0);

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  // New body object started
  // =======================
  if (od->is_object_start) {

     // Init tx data
    init_trx_data(tx);
    init_trx_data(tx_layer);

    current_layer_tag = NO_INDEX;
    delete[] current_layer_name;
    current_layer_name = NULL;
    bl = NULL;

    tx.tag = od->object_id;
    tx.is_checked = geometryIsChecked();
  }


  // ---------------
  // Body level data
  // ---------------

  //-Body name
  if ( LibFront::in(EMF_NAME, fn) ) {
    //update_dyna_string(tx.name, (char*) od->data);
    readName(od, tx.name);
  }

  //-Body type
  else if ( LibFront::in(EMF_TYPE, fn) ) {
    if ( LibFront::in("Open", (char*) od->data) ) {
      tx.is_open = true;
    } else if ( LibFront::in("Bem", (char*) od->data) ) {
      tx.is_checked = true;
      tx.is_bem = true;
    } else if ( LibFront::in("Virtual", (char*) od->data) ) {
      tx.is_checked = true;
      tx.is_virtual = true;
    }
   }

  //-Body color
  else if ( LibFront::in(EMF_COLOR, fn) ) {
    if ( readColor(od, tx.color) ) {
      tx.has_color = true;
    }
  }

  //-Body Force id
  else if ( LibFront::in(EMF_BODY_FORCE, fn) ) {
    LibFront::setNumericData(tx.body_force_id, 0);
  }

  //-Body Parameter id
  else if ( LibFront::in(EMF_BODY_PARAMETER, fn) ) {
    LibFront::setNumericData(tx.body_param_id, 0);
  }

   //-Equation id
  else if ( LibFront::in(EMF_EQUATION, fn) ) {
    LibFront::setNumericData(tx.equation_id, 0);
  }

  //-Initial condition
  else if ( LibFront::in(EMF_INITIAL_CONDITION, fn) ) {
    LibFront::setNumericData(tx.init_cond_id, 0);
  }

  //-Material
  else if ( LibFront::in(EMF_MATERIAL, fn) ) {
    LibFront::setNumericData(tx.material_id, 0);
  }

  //-Edge groups (for virtual body)
  //
  else if ( LibFront::in("Edge Groups", fn) ||
            LibFront::in("Element Groups", fn)
          ) {

    int tag;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tag, i);
      edge_group_tags.push_back(tag);
    }
  }


  // ----------------
  // Layer level data
  // ----------------

  //-Layer tag
  else if ( LibFront::in(EMF_LAYER, fn) ||
            LibFront::in(EMF_LAYER_TAG, fn)
          ) {
    LibFront::setNumericData(current_layer_tag, 0);
  }

  //-Layer type
  else if ( LibFront::in(EMF_LAYER_TYPE, fn) ) {
    if ( LibFront::in("Open", (char*) od->data) ) {
      tx_layer.is_open = true;
    }
  }

   //-Layer name
  else if ( LibFront::in(EMF_LAYER_NAME, fn) ) {
    tx_layer.has_name = true;
    update_dyna_string(current_layer_name, (char*) od->data);
  }

  //-Layer color
  else if ( LibFront::in(EMF_LAYER_COLOR, fn) ) {
    if ( readColor(od, tx_layer.color) ) {
      tx_layer.has_color = true;
    }
  }

  //-Element loop tags
  // EMF_EDGE_LOOPS (egf-style)
  // EMF_ELEMENT_LOOPS (emf-style)
  //
  else if ( LibFront::in(EMF_EDGE_LOOPS, fn) ||
            LibFront::in(EMF_ELEMENT_LOOPS, fn)
          ) {
    new_layer = true;

    tx_layer.nof_elem_loops = od->data_length;
    delete[] tx_layer.elem_loop_tags;
    tx_layer.elem_loop_tags = NULL;

    if ( tx_layer.nof_elem_loops > 0 ) {
      tx_layer.elem_loop_tags = new int[tx_layer.nof_elem_loops];
    }

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx_layer.elem_loop_tags[i], i);
    }
  }

  //-Body vertices as tags (short egf-style)
  //
  else if ( LibFront::in(EMF_VERTICES, fn) ||
            LibFront::in(EMF_POLYGON, fn)
          ) {

    new_layer = true;

    vertex_group_id++;

    int tag, first_tag;

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tag, i);
      vertex_groups.push_back(vertex_group_id);
      vertex_tags.push_back(tag);

      if ( i == 0) {
        first_tag = tag;
      }
    }

    // Close the loop if given as open!
    if ( tag != first_tag ) {
      vertex_tags.push_back(first_tag);
      vertex_groups.push_back(vertex_group_id);
    }
  }

  //-Edge tags
  //
  else if ( LibFront::in(EMF_EDGES, fn) ) {

    new_layer = true;

    int tag;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tag, i);
      edge_tags.push_back(tag);
    }
  }

  //-Grid parameter ids
  //
  else if ( LibFront::in(EMF_GRID_PARAMETER_IDS, fn) ) {
    tx_layer.nof_grid_param_ids = od->data_length;
    tx_layer.grid_param_ids = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx_layer.grid_param_ids[i], i);
    }

    if ( bl != NULL ) {
      bl->setGridParameterIds(od->data_length,
                              tx_layer.grid_param_ids);
    }
  }

  //-Excluded mesh indices
  //
  else if ( LibFront::in(EMF_EXCLUDED_MESH_INDICES, fn) ) {
    tx_layer.nof_excluded_meshes = od->data_length;
    tx_layer.excluded_mesh_indices = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx_layer.excluded_mesh_indices[i], i);
    }

    if ( bl != NULL ) {
      bl->setExcludedMeshData(od->data_length,
                              tx_layer.excluded_mesh_indices);
    }

  }

  //-Grid parameter mesh indices
  //
  else if ( LibFront::in(EMF_GRID_PARAMETER_MESH_INDICES, fn) ) {
    tx_layer.grid_param_mesh_indices = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx_layer.grid_param_mesh_indices[i], i);
    }

    if ( bl != NULL ) {
      bl->setGridParameterMeshIndices(od->data_length,
                                      tx_layer.grid_param_mesh_indices);
    }

  }

  //-Unknown field
  //
  else {
    unknownFieldMsg(od, IS_FATAL);
  }

  //----Body and the first layer or some additional layer is ready
  //
  if ( new_layer ) {

    // First layer --> a new body
    if ( layer == 0 ) {
      model->addBody(tx);
      body = model->getBodyByTag(tx.tag);
    }

    // Add new layer to the body
    // =========================
    if ( body != NULL ) {

      tx_layer.tag = current_layer_tag;
      update_dyna_string(tx_layer.name, current_layer_name);

      tx_layer.body_id = body->Id();
      tx_layer.body_tag = body->Tag();

      body->addLayer(tx_layer);
      body->addElementLoopTags(layer, tx_layer.nof_elem_loops, tx_layer.elem_loop_tags);

      int nof_edges = edge_tags.size();
      int nof_vertices = vertex_tags.size();

      // Store edges as pending elements (will be resolved later when
      // the whole file is read
      if ( nof_edges > 0 ) {
        for (int i = 0; i < nof_edges; i++) {
          body->addPendingElement(layer, edge_tags[i]);
        }
        edge_tags.clear();
      }

      // Store vertices as pending start-end points (will be resolved later when
      // the whole file is read
      if ( nof_vertices > 0 ) {
        for (int i = 0; i < nof_vertices; i++) {
          body->addPendingVertex(layer, vertex_groups[i], vertex_tags[i]);
        }
        vertex_groups.clear();
        vertex_tags.clear();
        vertex_group_id = 0;
      }

      bl = body->getLayer(layer);

      new_layer = false;
      layer++;
      init_trx_data(tx_layer);
    }
  }

  // Reset for the next body
  //
  if ( od->is_object_end ) {

    int nof_edge_groups = edge_group_tags.size();

    if ( !tx.is_virtual && nof_edge_groups > 0 ) {
      strm1 << "***ERROR in definition for Body " << tx.tag << ends;
      strm2 << "Edge Groups are valid only for virtual bodies (Type=virtual)" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());

      goto error;
    }

    if ( !tx.is_virtual && body == NULL ) {
      strm1 << "***ERROR in definition for Body " << tx.tag << ends;
      strm2 << "No geometry defined for the body!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());

      goto error;
    }

    if ( tx.is_virtual && body == NULL && nof_edge_groups == 0) {
      strm1 << "***ERROR in definition for Body " << tx.tag << ends;
      strm2 << "No edge groups defined for a virtual body!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());

      goto error;
    }

    // If body not yet created (a virtual body)
    //
    if ( body == NULL ) {
      model->addBody(tx);
      body = model->getBodyByTag(tx.tag);
    }

    // Add possible pending group tags
    //
    if ( body != NULL && nof_edge_groups > 0 ) {
      for (int i = 0; i < nof_edge_groups; i++) {
        body->addElementGroupTag(edge_group_tags[i]);
      }
      edge_group_tags.clear();
    }

    body = NULL;
    bl = NULL;
    layer = 0;
    new_layer = false;

    reset_trx_data(tx);
  }

  return isOk;

  // Error
  error:
  reset_trx_data(tx);
  return notOk;
}


// Read boundary group
int
InputFront::readElementGroup(emf_ObjectData_X* od)
{
  UserInterface* gui = theControlCenter->getGui();
  const char* fn = od->field_name;

  static ecif_ElementGroup_X tx;
  static enum objectType group_type = OT_ELEMENT_GROUP;
  static enum objectType bndr_type = OT_NONE;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  //---New loop is started
  if (od->is_object_start) {

    // Init tx data
    init_trx_data(tx);
    tx.tag = od->object_id;

  }

  // Parse fields
  // ============

  //-Element ids
  if ( LibFront::in(EMF_ELEMENTS, fn) ||
       LibFront::in("Faces", fn) ||
       LibFront::in("Edges", fn) ||
       LibFront::in("Vertices", fn)
     ) {
    int size = od->data_length;
    tx.element_tags = new int[size];
    tx.nof_elements = size;
    for (int i = 0; i < size; i++)
      LibFront::setNumericData(tx.element_tags[i], i);

    // Set boundary group type
    if ( LibFront::in("Faces", fn) ) {
      bndr_type = OT_FACE;
    } else if ( LibFront::in("Edges", fn) ) {
      bndr_type = OT_EDGE;
    } else if ( LibFront::in("Vertices", fn) ) {
      bndr_type = OT_VERTEX;
    }
  }

  //-Name
  else if ( LibFront::in(EMF_NAME, fn) ) {
    //update_dyna_string(tx.name, (char*) od->data);
    readName(od, tx.name);
  }

  //-Group type
  else if ( LibFront::in(EMF_TYPE, fn) ) {
    if ( LibFront::in("Virtual", (char*) od->data) ) {
      tx.is_virtual = true;
    }
  }

  //-Boundary Condition id
  else if ( LibFront::in(EMF_BOUNDARY_CONDITION, fn) ) {
    LibFront::setNumericData(tx.boundary_cond_id, 0);
  }

  //-Boundary Parameter id
  else if ( LibFront::in(EMF_BOUNDARY_PARAMETER, fn) ) {
    LibFront::setNumericData(tx.boundary_param_id, 0);
  }

  //-Unknown field
  else {
    return unknownFieldMsg(od, IS_FATAL);
  }

  //----Group is ready, create it (as a model object)
  if (od->is_object_end) {
    BodyElementGroup* bg = new BodyElementGroup(tx, bndr_type);
    reset_trx_data(tx);
  }

  return isOk;
}


bool
InputFront::readColor(emf_ObjectData_X* od, Color4 color)
{
  static UserInterface* gui = theControlCenter->getGui();
  strstream strm;

  if ( LibFront::in(od->data_type, "string") ) {

    char* nm = NULL;
    readName(od, nm);
    bool rc = Model::getColorValue(nm, color);

    if (rc) {
      delete[] nm;
      return true;
    } else {

      strm << "***WARNING Invalid color name: " << nm << ends;
      gui->showMsg(strm.str());
      delete[] nm;
      return false;
    }

  } else {

    int nof_cindices = 4;

    if ( od->data_length < nof_cindices )
      nof_cindices = od->data_length;

    for (short i = 0; i < nof_cindices; i++) {
      LibFront::setNumericData(color[i], i);
    }

    return true;
  }

  return false;
}


// Read one field for an edge
int
InputFront::readEdge(emf_ObjectData_X* od)
{
  static UserInterface* gui = theControlCenter->getGui();
  strstream strm1;
  strstream strm2;

  int rc = isOk;

  const char* fn = od->field_name;

  static ecif_Element_X tx;
  static ecif_geometryType gtype;
  static ecif_DllArg da;

  static bool component_added;
  static bool is_by_geometry;

  static bool is_cpp = true;  // Default!
  static bool is_f95 = false;
  static bool is_matc = false;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  //---New element is started
  if (od->is_object_start) {

    // Init tx data
    init_trx_data(tx);
    tx.tag = od->object_id;
    tx.bndr_tag = NO_INDEX;
    tx.tplg_type = ECIF_EDGE;

    gtype = ECIF_NODIM;
    component_added = false;
    is_by_geometry = false;

    is_cpp = false;
    is_f95 = false;
    is_matc = false;
  }

  // Parse fields
  // ============

  //-No data for the element
  if ( od->field_name_length == 0 ) {
    ; // Do nothing!
  }

  //-User function
  else if ( LibFront::in(EMF_FUNCTION, fn) ||
            LibFront::in("FunctionC", fn) ||
            LibFront::in("FunctionF", fn)
          ) {

    char* data = (char*) od->data;
    char* dll_nms[2];

    int pos = 0;
    for (int i = 0; i < od->nof_entries; i++) {
      int len = od->data_lengths[i];
      dll_nms[i] = new char[1+len];
      for (int j = 0; j < len; j++) {
        dll_nms[i][j] = data[pos++];
      }
      dll_nms[i][len] = '\0';
    }

    bool must_have_lib = false;

    if ( LibFront::in("FunctionC", fn) ) {
      must_have_lib = true;
      is_cpp = true;
    }

    else if ( LibFront::in("FunctionF", fn) ) {
      must_have_lib = true;
      is_f95 = true;
    }

    else if ( LibFront::in("FunctionM", fn) ) {
      is_matc = true;
    }

    if ( !is_by_geometry ) {
      strm1 << "***ERROR Invalid function for Edge " << tx.tag << ends;
      strm2 << "No Geometry keyword given (Geometry = Circle/Curve)!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());
      goto error;
    }

    if ( od->nof_entries == 1 || dll_nms[1] == NULL || dll_nms[1][0] == '\0' ) {
      if ( must_have_lib ) {
        strm1 << "***ERROR Invalid function definition for Edge " << tx.tag << ends;
        strm2 << "Syntax is: Function Func-name Lib-name!" << ends;
        gui->showMsg(strm1.str());
        gui->showMsg(strm2.str());
        goto error;
      } else {
        is_matc = true;
      }
    }

    if ( !(is_cpp || is_f95 || is_matc)) {
      is_cpp = true;
    }

    // Create new component
    if ( !component_added && !addElementComponent(tx, gtype) ) {
      goto error;
    }

    da.is_cpp = is_cpp;
    da.is_f95 = is_f95;
    da.is_matc = is_matc;

    update_dyna_string(da.func, dll_nms[0]);

    if ( is_cpp || is_f95 ) {
      update_dyna_string(da.lib, dll_nms[1]);
    }

    storeMatcData(da.matcTable, EMF_FUNCTION, od);

    // Pick component and copy dll-argument etc. to the component
    ecif_ElementComponent_X* txc = tx.components[tx.nof_components-1];
    if ( txc != NULL ) {
      txc->isFunction = true;
      addFunctionComponentData(da, *txc);
    } else {
      goto error;
    }

    // Init for the possible next component
    component_added = false;
    da.init();
  }

  //-Function arguments
  else if ( LibFront::in(EMF_ARGUMENTS, (char*)fn) ) {
    da.argc = od->data_length;
    da.argv = new double[od->data_length];
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(da.argv[i], i);
    }
    storeMatcData(da.matcTable, EMF_ARGUMENTS, od);
  }

  //-Start vertex for a function geometry
  else if ( LibFront::in(EMF_START_VERTEX, (char*)fn) ) {
   LibFront::setNumericData(da.start_vertex, 0);
   storeMatcData(da.matcTable, EMF_START_VERTEX, od);
  }

  //-End vertex for a function geometry
  else if ( LibFront::in(EMF_END_VERTEX, (char*)fn) ) {
   LibFront::setNumericData(da.end_vertex, 0);
   storeMatcData(da.matcTable, EMF_END_VERTEX, od);
  }

  //-Start point for a function geometry
  else if ( LibFront::in(EMF_START_POINT, (char*)fn) ) {
    da.has_start_point = true;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(da.start_point[i], i);
      da.start_point[i] *= inputUnit;
    }
    storeMatcData(da.matcTable, EMF_START_POINT, od);
  }

  //-End point for a function geometry
  else if ( LibFront::in(EMF_END_POINT, (char*)fn) ) {
    da.has_end_point = true;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(da.end_point[i], i);
      da.end_point[i] *= inputUnit;
    }
    storeMatcData(da.matcTable, EMF_END_POINT, od);
  }

  //-Boundary tag
  else if ( LibFront::in(EMF_BOUNDARY_TAG, fn) ) {
    LibFront::setNumericData(tx.bndr_tag, 0);
  }

  //-Boundary Condition id
  else if ( LibFront::in(EMF_BOUNDARY_CONDITION, fn) ) {
    LibFront::setNumericData(tx.bndr_cond_id, 0);
  }

  //-Boundary Parameter id
  else if ( LibFront::in(EMF_BOUNDARY_PARAMETER, fn) ) {
    LibFront::setNumericData(tx.bndr_param_id, 0);
  }

  //-Name
  else if ( LibFront::in(EMF_NAME, fn) ) {
    //update_dyna_string(tx.name, (char*) od->data);
    readName(od, tx.name);
  }

  //-Boundary group tag
  else if ( LibFront::in(EMF_GROUP, fn) ) {
    LibFront::setNumericData(tx.bndr_group_tag, 0);
  }

  //-Symmetry axis flag
  // NOTE: Not stored in the element!
  else if ( LibFront::in("On Symmetry Axis", fn) ) {
  }

  //-Boundary vertices (= boundary points)
  // NOTE: Not read any more from emf-file (ie. is pre version 5 stuff!)
  else if ( LibFront::in("Boundary Vertices", fn) ) {
  }

  //-Grid parameter ids
  else if ( LibFront::in("Gridh Ids", fn) ) {
    tx.nof_gridh_ids = od->data_length;
    tx.gridh_ids = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_ids[i], i);
    }
  }

  //-GridH mesh indices
  else if ( LibFront::in("Gridh Mesh Indices", fn) ) {
    tx.gridh_mesh_indices = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_mesh_indices[i], i);
    }
  }

  //-Extra vertices (neede mainly for closed geometry and mesh geometry)
  else if ( LibFront::in(EMF_EXTRA_VERTICES, fn) ) {
    tx.nof_extra_vertices = od->data_length;
    tx.extra_vertex_tags = new int[od->data_length];
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.extra_vertex_tags[i], i);
    }
  }

  //-Linear geometry by vertex tags
  // NOTE: Only linear geometry can be defined without type,
  //       by just giving the vertices!
  else if ( LibFront::in(EMF_VERTICES, fn) ) {

    // If no type given --> Linear, add new linear component
    if ( !is_by_geometry ) {

      if ( od->data_length == 2 ) {
        addElementComponent(tx, ECIF_LINE);

      } else if ( od->data_length > 2 ) {
        addElementComponent(tx, ECIF_POLYLINE);

      } else {
        strm1 << "***ERROR Invalid definition for Edge " << tx.tag << ends;
        strm2 << "At least two vertices must be given!" << ends;
        gui->showMsg(strm1.str());
        gui->showMsg(strm2.str());
        goto error;
      }
    }

    ecif_ElementComponent_X* txc = tx.components[tx.nof_components-1];

    txc->nof_vertices = od->data_length;
    txc->vertex_tags = new int[txc->nof_vertices];
    for (int i = 0; i < od->data_length; i++) {
      int tag;
      LibFront::setNumericData(tag, i);

      if ( !model->checkVertexExistence(tag) ) {
        strm1 << "***ERROR Invalid definition for Edge " << tx.tag << ends;
        strm2 << "Illegal vertex tag: " << tag << ends;
        gui->showMsg(strm1.str());
        gui->showMsg(strm2.str());
        goto error;
      }

      txc->vertex_tags[i] = tag;
    }
  }

  //-Geometry type
  // NOTE: This type must be given before any parametric data
  // NOTE: Only linear geometry can be defined without type,
  // by just giving the vertices!
  else if ( LibFront::in(EMF_GEOMETRY, fn) ) {
    char* tp_nm = NULL;
    readName(od, tp_nm);
    gtype = getElementGeometryType(tp_nm, tx);

    if ( gtype == ECIF_NODIM ) {
      strm1 << "***ERROR Invalid geometry definition for Edge " << tx.tag << ends;
      strm2 << "Unknown geometry type: " << tp_nm << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());
      goto error;
    }

    delete[] tp_nm;

    is_by_geometry = true;

    if ( !addElementComponent(tx, gtype) ) {
      goto error;
    }

    component_added = true;

#if 0
    if ( !component_added ) {
      if ( !addElementComponent(tx, gtype) ) {
        goto error;
      }
      component_added = true;
    }
#endif

#if 0
    component_added = false;
#endif

    storeMatcData(da.matcTable, EMF_GEOMETRY, od);
  }

  // Some edge geometry component
  else {

    if ( !is_by_geometry ) {
      strm1 << "***ERROR Invalid definition for Edge " << tx.tag << ends;
      strm2 << "A geometry component given, but geometry type not defined!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());
      goto error;
    }

    if ( !component_added ) {
      if ( !addElementComponent(tx, gtype) ) {
        goto error;
      }
      component_added = true;
    }

    ecif_ElementComponent_X* txc = tx.components[tx.nof_components-1];

    rc = readElementGeometry2D(od, *txc);
  }

  if (rc != isOk) {
    goto error;
  }

  //----Element is ready
  if ( od->is_object_end ) {

    if ( tx.nof_components <= 0 ) {
      strm1 << "***ERROR Invalid definition for Edge " << tx.tag << ends;
      strm2 << "Edge at end, but no actual geometry defined!" << ends;
      //gui->showMsg(strm1.str());
      //gui->showMsg(strm2.str());
      //goto error;

    }

    if ( !model->addBodyElement(tx) ) {
      goto error;
    }

    reset_trx_data(tx);
  }

  // Ok
  return isOk;

  // Error
  error:
  reset_trx_data(tx);
  return notOk;
}


// Read 1D element geometry (vertex)
int
InputFront::readElementGeometry1D(emf_ObjectData_X* od, ecif_ElementComponent_X& tx)
{
  const char* fn = od->field_name;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  //-Vertex point (always 3D coordinates)
  if ( LibFront::in("Point", fn) ) {
    for (short j = 0; j < 3; j++) {
      LibFront::setNumericData(tx.geometry.vertex->point[j], j);
      tx.geometry.vertex->point[j] *= inputUnit;
    }
  }

  //-ERROR: Unknown field
  else {
    return unknownFieldMsg(od, IS_FATAL);
  }

  return isOk;
}


// Read 2D element geometry (edge)
int
InputFront::readElementGeometry2D(emf_ObjectData_X* od, ecif_ElementComponent_X& tx)
{
  const char* fn = od->field_name;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  //-Radius
  if ( LibFront::in("Radius", (char*)fn) ) {
    LibFront::setNumericData(tx.geometry.edge->radius1, 0);
    tx.geometry.edge->radius1 *= inputUnit;

    storeMatcData(tx.geometry.edge->matcTable, EMF_RADIUS, od);
  }

  //-Center
  else if ( LibFront::in("Center", (char*)fn) ) {
    tx.geometry.edge->location = new Point3[1];
    initPoint3(*tx.geometry.edge->location, 0.0);
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData((*tx.geometry.edge->location)[i], i);
      (*tx.geometry.edge->location)[i] *= inputUnit;
    }

    storeMatcData(tx.geometry.edge->matcTable, EMF_CENTER, od);
  }

  //-Defining points
  else if ( LibFront::in("Defining Points", (char*)fn) ) {
    tx.geometry.edge->nofDefiningPoints = od->dimension1;
    tx.geometry.edge->location = new Point3[od->dimension1];
    for (int i = 0; i < od->dimension1; i++) {
      for (int j = 0; j < od->dimension2; j) {
        int pos = i * od->dimension1;
        LibFront::setNumericData(tx.geometry.edge->definingPoints[i][j], pos + j);
        tx.geometry.edge->definingPoints[i][j] *= inputUnit;
      }
    }
  }

  //-Delta-h for linearizing (interval length space)
  else if ( LibFront::in(EMF_DELTA_H, fn) ||
            LibFront::in(EMF_MESH_H, fn)
          ) {
    tx.lin_delta_type = LIN_DELTA_H;
    for (int i = 0; i < 1 && i < od->data_length; i++) {
      LibFront::setNumericData(tx.lin_delta[i], i);
    }

    storeMatcData(tx.geometry.edge->matcTable, EMF_MESH_H, od);
  }

  //-Delta-n for linearizing (interval count space)
  else if ( LibFront::in(EMF_DELTA_N, fn) ||
            LibFront::in(EMF_MESH_N, fn)
          ) {
    tx.lin_delta_type = LIN_DELTA_N;
    for (int i = 0; i < 1 && i < od->data_length; i++) {
      LibFront::setNumericData(tx.lin_delta[i], i);
    }

    storeMatcData(tx.geometry.edge->matcTable, EMF_MESH_N, od);
  }

#if 0
  //-Delta-u for linearizing (parameter space)
  else if ( LibFront::in(EMF_DELTA_U, fn) ||
            LibFront::in(EMF_MESH_U, fn)
          ) {
    tx.lin_delta_type = LIN_DELTA_U;
    for (int i = 0; i < 1 && i < od->data_length; i++) {
      LibFront::setNumericData(tx.lin_delta[i], i);
    }
  }
#endif

  // Use (force)  N: setting in meshing
  else if ( LibFront::in(EMF_USE_MESH_N, fn) ) {
    LibFront::setNumericData(tx.use_fixed_mesh_n, 0);
  }

  //-ERROR: Unknown field
  else {
    return unknownFieldMsg(od, IS_FATAL);
  }

  return isOk;
}


// Read element loop
int
InputFront::readElementLoop(emf_ObjectData_X* od)
{
  UserInterface* gui = theControlCenter->getGui();
  const char* fn = od->field_name;

  static ecif_ElementLoop_X tx;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  //---New loop is started
  if (od->is_object_start) {

    // Init tx data
    init_trx_data(tx);
    tx.is_checked = geometryIsChecked();
    tx.tag = od->object_id;
  }

  // Parse fields
  // ============

  //-Element tags
  // NOTE: EMF_ELEMENT_IDS: pre version 9 emf-format
  if ( LibFront::in(EMF_ELEMENTS, fn) ||
       LibFront::in(EMF_ELEMENT_IDS, fn) ||
       LibFront::in("Faces", fn) ||
       LibFront::in("Edges", fn)
     ) {
    int size = od->data_length;
    tx.element_tags = new int[size];
    tx.nof_elements = size;
    for (int i = 0; i < size; i++)
      LibFront::setNumericData(tx.element_tags[i], i);
  }

  //-Boundary group tag
  else if ( LibFront::in(EMF_GROUP, fn) ) {
    LibFront::setNumericData(tx.bndr_group_tag, 0);
  }

  //-Loop type
  else if ( LibFront::in(EMF_TYPE, fn) ) {
    if ( LibFront::in("Open", (char*) od->data) ) {
      tx.is_open = true;
    }
  }

  //-Unknown field
  else {
    return unknownFieldMsg(od, IS_FATAL);
  }

  //----ElementLoop is ready
  if (od->is_object_end) {
    model->addBodyElementLoop(tx);
    reset_trx_data(tx);
  }

  return isOk;
}


// Read one field for a face
int
InputFront::readFace(emf_ObjectData_X* od)
{
  static UserInterface* gui = theControlCenter->getGui();
  strstream strm1;
  strstream strm2;
  int i;

  int rc = isOk;

  static IdArray edge_tags;
  static IdArray vertex_tags;

  const char* fn = od->field_name;

  static ecif_Element_X tx;

  //---New element is started
  if (od->is_object_start) {

    // Init tx data
    init_trx_data(tx);
    tx.tag = od->object_id;
    tx.bndr_tag = NO_INDEX;
    tx.tplg_type = ECIF_FACE;
  }

  // Parse fields
  // ============

  //-No data for the element (but id)
  if ( od->field_name_length == 0) {
    ; // Do nothing!
  }

  //-Boundary tag
  else if ( LibFront::in(EMF_BOUNDARY_TAG, fn) ) {
    LibFront::setNumericData(tx.bndr_tag, 0);
  }

  //-Boundary Condition id
  else if ( LibFront::in(EMF_BOUNDARY_CONDITION, fn) ) {
    LibFront::setNumericData(tx.bndr_cond_id, 0);
  }

  //-Boundary Parameter id
  else if ( LibFront::in(EMF_BOUNDARY_PARAMETER, fn) ) {
    LibFront::setNumericData(tx.bndr_param_id, 0);
  }

  //-Boundary name
  else if ( LibFront::in(EMF_NAME, fn) ) {
    //update_dyna_string(tx.name, (char*) od->data);
    readName(od, tx.name);
  }

  //-Edge tags
  else if ( LibFront::in(EMF_EDGES, fn) ) {
    int tag;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tag, i);
      edge_tags.push_back(tag);
    }
  }

  //-Vertex tags
  // NOTE: This is for mesh bodies which may not have any edges
  // but we still want to store some vertices in the model
  //
  else if ( LibFront::in(EMF_VERTICES, fn) ) {
    int tag;
    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tag, i);
      vertex_tags.push_back(tag);
    }
  }

  //-Grid parameter ids
  else if ( LibFront::in("Gridh Ids", fn) ) {
    tx.nof_gridh_ids = od->data_length;
    tx.gridh_ids = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_ids[i], i);
    }
  }

  //-GridH mesh indices
  else if ( LibFront::in("Gridh Mesh Indices", fn) ) {
    tx.gridh_mesh_indices = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_mesh_indices[i], i);
    }
  }

  if (rc != isOk)
    return !isOk;

  //----Element is ready
  if ( od->is_object_end ) {

    model->addBodyElement(tx);

    // Add possible pending edge definitions
    // into the created face bodyelement
    BodyElement* be = model->getBodyElementByTag(OT_FACE, tx.tag);

    if ( be != NULL ) {

      // Store edges as pending elements (will be resolved later when
      // the whole file is read
      int nof_edges = edge_tags.size();
      if ( nof_edges > 0 ) {
        for (i = 0; i < nof_edges; i++)
          be->addPendingEdge(edge_tags[i]);
      }
      edge_tags.clear();

      // Store vertices as pending elements (will be resolved later when
      // the whole file is read
      int nof_vertices = vertex_tags.size();
      if ( nof_vertices > 0 ) {
        for (i = 0; i < nof_vertices; i++)
          be->addPendingVertex(vertex_tags[i]);
      }
      vertex_tags.clear();
    }

    reset_trx_data(tx);
  }

  return isOk;
}


int
InputFront::readIncludeFile(emf_ObjectData_X* od)
{
  return isOk;
}


bool
InputFront::readName(emf_ObjectData_X* od, char*& name)
{
  name = NULL;

  char* data = (char*) od->data;
  strstream strm;

  int pos = 0;
  for (int i = 0; i < od->nof_entries; i++) {
    int len = od->data_lengths[i];
    for (int j = 0; j < len; j++) {
      strm << data[pos++];
    }

    if ( i < od->nof_entries - 1 ) {
      strm << ' ';
    }
  }

  strm << ends;

  update_dyna_string(name, strm.str());

  return true;
}


void
InputFront::readNumericVector(int read_count, int*& target_vector,
                              int init_count, int init_value)
{
  int i;

  for (i = 0; i < init_count; i++) {
    target_vector[i] = init_value;
  }

  for (i = 0; i < read_count; i++) {
    LibFront::setNumericData(target_vector[i], i);
  }
}


void
InputFront::readNumericVector(int read_count, double*& target_vector,
                             int init_count, double init_value)
{
  int i;

  for (i = 0; i < init_count; i++) {
    target_vector[i] = init_value;
  }

  for (i = 0; i < read_count; i++) {
    LibFront::setNumericData(target_vector[i], i);
  }
}


void
InputFront::readPoint3(int read_count, Point3& point, double init_value)
{
  int i;

  for (i = 0; i < 3; i++) {
    point[i] = init_value;
  }

  for (i = 0; i < read_count; i++) {
    LibFront::setNumericData(point[i], i);
  }
}


// Read one field for a vertex
int
InputFront::readVertex(emf_ObjectData_X* od)
{
  static UserInterface* gui = theControlCenter->getGui();
  strstream strm1;
  strstream strm2;

  int rc = isOk;

  const char* fn = od->field_name;

  static ecif_Element_X tx;

  //---New element is started
  if (od->is_object_start) {

    // Init tx data
    init_trx_data(tx);
    tx.tag = od->object_id;
    tx.bndr_tag = NO_INDEX;
    tx.tplg_type = ECIF_VERTEX;
  }

  // Parse fields
  // ============

  //-No data for the element
  if ( od->field_name_length == 0 ) {
    ; // Do nothing!
  }

  //-Boundary tag
  else if ( LibFront::in(EMF_BOUNDARY_TAG, fn) ) {
    LibFront::setNumericData(tx.bndr_tag, 0);
  }

  //-Boundary Condition id
  else if ( LibFront::in(EMF_BOUNDARY_CONDITION, fn) ) {
    LibFront::setNumericData(tx.bndr_cond_id, 0);
  }

  //-Boundary Parameter id
  else if ( LibFront::in(EMF_BOUNDARY_PARAMETER, fn) ) {
    LibFront::setNumericData(tx.bndr_param_id, 0);
  }

  //-Name
  else if ( LibFront::in(EMF_NAME, fn) ) {
    update_dyna_string(tx.name, (char*) od->data);
  }

  //-Boundary group tag
  else if ( LibFront::in(EMF_GROUP, fn) ) {
    LibFront::setNumericData(tx.bndr_group_tag, 0);
  }

  //-Grid parameter ids
  else if ( LibFront::in("Gridh Ids", fn) ) {
    tx.nof_gridh_ids = od->data_length;
    tx.gridh_ids = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_ids[i], i);
    }
  }

  //-GridH mesh indices
  else if ( LibFront::in("Gridh Mesh Indices", fn) ) {
    tx.gridh_mesh_indices = new int[od->data_length];

    for (int i = 0; i < od->data_length; i++) {
      LibFront::setNumericData(tx.gridh_mesh_indices[i], i);
    }
  }

  // Some vertex geometry component
  else {

    if ( tx.nof_components == 0 ) {
      addElementComponent(tx, ECIF_POINT);
    }

    ecif_ElementComponent_X* txc = tx.components[tx.nof_components-1];

    rc = readElementGeometry1D(od, *txc);
  }

  if (rc != isOk) {
    goto error;
  }

  //----Element is ready
  if ( od->is_object_end ) {

    // NOTE: Check NOT in use!
    if ( false && tx.nof_components <= 0 ) {
      strm1 << "***ERROR Invalid definition for Vertex " << tx.tag << ends;
      strm2 << "Vertex at end, but no geometry point given!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str());
      goto error;
    }

    model->addBodyElement(tx);
  }

  return isOk;

  // Error
  error:
  return notOk;
}


// Methods read a vertex table
int
InputFront::readVertexTable(emf_ObjectData_X* od)
{
  const ModelInfo* mi = model->getModelInfo();
  int inputVersionNbr = mi->frontInputVersionNbr;

  UserInterface* gui = theControlCenter->getGui();
  const char* fn = od->field_name;

  static ecif_Vertex_X tx;
  static GcPoint point;

  int nofVertices = 0;
  int* vertexIds = NULL;
  MatcValueTable matcTable;

  bool isEgf = isEgfInput;
  bool isEmf = isEmfInput;

  reset_trx_data(tx);

  // Point table (typical Egf format)
  // ================================
  if ( LibFront::in("Points", fn) ) {

    if ( !LibFront::ncEqual(od->data_type, "real") ) {
      gui->showMsg("Incorrect data format for vertex points (should be Real!)");
      return 1;
    }

    int tag, dim1, dim2;
    bool indexed_table;
    double coord[3];
    BodyElement* vertex;

    if ( od->nof_variables == 1 &&
         LibFront::ncEqual(od->variable_names[0], "index")
       ) {
      indexed_table = true;
      dim1 = od->nof_entries;
      dim2 = od->dimension1;
    } else {
      indexed_table = false;
      dim1 = od->dimension1;
      dim2 = od->dimension2;
    }

    vertexIds = new int[dim1];

    storeMatcData(matcTable, EMF_POINTS, od);

    // Read vertex table
    for (int i = 0; i < dim1; i++) {

      coord[0] = coord[1] = coord[2] = 0.0;

      for (short j = 0; j < dim2; j++) {
        LibFront::setNumericData(coord[j], j + i * dim2);
        coord[j] *= inputUnit;
      }

      point.setPosit(coord[0], coord[1], coord[2]);

      if ( indexed_table ) {
        LibFront::setNumericVariable(tag, i);
        vertex = new BodyElement1D(tag, &point);

      } else {
        vertex = new BodyElement1D(&point);
      }

      vertexIds[i] = vertex->Id();

      model->addBodyElement(vertex);
    }

    model->setVertexTable(dim1, dim2, vertexIds, matcTable);
  }

  // Ids and Point table (typical Emf format)
  // ========================================
  // NOTE: New format
  // ----------------
  else if ( LibFront::in("Ids And Points", fn) ) {

    if ( !LibFront::ncEqual(od->data_type, "real") ) {
      gui->showMsg("Incorrect data format for vertex points (should be Real!)");
      return 1;
    }

    int data_size = od->dimension1;

    int var_size = 1; // Id field (index)

    int nof_coord;

    if ( inputVersionNbr < 5 ) {
      nof_coord = data_size;     // Nothing but index variable (id)  before coordinates
    } else {
      nof_coord = data_size - 2; // Boundary tag and boundary condition id added before coordinates
    }

     // Read table
    for (int i = 0; i < od->nof_entries; i++) {

      int var_pos = i * var_size;
      int data_pos = i * data_size;

      // Read id (as index variable!)
      LibFront::setNumericVariable(tx.tag, var_pos);

      if ( inputVersionNbr >= 5 ) {
        LibFront::setNumericData(tx.bndr_tag, data_pos++);
        LibFront::setNumericData(tx.bndr_cond_id, data_pos++);
      }

      // Read coordinates (3D)
      for (short j = 0; j < nof_coord; j++) {
        LibFront::setNumericData(tx.point[j], data_pos++);
        tx.point[j] *= inputUnit;
      }

      model->addBodyElement(tx);
    }
  }

  // Point and Constraint ids table (typical Emf format)
  // ===================================================
  // NOTE: Old format!
  // -----------------
  else if ( LibFront::in("Points And Constraint Ids", fn) ) {
    if ( !LibFront::ncEqual(od->data_type, "real") ) {
      gui->showMsg("Incorrect data format for vertex points (should be Real!)");
      return 1;
    }

    int data_size = od->dimension1;

    int nof_coord = data_size - 2;  // two ids after coordinates
    int var_size = 1;

     // Read vertex table
    for (int i = 0; i < od->nof_entries; i++) {

      int var_pos = i * var_size;
      int data_pos = i * data_size;

      // Read id
      LibFront::setNumericVariable(tx.tag, var_pos);

      // Read coordinates (3D)
      for (short j = 0; j < nof_coord; j++) {
        LibFront::setNumericData(tx.point[j], data_pos++);
        tx.point[j] *= inputUnit;
      }

      // Read boundary condition id
      LibFront::setNumericData(tx.bndr_cond_id, data_pos++);

      // Read boundary id
      LibFront::setNumericData(tx.bndr_tag, data_pos++);

      model->addBodyElement(tx);
    }
  }

  //-Unknown field
  else {
    return unknownFieldMsg(od, IS_FATAL);
  }

  delete[] vertexIds;
  purgeMatcValueTable(matcTable);

  return isOk;
}


// Store field data in Matc-expression table if it contains any Matc-variables
//
bool
InputFront::storeMatcData(MatcValueTable& matcTable, const char* key, emf_ObjectData_X* od)
{
  if ( !od->dataHasMatcVars ) {
    return false;
  }

  // Call external store function
  storeMatcString(matcTable, key, od->dataAsString);

  // Inform gui!
  UserInterface* gui = theControlCenter->getGui();
  gui->setModelHasMatcDefinitions();

  return true;
}


int
InputFront::unknownFieldMsg(emf_ObjectData_X* object_data, bool is_fatal)
{
  UserInterface* gui = theControlCenter->getGui();
  strstream strm;

  if ( is_fatal ) {
    strm << "***ERROR: Unknown field name (";
  } else {
    strm << "***WARNING: Unknown field name (";
  }

  strm << object_data->field_name
       << ") when reading object: "
       << object_data->object_name;

  if ( object_data->object_id != NO_INDEX ) {
    strm << " " << object_data->object_id;
  }

  strm << ends;

  gui->showMsg(strm.str());

  if (is_fatal)
    return notOk;
  else
    return isOk;
}


int
InputFront::unknownObjectMsg(emf_ObjectData_X* object_data, bool is_fatal)
{
  UserInterface* gui = theControlCenter->getGui();
  strstream strm;

  if ( is_fatal ) {
    strm << "***ERROR: Unknown object name:";
  } else {
    strm << "***WARNING: Unknown object name:";
  }

  strm << object_data->object_name
       << ends;

  gui->showMsg(strm.str());

  if (is_fatal)
    return notOk;
  else
    return isOk;
}
