/***********************************************************************
*
*       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_model.cpp
Language:   C++
Date:       12.11.98
Version:    1.00
Author(s):  Martti Verho
Revisions:

Abstract:   Implementation

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

#include <eio_api.h>
#include "ecif_body.h"
#include "ecif_body2D.h"
#include "ecif_body3D.h"
#include "ecif_bodyLayer.h"
#include "ecif_bodyElement.h"
#include "ecif_bodyElement1D.h"
#include "ecif_bodyElement2D.h"
#include "ecif_bodyElement3D.h"
#include "ecif_bodyElementGroup.h"
#include "ecif_bodyElementLoop.h"
#include "ecif_bodyForce.h"
#include "ecif_bodyParameter.h"
#include "ecif_boundbox.h"
#include "ecif_boundaryCondition.h"
#include "ecif_boundaryParameter.h"
#include "ecif_control.h"
#include "ecif_calculator.h"
#include "ecif_constant.h"
#include "ecif_coordinate.h"
#include "ecif_datafile.h"
#include "ecif_equation.h"
#include "ecif_equationVariables.h"
#include "ecif_geometry.h"
#include "ecif_gridH.h"
#include "ecif_gridParameter.h"
#include "ecif_initialCondition.h"
#include "ecif_inputIdeas.h"
#include "ecif_inputElmer.h"
#include "ecif_inputThetis.h"
#include "ecif_material.h"
#include "ecif_mesh.h"
#include "ecif_model.h"
#include "ecif_modelMeshManager.h"
// #include "ecif_modelOutputManager.h"
#include "ecif_modelParameter.h"
#include "ecif_model_aux.h"
#include "ecif_modelObject.h"
#include "ecif_parameter.h"
#include "ecif_parameterField.h"
#include "ecif_renderer.h"
#include "ecif_simulationParameter.h"
#include "ecif_solver.h"
#include "ecif_solverControl.h"
#include "ecif_timer.h"
#include "ecif_timestep.h"
#include "ecif_userinterface.h"
#include "ecif_userSettings.h"

void pressAnyKey();
extern char read_buffer[];

Control* Model::theControlCenter = NULL;
NameTable* Model::colorNameTable = new NameTable;
RGBColorTable* Model::colorValueTable = new RGBColorTable;
double Model::meshInputUnit = 1.0;

Model::Model(char* model_name, ecif_modelSource source, char* in_file_name)
{
  id = 1;
  lastObjectId = 0; // System-wide unique object id (for anyone who needs it)

  Body::initClass(this);
  BodyElement::initClass(this);
  BodyElementGroup::initClass(this);
  BodyElementLoop::initClass(this);
  BodyForce::initClass(this);
  BodyLayer::initClass(this);
  BodyPair::initClass(this);
  BoundaryCondition::initClass(this);
  Constant::initClass(this);
  Coordinate::initClass(this);
  Datafile::initClass(this);
  Equation::initClass(this);
  Geometry::initClass(this);
  GridParameter::initClass(this);
  InitCondition::initClass(this);
  Input::initClass(this);
  Material::initClass(this);
  ModelMeshManager::initClass(this);
  ModelOutputManager::initClass(this);
  MeshElementTable::initClass(this);
  ModelObject::initClass(this);
  Parameter::initClass(this);
  ParameterField::initClass(this);
  Renderer::initClass(this);
  Solver::initClass(this);
  Timestep::initClass(this);

  modelData = new ModelData;
  modelFlags = new bool[MAX_NOF_FLAG_NAMES];
  for (short i = 0; i < MAX_NOF_FLAG_NAMES; i++) {
    modelFlags[i] = false;
  }
  modelInfo = new ModelInfo(model_name, source, in_file_name);
  modelStatistics = new ModelStatistics;
  parallelInfo = new ParallelInfo;
  pickInfo = new PickInfo;

  modelBox = new BoundBox;

  initMeshData();

  initSplitCombineInfos();

  meshManager = new ModelMeshManager();
  meshManager->setMeshData(meshData, meshInfo, meshBox);
  meshManager->setModelData(modelData, modelInfo);

  outputManager = new ModelOutputManager();

  MeshElementTable::setMeshData(meshData, meshInfo);

}


Model::~Model()
{
  modelInfo->dimension = ECIF_ND;

  deleteMeshData();

  delete modelBox;
  delete modelData;
  delete[] modelFlags;

  delete outputManager;
  delete meshManager;
}


// Method adds a new body to the model.
bool
Model::addBody(Body* body)
{
  if ( !body->objectIsOk() ) return false;

  GBODY = body;
  modelStatistics->nofBodies++;
  return true;
}


// Method adds a new transfer-format body to the model.
bool
Model::addBody(ecif_Body_X& trx_body, bool add_default_layer)
{
  int body_tag = trx_body.tag;
  Body* body = this->getBodyByTag(body_tag);

  //-Possible old body with the same id is deleted first
  if (NULL != body) {
    removeBody(body);
    delete body;
  }

  //-New body is created with preset id!
  switch (modelInfo->dimension) {
  case 2:
    body = new Body2D(trx_body, add_default_layer);
    break;
  case 3:
    body = new Body3D(trx_body, add_default_layer);
    break;
  default:
    UserInterface* gui = theControlCenter->getGui();
    strstream strm;
    strm << "***ERROR Model dimension is zero, cannot add Body " << body_tag << ends;
    gui->showMsg(strm.str());
    return NO_INDEX;
  }

  return this->addBody(body);
}


// Method adds a new bodyelement into the model.
bool
Model::addBodyElement(BodyElement* be)
{
  if ( !be->objectIsOk() ) {
    return false;
  }

  be->checkLastTag();
  be->checkLastBoundaryTag();

  if ( OT_VERTEX == be->getObjectType() ) {
    addVertex(be);
  } else {
    modelStatistics->nofElements++;
  }

  return true;
}


// Method adds a new bodyelement into the model.
bool
Model::addBodyElement(BodyElement* be, bool add_to_bodies)
{
  if (add_to_bodies) {
    int body1_tag = be->getParentTag(1);
    int body1_layer = be->getParentLayer(1);
    int body2_tag = be->getParentTag(2);
    int body2_layer = be->getParentLayer(2);
    return addBodyElement(be, body1_tag, body1_layer, body2_tag, body2_layer);

  } else {
    return addBodyElement(be);
  }
}


bool
Model::addBodyElement(BodyElement* be,
                      int body1_tag, int body1_layer,
                      int body2_tag, int body2_layer)
{
  Body* body1 = getBodyByTag(body1_tag);
  Body* body2 = getBodyByTag(body2_tag);

  // No success!
  if ( body1 == NULL ) {
    return false;
  }

  // Add to relevant bodies and also create corresponding
  // inner/outer boundary entry

  // Outer boundary
  if (body2 == NULL) {
    body1->addElement(body1_layer, be);
    be->addStatus(BE_OUTER);

  // Inner boundary
  } else {
    body1->addElement(body1_layer, be);
    body2->addElement(body2_layer, be);
    be->addStatus(BE_INNER);
  }

  // Add the body element itself
  return addBodyElement(be);
}


// Method adds a new transfer-format bodyelement (edge or face) into the model.
bool
Model::addBodyElement(ecif_Element_X& tx)
{
  int be_tag = tx.tag;

  BodyElement* be = NULL;

  if ( tx.tplg_type == ECIF_VERTEX )
    be = getVertexByTag(be_tag);

  else if ( tx.tplg_type == ECIF_EDGE )
    be = getEdgeByTag(be_tag);

  else if ( tx.tplg_type == ECIF_FACE )
    be = getFaceByTag(be_tag);

  //-Possible old bodyelement with the same tag
  // is updated!
  if (NULL != be) {
    //delete be;
    be->update(tx);
    return true;
  }

  //-New bodyelement is created
  switch (tx.tplg_type) {

  case ECIF_VERTEX:
    be = new BodyElement1D(tx);
    break;
  case ECIF_EDGE:
    be = new BodyElement2D(tx);
    break;
  case ECIF_FACE:
    be = new BodyElement3D(tx);
    break;
  default:
    return NO_INDEX;
  }

  return this->addBodyElement(be);
}


// Method adds a new transfer-format bodyelement (vertex) to the model.
bool
Model::addBodyElement(ecif_Vertex_X& tx)
{
  BodyElement* be = new BodyElement1D(tx);

  return addBodyElement(be);
}


// Method adds a new bodyelement into the model.
bool
Model::addBodyElementGroup(BodyElementGroup* beg)
{
  if ( !beg->objectIsOk() ) return false;

  modelStatistics->nofElementGroups++;
  return true;
}


// Method adds a new bodyelement-loop into the model.
bool
Model::addBodyElementLoop(ecif_ElementLoop_X& tx)
{
  int bel_tag = tx.tag;

  BodyElementLoop* bel = this->getBodyElementLoopByTag(bel_tag);

  //-Possible old bodyelement-loop with the same id is deleted first
  if (NULL != bel) {
    removeBodyElementLoop(bel->Id());
    delete bel;
  }


  //-New bodyelement-loop is created with preset id!
  //
  // NOTE: Loop element type is given as a generic boundary!
  //
  bel = new BodyElementLoop(bel_tag,
                            tx.nof_elements,
                            tx.element_tags,
                            tx.is_open,
                            OT_BOUNDARY);

  return this->addBodyElementLoop(bel);
}


// Method adds a new bodyelement into the model.
bool
Model::addBodyElementLoop(BodyElementLoop* bel)
{
  if ( !bel->objectIsOk() ) return false;

  modelStatistics->nofElementLoops++;
  return true;
}


bool
Model::addBodyPair(BodyPair* bp)
{
  if ( !bp->objectIsOk() ) return false;

  modelStatistics->nofBodyPairs++;
  return true;

}


void
Model::addColorName(char* name, Color4 color)
{
  static char buf[1024];
  int i;

  Color4* c = new Color4[1];

  int len = strlen(name);

  for (i = 0; i < len; i++) {
    buf[i] = tolower(name[i]);
  }
  buf[len] = '\0';

  string nm(buf);

  for (i = 0; i < 4; i++) {
    (*c)[i] = color[i];
  }

  (*colorValueTable)[nm] = c;
}


void
Model::addColorValue(int color_value, char* name)
{
  (*colorNameTable)[color_value] = name;
}


void
Model::addCoveringElementList(int elem_id, IdList* se_list)
{
  IdList* old_list = (*modelData->coveringElementTable)[elem_id];

  if ( old_list != NULL ) {
    delete old_list;
  }

  // Temprary debugging
  IdList::iterator pos = se_list->begin();

  while (pos != se_list->end()) {
    int id = *pos++;
  }

  (*modelData->coveringElementTable)[elem_id] = se_list;
}


void
Model::addMatcDefinition(char* def)
{
  char* res = mtc_domath(def);

  if ( res != NULL && res[0] != '\0' ) {
    UserInterface* gui = theControlCenter->getGui();
    strstream strm;
    int len = strlen(def);

    for (int i = 0; i < len; i++ ) {
      if ( def[i] < 0 ) {
        def[i] = '\0';
        break;
      }
    }
    strm << "***" << res << " in: " << def << ends;
    gui->showMsg(strm.str());
  }
}


Rc
Model::addMeshBoundaryElement(int bndr_tag, meshElementCode elem_code,
                              int ext_parent1_id, int ext_parent2_id,
                              const int* ext_node_ids,
                              bool& is_added_to_bndr)
{
  int elem_id = meshManager->addMeshBoundaryElement(bndr_tag, elem_code, ext_parent1_id, ext_parent2_id,
                                                    ext_node_ids, is_added_to_bndr);

  if ( elem_id == NO_INDEX )
    return ECIF_ERROR;
  else
    return ECIF_OK;
}


Rc
Model::addMeshBulkElement(int ext_id, int material_id,
                          meshElementCode elem_code, const int* ext_node_ids,
                          int nof_ngbrs, const int* ext_ngbr_ids)
{
  return meshManager->addMeshBulkElement(ext_id, material_id, elem_code, ext_node_ids, nof_ngbrs, ext_ngbr_ids);
}


// Add a temporary element (bulk or boundary )
// This is used when only the total number elements is
// known and we do not want to read the mesh file twice
// to know separately the nofBulkElements and nofBoundaryElements
Rc
Model::addMeshInputElement(int elem_type,
                           int ext_id, int body_tag, int bndr_tag,
                           int* ext_node_ids)
{
  return meshManager->addMeshInputElement(elem_type, 
                                          ext_id, body_tag, bndr_tag,
                                          ext_node_ids);
}



Rc
Model::addMeshNode(int int_id, int ext_id, Point3& point)
{
  return meshManager->addMeshNode(int_id, ext_id, point);
}


// Add new model object. Increase id-cunter and set new counter as the object id
//
bool
Model::addModelObject(ModelObject* object, enum objectType otype)
{
  object->setObjectType(otype);

  object->setId(++lastObjectId);

  modelData->modelObjects->push_back(object);

  modelStatistics->nofModelObjects++;

  return true;
}


// Method adds a parameter of the type "parameter-type" to the model.
bool
Model::addParameter(ecif_parameterType parameter_type, Parameter* parameter)
{
  ParameterTable* table;

  // NOTE: This will be scalar pointer to a modelStatistics-counter,
  // do NOT delete it!
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, use_counter) )
    return false;

  int pid = parameter->ID();

  (*table)[pid] = parameter;

  int count = table->size();

  // NOTE!! Success of addition should be checked first! ***!!!***
  (*use_counter)++;

  return true;
}


void
Model::addPendingMeshElements()
{
  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;
    be->addAllPendingMeshElements();
    be->createExtraVertices();
  }
  
  markActiveObjects();
  updateModelStatistics();
}


void
Model::addSwapElement(int orig_elem_id, int swap_elem_id)
{
  (*modelData->swapElementTable)[orig_elem_id] = swap_elem_id;
}


// Add body element to proper boundary group. Create the group
// if it does not exist.
// Return group's object id
//
int
Model::addToElementGroup(BodyElement* be, int group_tag)
{
  objectType ot = OT_ELEMENT_GROUP;
  objectType bt = be->getObjectType();

  BodyElementGroup* beg = (BodyElementGroup*)getModelObjectByTag(ot, group_tag);

  if ( beg == NULL ) {
    beg = new BodyElementGroup();
    beg->setObjectType(ot);
    beg->setElementType(bt);
  }

  beg->addElement(be->Id());

  return beg->Id();
}


// Method adds a new point into model.
// Idea is to store points only once.
// This concerns points which are connected to vertices.
// Points used in the representation of curves and surfaces are not
// stored in this table.
// Returns true if new point was added.
bool
Model::addToHashPoints(GcPoint* point)
{
  bool new_point = false;
  bool hash_key_found = false;

  // Test if point is already in the table.
  int key = point->hashKey();
  PointHashTable::iterator itr = modelData->modelPoints->find(key);
  PointList* plist;

  if (itr != modelData->modelPoints->end()) {
    plist = (*itr).second;
    hash_key_found = true;
  }

  new_point = new_point || !hash_key_found;

  // Hash-key not in the table, a completely new point-list is added.
  if (!hash_key_found) {

    plist = new PointList;
    plist->push_front(point);
    modelStatistics->nofPoints++;
    (*modelData->modelPoints)[key] = plist;
  }

  // Hash-key was found, but we have to check if point really exist.
  else {

    bool point_exists = ( NULL != findPoint(plist, point) );

    new_point = new_point || !point_exists;

    if (!point_exists) {

      plist->push_front(point);
      modelStatistics->nofPoints++;
    }
  }

  return new_point;
}


// Method adds a new vertex to the model.
// Point2Vertex-table and model's point hashtable is also updated
int
Model::addVertex(BodyElement* vertex)
{
  GcPoint* vpoint = (GcPoint*)vertex->getGeometry();

  (*modelData->modelPoint2Vertices)[vpoint] = vertex;

  addToHashPoints(vpoint);

  return ++modelStatistics->nofVertices;
}


void
Model::bodySelected(Renderer* renderer, int body_id, int lr_id)
{
  Body* body = getBodyById(body_id);

  if (body == NULL) {
    return;
  }

  modelInfo->selectedBody1Id = body_id;
  modelInfo->selectedLayer1Id = lr_id;
  modelInfo->selectedBody2Id = NO_INDEX;
  modelInfo->selectedLayer2Id = NO_INDEX;
  modelInfo->selectedBodyElementId = NO_INDEX;

  objectDrawingMode dmode = body->getDrawMode();

#if 0
  if (dmode == SELECTED) {
    body->setDrawMode(NORMAL);
  } else {
    body->setDrawMode(SELECTED);
  }
#endif

  UserInterface* gui = theControlCenter->getGui();

  gui->selectBody(body_id, lr_id, NO_INDEX, NO_INDEX, true);
}


void
Model::boundarySelected(Renderer* renderer, int bndr_id,
                        int body1_id, int layer1_id,
                        int body2_id, int layer2_id,
                        bool accept_body_change, bool update_gui)
{
  // Selected body element or boundary group
  ModelObject* obj = getModelObjectById(bndr_id);

  const int* bndr_ids = NULL;
  int nof_bndrs = 0;

  int bndr_id1[1];

  BodyElement* be = NULL;
  BodyElementGroup* beg = NULL;

  switch (obj->getObjectType()) {

  // Objects are normal boundaries
  case OT_FACE:
  case OT_EDGE:
  case OT_VERTEX:
    bndr_id1[0] = bndr_id;
    bndr_ids = bndr_id1;
    nof_bndrs = 1;
    be = getBodyElementById(bndr_id);
    break;

  // Objects are element groups (BC panel)
  case OT_ELEMENT_GROUP:
    beg = (BodyElementGroup*) obj;
    nof_bndrs = beg->getNofElements();
    bndr_ids = beg->getElementIds();

    int be_id = beg->getElementId(0);
    be = getBodyElementById(be_id);
    break;
  }

#if 0
  if ( modelInfo->dimension == ECIF_2D )
    be = getEdge(bndr_id);
  else
    be = getFace(bndr_id);
#endif

  // If a non existing id (this should not really happen!)
  //
  if (be == NULL) return;

  int current_body_ids[2] = {modelInfo->selectedBody1Id, modelInfo->selectedBody2Id};

  int body_ids[2] = {NO_INDEX, NO_INDEX};

  int count, i;
  bool is_selected;

  UserInterface* gui = theControlCenter->getGui();

  int bd1_id = be->getParentId(1);
  int bd2_id = be->getParentId(2);

  if ( body2_id == NO_INDEX ) {

    // Element is an inner boundary
    if ( be->isInnerBoundary() ) {

      // inner boundaries are stored the smaller body id
      // always as the first, so we have to check which id
      // is for the body2
      if (body1_id == bd1_id)
        body2_id = bd2_id;
      else
        body2_id = bd1_id;
    }

    // Outer boundary (we make body2_id = body1_id)
    else {
      body2_id = body1_id;
    }
  }

  body_ids[0] = body1_id;
  body_ids[1] = body2_id;

  bool same_bodies = ( current_body_ids[0] == body_ids[0] &&
                       current_body_ids[1] == body_ids[1]
                     );

  // Reset current bodies (body-pair) if we have changed
  // the body
  // NOTE: We don't reset current body if it remains the
  // same, because we can have multiple elements selected
  // in a body
  if ( accept_body_change ||
       same_bodies ||
       current_body_ids[0] == NO_INDEX
     ) {
    count = 0;

  } else if ( current_body_ids[0] == current_body_ids[1] ||
              current_body_ids[1] == NO_INDEX
            ) {
    count = 1;

  } else {
    count = 2;
  }

  // Reset current bodies if changed
  for (i = 0; i < count; i++) {

    int current_body_id = current_body_ids[i];
    Body* current_body = getBodyById(current_body_id);

    if ( current_body == NULL ) continue;

    int index = 0;
    while (true) {
      BodyElement* cbe = current_body->getElement(index++);
      if (cbe==NULL) break;
      gui->setBoundarySelectionMode(cbe->Id(), false);
      cbe->setDrawState(DS_NORMAL);
    }
  }

  // Reset current boundary selections
  resetBoundarySelections(update_gui, beg != NULL, nof_bndrs, bndr_ids, false);

  // Update current ids
  current_body_ids[0] = body1_id;
  current_body_ids[1] = body2_id;

  modelInfo->selectedBody1Id = body1_id;
  modelInfo->selectedBody2Id = body2_id;

  modelInfo->selectedBodyElementId = bndr_id;

  for (i = 0; i < nof_bndrs; i++) {

    be = getBodyElementById(bndr_ids[i]);

    // Pick selected bodyelement state
    objectDrawingState dstate = be->getDrawState();

    // Set state for the current
    if (dstate == DS_SELECTED) {

      be->setDrawState(DS_NORMAL);
      is_selected = false;

    } else {

      be->setDrawState(DS_SELECTED);
      is_selected = true;
    }
  }

  // Set element's selection state in the Gui
  if (update_gui) {

    gui->setBoundarySelectionMode(bndr_id, is_selected, true);

    if ( body1_id == body2_id ) {
      body2_id = NO_INDEX;
    }

    gui->selectBoundary(bndr_id, body1_id, layer1_id, body2_id, layer2_id, modelFlags[SELECT_OBJECTS_EXTEND]);
  }

  gui->markSelectedBoundaries();
}


double
Model::calcInitialMeshH()
{
  double initial_mesh_h = MAX_RANGE;

  if (modelInfo->dimMin > 0 && modelInfo->dimMin < initial_mesh_h)
    initial_mesh_h = MESH_H_INIT_FACTOR * modelInfo->dimMin;

  if (modelInfo->minEdgeSize > 0 && modelInfo->minEdgeSize < initial_mesh_h)
    initial_mesh_h = modelInfo->minEdgeSize;

  return initial_mesh_h;

}


// Method checks that all model's bodies are ok.
// Return true if there are no bodies or if all are ok.
//
bool
Model::checkBodies()
{
  // A table (a stack) for available default colors.
  ColorIndexArray  color_table;

  for(int i = MAX_NOF_BODIES-1; i >= 0; i--)
    color_table.push_back(defaultColorIndices[i]);

  RangeVector rv;
  colorIndices body_color;
  ColorIndexArray::iterator pos;

  int index = 0;
  while (true) {

    Body* body = getBody(index++);

    if (body==NULL) break;

    body->check();

    if ( !body->isOk() ) {
      return false;
    }

    // If body is ok, update model's bounding box.
    body->getRangeVector(rv);
    modelBox->extendByRange(rv);

    // Remove used non-default color from unused-colors.
    body_color = body->getColorIndex();

    if (body_color != DEFAULT_COLOR_INDEX) {

		  pos = std::find(color_table.begin(), color_table.end(), body_color);

      if (pos != color_table.end())
        color_table.erase(pos);
    }
  }

  // Replace non-defined (=DEFAULT_COLOR_INDEX) with
  // colors from default-indices list.
  setBodyColors(color_table);

  // Set bounding box info
  modelBox->getRangeVector(rv);

  modelInfo->minX = rv[0];
  modelInfo->maxX = rv[1];
  modelInfo->minY = rv[2];
  modelInfo->maxY = rv[3];
  modelInfo->minZ = rv[4];
  modelInfo->maxZ = rv[5];

  // Model dimensions
  modelInfo->dimX = modelInfo->maxX - modelInfo->minX;
  modelInfo->dimY = modelInfo->maxY - modelInfo->minY;
  modelInfo->dimZ = modelInfo->maxZ - modelInfo->minZ;

  modelInfo->dimAvg = modelInfo->dimX + modelInfo->dimY + modelInfo->dimZ;
  modelInfo->dimAvg /= modelInfo->dimension;

  modelInfo->dimMax = modelInfo->dimX;
  if (modelInfo->dimY > modelInfo->dimMax)
    modelInfo->dimMax = modelInfo->dimY;
  if (modelInfo->dimension == ECIF_3D && modelInfo->dimZ > modelInfo->dimMax )
    modelInfo->dimMax = modelInfo->dimZ;

  modelInfo->dimMin = modelInfo->dimX;
  if (modelInfo->dimY < modelInfo->dimMin)
    modelInfo->dimMin = modelInfo->dimY;
  if (modelInfo->dimension == ECIF_3D && modelInfo->dimZ < modelInfo->dimMin )
    modelInfo->dimMin = modelInfo->dimZ;

  if ( modelInfo->modelSourceType != ECIF_MESH_FILE &&
       modelInfo->dimAvg > 0.0
     )
    setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_CAD, true);
  else
    setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_CAD, false);

  return true;
}


// Method checks that all model's bodyelement loops are correct.
// 2D: ccw-oriented
// 3D: nothing special currently
// Return true if no loops or if all could be coreclty oriented
//
// NOTE: An error (in 2D) means that loop is not continuous!
//
bool
Model::checkBodyElementLoops()
{
  int index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    if ( !bel->check() ) {
      return false;
    }
  }

  return true;
}


bool
Model::checkBodyElements()
{
  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;
    be->addAllPendingSubElements();
  }

  return true;
}


bool
Model::checkBoundaries()
{
  // Check outer boundaries which possibly have "hanging"
  // components to be created
  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    if ( !be->checkOuterBoundaries() ) {
      return false;
    }
  }

  // Next remove splitted boundaries from bodies
  // and replace them with corresponding covering
  // subelements
  index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( !body->checkElements() ) {
      return false;
    }
  }

  // Next remove splitted boundaries from element loops
  // and replace them with corresponding covering
  // subelements
  index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    if ( !bel->checkElements() ) {
      return false;
    }
  }

  return true;
}


bool
Model::checkElementGroupData()
{
  int index, be_id;
  BodyElementGroup* beg;

  // Check boundary  groups
  // ----------------------
  index = 0;
  while (true) {
    BodyElementGroup* beg = getBodyElementGroup(index++);
    if (beg==NULL) break;
    if ( !beg->check() ) return false;
  }

  // Check all boundaries
  // --------------------
  index = 0;
  while (true) {
    BodyElement* be = getFace(index++);
    if (be==NULL) break;
    if (!be->checkElementGroupData()) return false;
  }

  index = 0;
  while (true) {
    BodyElement* be = getEdge(index++);
    if (be==NULL) break;
    if (!be->checkElementGroupData()) return false;
  }

  index = 0;
  while (true) {
    BodyElement* be = getVertex(index++);
    if (be==NULL) break;
    if (!be->checkElementGroupData()) return false;
  }

  return true;
}


void
Model::checkDiffuseGrayRadiation()
{
  modelInfo->hasDiffuseGrayRadiation = false;

  int index = 0;
  while (true) {
    Parameter* bc = getParameter(index++, ECIF_BOUNDARY_CONDITION);
    if (bc==NULL) break;
    if ( bc->IsApplied() &&
         bc->hasFieldValueBySifName("Radiation", "Diffuse gray")
       ) {
      modelInfo->hasDiffuseGrayRadiation = true;
      return;
    }
  }
}


// Method checks that all model's mesh bodies are ok.
// Return true if there are no bodies or if all are ok.
bool
Model::checkMeshBodies()
{
  int index = 0;
  while (true) {
    Body* bd = getBody(index++);
    if (bd==NULL) break;
    bd->calcMeshBox();
  }

  MeshInfo* mi = meshInfo;

  //-----Update model's mesh bounding box
  RangeVector rv;
  rv[0] = mi->minX;
  rv[1] = mi->maxX;
  rv[2] = mi->minY;
  rv[3] = mi->maxY;
  rv[4] = mi->minZ;
  rv[5] = mi->maxZ;

  meshBox->extendByRange(rv);

  mi->dimX = mi->maxX - mi->minX;
  mi->dimY = mi->maxY - mi->minY;
  mi->dimZ = mi->maxZ - mi->minZ;

  mi->dimAvg = mi->dimX + mi->dimY + mi->dimZ;
  mi->dimAvg /= modelInfo->dimension;

  double pick_tol = 0.05 * mi->dimAvg;
  MeshEdgeElementTable::setPickingTolerance(pick_tol);

  if (meshInfo->dimAvg < 0.0)
    setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_MESH, false);
  else
    setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_MESH, true);

  return true;
}



void
Model::checkVertexExistence()
{
  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;
    be->createExtraVertices();
  }

  markActiveObjects();
  updateModelStatistics();
}

// Check if a verex exists 
bool
Model::checkVertexExistence(int tag)
{
  if ( NULL == getVertexByTag(tag) ) 
    return false;
  else
    return true;
}


ecif_modelStatus
Model::checkStatus()
{
  ecif_modelStatus modelStatus = STATUS_OK;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    ecif_modelStatus body_status = body->checkStatus();
    modelStatus |= body_status;
  }

  return modelStatus;
}


// Combine mesh boundaries (in one body or body-pair)
//
void
Model::combineBoundaries(int body1_id, int body2_id)
{
  int i,j;
  UserInterface* gui = theControlCenter->getGui();

  Body* body1 = getBodyById(body1_id);
  Body* body2 = getBodyById(body2_id);

  int body1_tag = NO_INDEX;
  int body2_tag = NO_INDEX;

  int body1_layer = NO_INDEX;
  int body2_layer = NO_INDEX;

  if ( body1 != NULL ) {
    body1_tag = body1->Tag();
  }

  if ( body2 != NULL ) {
    body2_tag = body2->Tag();
  }

  int* source_ids = new int[modelStatistics->nofElements];
  int nof_source_ids = 0;

  //---Count nof mesh elements in the new body element
  //   and the number of contributing boundaries
  int nof_mesh_elements = 0;

  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    if ( DS_SELECTED == be->getDrawState() ) {
      source_ids[nof_source_ids++] = be->Id();
      nof_mesh_elements += be->getNofMeshElements();
      body1_layer = be->getParentLayer(1);
      body2_layer = be->getParentLayer(2);
    }
  }

  //---If nothing or only one element was selected
  if (nof_source_ids <= 1) {
    if (nof_source_ids == 0)
      gui->showMsg("No boundaries selected for combine!");
    else
      gui->showMsg("Only one boundary selected. Nothing to combine!");

    delete[] source_ids;

    return;
  }

  // If this is the first edit operation
  if ( modelInfo->editingMeshBoundaries == false ) {
    startEditMeshBoundaries();
  }

  // Delete old info
  short idx = modelData->splitCombineInfoIndex;
  delete (*modelData->splitCombineInfos)[idx];

  // Create new info entry and store it
  SplitCombineInfo* sc_info = new SplitCombineInfo;

  (*modelData->splitCombineInfos)[idx] = sc_info;

  // Update split/combine index for next insert
  setNewSplitCombineIndex(+1);

  //---Create new bodyelement, add to the model and to the bodies
  BodyElement* new_be = createBodyElement(body1_tag, body1_layer, body2_tag, body2_layer, nof_mesh_elements);

  new_be->setParentIds(body1_id, body2_id);
  new_be->setParentTags(body1_tag, body2_tag);
  new_be->checkElementGroupData();

  (*modelData->createdModelElements)[new_be->Id()] = new_be;

  // Set info data
  sc_info->canRedo = false;
  sc_info->canUndo = true;
  sc_info->combineTargetId = new_be->Id();
  sc_info->nofCombineSourceIds = nof_source_ids;
  sc_info->combineSourceIds = new int[nof_source_ids];

  //---Copy selected mesh elements to the new boundary
  //   and remove the original bodyelements from model
  for (i = 0; i < nof_source_ids; i++) {

    sc_info->combineSourceIds[i] = source_ids[i];

    BodyElement* be = getBoundaryById(source_ids[i]);

    int nof_elements = be->getNofMeshElements();

    //-Copy all subelements
    for (j = 0; j < be->getNofSubElements(); j++) {
      BodyElement* se = be->getSubElement(j);
      new_be->addSubElement(se);
    }

    //-Copy all mesh elements
    for (int j = 0; j < nof_elements; j++) {
      int elem_id = be->getMeshElementId(j);
      short elem_dir = be->getMeshElementDir(j);

      // Add mesh element to the new boundary
      new_be->addMeshElement(elem_id, elem_dir);
      meshData->boundaryElementBoundaryIds[elem_id] = sc_info->combineTargetId;
    }

    //-Remove boundary element from the model, but not the
    // subelements!
    //
    removeBodyElement(be, body1, body2, false);

  } // for source ids

  delete[] source_ids;

  body1->check();

  if (body2 != NULL) {
    body2->check();
  }

  // Update model
  new_be->findMeshBorder();
  updateModelStatistics();

  gui->updateBodyData(this);
  gui->updateBoundaryData(this);

  gui->setMeshEdited();

  refreshRenderer();
}



bool
Model::convertTags2Ids()
{
  int index;

  // Bodies
  // ======
  index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( !body->convertTags2Ids() ) return false;
  }

  // Boundary loop
  // =============
  index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    if ( !bel->convertTags2Ids() ) return false;
  }

  // Boundaries
  // =============
  index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    if ( !be->convertTags2Ids() ) return false;
  }

  return true;
}


// Creates one mesh geometry body element with given element-id
BodyElement*
Model::createBodyElement(int element_tag,
                         int body1_tag, int body1_layer,
                         int body2_tag, int body2_layer,
                         int nof_mesh_elements)
{
  Body* body1 = getBodyByTag(body1_tag);
  Body* body2 = getBodyByTag(body2_tag);

  if (body1 == NULL ) {
    return NULL;
  }

  BodyElement* be = NULL;

  switch (modelInfo->dimension) {
  case ECIF_2D:
    be = new BodyElement2D(element_tag, body1_tag, body2_tag, nof_mesh_elements);
    break;
  case ECIF_3D:
    be = new BodyElement3D(element_tag, body1_tag, body2_tag, nof_mesh_elements);
    break;
  }

  if (be != NULL) {
    be->setParentLayers(body1_layer, body2_layer);
  }

  // No success (nofElements still zero!)
  if ( 0 == addBodyElement(be, body1_tag, body1_layer, body2_tag, body2_layer) ) {
    delete be;
    be = NULL;
  }

  return be;
}


// Creates one mesh geometry body element
BodyElement*
Model::createBodyElement(int body1_tag, int body1_layer, int body2_tag, int body2_layer, int nof_mesh_elements)
{
  Body* body1 = getBodyByTag(body1_tag);
  Body* body2 = getBodyByTag(body2_tag);

  if (body1 == NULL ) {
    return NULL;
  }

  BodyElement* be = NULL;

  switch (modelInfo->dimension) {
  case ECIF_2D:
     be = new BodyElement2D(body1_tag, body2_tag, nof_mesh_elements);
    break;
  case ECIF_3D:
     be = new BodyElement3D(body1_tag, body2_tag, nof_mesh_elements);
    break;
  }

  if (be != NULL) {
    be->setParentLayers(body1_layer, body2_layer);
  }

  if ( 0 == addBodyElement(be, body1_tag, body1_layer, body2_tag, body2_layer) ) {
    delete be;
    be = NULL;
  }

  return be;
}


void
Model::createMeshBoundaryElementEdges()
{
  //---3D
  if ( modelInfo->dimension == ECIF_3D ) {

    // Boundary edges
    meshManager->findMeshElementEdges(meshData->boundaryElements, meshInfo->nofBoundaryEdges);

    delete meshData->boundaryEdges;
    meshData->boundaryEdges = new MeshEdgeElementTable(meshInfo->nofBoundaryEdges, false);

    meshManager->createMeshElementEdges(meshData->boundaryElements, meshData->boundaryEdges);

#if 1
    // Boundary vertices
    meshManager->findMeshElementEdges(meshData->boundaryEdges, meshInfo->nofBoundaryVertices);

    delete meshData->boundaryVertices;
    meshData->boundaryVertices = new MeshVertexElementTable(meshInfo->nofBoundaryVertices);

    meshManager->createMeshElementEdges(meshData->boundaryEdges, meshData->boundaryVertices);
#endif

  //---2D
  } else {

    // Boundary vertices
    meshManager->findMeshElementEdges(meshData->boundaryElements, meshInfo->nofBoundaryVertices);

    delete meshData->boundaryVertices;
    meshData->boundaryVertices = new MeshVertexElementTable(meshInfo->nofBoundaryVertices);

    meshManager->createMeshElementEdges(meshData->boundaryElements, meshData->boundaryVertices);
  }

}


void
Model::createMeshBulkElementEdges()
{
  meshManager->findMeshElementEdges(meshData->bulkElements, meshInfo->nofBulkEdges);

  delete[] meshData->bulkEdgeRendered;
  meshData->bulkEdgeRendered = new bool[meshInfo->nofBulkEdges];

  UserInterface* gui = theControlCenter->getGui();

  strstream strm;
  strm << "Nof bulk edges: " << meshInfo->nofBulkEdges << ends;
  gui->showMsg(strm.str());
}


const char*
Model::objectType2Name(objectType type, int max_buf_len, char* name_buffer)
{
  char* name;

  switch (type) {
  case OT_NONE:
    name = "None"; break;
  case OT_BODY:
    name = "Body"; break;
  case OT_BODY_LAYER:
    name = "Body Layer"; break;
  case OT_BODYPAIR:
    name = "Body Pair"; break;
  case OT_ELEMENT_LOOP:
    name = "Element Loop"; break;
  case OT_BOUNDARY:
    name = "Boundary"; break;
  case OT_FACE:
    name = "Face"; break;
  case OT_EDGE:
    name = "Edge"; break;
  case OT_VERTEX:
    name = "Vertex"; break;
  case OT_ELEMENT_GROUP:
    name = "Element Group"; break;
  default:
    name = "None"; break;
  }

  if ( max_buf_len > 0  && name_buffer != NULL ) {
    strncpy(name_buffer, name, max_buf_len);
  }

  return name;
}


objectType
Model::objectName2Type(const char* name)
{
  if ( name == NULL || LibFront::in(name, "None") )
    return OT_NONE;
  else if (LibFront::in(name, "Body") )
    return OT_BODY;
  else if (LibFront::in(name, "Body Layer") )
    return OT_BODY_LAYER;
  else if (LibFront::in(name, "Body Pair") )
    return OT_BODYPAIR;
  else if (LibFront::in(name, "Element Loop") )
    return OT_ELEMENT_LOOP;
  else if (LibFront::in(name, "Boundary") )
    return OT_BOUNDARY;
  else if (LibFront::in(name, "Face") )
    return OT_FACE;
  else if (LibFront::in(name, "Edge") )
    return OT_EDGE;
  else if (LibFront::in(name, "Vertex") )
    return OT_VERTEX;
  else if (LibFront::in(name, "Element Group") )
    return OT_ELEMENT_GROUP;
  else
    return OT_NONE;
}


ostream&
Model::outputSolverTargetFields_sif(ostream& out, short indent_size, short indent_level, const char* source_eq_name)
{
  return outputManager->sif_outputSolverTargetFields(out, indent_size, indent_level, source_eq_name);

}



Parameter*
Model::createNewParameter(ecif_parameterType param_type,
                          int pid, int parent_id,
                          char* param_value, char* param_name)
{

  switch (param_type) {
  case ECIF_BODY_FORCE:
    return new BodyForce(pid, parent_id, param_value, param_name);
  case ECIF_BODY_PARAMETER:
    return new BodyParameter(pid, parent_id, param_value, param_name);
  case ECIF_BOUNDARY_CONDITION:
    return new BoundaryCondition(pid, parent_id, param_value, param_name);
  case ECIF_BOUNDARY_PARAMETER:
    return new BoundaryParameter(pid, parent_id, param_value, param_name);
  case ECIF_CALCULATOR:
    return new Calculator(pid, param_value, param_name);
  case ECIF_CONSTANT:
    return new Constant(pid, param_value, param_name);
  case ECIF_COORDINATE:
    return new Coordinate(pid, param_value, param_name);
  case ECIF_DATAFILE:
    return new Datafile(pid, param_value, param_name);
  case ECIF_EQUATION:
    return new Equation(pid, param_value, param_name);
  case ECIF_EQUATION_VARIABLE:
    return new EquationVariable(pid, param_value, param_name);
  case ECIF_GRID_H:
    return new GridH(pid, parent_id, param_value, param_name);
  case ECIF_GRID_PARAMETER:
    return new GridParameter(pid, parent_id, param_value, param_name);
  case ECIF_INITIAL_CONDITION:
    return new InitCondition(pid, parent_id, param_value, param_name);
  case ECIF_MATERIAL:
    return new Material(pid, parent_id, param_value, param_name);
  case ECIF_MODEL_PARAMETER:
    return new ModelParameter(pid, param_value, param_name);
  case ECIF_SIMULATION_PARAMETER:
    return new SimulationParameter(pid, param_value, param_name);
  case ECIF_SOLVER:
    return new Solver(pid, param_value, param_name);
  case ECIF_SOLVER_CONTROL:
    return new SolverControl(pid, param_value, param_name);
  case ECIF_TIMESTEP:
    return new Timestep(pid, param_value, param_name);
  case ECIF_USER_SETTING:
    return new UserSetting(pid, param_value, param_name);
  default:
    return NULL;
  }
}


Parameter*
Model::createNewParameter(ecif_parameterType parameter_type, int p_id)
{
  Parameter* parameter;

  switch (parameter_type) {
  case ECIF_BODY_FORCE:
    parameter = new BodyForce(p_id);
    break;
  case ECIF_BODY_PARAMETER:
    parameter = new BodyParameter(p_id);
    break;
  case ECIF_BOUNDARY_CONDITION:
    parameter = new BoundaryCondition(p_id);
    break;
  case ECIF_BOUNDARY_PARAMETER:
    parameter = new BoundaryParameter(p_id);
    break;
  case ECIF_CALCULATOR:
    parameter = new Calculator(p_id);
    break;
  case ECIF_CONSTANT:
    parameter = new Constant(p_id);
    break;
  case ECIF_COORDINATE:
    parameter = new Coordinate(p_id);
    break;
  case ECIF_DATAFILE:
    parameter = new Datafile(p_id);
    break;
  case ECIF_EQUATION:
    parameter = new Equation(p_id);
    break;
  case ECIF_EQUATION_VARIABLE:
    parameter = new EquationVariable(p_id);
    break;
  case ECIF_GRID_H:
    parameter = new GridH(p_id);
    break;
  case ECIF_GRID_PARAMETER:
    parameter = new GridParameter(p_id);
    break;
  case ECIF_INITIAL_CONDITION:
    parameter = new InitCondition(p_id);
    break;
  case ECIF_MATERIAL:
    parameter = new Material(p_id);
    break;
  case ECIF_MODEL_PARAMETER:
    parameter = new ModelParameter(p_id);
    break;
  case ECIF_SIMULATION_PARAMETER:
    parameter = new SimulationParameter(p_id);
    break;
  case ECIF_SOLVER:
    parameter = new Solver(p_id);
    break;
  case ECIF_SOLVER_CONTROL:
    parameter = new SolverControl(p_id);
    break;
  case ECIF_TIMESTEP:
    parameter = new Timestep(p_id);
    break;
  case ECIF_USER_SETTING:
    parameter = new UserSetting(p_id);
    break;
  default:
    parameter = NULL;
    break;
  }

  parameter->checkLastId(p_id);

  parameter->setChangedState(false);

  return parameter;
}


void
Model::deleteMeshData()
{
  int index = 0;

  setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_MESH, false);
  setFlagValue(DRAW_SOURCE, DRAW_SOURCE_MESH, false);

  theControlCenter->getGui()->updateModelFlags(this);
  theControlCenter->getGui()->configureButtons("draw_source_mesh", 0);

  delete meshData; meshData = NULL;
  delete meshInfo; meshInfo = NULL;
  delete meshBox;  meshBox  = NULL;

  index = 0;
  while(true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    body->deleteMeshElements();
  }

  index = 0;
  while(true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    be->deleteMeshElements();
  }
}


// Delete all parameters from the table defined
// by the parameter_type
void
Model::deleteParameters(ecif_parameterType parameter_type)
{
  ParameterTable* table;

  // NOTE: This will be scalar pointer to a modelStatistics-counter,
  // do NOT delete it!
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, use_counter) ) {
    return;
  }

  table->clear();
  (*use_counter) = 0;

  // Reset objects' parameter counters
  switch (parameter_type) {
  case ECIF_EQUATION:
    modelStatistics->nofBodiesWithEquation = 0;
    break;
  case ECIF_MATERIAL:
    modelStatistics->nofBodiesWithMaterial = 0;
    break;
  case ECIF_BODY_FORCE:
    modelStatistics->nofBodiesWithBodyForce = 0;
    break;
  case ECIF_INITIAL_CONDITION:
    modelStatistics->nofBodiesWithInitialCondition  = 0;
    break;
  case ECIF_BOUNDARY_CONDITION:
    modelStatistics->nofInnerBoundariesWithCondition = 0;
    modelStatistics->nofOuterBoundariesWithCondition = 0;
    break;
  }

}


// Delete one parameter by id from the table defined
// by the parameter_type
int
Model::deleteParameter(ecif_parameterType parameter_type, int pid)
{
  ParameterTable* table;

  // NOTE: This will be scalar pointer to a modelStatistics-counter,
  // do NOT delete it!
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, use_counter) ) {
    return NO_INDEX;
  }

  if ( 0 == table->erase(pid))
    return NO_INDEX;

  return --(*use_counter);
}


void
Model::deleteCadData()
{
  UserInterface* gui = theControlCenter->getGui();

  setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_CAD, false);
  setFlagValue(DRAW_SOURCE, DRAW_SOURCE_CAD, false);

  gui->updateModelFlags(this);
  gui->configureButtons("draw_source_cad", 0);

  int index = 0;
  while(true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    be->deleteCadData();
  }

}


void
Model::fieldNameGuiToSif(const char* gui_name, char* sif_name_buffer)
{
  theControlCenter->getUI()->fieldNameGuiToSif(gui_name, sif_name_buffer);
}


void
Model::fieldNameSifToGui(const char* sif_name, char* gui_name_buffer)
{
  theControlCenter->getUI()->fieldNameSifToGui(sif_name, gui_name_buffer);
}


// Find body pairs from body element parents
//
void
Model::findBodyPairs()
{

  int be_id, bd1_id, bd2_id;

  // Loop all elements
  int index = 0;
  while (true) {

    BodyElement* be = getBoundary(index++);

    if (be==NULL) break;

    int bd1_id = be->getParentId(1);
    int bd2_id = be->getParentId(2);

    if ( bd1_id == NO_INDEX || bd2_id == NO_INDEX ) {
      continue;
    }

    // This is a boundary between connected body layers!
    // It does not create a body pair!!!
    //
    if ( bd1_id == bd2_id ) {
      continue;
    }

    Body* body1 = getBodyById(bd1_id);
    Body* body2 = getBodyById(bd2_id);

    // Virtual bodies cannot be a pair member
    //
    if ( body1->isVirtual() || body2->isVirtual() ) {
      continue;
    }

    BodyPair* bp = getBodyPairById(body1, body2);

    // Create new bodypair
    //
    if ( bp == NULL ) {
      bp = new BodyPair(body1, body2);
      bp->setTag();
      bp->setId();
      addBodyPair(bp);
    }

  }
}


// Method finds neigbouring bodies and innerBoundaries between these
// bodies.
void
Model::findBoundaries()
{
  // Find all candiate neigbours (body pairs).
  modelData->neighbourCandidates = findNeighbourCandidates();

  // And find all candidate innerBoundaries beteween candidate bodies.
  modelData->boundaryCandidates = findBoundaryCandidates();

  // And find real neigobour bodies and adjacent innerBoundaries.
  findInnerBoundaries();

  checkBoundaries();
}


// Method finds all potential adjacent innerBoundaries beteween potential
// neighbour bodies.
AdjacentPairArray*
Model::findBoundaryCandidates()
{
  // This method creates a table where we have pairs of (Body,Element)-pairs.
  // Each pair is a candidate for an adjancent surface because bodyelement
  // pairs are overlapping (this is a necessary but not a sufficient
  // condition for surfaces being adjacent).
  AdjacentPairArray* cp_array = new AdjacentPairArray;
  BodyElement* be1;
  BoundBox* be1_box;
  BodyElement* be2;
  BoundBox* be2_box;
  BoundBox* body2_box;
  BodyElement** be_array1;
  BodyElement** be_array2;
  int be_count1, be_count2;

  int bp_count = modelData->neighbourCandidates->size();
  BodyPair* bp;

  //We read each pair from *bp_array* and check if the elements in the bodies
  //overlap.
  for (int i = 0; i < bp_count; i++) {
    bp = (*modelData->neighbourCandidates)[i];

    if (bp == NULL)
      continue;

    const Body* bd1;
    const Body* bd2;

    bp->getBodies(bd1, bd2);

    Body* body1 = (Body*) bd1;
    Body* body2 = (Body*) bd2;

    int layer1 = -1;
    while (true) {

      if (!body1->selectLayer(++layer1)) break;

      // Elements from the body1-layer into a table.
      be_array1 = body1->getElementArray(layer1);
      be_count1 = body1->getElementCount(layer1);

      int layer2 = -1;
      while (true) {

        if (!body2->selectLayer(++layer2)) break;

        // Elements from the body2-layer into a table.
        be_array2 = body2->getElementArray();
        be_count2 = body2->getElementCount(layer2);

        //Next we loop all elements of the body1 and check if they overlap
        //with elements in the body2.
        body2_box = body2->getBoundBox(layer2); //each be1 must overlap this!
        for (int j = 0; j < be_count1; j++) {

          be1 = be_array1[j];
          be1_box = be1->getBoundBox();

          if (! be1_box->overlap(body2_box)) continue;

          for (int k = 0; k < be_count2; k++) {

            be2 = be_array2[k];
            be2_box = be2->getBoundBox();

            if (! be1_box->overlap(be2_box)) continue;

            AdjacentHalf** adj_pair = new AdjacentHalf*[2];
            adj_pair[0] = new AdjacentHalf;
            adj_pair[1] = new AdjacentHalf;
            adj_pair[0]->body = body1;
            adj_pair[0]->bodyLayer = layer1;
            adj_pair[0]->element = be1;
            adj_pair[1]->body = body2;
            adj_pair[1]->bodyLayer = layer2;
            adj_pair[1]->element = be2;
            cp_array->push_back(adj_pair);
          }
        }

        delete[] be_array2;
      }

      delete[] be_array1;
    }
  }

  //delete[] b_array;
  return cp_array;
}

// Method finds body layers which are completely inside an other body layer.
// The outer boundary of the contained layer becomes an inner boundary!
void
Model::findContainedBodies()
{
  //Read bodies into an array.
  int b_count = modelStatistics->nofBodies;

  Body** b_array = new Body*[b_count];

  int row = 0;
  int index = 0;
  while (true) {

    Body* body = getBody(index++);
    if (body==NULL) break;

    if ( body->isVirtual() ) {
      b_count--;
      continue;
    }

    b_array[row++] = body;
  }

  // Loop each body1
  for (int i = 0; i < b_count; i++) {

    // Loop each body2
    for (int j = i+1; j < b_count; j++) {

      Body* body1 = b_array[i];
      Body* body2 = b_array[j];

      // If this is already an existing body-pair, do nothing!
      if ( NULL != getBodyPairById(body1, body2) ) {
        continue;
      }

      int layer1 = -1;
      int layer2 = -1;

      // Each body1 layer
      //
      while (true) {

        if (!body1->selectLayer(++layer1)) break;

        // Each body2 layer
        while (true) {

          if (!body2->selectLayer(++layer2)) break;

          Body* bd1 = NULL;
          Body* bd2 = NULL;
          int lr1 = NO_INDEX;
          int lr2 = NO_INDEX;

          // Select "outer" and "inner" bodies (layers)
          if ( body1->hasInside(layer1, body2, layer2) ) {
            bd1 = body1;
            lr1 = layer1;
            bd2 = body2;
            lr2 = layer2;
          } else if ( body2->hasInside(layer2, body1, layer1) ) {
            bd1 = body2;
            lr1 = layer2;
            bd2 = body1;
            lr2 = layer1;
          }

          // Layers do not form any inner boundaries
          if ( bd1 == NULL || bd2 == NULL ) continue;

          BodyElementLoop* bel = bd2->getElementLoop(lr2);

          // Insert bd2 outer boundary as an inner loop
          // into the bd1
          int nof_loop_ids1 = bd1->getNofElementLoops(lr1);
          int* new_loop_ids = new int[1 + nof_loop_ids1];
          int* new_loop_tags = new int[1 + nof_loop_ids1];

          new_loop_ids[0] = bd1->getElementLoopId(lr1, 0);
          new_loop_ids[1] = -1 * bel->Id();

          new_loop_tags[0] = bd1->getElementLoopTag(lr1, 0);
          new_loop_tags[1] = bel->Tag();

          for(int i = 1; i < nof_loop_ids1; i++) {
            new_loop_ids[1 + i] = bd1->getElementLoopId(lr1, i);
            new_loop_tags[1 + i] = bd1->getElementLoopTag(lr1, i);
          }

          bd1->setElementLoops(lr1, 1 + nof_loop_ids1, new_loop_ids, new_loop_tags);

          // Add all elements in the loop to the bd1 and marks it
          // as the second parent
          int index = 0;
          while (true) {
            BodyElement* be = bel->getElement(index++);
            if (be==NULL) break;
            int bd1_id = bd1->Id();
            int bd2_id = bd2->Id();

            if ( bd1_id < bd2_id ) {
              be->setParentIds(bd1_id, bd2_id);
            } else {
              be->setParentIds(bd2_id, bd1_id);
            }

            bd1->addElement(lr1, be);
          }

        } // Each body2 layer
      } // Each body1 layer
    } // Body2 loop
  } // Body1 loop
}


// Method checks which of the candidate pair of bodyelelements
// really are adjacent and creates bodypairs
// NOTE: body-pairs must be 'lexicographically' ordered in
// *boundaryCandidates*, otherwise *neigbours* is not correctly created.
void
Model::findInnerBoundaries()
{
  IdArray swap1_ids;
  IdArray swap2_ids;
  IdArray relative_dirs;

  int count = modelData->boundaryCandidates->size();

  for (int i = 0; i < count; i++) {

    AdjacentHalf** adj_pair = (*modelData->boundaryCandidates)[i];

    if (adj_pair == NULL)
      continue;

    BodyElement* be1 = adj_pair[0]->element;
    BodyElement* be2 = adj_pair[1]->element;
    BodyElement* common = NULL;

    matchType match_type = be1->findCommonBoundary(be2, common);

    if (match_type != MATCH_NONE) {
      //new body-pair and boundary structures are created.

      // Bodies and layers:
      Body* b1 = adj_pair[0]->body;
      Body* b2 = adj_pair[1]->body;
      int lr1  = adj_pair[0]->bodyLayer;
      int lr2  = adj_pair[1]->bodyLayer;

      b1->incrBndrCount(lr1, INNER_ELEMENT);
      b2->incrBndrCount(lr2, INNER_ELEMENT);

      // info concerning the common boundary is added to both bodyelements.
      switch (match_type) {
      case MATCH_1_INSIDE:
        be2->addCoveringElement(common, BE_INNER);
        break;
      case MATCH_2_INSIDE:
        be1->addCoveringElement(common, BE_INNER);
        break;
      case MATCH_OVERLAP:
        be1->addCoveringElement(common, BE_INNER);
        be2->addCoveringElement(common, BE_INNER);
        break;
      case MATCH_EXACT:
        be1->addStatus(BE_INNER);
        be2->addStatus(BE_INNER);
        b1->swapBodyElements(lr1, be1, common);
        b2->swapBodyElements(lr2, be2, common);

        if ( be1 == common) {
          swap1_ids.push_back(be2->Id());
        } else {
          swap1_ids.push_back(be1->Id());
        }

        swap2_ids.push_back(common->Id());

        relative_dirs.push_back(getRelativeOrientation(be1, be2));
        break;
      }

    } // if match-type != none

  } // for all boundaries candidates

  if ( swap1_ids.size() > 0 ) {
    swapBodyElements(&swap1_ids, &swap2_ids, &relative_dirs);
  }

}


// Method finds all body-pairs which potentially are adjacent neighbour bodies.
BodyPairArray*
Model::findNeighbourCandidates()
{
  //Method finds bodies which are 'neighbour bodies', ie their bounding
  // boxes are overlapping (this is a necessary but not sufficient
  // condition for common innerBoundaries between bodies).

  //Read bodies into an array.
  int b_count = modelStatistics->nofBodies;

  Body** b_array = new Body*[b_count];

  int row = 0;
  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    b_array[row++] = body;
  }

  //Create a table of body-pairs which are overlapping.
  BodyPairArray* bp_array = new BodyPairArray;

  BoundBox* box1;
  BoundBox* box2;
  BodyPair* bp;

  int bp_count = 0;

  for (int i = 0; i < b_count; i++) {
    box1 = b_array[i]->getBoundBox();

    for (int j = i+1; j < b_count; j++) {
      box2 = b_array[j]->getBoundBox();

      if (box1->overlap(box2)) {
        bp = new BodyPair(b_array[i], b_array[j]);
        bp_array->push_back(bp);
        bp_count++;
      }
    }
  }

  return bp_array;
}


// Methods checks if a point is stored in the point-list *plist*
GcPoint*
Model::findPoint(PointList* plist, GcPoint* point)
{
  // Note: Point comparision must be based on objects, not pointers, because same
  // point-geometry may have been read into a new point-object from the input file.
  PointList::iterator i = plist->begin();
  while ( i != plist->end()) {

    // NOTE: GcPont class comparison operator is
    // epsilon sensitive!
    if ( **i == *point)
      return *i;
    i++;
  }

  // Point was not found.
  return NULL;
}


// Find selected mesh boundary element index using ray-casting
int
Model::findSelectedMeshBoundaryElement(Renderer* renderer, Point3& ray_start, Point3& ray_dir,
                                       bool try_current_bndr, int& bndr_id,
                                       int& body1_id, int& layer1_id,
                                       int& body2_id, int& layer2_id)
{
  return meshManager->findSelectedMeshBoundaryElement(renderer, ray_start, ray_dir,
                                                      try_current_bndr, bndr_id,
                                                      body1_id, layer1_id,
                                                      body2_id,layer2_id);
}


// Find vertex by geometry point
//
BodyElement*
Model::findVertex(GcPoint* point)
{
  BodyElement* vertex = NULL;

  // Try if point stored in the model
  GcPoint* stored_point = this->getPoint(point);

  // If point already exist in the model, check if a vertex also exists
  if ( stored_point != NULL ) {
    vertex = getVertex(stored_point);
  }

  return vertex;
}


const char*
Model::getActiveMeshName(int active_mesh_index)
{
  if ( active_mesh_index < 0 ||
       active_mesh_index >= modelInfo->nofActiveMeshes
     ) {
    return NULL;
  }

  int mindex = modelInfo->activeMeshIndices[active_mesh_index];

  if ( mindex < 0 || mindex >= modelInfo->nofMeshes ) {
    return NULL;
  }

  return modelInfo->meshNames[mindex];
}


// Method finds a body by index
Body*
Model::getBody(int index, bool only_active)
{
  return (Body*)getModelObject(index, OT_BODY, only_active);
}


Body*
Model::getBodyById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_BODY)
    return NULL;
  else
    return (Body*)obj;
}


// Method checks if a body with the id-key exists.
// Returns pointer to the body or NULL if not found.
Body*
Model::getBodyByTag(int tag) const
{
  return (Body*)getModelObjectByTag(OT_BODY, tag);
}


// Method finds a body element by index.
// NOTE: order of Faces/Edges/Vertices is not specified, so they are
// delivered in what order they are encountered
//
BodyElement*
Model::getBodyElement(int index, bool only_active)
{
  int count = modelData->modelObjects->size();

  if ( index < 0 || index >= count ) {
    return NULL;
  }

  int obj_index = 0;
  int counter = 0;

  while (true) {

    ModelObject*obj = getModelObject(obj_index++);

    if ( obj == NULL ) {
      return NULL;
    }

    if ( only_active && !obj->isActive() ) {
      continue;
    }

    objectType otp = obj->getObjectType();
    if ( otp != OT_FACE && otp != OT_EDGE && otp != OT_VERTEX ) {
      continue;
    }

    if ( counter++ == index ) {
      return (BodyElement*)obj;
    }
  }

  return NULL;
}


BodyElement*
Model::getBodyElementById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL )
    return NULL;

  objectType otp = obj->getObjectType();

  if ( otp != OT_FACE && otp != OT_EDGE && otp != OT_VERTEX)
    return NULL;

  return (BodyElement*)obj;
}


BodyElement*
Model::getBodyElementByBoundaryTag(int btag)
{
  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;
    if ( btag == be->getBoundaryTag() ) {
      return be;
    }
  }

  return NULL;
}


BodyElement*
Model::getBodyElementByTag(objectType type, int tag)
{
  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;
    if ( type == be->getObjectType() && tag == be->Tag() ) {
      return be;
    }
  }

  return NULL;
}


// Method finds a bodyelementloop by index.
BodyElementLoop*
Model::getBodyElementLoop(int index, bool only_active)
{
  return (BodyElementLoop*)getModelObject(index, OT_ELEMENT_LOOP, only_active);
}


BodyElementLoop*
Model::getBodyElementLoopById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_ELEMENT_LOOP)
    return NULL;
  else
    return (BodyElementLoop*)obj;
}


// Method checks if a bodyElement-loop with the id-key exists.
// Returns pointer to the bodyElementLoop or NULL if not found.
BodyElementLoop*
Model::getBodyElementLoopByTag(int tag) const
{
  return (BodyElementLoop*)getModelObjectByTag(OT_ELEMENT_LOOP, tag);
}


// Find element-loop by elements in the loop.
//
// Return true if a matching loop found
// Return loop id in the reference argument 'id'
bool
Model::getBodyElementLoopId(IdList* loop_ids, int& id, int& direction)
{
  // Collect element ids into an array
  //
  int nof_ids = loop_ids->size();

  int* ids = new int[nof_ids];

  IdList::iterator pos = loop_ids->begin();

  int index = 0;
  while ( pos != loop_ids->end() ) {
    ids[index++] = *pos++;
  }

  return getBodyElementLoopId(nof_ids, ids, id, direction);

  delete[] ids;
}


// Find element-loop by elements in the loop.
//
// Return true if a matching loop found
// Return loop id in the reference argument 'id'
//
// A helper function
bool
Model::getBodyElementLoopId(int nof_ids, const int* loop_ids, int& id, int& direction)
{
  const int* ids;
  int start1, start2;

  int index = 0;

  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);

    if (bel==NULL) break;

    if ( bel->getNofElements() != nof_ids ) continue;

    ids = bel->getElementIds();

    // Matching loops!
    if ( idLoopsAreMatching(nof_ids, nof_ids,
                            ids, loop_ids,
                            direction, start1, start2)
       ) {
      id = bel->Id();
      return true;
    }
  }

  id = NO_INDEX;
  direction = 0;

  return false;
}


BodyLayer*
Model::getBodyLayer(int index, bool only_active)
{
  return (BodyLayer*)getModelObject(index, OT_BODY_LAYER, only_active);
}


BodyLayer*
Model::getBodyLayerById(int id)
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_BODY_LAYER)
    return NULL;
  else
    return (BodyLayer*)obj;
}


BodyLayer*
Model::getBodyLayerByTag(int tag)
{
  int index = 0;
  while (true) {
    BodyLayer* bl = getBodyLayer(index++);
    if (bl==NULL) break;
    if ( OT_BODY_LAYER == bl->getObjectType() && tag == bl->Tag() ) {
      return bl;
    }
  }

  return NULL;
}


// Find layer for a body by body-tag
// Return layer-id or NO_INDEX if not found
//
int
Model::getBodyLayerByBodyId(int bd_id)
{
  int index = 0;

  while(true) {
    BodyLayer* bl = getBodyLayer(index++);
    if (bl==NULL) break;
    if (bd_id == bl->getBodyId() ) {
      return bl->Id();
    }
  }

  return NO_INDEX;
}


// Method finds a bodypair by index.
BodyPair*
Model::getBodyPair(int index, bool only_active)
{
  return (BodyPair*)getModelObject(index, OT_BODYPAIR, only_active);
}


BodyPair*
Model::getBodyPairById(const Body* bd1, const Body* bd2)
{
  int index = 0;
  while (true) {

    BodyPair* bp = getBodyPair(index++);

    if (bp==NULL) break;

    const Body* b1;
    const Body* b2;

    bp->getBodies(b1, b2);

    if ( b1 == bd1 && b2 == bd2 ||
         b1 == bd2 && b2 == bd1
         ) {
      return bp;
    }
  }

  return NULL;
}


int
Model::getBodyTagExt2Int(int external_id)
{
  if (external_id < 0 || external_id > MAX_NOF_BODIES ) {
    return NO_INDEX;
  }

  return meshData->bodyExt2Int[external_id];
}


int
Model::getBodyTagInt2Ext(int internal_id)
{
  if (internal_id < 0 || internal_id > MAX_NOF_BODIES ) {
    return NO_INDEX;
  }

  return meshData->bodyInt2Ext[internal_id];
}


void
Model::getBodyTags(int bd1_id, int bd2_id, int& bd1_tag, int& bd2_tag)
{
  //bd1_tag = NO_INDEX;
  //bd2_tag = NO_INDEX;

  bd1_tag = bd1_id;
  bd2_tag = bd2_id;

  if (!modelInfo->hasGeometry) {

    //bd1_tag = bd1_id;
    //bd2_tag = bd2_id;

    //return;
  }

  Body* bd1 = getBodyById(bd1_id);
  Body* bd2 = getBodyById(bd2_id);

  if ( bd1 != NULL ) {
    bd1_tag = bd1->Tag();
  }

  if ( bd2 != NULL ) {
    bd2_tag = bd2->Tag();
  }
}


// Method finds the next boundary (edge or face)
//
BodyElement*
Model::getBoundary(int index, bool only_active)
{
  if ( modelInfo->dimension == ECIF_2D )
    return (BodyElement*)getModelObject(index, OT_EDGE, only_active);
  else
    return (BodyElement*)getModelObject(index, OT_FACE, only_active);

}


// Method checks if a bodyElement with the id-key exists.
// Returns pointer to the bodyElement or NULL if not found.
BodyElement*
Model::getBoundaryById(int id) const
{
  if ( modelInfo->dimension == ECIF_2D )
    return getEdgeById(id);
  else
    return getFaceById(id);
}


// Method checks if a bodyElement with the id-key exists.
// Returns pointer to the bodyElement or NULL if not found.
BodyElement*
Model::getBoundaryByTag(int tag) const
{
  if ( modelInfo->dimension == ECIF_2D )
    return getEdgeByTag(tag);
  else
    return getFaceByTag(tag);
}


// Methods finds (the FIRSTt) body element for the body
// pair (body1,body2). This is meant mainly when there
// are unique boundaries per body/body-pair like in Ideas
// mesh files where boundaries are implied by material ids
BodyElement*
Model::getBoundaryByTags(int body1_tag, int body2_tag)
{
  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    int bd1_tag = be->getParentTag(1);
    int bd2_tag = be->getParentTag(2);

    if ( bd1_tag == body1_tag && bd2_tag == body2_tag ) {
      return be;
    }
  }

  // Not found
  return NULL;
}


void
Model::getBoundaries(int body1_id, int body2_id,
                     int& nof_boundaries,
                     BodyElement**& boundaries)
{
  nof_boundaries = 0;
  boundaries = NULL;

  if (body1_id == NO_INDEX) {
    return;
  }

  // Count boundaries
  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    int bd1_id = be->getParentId(1);
    int bd2_id = be->getParentId(2);

    if ( bd1_id == body2_id && bd2_id == body2_id ) {
      nof_boundaries++;
    }
  }

  if ( nof_boundaries == 0 ) return;

  boundaries = new BodyElement*[nof_boundaries];
  nof_boundaries = 0;

  // Store boundaries
  index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    int bd1_id = be->getParentId(1);
    int bd2_id = be->getParentId(2);

    if ( bd1_id == body2_id && bd2_id == body2_id ) {
      boundaries[nof_boundaries++] = be;
    }
  }

}


// Method finds the next boundary group
//
BodyElementGroup*
Model::getBodyElementGroup(int index, bool only_active)
{
  return (BodyElementGroup*)getModelObject(index, OT_ELEMENT_GROUP, only_active);
}


// Method checks if a boundary group with the id-key exists.
// Returns pointer to the boundary group or NULL if not found.
BodyElementGroup*
Model::getBodyElementGroupById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL ) return NULL;

  objectType ot = obj->getObjectType();

  if ( OT_ELEMENT_GROUP != obj->getObjectType() ) return NULL;

  return (BodyElementGroup*)obj;
}


// Method finds a boundary group by tag
BodyElementGroup*
Model::getBodyElementGroupByTag(int tag) const
{
  return (BodyElementGroup*)getModelObjectByTag(OT_ELEMENT_GROUP, tag);
}


void
Model::getBoundingBox(double& x1, double& x2, double& y1, double& y2, double& z1, double&z2) const
{
  RangeVector rv;
  modelBox->getRangeVector(rv);

  x1 = rv[0]; x2 = rv[1];
  y1 = rv[2]; y2 = rv[3];
  z1 = rv[4]; z2 = rv[5];
}


// Get all bodies bounding box for the model;
void
Model::getBoundingBox(RangeVector rv) const
{
  modelBox->getRangeVector(rv);
}


void
Model::getCoordinateLabels(int max_len, char* label_x, char* label_y, char* label_z)
{
  static int len = 1;
  static char cartesian[] = "XYZ";
  static char cylindric[] = "RZP";
  static char polar[]     = "RTP";

  int i1 = modelInfo->coordinateMapping[0] - 1;
  int i2 = modelInfo->coordinateMapping[1] - 1;
  int i3 = modelInfo->coordinateMapping[2] - 1;

  label_x[max_len] = '\0';
  label_y[max_len] = '\0';
  label_z[max_len] = '\0';

  if (max_len < len) return;

#if 0
  // NOTE: Fixed labels!
  label_x[0] = cartesian[0];
  label_y[0] = cartesian[1];
  label_z[0] = cartesian[2];
  return;
#endif

  // Set labels according to selected
  // coordinate system
  switch (modelInfo->coordinateType) {

  case COORD_CARTESIAN:
    label_x[0] = cartesian[i1];
    label_y[0] = cartesian[i2];
    label_z[0] = cartesian[i3];
    break;

  case COORD_CYLINDRIC:
    label_x[0] = cylindric[i1];
    label_y[0] = cylindric[i2];
    label_z[0] = cylindric[i3];
    break;

  case COORD_POLAR:
    label_x[0] = polar[i1];
    label_y[0] = polar[i2];
    label_z[0] = polar[i3];
    break;
  }

  label_x[len] = '\0';
  label_y[len] = '\0';
  label_z[len] = '\0';

}


// Get active bodies bounding box for the model;
void
Model::getCurrentBoundingBox(RangeVector rv)
{
  BoundBox current_box(rv);
  RangeVector body_rv;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( !DM_HIDDEN == body->getDrawMode() ) {
      body->getRangeVector(body_rv);
      current_box.extendByRange(body_rv);
    }
  }

  current_box.getRangeVector(rv);
}


// Get active bodies bounding box for the model;
void
Model::getCurrentMeshBoundingBox(RangeVector rv)
{
  BoundBox current_box(rv);
  RangeVector body_rv;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( !DM_HIDDEN == body->getDrawMode() ) {
      body->getRangeVector(body_rv);
      current_box.extendByRange(body_rv);
    }
  }

  current_box.getRangeVector(rv);
}


const char*
Model::getCurrentMeshName()
{
  if ( modelInfo->nofMeshes == 0 || modelInfo->currentMeshIndex == NO_INDEX )
    return NULL;
  else
    return modelInfo->meshNames[modelInfo->currentMeshIndex];
}


void
Model::getCurrentTime(char* buffer)
{
  time_t t = time(NULL);
  struct tm* mt = localtime(&t);
  strftime(buffer, 64, "%d.%m.%Y  %H:%M:%S.", mt);
}


bool
Model::getColorValue(char* name, Color4 color)
{
  static char buf[1024];

  int i;
  int len = strlen(name);

  for (i = 0; i < len; i++) {
    buf[i] = tolower(name[i]);
  }
  buf[len] = '\0';

  string nm(buf);

  //Color4* c = colorTable[buf];
  Color4* c = (*colorValueTable)[nm];

  if ( c == NULL ) return false;

  for (i = 0; i < 4; i++) {
    color[i] = (*c)[i] ;
  }

  return true;
}


bool
Model::getColorName(int cn_id, char* buffer)
{
  buffer[0] = '\0';

  char* name = (*colorNameTable)[cn_id];

  if ( name == NULL ) return false;

#if 0
  if (itr != modelData->colorNames_RGB->end()) {
    char* name = (*itr).second;
    int len = strlen(name);
    strcpy(buffer, name);
    buffer[len] = '\0';
    return true;
  }
#endif

    int len = strlen(name);
    strcpy(buffer, name);
    buffer[len] = '\0';

    return true;
}


IdList*
Model::getCoveringElementList(int elem_id)
{
  return (*modelData->coveringElementTable)[elem_id];
}


bool
Model::getCoveringElementList(int elem_id, IdList& covering_elem_ids)
{
  IdList* ids = (*modelData->coveringElementTable)[elem_id];

  if ( ids == NULL ) {
    return false;
  }

  IdList::iterator pos = ids->begin();

  while (pos != ids->end()) {
    int id = *pos++;
    covering_elem_ids.push_back(id);
  }

  return true;
}


// Method finds a edge by index.
BodyElement*
Model::getEdge(int index, bool only_active)
{
  return (BodyElement*)getModelObject(index, OT_EDGE, only_active);
}


BodyElement*
Model::getEdgeById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_EDGE)
    return NULL;
  else
    return (BodyElement*)obj;
}


BodyElement*
Model::getEdgeByTag(int tag) const
{
  return (BodyElement*)getModelObjectByTag(OT_EDGE, tag);
}


// Method finds a face by index.
BodyElement*
Model::getFace(int index, bool only_active)
{
  return (BodyElement*)getModelObject(index, OT_FACE, only_active);
}


BodyElement*
Model::getFaceById(int id) const
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_FACE)
    return NULL;
  else
    return (BodyElement*)obj;
}



BodyElement*
Model::getFaceByTag(int tag) const
{
  return (BodyElement*)getModelObjectByTag(OT_FACE, tag);
}



bool
Model::getFlagValue(flagName name)
{
  bool value = modelFlags[name];

  return value;
}


const UserInterface*
Model::getGui()
{
  return theControlCenter->getGui();
}


bool
Model::getLabelDisplayFlagValue(BodyElement* be)
{
  objectType ot = be->getObjectType();

  switch (ot) {
  case OT_VERTEX:
    return modelFlags[LABEL_DISPLAY_VERTEX];
  case OT_EDGE:
    return modelFlags[LABEL_DISPLAY_EDGE];
  case OT_FACE:
    return modelFlags[LABEL_DISPLAY_FACE];
  }

  return false;
}


// Get all bodies bounding box for the model;
void
Model::getMeshBoundingBox(RangeVector rv) const
{
  meshBox->getRangeVector(rv);
}


MeshElementTable*
Model::getMeshBoundaryElementEdges()
{
  if ( modelInfo->dimension == ECIF_3D ) {
    return meshData->boundaryEdges;

  } else {
    return meshData->boundaryVertices;
  }
}


double
Model::getMeshF(int mesh_index)
{
  if ( mesh_index  < 0 || mesh_index >= modelInfo->nofMeshes )
    return -1;

  if (modelInfo->meshHs == NULL)
    return 0;

  return modelInfo->meshFs[mesh_index];
}


double
Model::getMeshH(int mesh_index)
{
  if ( mesh_index  < 0 || mesh_index >= modelInfo->nofMeshes )
    return -1;

  if (modelInfo->meshHs == NULL)
    return 0;

  return modelInfo->meshHs[mesh_index];
}


int
Model::getMeshIndex(const char* mesh_name)
{
  if ( modelInfo->nofMeshes == 0 ) {
    return NO_INDEX;
  }

  for (int i = 0; i < modelInfo->nofMeshes; i++) {

    if ( 0 == strcmp(mesh_name, modelInfo->meshNames[i]) ) {
      return i;
    }
  }

  return NO_INDEX;
}


bool
Model::getMeshInputFileName(char*& mif_file_name, int mesh_index)
{
  if ( modelInfo->nofActiveMeshes == 0 ||
       modelInfo->meshNames == NULL
     ) {
    return false;
  }

  double h = getMeshH(mesh_index);

  if ( h < 0 ) {
    return false;
  }

  UserInterface* gui = theControlCenter->getGui();

  // Ok, ask the mif-file-name
  return gui->getMeshInputFileName(mif_file_name);
}


void
Model::getMeshNames(int& nof_meshes, char**& mesh_names)
{
  nof_meshes = modelInfo->nofMeshes;
  mesh_names = NULL;

  if ( nof_meshes == 0 )
    return;

  mesh_names = new char*[nof_meshes];

  for (int i = 0; i < nof_meshes; i++) {

    int len = strlen(modelInfo->meshNames[i]);

    // Alloc space for each mesh name
    mesh_names[i] = new char[1 + len];

    strcpy(mesh_names[i], modelInfo->meshNames[i]);
  }

}


int
Model::getMeshNodeIdExt2Int(int ext_id)
{
  if (ext_id != NO_INDEX)
    return meshData->nodeExt2Int[ext_id];
  else
    return NO_INDEX;
}


int
Model::getMeshNodeIdInt2Ext(int int_id)
{
  if (int_id != NO_INDEX)
    return meshData->nodeInt2Ext[int_id];
  else
    return NO_INDEX;
}


// Range vector from the model's mesh bounding box
void
Model::getMeshRangeVector(RangeVector rv) const
{
  meshBox->getRangeVector(rv);
}


ostream&
Model::getModelStatusMessage(ostream& out) const
{
  ecif_modelStatus status = modelInfo->modelStatus;

  if (status == STATUS_OK) {
    out << "Model is ok" << endl;
    return out;
  }

  if (status & BODY_EQUATION_MISSING ) {
    out << "All bodies do not have an EQUATION definition." << endl;
  }

  else if (status & BODY_MATERIAL_MISSING ) {
    out << "All bodies do not have a MATERIAL definition." << endl;
  }

  return out;
}


// Get model object by type and index
ModelObject*
Model::getModelObject(int index) const
{
  int count = modelData->modelObjects->size();

  if (index < 0 || index >= count ) return NULL;

  int counter = -1;
  for (int i = 0; i < count && counter < index; i++) {
    ModelObject* obj = (*modelData->modelObjects)[i];
    if ( obj != NULL && ++counter == index) {
      return obj;
    }
  }

  return NULL;
}


// Get model object by index, type and activity flag
ModelObject*
Model::getModelObject(int index, objectType type, bool only_active) const
{
  int count = modelData->modelObjects->size();

  if (index < 0 || index >= count ) return NULL;

  int counter = -1;
  for (int i = 0; i < count; i++) {

    ModelObject* obj = (*modelData->modelObjects)[i];

    if ( obj != NULL && obj->getObjectType() == type ) {
      if ( (!only_active || obj->isActive()) &&
           (++counter == index)
         ) {
        return obj;
      }
    }
  }

  return NULL;
}


// Get model object by object id
ModelObject*
Model::getModelObjectById(int object_id) const
{
  int count = modelData->modelObjects->size();

  for (int i = 0; i < count; i++) {

    ModelObject* obj = (*modelData->modelObjects)[i];

    if ( obj != NULL &&
         obj->Id() == object_id
       ) {
      return obj;
    }
  }

  return NULL;
}


// Get model object by type and id tag
ModelObject*
Model::getModelObjectByTag(objectType type, int tag) const
{
  int count = modelData->modelObjects->size();

  for (int i = 0; i < count; i++) {

    ModelObject* obj = (*modelData->modelObjects)[i];

    if ( obj != NULL &&
         obj->getObjectType() == type &&
         obj->Tag() == tag
       ) {
      return obj;
    }
  }

  return NULL;
}


const char*
Model::getModelObjectNameById(int oid)
{
  ModelObject* obj = getModelObjectById(oid);

  if (obj == NULL ) {
    return NULL;
  } else {
    return obj->getName();
  }
}


// Get model object tag by object id
int
Model::getModelObjectTagById(int object_id) const
{
  ModelObject* obj = getModelObjectById(object_id);

  if ( obj == NULL )
    return NO_INDEX;

  else
    return obj->Tag();
}


int
Model::getNewObjectId()
{
  return ++lastObjectId;
}


MeshCornerElement*
Model::getMeshCornerElement(int index)
{
  if ( index < 0 ) return NULL;

  MeshCornerElementList::iterator pos = modelData->meshCornerElements->begin();
  MeshCornerElementList::iterator end_pos = modelData->meshCornerElements->end();

  for (int i = 0; i < index && pos != end_pos; i++,pos++);

  if ( pos == end_pos ) {
    return NULL;
  } else {
    return *pos;
  }
}


//Method finds the next available (1+previous largest) parameter id for
// parameter type "parameter_type"
int
Model::getNextNewParameterId(ecif_parameterType parameter_type)
{
  int largest_pid = 0;
  int index = 0;
  while (true) {
    Parameter* param = getParameter(index++, parameter_type);
    if ( param == NULL ) break;
    int pid = param->ID();
    if (largest_pid < pid) {
      largest_pid = pid;
    }
  }

  return ++largest_pid;
}


int
Model::getNofTimestepSteps()
{
  int index = 0;

  while (true) {

    Parameter* ts = getParameter(index++, ECIF_TIMESTEP);

    if (ts == NULL) break;

    // Take first active!
    if ( !ts->IsActive() ) {
      continue;
    }

    ParameterField* ts_intervals = NULL;

    if (modelHasSteadyStateProblem()) {
      ts_intervals = ts->getFieldBySifName("Steady State Max Iterations");
    } else {
      ts_intervals = ts->getFieldBySifName("Timestep Intervals");
    }

    if (ts_intervals == NULL) {
      return -1;
    }

    int ts_count = 0;

    char** data = ts_intervals->getDataStrings();
    int nof_entries = ts_intervals->getNofDataStrings();

    if (nof_entries > 0) {
      strstream strm;
      strm << data[0];

      int steps = 0;

      while (!strm.eof()) {
        strm >> steps;
        ts_count += steps;
        steps = 0; //to nullify nasty effects of eol in the stream
      }
    }

    return ts_count;
  }

  // No active found!
  return -1;
}


Parameter*
Model::getParameter(int index, ecif_parameterType parameter_type)
{
  ParameterTable* table;
  Parameter* param = NULL;

  // NOTE: This will be scalar pointer to a modelStatistics-counter,
  // do NOT delete it!
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, use_counter) ) {
    return NULL;
  }

  ParameterTable::iterator pos = table->begin();
  ParameterTable::iterator end_pos = table->end();

  param = (*pos).second;

  int count = table->size();

  for (int i = 0; i < index && pos != end_pos; i++,pos++);

  if (pos == end_pos) {
    return NULL;
  } else {
    param = (*pos).second;
    return param;
  }

}


// Method checks if a paramter with the type paramter-type and id-key pid exists.
// Returns pointer to the parameter or NULL if nothing found.
Parameter*
Model::getParameterById(ecif_parameterType parameter_type, int pid)
{
  if ( pid == NO_INDEX ) return NULL;

  ParameterTable* table;

  // NOTE: This will be a scalar pointer to a
  // modelStatistic counter, so shoud not be deleted!
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, use_counter) ) {
    return NULL;
  }

  ParameterTable::iterator pos = table->find(pid);

  if (pos != table->end()) {
    return (*pos).second;
  } else {
    return NULL;
  }
}



ParameterFieldInfo*
Model::getParameterFieldInfo(const char* parameter, const char* field)
{
  static char name_buffer[1 + 1024];
  name_buffer[0] = name_buffer[1024] = '\0';

  ParameterFieldInfo* fi = new ParameterFieldInfo;

  //--Try to get parameter field info from Gui
  if ( !theControlCenter->getUI()->getParameterFieldInfo(parameter, field, *fi) ) {
    delete fi;
    return NULL;
  }

  //--Add some more info

  //-Store field's Gui-name
  update_dyna_string(fi->guiName, (char*)field);

  //-Create field's Sif-name, if not delivered from Gui
  if ( fi->sifName == NULL || fi->sifName[0] == '\0' ) {
    fieldNameGuiToSif(field, name_buffer);
    update_dyna_string(fi->sifName, name_buffer);
  }

  return fi;
}


bool
Model::getSolverKeywordTypeGiven(const char* parameter, const char* field)
{
  if ( parameter == NULL || field == NULL ) {
    return false;
  } else {
    return theControlCenter->getUI()->getSolverKeywordTypeGiven(parameter, field);
  }
}


// Returns pointer to an existing point if the geometric-point
// is already in the model or returns null-pointer.
//
GcPoint*
Model::getPoint(GcPoint* point)
{
  int key = point->hashKey();

  PointHashTable::iterator itr = modelData->modelPoints->find(key);

  // If nothing found by the key return null.
  if (itr == modelData->modelPoints->end())
    return NULL;

  // Find the point from the key's bucket.
  else {
    PointList* plist = (*itr).second;
    return findPoint(plist, point);
  }
}


// Range vector from the model's bounding box
void
Model::getRangeVector(RangeVector rv) const
{
  modelBox->getRangeVector(rv);
}


// Method checks relative orientation of two matching edges
// NOTE: We suppouse that elements are exactly matching, but
// possibly differently oriented
// This should be used only with swapped elements!!!
int
Model::getRelativeOrientation(BodyElement* be1, BodyElement* be2)
{
  int dir12 = 1;

  // We have exact match. Mutual orientation can
  // be concluded from starting vertices only !!!###!!!
  BodyElement* v11 = be1->getFirstSubElement();
  BodyElement *v21 = be2->getFirstSubElement();

  if (v11 != v21)
    dir12 = -1;

  return dir12;
}


// Method checks if a bodyElement with the id-key exists in teh removed list.
// Returns pointer to the bodyElement or NULL if not found.
BodyElement*
Model::getRemovedBodyElement(int be_id) const
{
  BodyElementTable::iterator itr = modelData->removedModelElements->find(be_id);

  if (itr != modelData->removedModelElements->end()) {
    return (*itr).second;
  }
  else {
    return NULL;
  }
}


int
Model::getRenumberedMeshBulkElementId(int original_id)
{
  if ( meshData->bulkRenumbering == NULL ) {
    return original_id;

  } else {
    return meshData->bulkRenumbering[original_id];
  }
}


flagName
Model::getSelectionMethod()
{
  short nof_flags = 7;
  flagName flags[] = {
    SELECT_METHOD_SINGLE,
    SELECT_METHOD_ALL,
    SELECT_METHOD_BY_NEIGHBOR,
    SELECT_METHOD_BY_NORMAL,
    SELECT_METHOD_BY_PLANE,
    SELECT_METHOD_BY_BOX,
    SELECT_METHOD_BY_RECTANGLE
  };

  for (short i = 0; i < nof_flags; i++) {
    if ( modelFlags[flags[i]] )
      return flags[i];
  }

  return SELECT_METHOD_SINGLE;
}


flagName
Model::getSelectionMode()
{
  short nof_flags = 3;
  flagName flags[] = {
    SELECT_MODE_TOGGLE, SELECT_MODE_EXTEND, SELECT_MODE_REDUCE
  };

  for (short i = 0; i < nof_flags; i++) {
    if ( modelFlags[flags[i]] )
      return flags[i];
  }

  return SELECT_MODE_EXTEND;
}


int
Model::getSwapElementId(int orig_elem_id)
{
  IdNumberTable::iterator
  itr = modelData->swapElementTable->find(orig_elem_id);

  if (itr != modelData->swapElementTable->end())
    return (*itr).second;
  else
    return NO_INDEX;
}


bool
Model::getSymmetryAxis(double start[3], double end1[3], double end2[3] )
{
  //-Initialize
  for (int i=0; i < 3; i++) {
    start[i] = end1[i] = end2[i] = 0;
  }

  //-If there is no symmetry-axis defined
  Parameter* simulation = getParameter(0, ECIF_COORDINATE);

  if (simulation == NULL )
    return false;

  ParameterField* param_field = simulation->getFieldBySifName("Symmetry Plane");

  if (param_field == NULL)
    return false;

  char** symmetry_data = param_field->getDataStrings();
  char* symmetry = (char*)symmetry_data[0];

  //-Ok, find symmetry axis based on model box
  //-NOTE: A nurbs near an edge could confuse things here
  // Check how nurbs-bounding box is calulated !!!###!!!
  int crn1, crn2;
  // Bounding box corners are numbered ccw.
  // z=0: 1,2,3,4; z=1: 5,6,7,8

  if ( LibFront::ncEqual(symmetry, "None") )
    return false;
  else if ( LibFront::ncEqual(symmetry, "Y Left") ) {
    crn1 = 1; crn2 = 2;
  }
  else if ( LibFront::ncEqual(symmetry, "Y Right") ) {
    crn1 = 4; crn2 = 3;
  }
  else if ( LibFront::ncEqual(symmetry, "X Bottom") ) {
    crn1 = 1; crn2 = 4;
  }
  else if ( LibFront::ncEqual(symmetry, "X Top") ) {
    crn1 = 2; crn2 = 3;
  }

  modelBox->getBoxAxis(crn1, crn2, start, end1, end2);

  return true;
}

// Method finds a vertex by index.
BodyElement*
Model::getVertex(int index, bool only_active)
{
  return (BodyElement*)getModelObject(index, OT_VERTEX, only_active);
}


BodyElement*
Model::getVertex(GcPoint* point)
{
  Point2VertexTable::iterator itr = modelData->modelPoint2Vertices->find(point);

  if (itr != modelData->modelPoint2Vertices->end())
    return (*itr).second;
  else
    return NULL;
}


BodyElement*
Model::getVertexById(int id)
{
  ModelObject* obj = getModelObjectById(id);

  if ( obj == NULL || obj->getObjectType() != OT_VERTEX)
    return NULL;
  else
    return (BodyElement*)obj;
}


BodyElement*
Model::getVertexByNodeId(int node_id)
{
  bool only_active = false;

  int index = 0;
  while (true) {
    BodyElement* v = getVertex(index++, only_active);
    if (v==NULL) break;
    int nd_id = v->getMeshElementId(0);
    if ( nd_id == node_id ) {
      return v;
    }
  }
  return NULL;
}


BodyElement*
Model::getVertexByTag(int tag)
{
  return (BodyElement*)getModelObjectByTag(OT_VERTEX, tag);
}


// Init boundaries so that vertices get boundary ids as their
// parent-ids
void
Model::initBoundaries()
{
  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    //-Check status
    beStatus be_stat = be->getStatus();
  }
}


void
Model::initMeshData()
{
  meshBox = new BoundBox;
  meshData = new MeshData;
  meshInfo = new MeshInfo;
}


// NOTE: This is called after reading the model file!
// So, do not init any flags here which are set in the model file!
void
Model::initModelFlags()
{
  // Cad geometry is shown if it exists
  if (modelFlags[GEOMETRY_TYPE_CAD]) {
    modelFlags[DRAW_SOURCE_CAD] = true;
  }

  // Mesh geometry is also shown if it exists
  if (modelFlags[GEOMETRY_TYPE_MESH]) {
    modelFlags[DRAW_SOURCE_MESH] = true;
  }


  // Draw mode depends on geometry type and dimension
  //--2D
  if (modelInfo->dimension == ECIF_2D) {
    // If only mesh geometry
    if (!modelFlags[GEOMETRY_TYPE_CAD]) {
      modelFlags[DRAW_TARGET_EDGES] = true;
      modelFlags[DRAW_TARGET_BOUNDARIES] = true;
      modelFlags[DRAW_TARGET_BODIES] = false;
    // If at least Cad geometry
    } else {
      modelFlags[DRAW_TARGET_BODIES] = true;
      modelFlags[DRAW_TARGET_EDGES] = false;
      modelFlags[DRAW_TARGET_BOUNDARIES] = false;
    }

    if (modelFlags[GEOMETRY_TYPE_CAD]) {
      modelFlags[LABEL_DISPLAY_EDGE] = true;
    }

  //--3D
  } else if (modelInfo->dimension == ECIF_3D) {
    modelFlags[DRAW_TARGET_SURFACES] = true;
    modelFlags[DRAW_TARGET_BOUNDARIES] = true;

    if (modelFlags[GEOMETRY_TYPE_CAD]) {
      modelFlags[LABEL_DISPLAY_FACE] = true;
    }
  }

  modelFlags[SELECT_MODE_TOGGLE] = true;
  modelFlags[SELECT_METHOD_SINGLE] = true;
  modelFlags[SELECT_OBJECTS_TOGGLE] = true;
}


bool
Model::modelHasCadGeometry()
{
  if ( modelInfo->geometryType == GEOM_CAD ||
       modelInfo->geometryType == GEOM_CAD_AND_MESH
       ) {
    return true;
  } else {
    return false;
  }
}


bool
Model::modelHasDiffuseGrayRadiation()
{
  return modelInfo->hasDiffuseGrayRadiation;
}


bool
Model::modelHasEquation(const char* equation_name)
{
  int index = 0;
  while (true) {
    Parameter* eq = getParameter(index++, ECIF_EQUATION);
    if (eq==NULL) break;
    if ( eq->hasFieldValueBySifName(equation_name, "True") ) {
      return true;
    }
  }

  return false;
}


bool
Model::modelHasMeshGeometry()
{
  if ( modelInfo->geometryType == GEOM_MESH ||
       modelInfo->geometryType == GEOM_CAD_AND_MESH
       ) {
    return true;
  } else {
    return false;
  }

}


bool
Model::modelHasParameter(ecif_parameterType parameter_type, const char* param_name)
{
  int index = 0;
  while (true) {
    Parameter* p = getParameter(index++, parameter_type);
    if (p==NULL) break;
    if ( 0 == strcmp(p->getName(), param_name) ) {
      return true;
    }
  }

  return false;
}


// Check if the model is a steady-state model
//
bool
Model::modelHasSteadyStateProblem()
{
  int index = 0;
  while (true) {
    Parameter* ts = getParameter(index++, ECIF_TIMESTEP);
    if (ts==NULL) break;
    if ( ts->IsActive() && ts->hasFieldValueBySifName("Simulation Type", "Steady State") ) {
      return true;
    }
  }

  return false;
}


void
Model::initSplitCombineInfos()
{
  modelData->splitCombineInfos = new SplitCombineInfoArray(MAX_NOF_SPLIT_COMBINE_INFOS);
  for (short i = 0; i < MAX_NOF_SPLIT_COMBINE_INFOS; i++)
    (*modelData->splitCombineInfos)[i] = NULL;

  modelData->splitCombineInfoIndex = 0;
}



#if 0
void
Model::linearizeBoundaries(double delta_u, double delta_v)
{
  modelData->purgeBoundaryVertices();
  modelData->boundaryVertices = new BoundaryVertexList;

  modelStatistics->nofBoundaryVertices = 0;
  modelData->lastBoundaryVertexId = 1 + modelStatistics->nofVertices;

  // Loop all bodies in the model
  // ============================
  Body* body = getFirstBody();
  while (body != NULL ) {

    // Loop all elements in the body
    // =============================
    BodyElement* be = body->getFirstElement();
    while ( be != NULL ) {

      //---Calculate linearizing vertices
      be->calcBoundaryVertices(delta_u, delta_v);

      be = body->getNextElement();
    } // all elements in the body

    body = getNextBody();
  } // all bodies in the model

  modelStatistics->nofBoundaryVertices =  modelData->boundaryVertices->size();

  sortBoundaryVertices(GEOM_CAD);
}
#endif

#if 0
void
Model::linearizeBoundaries(double delta_u, double delta_v)
{
  modelData->purgeBoundaryVertices();
  modelData->boundaryVertices = new BoundaryVertexList;

  modelStatistics->nofBoundaryVertices = 0;
  modelData->lastBoundaryVertexId = 1 + modelStatistics->nofVertices;

  int nof_bpoints = 0;
  BoundaryVertex** bpoints;
  BodyElement** mapping_vertices;
  int* local_vertex_indices;
  int* bp_ids;

  // Table to handle current (real) vertices
  // First column is a direct key to check if the vertex
  // is already added to the list of linearized vertices
  // Second column is the new renumbered index for the vertex
  int vertex_count = modelData->modelVertices->size();
  bool* vertex_done = new bool[1 + vertex_count];

  for (int i = 0; i <= vertex_count; i++) {
    vertex_done[i] = false;
  }

  // Loop all bodies in the model
  // ============================
  Body* body = getFirstBody();
  while (body != NULL ) {

    bp_ids = NULL;
    mapping_vertices = NULL;
    local_vertex_indices = NULL;

    // Loop all elements in the body
    // =============================
    BodyElement* be = body->getFirstElement();
    while ( be != NULL ) {

      //---Calculate linearizing vertices
      be->calcBoundaryVertices(nof_bpoints,
                               bpoints,
                               mapping_vertices,
                               local_vertex_indices,
                               delta_u, delta_v);

      // Allocate table for element's linearizing vertex ids
      // NOTE: DO NOT DELETE this!!!
      // This will be given the boundary element!!!
      bp_ids = new int[nof_bpoints];
      int bp_id;

      //---Add (new) linearizing vertices to the model
      //   and store vertex ids (renumbered) in the element
      for (int i = 0; i < nof_bpoints; i++) {

        BoundaryVertex* bp = bpoints[i];

        BodyElememt* v = mapping_vertices[i];

        bool add_point;

        //-Check possible mapping vertex
        if (v != NULL) {

          int v_id = v->Tag();

          bp_id = v_id;

          // If already handled
          if ( vertex_done[v_id] ) {
            delete bp;
            add_point = false;            // do not add

          // Otherwise add
          } else {
            add_point = true;
            bp->id = bp_id;
            bp->original = true;
          }

          // Mark this vertex visited
          vertex_done[v_id] = true;
        }

        //-Check if possible closed curve/surface has marked vertices the same
        // as some previous local vertex
        else if (local_vertex_indices[i] != i) {

          int l_id = local_vertex_indices[i];

          // Pick id from already stored ids
          bp_id = bp_ids[l_id];
          bp->id = bp_id;
          add_point = false;
        }

        //-Append as a new boundary vertex
        else {
          bp_id = modelData->lastBoundaryVertexId;
          bp->id = bp_id;
          add_point = true;
          modelData->lastBoundaryVertexId++;
        }

        //-Add point to the model if it is new
        if (add_point) {
          bp->refId = bp->id;
          modelData->boundaryVertices->push_back(bp);
        }

        //-Set final id also for the element
        bp_ids[i] = bp_id;
      }

      //---Store ids in the element
      be->getTopology()->setBoundaryVertices(nof_bpoints, bp_ids);

      delete[] mapping_vertices;
      delete[] local_vertex_indices;

      be = body->getNextElement();
    } // all elements in the body

    body = getNextBody();
  } // all bodies in the model

  modelStatistics->nofBoundaryVertices =  modelData->boundaryVertices->size();

  sortBoundaryVertices(GEOM_CAD);

  delete[] vertex_done;
}
#endif


// Check if a vertex is in model's vertex-table
//
bool
Model::isInVertexTable(int vertex_id)
{
  VertexTable* vt = modelData->vertexTable;

  if ( vt == NULL ) return false;

  for (int i = 0; i < vt->dim1; i++) {
    if ( vt->vertexIds[i] == vertex_id ) {
      return true;
    }
  }

  return false;
}


bool
Model::loadDBMesh(char* disp_msg)
{
  if ( modelInfo->meshDirectory_absolute[0] == '\0' ||
       modelInfo->meshNames == NULL ||
       modelInfo->currentMeshIndex == NO_INDEX
     ) {
    return false;
  }

  Timer timer;
  timer.start();

  UserInterface* gui = theControlCenter->getGui();

  if (disp_msg != NULL) {
    gui->showMsg(disp_msg);
  }

  // NOTE: infile-stream (dummy_strm) is not really used by InputElmer, cause
  // eio-library does not use directly the given meshfile name, but the parent
  // directory
  // NOTE: It is important anyway here to add the filename itself to the path
  // (mesh.header) because it is suppoused to be there in InputElmer!
  // ( this in turn is because complete filename is delivered from Gui via
  //   Control's readMeshFile method to InputElmer!)
  strstream strm;
  strm << modelInfo->meshDirectory_absolute << "/" << "mesh.header" << ends;

  ifstream dummy_strm;
  InputElmer in(modelInfo->dimension, dummy_strm, strm.str());

  if ( ECIF_ND == in.loadMesh() ) {
    gui->showMsg("NOTE: No mesh file found for the model!");
    gui->configureMenuButtons("File", "LoadMesh", 0);
    gui->configureMenuButtons("File", "Mesh", 0);
    resetMeshData();
    return false;
  }

  //gui->showUsedTimeMsg(timer.stop(), "Reading the DB mesh file");

  if ( !processMeshFileData(&in) )
    return false;

  addPendingMeshElements();

  return true;
}


bool
Model::loadMesh()
{
  bool has_mesh_geometry = false;

  //---Read mesh geometry
  // NOTE: missing mesh geometry is not a fatal error,
  // so we return true although it is missing
  char* file1 = modelInfo->meshResultFile;
  char* file2 = modelInfo->meshSourceFile;

  Input* input = NULL;
  ifstream* in_file = NULL;

  FILE* mesh_file = NULL;

  UserInterface* ui = theControlCenter->getGui();

  // Try first to read Elmer DB mesh file
  // ====================================
  if ( !has_mesh_geometry ) {

    if ( loadDBMesh() ) {
      has_mesh_geometry = true;

    } else {
      ui->showMsg("***WARNING Could not read Elmer mesh!");
    }
  }

  // Try next to read mesh result file if it exists
  // ==============================================
  if ( !has_mesh_geometry && file1[0] != '\0' ) {

    ui->showMsg("***NOTE Trying to read mesh result file");

    // *** Check that input-file exists.
    mesh_file = fopen(file1, "r");

    if ( !mesh_file ) {
      fclose(mesh_file);
      ui->errMsg(0, "Error! Can't open mesh result file: ", file1);
    }
    else {

      //in_file = new ifstream(file1, ios::nocreate);
      in_file = new ifstream(file1);
      input = theControlCenter->create_mesh_input(modelInfo->dimension,
                                                  *in_file, file1);

      if (input == NULL) {
        fclose(mesh_file);
        ui->errMsg(0, "Error! Can't open mesh result file: ", file1);
      }

      else if ( ECIF_ND != input->readMeshFile() ) {
          has_mesh_geometry = true;
      }
    }
  }

  // Try finally to read the original mesh file
  // ==========================================
  if ( !has_mesh_geometry && file2[0] != '\0' ) {

    ui->showMsg("***NOTE Trying to read mesh source file");

    // *** Check that input-file exists.
    mesh_file = fopen(file2, "r");

    if ( mesh_file == NULL) {
      ui->errMsg(0, "Error! Can't find mesh source file: ", file2);

    } else {

      //in_file = new ifstream(file2, ios::nocreate);
      in_file = new ifstream(file2);

      input = theControlCenter->create_mesh_input(modelInfo->dimension,
                                                  *in_file, file2);

      if (input == NULL) {
        fclose(mesh_file);
        ui->errMsg(0, "Error! Can't open mesh source file: ", file2);
        has_mesh_geometry = false;

      } else if ( ECIF_ND != input->readMeshFile() ) {
          has_mesh_geometry = true;
      }
    }

  }

  if (mesh_file != NULL)
    fclose(mesh_file);

  // Process mesh file data
  // ======================
  if (has_mesh_geometry && input != NULL) {
    if ( !processMeshFileData(input) ) {
      has_mesh_geometry = false;
    }
  }

  // If success
  // ==========
  if (has_mesh_geometry) {

    UserInterface* gui = theControlCenter->getGui();

    setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_MESH, true);
    setFlagValue(DRAW_SOURCE, DRAW_SOURCE_MESH, true);
    gui->updateModelFlags(this);

    modelInfo->meshNeedsUpdate = false;
    gui->setWasUpdated("Mesh");

    gui->configureButtons("draw_source_mesh", 1);
    gui->configureMenuButtons("File", "LoadMesh", -1);

    setWindowTitles();
  }


  delete input;
  delete in_file;

  return has_mesh_geometry;
}


// Set active flags in objects
// NOTE: This must be done hierachically: bodies -> loops -> body elements
//
void
Model::markActiveObjects()
{
  int i, index;

  // Mark first all object inactive
  // ==============================
  int count = modelData->modelObjects->size();

  for (i = 0; i < count; i++) {

    ModelObject* obj = getModelObject(i);

    if ( obj != NULL ) {
      obj->setActive(false);
    }
  }

  // Mark all body layers active!
  // ============================
  index = 0;
  while (true) {
    BodyLayer* bl = getBodyLayer(index++, false);
    if (bl==NULL) break;
    bl->setActive(true);
  }

  // Mark first all bodies active!
  // ==============================
  index = 0;
  while (true) {
    Body* body = getBody(index++, false);
    if (body==NULL) break;
    body->setActive(true);
    body->markActiveObjects();
  }

  // Then bodypairs from bodies active!
  // ==================================
  index = 0;
  while (true) {
    BodyPair* bp = getBodyPair(index++, false);
    if (bp==NULL) break;
    const Body* body1;
    const Body* body2;
    bp->getBodies(body1, body2);
    Body* bd1 = (Body*) body1;
    Body* bd2 = (Body*) body2;

    if ( bd1 != NULL && bd1->isActive() &&
         bd2 != NULL && bd2->isActive()
       ) {
      bp->setActive(true);
    }
  }

  // Mark all boundary groups active!
  // ================================
  index = 0;
  while (true) {
    BodyElementGroup* beg = getBodyElementGroup(index++, false);
    if (beg==NULL) break;
    beg->setActive(true);
 }

  // Then read only active (sub) objects!
  // ====================================

  // Body element loop
  // =================
  index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    bel->markActiveObjects();
  }

  // Body elements
  // =============
  index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    be->markActiveObjects();
 }

}


void
Model::updateModelStatistics()
{
  int index;

  // Bodies
  // ======
  modelStatistics->nofBodies = 0;
  modelStatistics->nofElementLoops = 0;
  modelStatistics->nofElements = 0;
  modelStatistics->nofInnerBoundaries = 0;
  modelStatistics->nofOuterBoundaries = 0;
  modelStatistics->nofVertices = 0;

  modelStatistics->maxLoopSize = 0;

  index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( body->isActive() ) {
      modelStatistics->nofBodies++;
    }
  }

  // Body element loops
  // ==================
  index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    if ( bel->isActive() ) {
      modelStatistics->nofElementLoops++;

      int elem_c = bel->getNofElements();
      if ( elem_c > modelStatistics->maxLoopSize ) {
        modelStatistics->maxLoopSize = elem_c;
      }
    }
  }

  // Body elements
  // =============
  index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    if ( be->isActive() ) {
      modelStatistics->nofElements++;

      if ( NO_INDEX == be->getParentId(2) )
        modelStatistics->nofOuterBoundaries++;
      else
        modelStatistics->nofInnerBoundaries++;
    }
  }

  // Vertices
  // ========
  index = 0;
  while (true) {
    BodyElement* v = getVertex(index++);
    if (v==NULL) break;
    if ( v->isActive() ) {
      modelStatistics->nofVertices++;
    }
  }

}


bool
Model::markObjectActive(int id)
{
  ModelObject* obj = getModelObjectById(id);

  if (obj == NULL ) {
//theControlCenter->getGui()->showMsg("Model: not marking NULL object!", 1);
    return false;
  }

  obj->setActive(true);

  return true;
}


// Mesh boundary element selected by  renderer selection hit method
bool
Model::meshBoundaryElementSelectionHit(Renderer* renderer, int fem_id)
{
  if ( fem_id < 0 ||
       fem_id >= meshData->boundaryElements->NofElements()
     ) {
    return false;
  }

  meshInfo->selectedBndrElementId = fem_id;

  selectMeshBoundaryElement(fem_id);

  return true;
}


bool
Model::meshBoundaryElementSelected(Renderer* renderer, int fem_id)
{
  static int prev_fem_id = NO_INDEX;
  static flagName prev_select_mode = SELECT_MODE_EXTEND;

  flagName select_mode = getSelectionMode();

  int mk_state = renderer->getMouseKeyboardState();

  bool paint_action = ( 0 != (mk_state & MK_SHIFT & (MK_LBUTTON | MK_RBUTTON) ) );

  // When painting we want to avoid all
  // unnecesary rendering
  // If same element was selected and
  // selection mode remained the same
  // (extend or reduce), skip redisplay
  if ( paint_action &&
       prev_fem_id == fem_id &&
       select_mode != SELECT_MODE_TOGGLE &&
       prev_select_mode == select_mode
     ) {
    return false;
  }

  prev_fem_id = fem_id;
  prev_select_mode = select_mode;

  meshInfo->selectedBndrElementId = fem_id;

  // Left/right buttons do the opposite action!
  if (mk_state & MK_RBUTTON)
    unselectMeshBoundaryElement(fem_id);
  else
    selectMeshBoundaryElement(fem_id);

  return true;
}


// Mesh bulk element selected by  renderer selection hit method
bool
Model::meshBulkElementSelectionHit(Renderer* renderer, int fem_id)
{
  if ( fem_id < 0 ||
       fem_id >= meshData->bulkElements->NofElements()
     )
    return false;

  meshInfo->selectedBulkElementId = fem_id;


  if ( getFlagValue(SELECT_MODE_TOGGLE) )
    meshData->bulkElements->selected[fem_id] = !meshData->bulkElements->selected[fem_id];
  else if ( getFlagValue(SELECT_MODE_EXTEND) )
    meshData->bulkElements->selected[fem_id] = true;
  else if ( getFlagValue(SELECT_MODE_REDUCE) )
    meshData->bulkElements->selected[fem_id] = false;

  return true;
}


#if 0
void
Model::normalizeMeshPoints()
{
  return;

  RangeVector rv;
  getRangeVector(rv);
  // Normalize factors;
  double norm[3], shift[3];
  norm[0]   = +1 * (rv[1] - rv[0]) / 2;
  norm[1]   = +1 * (rv[3] - rv[2]) / 2;
  norm[2]   = +1 * (rv[5] - rv[4]) / 2;
  shift[0]  = -1 * (rv[1] + rv[0]) / 2;
  shift[1]  = -1 * (rv[3] + rv[2]) / 2;
  shift[2]  = -1 * (rv[5] + rv[4]) / 2;

  for (int i = 0; i < meshInfo->nofNodes; i++) {
    GcPoint* vp = meshNodeData[i];
    vp->normalize(norm, shift);
  }

}
#endif

void
Model::normalizeVertices()
{
  return;

  RangeVector rv;
  getRangeVector(rv);

  // Normalize factors;
  double norm[3], shift[3];
  norm[0]   = +1 * (rv[1] - rv[0]) / 2;
  norm[1]   = +1 * (rv[3] - rv[2]) / 2;
  norm[2]   = +1 * (rv[5] - rv[4]) / 2;
  shift[0]  = -1 * (rv[1] + rv[0]) / 2;
  shift[1]  = -1 * (rv[3] + rv[2]) / 2;
  shift[2]  = -1 * (rv[5] + rv[4]) / 2;

  int index = 0;
  while (true) {
    BodyElement* v = getVertex(index++);
    if (v==NULL) break;
    GcPoint* vp = (GcPoint*)v->getGeometry();
    vp->normalize(norm, shift);
  }
}


bool
Model::processCadFileData()
{
  UserInterface* gui = theControlCenter->getGui();

  strstream strm;
  strm << "Nof bodies found: " << modelStatistics->nofBodies << ends;
  gui->showMsg(strm.str());

  if ( !checkBodyElementLoops() ) {
    return false;
  }

  //--Update bodies' boundboxes
  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    body->updateBoundBox();
  }

  if ( !checkBodies() ) {
    return false;
  }

  //--Ok, now we have decent geometry
  modelInfo->hasGeometry = true;

  findBoundaries();
  initBoundaries();
  setBoundaryParentIdsAndTags();
  findBodyPairs();
  findContainedBodies();
  //normalizeVertices();

  //if ( !checkBodyElementLoops() ) {
  //  return false;
  //}

  // Check boundary group data
  if ( !checkElementGroupData() ) {
    return false;
  }

  markActiveObjects();

  setBoundaryTags();

  updateModelStatistics();

  setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_CAD, true);

  // Set default mesh-h
  setInitialMeshH();

  return true;
}


// NOTE: The order of processing is important here!
bool
Model::processMeshFileData(Input* input)
{
  if ( !input->processMeshFileData() ) {
    return false;
  }

  if (!modelInfo->hasGeometry) {
    setBoundaryParentIdsAndTags();
    findBodyPairs();
    removeEmptyBoundaries();
  }

  meshManager->findMeshElementNodeParents(meshData->boundaryElements,
                                          meshData->nofAllocNodes,
                                          meshData->nofBoundaryNodeParents,
                                          meshData->boundaryNodeParentIds);

  meshManager->findMeshBoundaryBorders();

  meshManager->findMeshCornerElements();

  theControlCenter->getGui()->showMsg("Reading mesh done.", 1);

  meshData->boundaryElements->calcNormalsAndDistances();

  meshManager->calcMeshBoundaryNodeNormals();

  if ( !checkMeshBodies() ) {
    return false;
  }

  // If we have only mesh source
  if ( !modelInfo->hasGeometry ) {

    checkBodies();

    // Create subelements
    //--3D: Create Edges and Vertices
    if ( modelInfo->dimension == ECIF_3D ) {
      meshManager->createMeshSubElements(3, 2);
      //meshManager->createMeshSubElements(2, 3);

    //--2D: Create Vertices
    } else {
      meshManager->createMeshSubElements(2, 2);
    }

    checkVertexExistence();

    //--Ok, now we have decent geometry
    modelInfo->hasGeometry = true;
    
    // This should not be applied here, it would set invalid values for
    // boundaries' 'isIntraLayer' flags!!! MVe 02.06.2004
    //
    //setBoundaryParentIdsAndTags();

    // Check boundary group data
    if ( !checkElementGroupData() ) {
      return false;
    }

    markActiveObjects();

    setBoundaryTags();

    updateModelStatistics();
  }

  RangeVector rv;
  meshBox->getRangeVector(rv);
  modelBox->extendByRange(rv);

  setInitialMeshH();

  // Dircet call for test, remove this!
  //classifyMeshCornerElements();
  //correctMeshZeroVelocityElements();

  return true;
}


bool
Model::processModelFileData()
{
  UserInterface* ui = theControlCenter->getGui();

  //--Update bodies' boundboxes
  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    body->updateBoundBox();
  }

  //--Check that bodies' geometry makes sense
  if (!checkBodies()) {
    return false;
  }

  if (!checkBodyElements()) {
    return false;
  }

  //--Ok, now we have decent geometry
  modelInfo->hasGeometry = true;

  setBoundaryParentIdsAndTags();
  findBodyPairs();

  // Check boundary group data
  if ( !checkElementGroupData() ) {
    return false;
  }

  markActiveObjects();

  // NOTE: Bondary tags are now read from the model file!
  // They must the same as in the elmer mesh boundary file, so
  // we cannot renumber them afterwards here (or anyway not without
  // rewriting the mesh!)
  //setBoundaryTags();

  updateModelStatistics();

  if ( modelInfo->frontInputVersionNbr <= 4 ) {
    updateParametersParentTags();
    setMeshFs();
    setMeshHs();
    setCurrentMeshIndex(0);
  }

  updateParametersParentId();

  updateParametersApplyCounts(ECIF_BODY_FORCE);
  updateParametersApplyCounts(ECIF_BOUNDARY_CONDITION);
  updateParametersApplyCounts(ECIF_EQUATION);
  updateParametersApplyCounts(ECIF_INITIAL_CONDITION);
  updateParametersApplyCounts(ECIF_MATERIAL);

  setInitialMeshH();

  //--Check if model has DiffuseGray radiation boundary condition
  //  This info is needed when checking if Viewfactors filename
  //  should be output etc.
  checkDiffuseGrayRadiation();

  modelInfo->meshNeedsUpdate = true;
  ui->setNeedsUpdate("Mesh");

  return true;
}


// Delete all un-marked parameters (they are considered as inactive!)
// This is done after updating all active parameters
void
Model::processParametersAfterUpdate(ecif_parameterType parameter_type)
{
#if 0
  // All un-marked parameters will be deleted as
  // inactive
  //
  Parameter* param = getFirstParameter(parameter_type);

  while (param != NULL) {

    if ( !param->getUpdateFlag() ) {
      deleteParameter(parameter_type, param->ID());
    }

    param = getNextParameter(parameter_type);
  }
#endif

}


// Mark all parameters as inactive
// This is used before updating all active parameters, so
// that all inactive can be easily deleted by the update-flag
void
Model::processParametersBeforeUpdate(ecif_parameterType parameter_type)
{
  deleteParameters(parameter_type);

#if 0
  // Mark all parameter as non-touched, so that
  // those which are non-touched after mass update,
  // can be deleted as inactive parametrs
  //
  Parameter* param = getFirstParameter(parameter_type);
  while (param != NULL) {
    param->setUpdateFlag(false);
    param->setApplyCount(0);
    param = getNextParameter(parameter_type);
  }
#endif

#if 0
// Old version of: setParameter(...)

  ParameterTable* table;
  ParameterTable::iterator* table_position;
  int* use_counter;

  if ( !selectParameterTable(parameter_type, table, table_position, use_counter) )
    return;

  *use_counter = 0;

  // Reset objects' parameter counters
  switch (parameter_type) {
  case ECIF_EQUATION:
    modelStatistics->nofBodiesWithEquation = 0;
    break;
  case ECIF_MATERIAL:
    modelStatistics->nofBodiesWithMaterial = 0;
    break;
  case ECIF_BODY_FORCE:
    modelStatistics->nofBodiesWithBodyForce = 0;
    break;
  case ECIF_INITIAL_CONDITION:
    modelStatistics->nofBodiesWithInitialCondition  = 0;
    break;
  case ECIF_BOUNDARY_CONDITION:
    modelStatistics->nofInnerBoundariesWithCondition = 0;
    modelStatistics->nofOuterBoundariesWithCondition = 0;
    break;
  }
#endif

}

// Read RGB colors into model colorTable from a file
//
int
Model::readColorFile(char* in_file)
{
  UserInterface* gui = theControlCenter->getGui();

  char buffer[256];
  Color4 color;
  color[3] = MAX_NOF_COLOR_LEVELS;
  int parts;
  char name_parts[3][32];
  //
  ifstream infile(in_file);
  infile.flags(ios::skipws);

  int counter = 0;
  while (!infile.eof()) {

    // Read one line into buffer
    infile.getline(buffer, 256);

    if ( strlen(buffer) == 0 ) break;

    // Skip comment rows
    if (buffer[0] == '!') continue;

    counter++;

    strstream strm;
    strm << buffer << ends;

    // Red, Green, Blue values (0-255)
    strm >> color[0] >> color[1] >> color[2];

    // Read name part(s)
    parts = -1;
    while (!strm.eof()) {
      strm >> name_parts[++parts];
    }
    // Combine all parts into the name string
    int name_len = 0;
    for (int i= 0; i <= parts; i++) {
      int len = strlen(name_parts[i]);
      strcpy(&buffer[name_len], name_parts[i]);
      name_len += len;
      if (i < parts)
        buffer[name_len++] = ' ';
    }

    char* name = NULL;
    update_dyna_string(name, buffer);

    // Store name in colorName2ValueTable (name --> value table)
    addColorName(name, color);

    // Store name in colorValue2Name table (value --> name table)
    int color_value = rgbColor2Id(color);
    addColorValue(color_value, name);
  }

  // Inform Gui about the file
  gui->colorFileWasRead(in_file);

  return counter;
}


// Read Matc definitions and load them into Matc
//
int
Model::readMatcFile(char* in_file, char* info, bool must_exists)
{
  UserInterface* gui = theControlCenter->getGui();

  char* source = NULL;
  char matc_buffer[10001];
  char name_buffer[256];
  bool is_var, is_func;

  int rc = LibFront::readFile(in_file, source);

  // If file not found or it is empty
  //
  if ( rc <= 0 ) {
    strstream strm;
    if ( rc == -1 ) {
      strm << "***WARNING: Matc file " << in_file << " not found!" << ends;
    } else {
      strm << "***WARNING: Matc file " << in_file << " is empty!" << ends;
    }

    gui->showMsg(strm.str());
    delete[] source;
    return 0;
  }

  strstream strm;
  strm << "format(8,\"rowform\")" << ends;
  mtc_domath( strm.str() );

  int source_pos = 0;
  int source_len = strlen(source);

  // Read source buffer till end
  //
  while (source_pos < source_len ) {

    // Read expression and set new source-pos just after the expression
    //
    source_pos = LibFront::readMatcExpression(source, source_pos, source_len,
                                              matc_buffer, 10000);

    LibFront::trim(matc_buffer);

    if ( matc_buffer[0] == '\0' ) continue;

    LibFront::getMatcName(matc_buffer, name_buffer, 255, is_var, is_func);

    // Evaluate the Matc-expression
    //
    char* matc_result = mtc_domath(matc_buffer);

    // An empty result
    if ( matc_result == NULL || matc_result[0] == '\0' ) continue;

    // Matc Error
    if ( LibFront::isMatcError(matc_result) ) {
      strstream strm, strm2;
      strm << "***WARNING: Matc evaluation error (" << matc_buffer << ")!" << ends;
      gui->showMsg(strm.str());
      strm2 << matc_result<< ends;
      gui->showMsg(strm2.str());
      continue;
    }
  }

  delete[] source;

  // Inform Gui about the file
  gui->matcFileWasRead(in_file);

  return 1;
}


// Makes an integer valued color-id from rgb vector
// rgb values: 0 - MAX_NOF_COLOR_LEVES
int
Model::rgbColor2Id(Color4& color)
{
  // create combined code
  int code = 0;
  code |= (color[0] << 16); // red
  code |= (color[1] << 8);  // green
  code |= color[2];       // blue
  return code;
}


// Makes an integer id from hex-string color value
int
Model::rgbColor2Id(int len, char* hex_value)
{
  // create combined code from hex string
  int code = 0;
  for (int i = 0; i < len; i++) {
    char c = hex_value[i];
    if ( c >= '0' && c <= '9')
      code |= (hex_value[i] - '0') << (4 * (len - i - 1));
    else
      code |= (10 + hex_value[i] - 'a') << (4 * (len - i - 1));
  }
  return code;
}


// Makes a hex string from integer valued color value
void
Model::rgbColorId2Hex(int color_id, char* hex_value, int len)
{
  int mask = 0x000000f << 4*(len - 1);
  for (int i = 0; i < len; i++) {
    int nbr = (color_id & mask) >> 4*(len - i - 1);
    if (nbr > 9)
      hex_value[i] = char('a' + nbr - 10);
    else
      hex_value[i] = char('0' + nbr);
    mask >>= 4;
  }
  hex_value[len] = '\0';
}


// Makes a color vector from hex string color
void
Model::rgbHex2Color(int len, char* hex_value, Color4& color)
{
  int nof_hex_nbrs = len / 3;
  int mask;
  int grp_len = nof_hex_nbrs * 4;
  switch (nof_hex_nbrs) {
  case 1: mask = 0x0000000f << 1 * 8; break;
  case 2: mask = 0x000000ff << 2 * 8; break;
  }
  int color_id = rgbColor2Id(len, hex_value);
  for (int i = 0; i < 3; i++) {
    int color_level = (color_id & mask) >> (3 - i - 1) * grp_len;
    color[i] = color_level;
    mask >>= grp_len;
  }
}


void
Model::refreshRenderer()
{
  if ( modelInfo->dimension == ECIF_ND ) {
    return;
  }

  Renderer* renderer = theControlCenter->getRenderer();

  if ( renderer != NULL && renderer->isVisible() )
    renderer->refresh();
}


// Methods removes a body from the model.
// What about element loops in the body??? Mve 12.11.02
int
Model::removeBody(Body* body)
{
  int index = 0;
  while ( true ) {

    BodyElement*be = body->getElement(index++);

    if (be==NULL) break;

    if ( be->isInnerBoundary() ) {

      beStatus be_st = be->getStatus();
      be->setStatus( (be_st & ~BE_INNER) | BE_OUTER );

      int bd1_id = be->getParentId(1);
      int bd2_id = be->getParentId(2);
      int bd1_tag = be->getParentTag(1);
      int bd2_tag = be->getParentTag(2);
      int bd1_lr = be->getParentLayer(1);
      int bd2_lr = be->getParentLayer(2);

      Body* body2;

      if ( bd1_id == body->Id() ) {
        body2 = getBodyById(bd2_id);
        be->setParentIds(bd2_id, NO_INDEX);
        be->setParentTags(bd2_tag, NO_INDEX);
        be->setParentLayers(bd2_lr, NO_INDEX);

      } else {
        body2 = getBodyById(bd1_id);
        be->setParentIds(bd1_id, NO_INDEX);
        be->setParentTags(bd1_tag, NO_INDEX);
        be->setParentLayers(bd1_lr, NO_INDEX);
      }

      removeBodyPair(body, body2);

      modelStatistics->nofInnerBoundaries--;
      modelStatistics->nofOuterBoundaries++;

    } else {
      removeBodyElement(be, true);
    }

  }

  removeModelObject(body->Id());

  return --modelStatistics->nofBodies;
}


// Methods removes a bodyelement from the model.
int
Model::removeBodyElement(BodyElement* be, bool remove_subs)
{
  be->checkLastTag(true);
  be->checkLastBoundaryTag(true);

  // Remove all sub elements
  if ( remove_subs ) {
    int nof_subs = be->getNofSubElements();
    for (int i = 0; i < nof_subs; i++) {

      BodyElement* se = be->getSubElement(i);

      if ( se != NULL ) {
        removeBodyElement(se, true);
      }
    }
  }

  // Update also point2Vertex info
  if ( OT_VERTEX == be->getObjectType() ) {
    removeVertex(be);
  } else {
    modelStatistics->nofElements--;
  }

  // Remove element from the group
  BodyElementGroup* beg = (BodyElementGroup*)be->getElementGroup();
  if ( beg != NULL ) {
    beg->removeElement(be->Id());
  }

  // Remove from active elements
  removeModelObject(be->Id());

  // Add to removed elements
  (*modelData->removedModelElements)[be->Id()] = be;

  return modelStatistics->nofElements;
}


// Methods removes a bodyelement from the model.
int
Model::removeBodyElement(BodyElement* be, bool remove_from_bodies, bool remove_subs)
{
  if (remove_from_bodies) {

    Body* body1 = getBodyById(be->getParentId(1));
    Body* body2 = getBodyById(be->getParentId(2));

    return removeBodyElement(be, body1, body2, remove_subs);
  }

  else {
    return removeBodyElement(be, remove_subs);
  }
}


// Methods removes a bodyelement from the model.
int
Model::removeBodyElement(BodyElement* be, Body* body1, Body* body2, bool remove_subs)
{
  // Remove element from bodies and remove also
  // the corresponding inner/outer boundary entry

  //-Orphant boundary!!!
  if (body1 == NULL) {
    this->removeBodyElement(be, remove_subs);

  //-Outer boundary
  } else if (body2 == NULL) {
    body1->removeElement(be->getParentLayer(1), be);

  //-Inner boundary
  } else {
    body1->removeElement(be->getParentLayer(1), be);
    body2->removeElement(be->getParentLayer(2), be);
  }

  // Remove the element itself
  return removeBodyElement(be, remove_subs);
}


// Methods removes a bodyelement group from the model.
int
Model::removeBodyElementGroup(int beg_id)
{
  BodyElementGroup* beg = getBodyElementGroupById(beg_id);

  if ( beg == NULL )
    return modelStatistics->nofElementGroups;

  removeModelObject(beg->Id());

  return --modelStatistics->nofElementGroups;
}


// Methods removes a bodyelement loop from the model.
int
Model::removeBodyElementLoop(int bel_id)
{
  BodyElementLoop* bel = getBodyElementLoopById(bel_id);

  if ( bel == NULL )
    return modelStatistics->nofElementLoops;

  removeModelObject(bel->Id());

  return --modelStatistics->nofElementLoops;
}


// Methods removes a bodylayer from the model.
int
Model::removeBodyLayer(BodyLayer* lr)
{
  if ( lr == NULL )
    return 0;

  removeModelObject(lr->Id());

  return 1;
}


int
Model::removeBodyPair(const Body* bd1, const Body* bd2)
{
  BodyPair* bp = NULL;

  int index = 0;
  while (true) {
    bp = getBodyPair(index++);
    if (bp==NULL) break;
    const Body* b1;
    const Body* b2;

    bp->getBodies(b1, b2);

    if ( b1 == bd1 && b2 == bd2 ||
         b1 == bd2 && b2 == bd1
       )
      break;
  }

  if ( bp != NULL ) {
    removeModelObject(bp->Id());
    modelStatistics->nofBodyPairs--;
  }

  return modelStatistics->nofBodyPairs;
}


void
Model::removeCadGeometry()
{
  deleteCadData();

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    body->setGmtrType(MESH_BODY);
  }
}


void
Model::removeEmptyBoundaries()
{
  BodyElement** bels = new BodyElement*[modelStatistics->nofElements];

  int counter = 0;

  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    if ( 0 == be->getNofMeshElements() ) {
      bels[counter++] = be;
    }
  }

  for (int i = 0; i < counter; i++) {
    removeBodyElement(bels[i], true);
  }
}



void
Model::removeMeshGeometry()
{
  resetMeshData();
}


int
Model::removeModelObject(int obj_id)
{
  (*(modelData->modelObjects))[obj_id] = NULL;

  return --modelStatistics->nofModelObjects;
}


// Method reomves a vertex from the model.
// Point2Vertex-table is also updated
int
Model::removeVertex(BodyElement* vertex)
{
  removeModelObject(vertex->Id());

  modelData->modelPoint2Vertices->erase( (GcPoint*)vertex->getGeometry() );

  return --modelStatistics->nofVertices;
}


// Methods stores a bodyelement back into the model.
int
Model::restoreBodyElement(BodyElement* be, bool add_to_bodies)
{
  int nof_model_objects = restoreModelObject(be);

  addBodyElement(be, true);

  BodyElementGroup* beg = (BodyElementGroup*)be->getElementGroup();

  if ( beg != NULL ) {
    beg->addElement(be->Id());
  } else {
    be->checkElementGroupData();
  }

  return nof_model_objects;
}


void
Model::restoreBoundaryNames()
{
  int index = 0;
  while(true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    be->restoreName();
  }
}


// Methods stores a model object back into the model.
int
Model::restoreModelObject(ModelObject* obj)
{
  (*(modelData->modelObjects))[obj->Id()] = obj;

  return ++modelStatistics->nofModelObjects;
}


void
Model::resetAllBoundarySelections(bool update_gui)
{
  UserInterface* gui = theControlCenter->getUI();

  // We loop all boundaries, edges and vertices!
  int index = 0;
  while (true) {

    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;

    be->setDrawState(DS_NORMAL);

    // Set element's selection state in the Gui
    if (update_gui) {
      gui->setBoundarySelectionMode(be->Id(), false);
    }
  }

  // If we have mesh geometry, deselect all
  // mesh elements
  if ( modelFlags[GEOMETRY_TYPE_MESH] ) {
    meshData->boundaryElements->resetSelected();
  }

  refreshRenderer();
}


void
Model::resetBoundarySelections(bool update_gui, bool use_boundary_groups,
                               int nof_skip_ids, const int* skip_bndr_ids,
                               bool call_update)
{
  // Don't remove any current selections if we are in
  // extended object selection mode
  if ( modelFlags[SELECT_OBJECTS_EXTEND] ) return;

  UserInterface* gui = theControlCenter->getUI();

  int index = 0;
  while (true) {

    BodyElement* be  = getBodyElement(index++);

    if ( be == NULL ) break;

    bool skip = false;

    for (int i = 0; i < nof_skip_ids; i++) {
      if ( be->Id() == skip_bndr_ids[i] ) {
        skip = true;
        break;
      }
    }

    if ( skip ) continue;

    be->setDrawState(DS_NORMAL);

    if (update_gui) {

      if (false && use_boundary_groups) {
        gui->setBoundarySelectionMode(be->getElementGroupId(), false, call_update);
      } else {
        gui->setBoundarySelectionMode(be->Id(), false, call_update);
      }
    }

  }
}


// **** Parameter id attachment reset methods.

void
Model::resetBoundaryConditions()
{
  int index = 0;
  while (true) {
    BodyElementGroup* beg = getBodyElementGroup(index++);
    if (beg==NULL) break;
    beg->setBoundaryConditionId(NO_INDEX);
  }
}


void
Model::resetInitialConditions()
{
  int index = 0;
  while (true) {
    Body* bd = getBody(index++);
    if (bd==NULL) break;
    bd->setInitialConditionId(NO_INDEX);
  }
}


void
Model::resetMeshData()
{
  deleteMeshData();
  initMeshData();

  meshManager->setMeshData(meshData, meshInfo, meshBox);
  MeshElementTable::setMeshData(meshData, meshInfo);

  setFlagValue(GEOMETRY_TYPE, GEOMETRY_TYPE_MESH, false);
  setFlagValue(DRAW_SOURCE, DRAW_SOURCE_MESH, false);
}


void
Model::resetModelData()
{
  modelData->reset();
  initSplitCombineInfos();
}


void
Model::saveElmerMesh(char* mesh_dir)
{
  outputManager->write_Elmer_mesh(mesh_dir);
}

void
Model::saveElmerPostMesh(char* filename)
{
  // Create outputfile
  ofstream out_file(filename, ios::out);
  outputManager->write_ElmerPost_mesh(out_file);
  out_file.close();
}


void
Model::saveThetisMesh(char* filename)
{
  // Update mesh result filename
  update_dyna_string(modelInfo->meshResultFile, filename);

  // Create outputfile
  ofstream out_file(filename, ios::out);
  outputManager->write_Thetis_mesh(out_file);
  out_file.close();
}


// Save Elmer Front Model File (emf-file)
//
ostream&
Model::saveFrontModelFile(ostream& out, char* filename)
{
  modelInfo->gebhardtFactorsNeedsUpdate = false;
  modelInfo->meshNeedsUpdate = false;
  modelInfo->solverNeedsUpdate = false;
  update_dyna_string(modelInfo->modelFileName, filename);

  return outputManager->emf_output(out, filename);
}


// Save Mesh Input File (mif-file)
//
ostream&
Model::saveMeshInputFile(ostream& out, char* filename)
{
  return outputManager->mif_output(out);
}


// Save Solver Input File (sif-file)
//
ostream&
Model::saveSolverInputFile(ostream& out, char* filename)
{
  return outputManager->sif_output(out);
}



// Save user settings into a (default) file
void
Model::saveUserSettingsFile(char* filename)
{
  Parameter* us = getParameter(0, ECIF_USER_SETTING);

  if (us == NULL) {
    return;
  }

  ofstream out(filename, ios::out);

  char time_buffer[80];
  getCurrentTime(time_buffer);

  out << "!Elmer Cadi default user settings" << endl;
  out << "!" << time_buffer << endl;
  out << endl;

  //-write parameter type "User Settings"
  //-no id
  //-output all
  SifOutputControl soc;
  soc.outputId = false;
  soc.outputAll = true;

  us->output_sif(out, 2, 0, soc);

  out << "End" << endl;

  out.close();
}


void
Model::selectMeshBoundaryElement(int fem_id)
{
  short current_level = meshData->boundaryElements->currentActionLevel;

  if ( getFlagValue(SELECT_MODE_TOGGLE) ) {
    meshData->boundaryElements->selected[fem_id] = !meshData->boundaryElements->selected[fem_id];
  }

  else if ( getFlagValue(SELECT_MODE_EXTEND) ) {
    if ( !meshData->boundaryElements->selected[fem_id] ) {
      meshData->boundaryElements->selected[fem_id] = true;
      meshData->boundaryElements->actionLevels[fem_id] = current_level;
    }
  }

  else if ( getFlagValue(SELECT_MODE_REDUCE) ) {
    if ( meshData->boundaryElements->selected[fem_id] ) {
      meshData->boundaryElements->selected[fem_id] = false;
      meshData->boundaryElements->actionLevels[fem_id] = -current_level;
    }
  }

}


void
Model::unselectMeshBoundaryElement(int fem_id)
{
  short current_level = meshData->boundaryElements->currentActionLevel;

  if ( getFlagValue(SELECT_MODE_TOGGLE) ) {
    meshData->boundaryElements->selected[fem_id] = !meshData->boundaryElements->selected[fem_id];
  }

  else if ( getFlagValue(SELECT_MODE_EXTEND) ) {
    if ( meshData->boundaryElements->selected[fem_id] ) {
      meshData->boundaryElements->selected[fem_id] = false;
      meshData->boundaryElements->actionLevels[fem_id] = -current_level;
    }
  }

  else if ( getFlagValue(SELECT_MODE_REDUCE) ) {
    if ( !meshData->boundaryElements->selected[fem_id] ) {
      meshData->boundaryElements->selected[fem_id] = true;
      meshData->boundaryElements->actionLevels[fem_id] = current_level;
    }
  }

}


void
Model::selectMeshBoundaryElements()
{
  MeshElementTable* table = meshData->boundaryElements;
  table->updateActionLevel(1);

  if ( getFlagValue(SELECT_METHOD_ALL) ) {
    selectMeshBoundaryElementsAll();
  }

  else if ( getFlagValue(SELECT_METHOD_BY_NEIGHBOR) ) {
    selectMeshBoundaryElementsByNeighbor();
  }

  else if ( getFlagValue(SELECT_METHOD_BY_NORMAL) ) {
    selectMeshBoundaryElementsByNormal();
  }

  else if ( getFlagValue(SELECT_METHOD_BY_PLANE) ) {
    selectMeshBoundaryElementsByPlane();
  }
}


void
Model::selectMeshBoundaryElementsAll()
{
  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);

  if (be == NULL) {
    return;
  }

  int nof_elements = be->getNofMeshElements();

  for (int i = 0; i < nof_elements; i++) {
    int index = be->getMeshElementId(i);
    selectMeshBoundaryElement(index);
  }

  refreshRenderer();
}


void
Model::selectMeshBoundaryElementsByNeighbor()
{
  if (modelInfo->selectedBodyElementId == NO_INDEX) {
    return;
  }

  if (meshInfo->selectedBndrElementId == NO_INDEX) {
    return;
  }


  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);

  if (be == NULL) {
    return;
  }

  MeshElementTable* table = meshData->boundaryElements;

  int ref_id = meshInfo->selectedBndrElementId;
  int ref_bndr_id = meshData->boundaryElementBoundaryIds[ref_id];

  double normal_tol = cos(TWO_PI * NORMAL_TOLERANCE / 360);

  double next_active_dgr;
  double next_active_tol = 0.0;
  int next_active_id = NO_INDEX;

  Ids2 id_pair;

  //Ids2Stack pair_stack;
  std::stack<Ids2> pair_stack;

  id_pair.id1 = ref_id;
  id_pair.id2 = NO_INDEX;

  // Init stack
  pair_stack.push(id_pair);

  while (!pair_stack.empty() ) {

    // Pick topmost from the stack
    Ids2 ids = pair_stack.top();
    pair_stack.pop();

    int id1 = ids.id1;
    int id2 = ids.id2;

    // Check neighbors if second id not
    // yet set
    if ( id2 == NO_INDEX ) {

      int elem_code = table->getElementCode(id1);
      int nof_sub_elems = MeshElementDesc[elem_code][DESC_NOF_BNDR_ELEMS];

      for (short i = 0; i < nof_sub_elems; i++) {

        int ngbr_id = table->neighborIds[id1][i];
        int ngbr_bndr_id = meshData->boundaryElementBoundaryIds[ngbr_id];

        // If neighbor beints to the boundary and
        // is not yet checked, accept it to the pair
        if ( !table->checked[ngbr_id] &&
             ngbr_bndr_id == ref_bndr_id
           ) {
          id_pair.id2 = ngbr_id;
          pair_stack.push(id_pair);
        }
      } // for sub-elements

      table->checked[id1] = true;
      continue;
    }

    double* ref_normal = table->normals[id1];
    double* normal = table->normals[id2];
    double normal_diff =  dot3(ref_normal, normal);

    // If change between the normals is small enough,
    // select the second and make it a new "point"
    // for neighbor selecting
    if ( normal_diff >= normal_tol ) {
      selectMeshBoundaryElement(id2);
      id_pair.id1 = id2;
      id_pair.id2 = NO_INDEX;
      pair_stack.push(id_pair);
    }
    // Otherwise the second is not useful
    else {
      if ( normal_diff > next_active_tol ) {
        next_active_tol = normal_diff;
        next_active_dgr = ( 360 * acos(next_active_tol) ) / TWO_PI;
        next_active_id = id2;
      }
      table->checked[id2] = true;
    }

  } // while stack not empty

  table->resetChecked();

  UserInterface* gui = theControlCenter->getGui();
  gui->updateNextActiveSelectionTolerance(.001 * int(1000 * next_active_dgr));

  refreshRenderer();
}


void
Model::selectMeshBoundaryElementsByNormal()
{
  if (modelInfo->selectedBodyElementId == NO_INDEX)
    return;

  if (meshInfo->selectedBndrElementId == NO_INDEX)
    return;


  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);
  if (be == NULL)
    return;

  MeshElementTable* table = meshData->boundaryElements;

  int ref_id = meshInfo->selectedBndrElementId;
  double* ref_normal = table->normals[ref_id];

  double normal_tol = cos(TWO_PI * NORMAL_TOLERANCE / 360);

  double next_active_dgr;
  double next_active_tol = 0.0;
  int next_active_id = NO_INDEX;

  // Loop all elements in the boundary
  int nof_elements = be->getNofMeshElements();
  for (int i = 0; i < nof_elements; i++) {

    int index = be->getMeshElementId(i);

    // Don't compare to myself!
    if (index == ref_id)
      continue;

    // Pick the the normal to compare and
    // calculate dot-product
    double* normal = table->normals[index];

    double normal_diff =  dot3(ref_normal, normal);

    bool same_direction = false;

    if ( normal_diff > normal_tol ) {
        same_direction = true;
    } else {
      if ( normal_diff > next_active_tol ) {
        next_active_tol = normal_diff;
        next_active_dgr = ( 360 * acos(next_active_tol) ) / TWO_PI;
        next_active_id = index;
      }
    }

    if (same_direction)
      selectMeshBoundaryElement(index);

  }

  UserInterface* gui = theControlCenter->getGui();
  gui->updateNextActiveSelectionTolerance(next_active_dgr);

  refreshRenderer();
}


void
Model::selectMeshBoundaryElementsByPlane()
{
  if (modelInfo->selectedBodyElementId == NO_INDEX)
    return;

  if (meshInfo->selectedBndrElementId == NO_INDEX)
    return;


  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);
  if (be == NULL)
    return;

  MeshElementTable* table = meshData->boundaryElements;

  int ref_id = meshInfo->selectedBndrElementId;
  double ref_distance = table->normalDistances[ref_id];
  double* ref_normal = table->normals[ref_id];

  double normal_tol = cos(NORMAL_TOLERANCE);
  double distance_tol = meshInfo->dimAvg * DISTANCE_TOLERANCE;

  double next_active_dst;
  double next_active_tol = 0.0;
  int next_active_id = NO_INDEX;

  // Loop all elements in the boundary
  int nof_elements = be->getNofMeshElements();
  for (int i = 0; i < nof_elements; i++) {

    int index = be->getMeshElementId(i);

    // Don't compare to myself!
    if (index == ref_id)
      continue;

    // Pick values to compare
    double distance = table->normalDistances[index];
    double* normal = table->normals[index];

    double distance_diff = ref_distance - distance;
    double normal_diff =  dot3(ref_normal, normal);

    if (distance_diff < 0)
      distance_diff *= -1;

    bool same_direction = false;

    // Compare normals and distances
    if ( normal_diff > normal_tol  &&
         distance_diff <= distance_tol
       ) {
     same_direction = true;
    } else {
      if (distance_diff < next_active_tol) {
        next_active_tol = distance_diff;

        if ( meshInfo->dimAvg > 0 )
          next_active_dst = next_active_tol / meshInfo->dimAvg;
        else
          next_active_dst = 0.0;

        next_active_id = index;
      }
    }

    if (same_direction)
      selectMeshBoundaryElement(index);

  }

  UserInterface* gui = theControlCenter->getGui();
  gui->updateNextActiveSelectionTolerance(next_active_dst);

  refreshRenderer();
}


void
Model::selectMeshBoundaryElementsRedo()
{
  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);

  if (be == NULL)
    return;

  int nof_elements = be->getNofMeshElements();

  MeshElementTable* table = meshData->boundaryElements;

  short current_level = 0;

  if ( table->currentActionLevel > 0 &&
       table->currentActionLevel < table->maxActionLevel
     )
    current_level = ++table->currentActionLevel;

  for (int i = 0; i < nof_elements; i++) {
    int index = be->getMeshElementId(i);
    short level = table->actionLevels[index];

    if (level == 0 )
      continue;

    bool is_neg = (level < 0);

    if (is_neg)
      level *= -1;

    if (level == current_level) {

      if (is_neg)
        table->selected[index] = false;
      else
        table->selected[index] = true;
    }
  }

  refreshRenderer();
}


void
Model::selectMeshBoundaryElementsUndo()
{
  BodyElement* be = getBoundaryById(modelInfo->selectedBodyElementId);

  if (be == NULL)
    return;

  int nof_elements = be->getNofMeshElements();

  MeshElementTable* table = meshData->boundaryElements;

  short current_level = 0;

  if (table->currentActionLevel > 0)
    current_level = table->currentActionLevel--;

  for (int i = 0; i < nof_elements; i++) {
    int index = be->getMeshElementId(i);
    short level = table->actionLevels[index];

    if (level == 0 )
      continue;

    bool is_neg = (level < 0);

    if (is_neg)
      level *= -1;

    if (level == current_level) {

      if (is_neg)
        table->selected[index] = true;
      else
        table->selected[index] = false;
    }
  }

  refreshRenderer();
}

// Select correct parameter table for the parameter type
//
// NOTE: use_counter is a pointer, because callres may want to
// upadte the corresponding modelStatistic-counter
//
bool
Model::selectParameterTable(ecif_parameterType parameter_type,
                            ParameterTable*& table,
                            int*& use_counter)
{
  switch (parameter_type) {
  case ECIF_BODY_FORCE:
    table = modelData->bodyForces;
    use_counter = &modelStatistics->nofBodyForces;
    break;
  case ECIF_BODY_PARAMETER:
    table = modelData->bodyParameters;
    use_counter = &modelStatistics->nofBodyParameters;
    break;
  case ECIF_BOUNDARY_CONDITION:
    table = modelData->boundaryConditions;
    use_counter = &modelStatistics->nofBoundaryConditions;
    break;
  case ECIF_BOUNDARY_PARAMETER:
    table = modelData->boundaryParameters;
    use_counter = &modelStatistics->nofBoundaryParameters;
    break;
  case ECIF_CALCULATOR:
    table = modelData->calculators;
    use_counter = &modelStatistics->nofCalculators;
    break;
  case ECIF_CONSTANT:
    table = modelData->constants;
    use_counter = &modelStatistics->nofConstants;
    break;
  case ECIF_COORDINATE:
    table = modelData->coordinates;
    use_counter = &modelStatistics->nofCoordinates;
    break;
  case ECIF_DATAFILE:
    table = modelData->datafiles;
    use_counter = &modelStatistics->nofDatafiles;
    break;
  case ECIF_EQUATION:
    table = modelData->equations;
    use_counter = &modelStatistics->nofEquations;
    break;
  case ECIF_EQUATION_VARIABLE:
    table = modelData->equationVariables;
    use_counter = &modelStatistics->nofEquationVariables;
    break;
   case ECIF_GRID_H:
    table = modelData->gridHs;
    use_counter = &modelStatistics->nofGridHs;
    break;
  case ECIF_GRID_PARAMETER:
    table = modelData->gridParameters;
    use_counter = &modelStatistics->nofGridParameters;
    break;
  case ECIF_INITIAL_CONDITION:
    table = modelData->initialConditions;
    use_counter = &modelStatistics->nofInitialConditions;
    break;
  case ECIF_MATERIAL:
    table = modelData->materials;
    use_counter = &modelStatistics->nofMaterials;
    break;
  case ECIF_MODEL_PARAMETER:
    table = modelData->modelParameters;
    use_counter = &modelStatistics->nofModelParameters;
    break;
  case ECIF_SIMULATION_PARAMETER:
    table = modelData->simulationParameters;
    use_counter = &modelStatistics->nofSimulationParameters;
    break;
  case ECIF_SOLVER:
    table = modelData->solvers;
    use_counter = &modelStatistics->nofSolvers;
    break;
  case ECIF_SOLVER_CONTROL:
    table = modelData->solverControls;
    use_counter = &modelStatistics->nofSolverControls;
    break;
  case ECIF_TIMESTEP:
    table = modelData->timesteps;
    use_counter = &modelStatistics->nofTimesteps;
    break;
  case ECIF_USER_SETTING:
    table = modelData->userSettings;
    use_counter = &modelStatistics->nofUserSettings;
    break;
  default:
    return false;
  }
  return true;
}


void
Model::separateBodies()
{
  bool* duplicated_object_flags = new bool[modelStatistics->nofModelObjects];

  for (int i = 0; i < modelStatistics->nofModelObjects; i++) {
    duplicated_object_flags[i] = false;
  }

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if ( body->getSeparateFlag() ) {
      body->separate(duplicated_object_flags);
    }
  }
}


void
Model::setActiveMeshIndices(int nof_meshes,  int* mesh_indices)
{
  delete[] modelInfo->activeMeshIndices;
  modelInfo->activeMeshIndices = NULL;

  modelInfo->nofActiveMeshes = nof_meshes;

  if ( nof_meshes == 0 )
    return;

  modelInfo->activeMeshIndices = new int[nof_meshes];

  for (int i = 0; i < nof_meshes; i++) {
    modelInfo->activeMeshIndices[i] = mesh_indices[i];
  }
}


void
Model::setBodyColors(ColorIndexArray& unused_colors)
{
  int index = 0;
  while (unused_colors.size() != 0) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    if (DEFAULT_COLOR_INDEX == body->getColorIndex()) {
      body->setColorIndex(unused_colors.back());
      unused_colors.pop_back();
    }
  }
}


// Set parent tags and layer indices for boundaries
//
void
Model::setBoundaryParentIdsAndTags()
{
  // Loop all bodies
  int index = 0;
  while (true) {

    Body* body = getBody(index++);

    if (body==NULL) break;

    int layer = -1;

    // Loop all layer and their elements in the body
    //
    while (true) {

      if (!body->selectLayer(++layer)) break;

      int be_index = 0;

      while (true) {

        BodyElement* be = body->getElement(layer, be_index++);

        if (be == NULL) break;

        int bd_id = body->Id();
        int bd_tg = body->Tag();

        int bd1_id = be->getParentId(1);
        int bd2_id = be->getParentId(2);

        // If body is already a parent this must be an intra layer boundary!
        if ( bd1_id == bd_id || bd2_id == bd_id ) {
          be->setIsIntraLayerBoundary(true);
          continue;
        }

        short body_nbr;

        // If body1-id not yet set this is set
        // as the first body
        if ( bd1_id == NO_INDEX ) {
          body_nbr = 1;

        // If body1-id already set (via an other body)
        // this is the second body
        } else {
          body_nbr = 2;
        }

        be->setParentId(body_nbr, bd_id);
        be->setParentTag(body_nbr, bd_tg);
        be->setParentLayer(body_nbr, layer);

      } // Each body element in the layer
    } // Each layer
  }
}

#if 0
// Set boundary element boundary condtions from boundary groups
// NOTE: Boundary condityions are set in hierarchical order!
void
Model::setBoundaryConditions()
{
  ElementGroup* eg;
  BodyElement* be;
  int i, index;

  // Face groups
  index = 0;
  while (true) {
    eg = getElementGroup(index++);
    if (eg==NULL) break;
    if ( OT_FACE != eg->getElementType() ) continue;
    int bc_pid = eg->getBoundaryConditionId();
    for (i = 0; i < eg->getNofElements(); i++) {
      be = (BodyElement*)eg->getElement(i);
      if ( be == NULL ) continue;
      be->setBoundaryConditionId(bc_pid);
    }
  }

  // Edge groups
  index = 0;
  while (true) {
    eg = getElementGroup(index++);
    if (eg==NULL) break;
    if ( OT_EDGE != eg->getElementType() ) continue;
    int bc_pid = eg->getBoundaryConditionId();
    for (i = 0; i < eg->getNofElements(); i++) {
      be = (BodyElement*)eg->getElement(i);
      if ( be == NULL ) continue;
      be->setBoundaryConditionId(bc_pid);
    }
  }

  // Vertex groups
  index = 0;
  while (true) {
    eg = getElementGroup(index++);
    if (eg==NULL) break;
    if ( OT_VERTEX != eg->getElementType() ) continue;
    int bc_pid = eg->getBoundaryConditionId();
    for (i = 0; i < eg->getNofElements(); i++) {
      be = (BodyElement*)eg->getElement(i);
      if ( be == NULL ) continue;
      be->setBoundaryConditionId(bc_pid);
    }
  }

}
#endif


// Set parent tags for boundaries
void
Model::setBoundaryTags()
{
  // Boundary tag counter
  int max_btag = 0;

  bool only_active = true;
  BodyElement* be;
  int index;

  // Normal boundaries use their own tags!
  //
  index = 0;
  while (true) {
    be = getBoundary(index++, only_active);
    if (be==NULL) break;
    int tag = be->Tag();

    be->setBoundaryTag(tag);

    if (max_btag < tag)
      max_btag = tag;
  }

  // Edges in 3D will be numbered simply after boundaries
  //
  if ( modelInfo->dimension == ECIF_3D ) {
    index = 0;
    while (true) {
      be = getEdge(index++, only_active);
      if (be==NULL) break;
      be->setBoundaryTag(++max_btag);
    }
  }

  // Vertices are numbered simply after boundaries or  edges
  //
  index = 0;
  while (true) {
    be = getVertex(index++, only_active);
    if (be==NULL) break;
    be->setBoundaryTag(++max_btag);
  }

  // Update class-variable
  BodyElement::setLastBoundaryTag(max_btag);
}


// Set boundary point tags and mesh density values
void
Model::setBoundaryPointData()
{

  int bp_counter = 0;
  int next_bp_tag = 1 + modelStatistics->nofVertices;

  int index = 0;
  while (true) {

    BodyElement* be = getBoundary(index++);

    if (be==NULL) break;
    
    be->checkBoundaryDiscretization(modelInfo->currentMeshIndex);

    int bp_count;
    BoundaryPoint** bp_points;

    be->getBoundaryPoints(bp_count, bp_points);

    int i;

    // Reset tags (this way we can control that
    // copied point (for closed boundaried) are
    // not numbered twice
    for (i = 0; i < bp_count; i++) {

      BoundaryPoint* bp = bp_points[i];

      if ( bp->isVertex() ) {
        continue;
      }

      bp->checked = false;
      bp->activeInMeshing = false;
      bp->tag = NO_INDEX;
    }

    // Now number points (but skip those which already have a tag!)
    for (i = 0;  i < bp_count; i++) {

      BoundaryPoint* bp = bp_points[i];

      if ( bp->isVertex() || bp->checked ) {
        continue;
      }

      bp_counter++;
      bp->tag = next_bp_tag++;
      bp->checked = true;
    }

    // Finally set possible density values for boundary points
    be->setBoundaryPointsMeshDensityValue(getCurrentMeshIndex());

  }

  modelStatistics->nofBoundaryPoints = bp_counter;
}


void
Model::setCurrentAnchorPoint(int vertex_id)
{
  BodyElement* vertex = getVertexById(vertex_id);
  GcPoint* point = (GcPoint*)vertex->getGeometry();

  Point3* p = point->getPoint();

  for (int i = 0; i < 3; i++) {
    pickInfo->anchorPoint[i] = (*p)[i];
  }
}


void
Model::setCurrentAnchorPoint(Point3 point)
{
  for (int i = 0; i < 3; i++) {
    pickInfo->anchorPoint[i] = point[i];
  }
}


void
Model::setCurrentPickInfo(Point3 point, Point3 dir)
{
  for (int i = 0; i < 2; i++) {
    pickInfo->pickPoint[i] = point[i];
    pickInfo->pickDir[i] = dir[i];
  }

  pickInfo->pickPoint[2] = 0.0;
  pickInfo->pickDir[2] = 0.0;

  refreshRenderer();
}


void
Model::drawCurrentPickVector()
{
  Renderer* renderer = theControlCenter->getRenderer();

  renderer->drawLine(DM_NORMAL, DS_NORMAL, 1, &(pickInfo->anchorPoint), &(pickInfo->pickPoint));
}


void
Model::setCurrentMeshIndex(int index)
{
  if ( index < 0 || index >= modelInfo->nofMeshes )
    modelInfo->currentMeshIndex = NO_INDEX;

  else
    modelInfo->currentMeshIndex = index;
}


void
Model::setInitialMeshH()
{
  UserInterface* ui = theControlCenter->getGui();

  double initial_mesh_h = calcInitialMeshH();

  if (initial_mesh_h < MAX_RANGE)
    ui->setInitialMeshH(initial_mesh_h);
  else
    ui->setInitialMeshH(-1.0);
}


void
Model::setFlagValue(flagGroup group, flagName name, bool value)
{
  bool refresh_renderer = false;

  // Reset exlusive flag sets
  switch (group) {

  case DRAW_SOURCE:
    refresh_renderer = true;
    break;

  case DRAW_TARGET:
    modelFlags[DRAW_TARGET_BODIES]      = false;
    modelFlags[DRAW_TARGET_SURFACES]    = false;
    modelFlags[DRAW_TARGET_EDGES]       = false;
    modelFlags[DRAW_TARGET_BOUNDARIES]  = false;
    refresh_renderer = true;
    break;

  case SELECT_METHOD:
    modelFlags[SELECT_METHOD_SINGLE]        = false;
    modelFlags[SELECT_METHOD_ALL]           = false;
    modelFlags[SELECT_METHOD_BY_NEIGHBOR]   = false;
    modelFlags[SELECT_METHOD_BY_NORMAL]     = false;
    modelFlags[SELECT_METHOD_BY_PLANE]      = false;
    modelFlags[SELECT_METHOD_BY_BOX]        = false;
    modelFlags[SELECT_METHOD_BY_RECTANGLE]  = false;
    break;

  case SELECT_MODE:
    modelFlags[SELECT_MODE_TOGGLE] = false;
    modelFlags[SELECT_MODE_EXTEND] = false;
    modelFlags[SELECT_MODE_REDUCE] = false;
    //refresh_renderer = true;
    break;

  case SELECT_OBJECTS:
    modelFlags[SELECT_OBJECTS_TOGGLE] = false;
    modelFlags[SELECT_OBJECTS_EXTEND] = false;
    //refresh_renderer = true;
    break;

  case LABEL_DISPLAY:
    // No exclusive values here!
    //modelFlags[LABEL_DISPLAY_NODE]     = false;
    //modelFlags[LABEL_DISPLAY_ELEMENT]  = false;
    //modelFlags[LABEL_DISPLAY_VERTEX]   = false;
    //modelFlags[LABEL_DISPLAY_EDGE]     = false;
    //modelFlags[LABEL_DISPLAY_FACE]     = false;
    //modelFlags[LABEL_DISPLAY_BODY]     = false;
    //modelFlags[LABEL_DISPLAY_BODYPAIR] = false;
    refresh_renderer = true;
    break;
  }

  // Set flag value
  modelFlags[name] = value;

  // Postprocess flags
  switch (group) {

  case DRAW_TARGET: // Check if we are drawing boundaries
    if ( modelInfo->dimension == ECIF_2D ) {
      if ( name == DRAW_TARGET_EDGES ) {
        modelFlags[DRAW_TARGET_BOUNDARIES] = true;
      }
    }
    if ( modelInfo->dimension == ECIF_3D ) {
      if ( name == DRAW_TARGET_SURFACES ) {
        modelFlags[DRAW_TARGET_BOUNDARIES] = true;
      }
    }
    break;

  case SELECT_METHOD:
    //selectMeshBoundaryElements();
    break;

  case SELECT_OBJECTS:
    // Set deafult value if no value set
    if ( modelFlags[SELECT_OBJECTS_TOGGLE] == false &&
         modelFlags[SELECT_OBJECTS_EXTEND] == false
       )
      modelFlags[SELECT_OBJECTS_TOGGLE] = true;
    break;
  }

  if ( refresh_renderer ) {
    refreshRenderer();
  }

}


void
Model::setMatcInputFileEmf(char* matc_input_file)
{
  update_dyna_string(modelInfo->matcInputFile_emf, matc_input_file);
}


void
Model::setMatcInputFileSif(char* matc_input_file)
{
  update_dyna_string(modelInfo->matcInputFile_sif, matc_input_file);
}


void
Model::setMeshBgMeshActives(int nof_files, int* bg_mesh_actives)
{
  delete[] modelInfo->meshBgMeshActives;
  modelInfo->meshBgMeshActives = NULL;

  if ( nof_files > 0 ) {

    // Alloc table
    modelInfo->meshBgMeshActives = new bool[nof_files];

    for (int i = 0; i < nof_files; i++) {
      modelInfo->meshBgMeshActives[i] = (bool) bg_mesh_actives[i];
    }
  }
}


void
Model::setMeshBgMeshControls(int nof_files, int* bg_mesh_controls)
{
  delete[] modelInfo->meshBgMeshControls;
  modelInfo->meshBgMeshControls = NULL;

  if ( nof_files > 0 ) {

    // Alloc table
    modelInfo->meshBgMeshControls = new bool[nof_files];

    for (int i = 0; i < nof_files; i++) {
      modelInfo->meshBgMeshControls[i] = (bool) bg_mesh_controls[i];
    }
  }
}


void
Model::setMeshBgMeshFiles(int nof_files, char** bg_mesh_files)
{
  delete[] modelInfo->meshBgMeshFiles;
  modelInfo->meshBgMeshFiles = NULL;

  if ( nof_files > 0 ) {

    // Alloc table
    modelInfo->meshBgMeshFiles = new char*[nof_files];

    for (int i = 0; i < nof_files; i++) {

      modelInfo->meshBgMeshFiles[i] = NULL;

      if ( bg_mesh_files[i] == NULL ) {
        continue;
      }

      int len = strlen(bg_mesh_files[i]);

      if ( len == 0 ) {
        continue;
      }

      // Alloc space for each mesh name
      modelInfo->meshBgMeshFiles[i] = new char[1 + len];

      strcpy(modelInfo->meshBgMeshFiles[i], bg_mesh_files[i]);
    }
  }

}


void
Model::setMeshBgMeshFileIndices(int nof_files, int* bg_mesh_file_indices)
{
  int i;

  delete[] modelInfo->meshBgMeshFileIndices;

  modelInfo->nofBgMeshFiles = nof_files;
  modelInfo->meshBgMeshFileIndices = NULL;

  if ( nof_files > 0 ) {

    // Alloc table
    modelInfo->meshBgMeshFileIndices = new int[nof_files];

    for (i = 0; i < nof_files; i++) {
      modelInfo->meshBgMeshFileIndices[i] = bg_mesh_file_indices[i];
    }
  }
}


void
Model::setMeshFs(int nof_values, double* mesh_fs)
{
  delete[] modelInfo->meshFs;
  modelInfo->meshFs = NULL;

  if ( nof_values == 0 )
    return;

  modelInfo->meshFs = new double[nof_values];

  for (int i = 0; i < nof_values; i++) {
    modelInfo->meshFs[i] = mesh_fs[i];
  }
}


void
Model::setMeshHs(int nof_values, double* mesh_hs)
{
  delete[] modelInfo->meshHs;
  modelInfo->meshHs = NULL;

  if ( nof_values == 0 )
    return;

  modelInfo->meshHs = new double[nof_values];

  for (int i = 0; i < nof_values; i++) {
    modelInfo->meshHs[i] = mesh_hs[i];
  }
}


void
Model::setMeshInputUnit(double unit)
{
  meshInputUnit = unit;
}


void
Model::setMeshNames(int nof_meshes, char** mesh_names)
{
  int i;

  for (i = 0; i < modelInfo->nofMeshes; i++) {
    delete[] modelInfo->meshNames[i];
  }
  delete[] modelInfo->meshNames;

  modelInfo->meshNames = NULL;
  modelInfo->nofMeshes = nof_meshes;

  if ( nof_meshes > 0 ) {

    // Alloc table
    modelInfo->meshNames = new char*[nof_meshes];

    for (i = 0; i < nof_meshes; i++) {

      int len = strlen(mesh_names[i]);

      // Alloc space for each mesh name
      modelInfo->meshNames[i] = new char[1 + len];

      strcpy(modelInfo->meshNames[i], mesh_names[i]);
    }
  }

}


void
Model::setMeshNodes()
{
  MeshElementTable::setMeshNodes(meshData->nodes);
}


void
Model::setModelDescriptions(char* model_desc, char* problem_desc)
{
  update_dyna_string(modelInfo->modelDescription, model_desc);
  update_dyna_string(modelInfo->problemDescription, problem_desc);
}


void
Model::setModelDimension(ecif_modelDimension dim)
{
  modelInfo->dimension = dim;
}


void
Model::setModelFileDirectories(char* model_dir, char* include_path, char* results_dir, char* temporary_dir)
{
  update_dyna_string(modelInfo->modelDirectory, model_dir);
  update_dyna_string(modelInfo->includePath, include_path);
  update_dyna_string(modelInfo->resultsDirectory, results_dir);
  update_dyna_string(modelInfo->temporaryFilesDirectory, temporary_dir);
}


void
Model::setModelFileDirectoriesAbs(char* model_dir, char* include_path, char* results_dir, char* temporary_dir)
{
  update_dyna_string(modelInfo->modelDirectory_absolute, model_dir);
  update_dyna_string(modelInfo->includePath_absolute, include_path);
  update_dyna_string(modelInfo->resultsDirectory_absolute, results_dir);
  update_dyna_string(modelInfo->temporaryFilesDirectory_absolute, temporary_dir);
}

void
Model::setModelFileDirectoriesSave(bool include_path, bool results_dir, bool temporary_dir)
{
  modelInfo->includePath_save = include_path;
  modelInfo->resultsDirectory_save = results_dir;
  modelInfo->temporaryFilesDirectory_save = temporary_dir;
}


void
Model::setModelFileCreated(char* created_str)
{
  update_dyna_string(modelInfo->created, created_str);
}


void
Model::setModelFileModified(char* modified_str)
{
  update_dyna_string(modelInfo->modified, modified_str);
}


void
Model::setModelMeshDirectory(char* mesh_dir)
{
  update_dyna_string(modelInfo->meshDirectory, mesh_dir);
}


void
Model::setModelMeshDirectoryAbs(char* mesh_dir)
{
  update_dyna_string(modelInfo->meshDirectory_absolute, mesh_dir);
}


void
Model::setModelNameAndDirectory(char* file_path)
{
  char name_buffer[1024];
  char dir_buffer[1024];

  int len = strlen(file_path);

  for (int i = 0; i< len; i++) {
    if ( file_path[i] == '\\' )
      file_path[i] = '/';
  }

  int counter;
  int pos = len -1;

  // Move at the end of name
  while ( pos >= 0 && file_path[pos] != '/' )
    pos--;

  // Read name (in reversed order!)
  if ( pos >= 0 && file_path[pos] == '/' )
    pos--;
  counter = 0;
  while ( pos >= 0 && file_path[pos] != '/' ) {
    name_buffer[counter++] = file_path[pos--];
  }
  name_buffer[counter] = '\0';

  // Read dir (in reversed order!)
  if ( pos >= 0 && file_path[pos] == '/' )
    pos--;
  counter = 0;
  while ( pos >= 0 ) {
    dir_buffer[counter++] = file_path[pos--];
  }
  dir_buffer[counter] = '\0';


  //- Reverse name buffer
  len = strlen(name_buffer);
  counter = 0;
  while (counter < len / 2) {
    char tmp = name_buffer[counter];
    name_buffer[counter] = name_buffer[len - 1 - counter];
    name_buffer[len - 1 - counter] = tmp;
    counter++;
  }

  //- Reverse dir buffer
  len = strlen(dir_buffer);
  counter = 0;
  while (counter < len / 2) {
    char tmp = dir_buffer[counter];
    dir_buffer[counter] = dir_buffer[len - 1 - counter];
    dir_buffer[len - 1 - counter] = tmp;
    counter++;
  }

  update_dyna_string(modelInfo->modelName, name_buffer);
  update_dyna_string(modelInfo->modelDirectory, dir_buffer);

  setWindowTitles();
}


void
Model::setModelNames(char* model_name, char* problem_name)
{
  update_dyna_string(modelInfo->modelName, model_name);
  update_dyna_string(modelInfo->problemName, problem_name);

  setWindowTitles();
}


bool
Model::setModelObjectNameById(int oid, char*name)
{
  ModelObject* obj = getModelObjectById(oid);

  if (obj == NULL ) return false;

  obj->setName(name);

  return true;
}


bool
Model::setModelObjectTagById(int oid, int tag)
{
  ModelObject* obj = getModelObjectById(oid);

  if (obj == NULL ) return false;

  obj->setTag(tag);

  return true;
}


// Method updates current model outfile time
void
Model::setModelFileTime(char* outfile_time)
{
  update_dyna_string(modelInfo->modelFileTs, outfile_time);
}


void
Model::setModelHasDiffuseGrayRadiation(bool value)
{
  modelInfo->hasDiffuseGrayRadiation = value;
}


void
Model::setSelectionsToGui()
{
  bool has_selections = false;

  UserInterface* gui = theControlCenter->getGui();

  int index = 0;
  while (true) {

    BodyElement* be = getBoundary(index++);

    if (be==NULL) break;

    if ( DS_SELECTED == be->getDrawState() ) {

      int bndr_id = be->Id();

      // If first selected bodyelement was found
      if (!has_selections) {
        has_selections = true;

        int bd1_id = modelInfo->selectedBody1Id;
        int lr1_id = modelInfo->selectedLayer1Id;

        int bd2_id = modelInfo->selectedBody2Id;
        int lr2_id = modelInfo->selectedLayer2Id;

        gui->selectBoundary(bndr_id, bd1_id, lr1_id, bd2_id, lr2_id, true);
      }

      gui->setBoundarySelectionMode(bndr_id, true);
    }

  }
}


// Method updates timestamp for the "target_name" related data.
void
Model::setTimestamp(char* target_name, char* ts)
{
  // Predefined target names
  const char* target_names[7]= {
    "Database",
    "Front",
    "Gebhardt Factors",
    "Grid Parameter",
    "Mesh",
    "Solver",
    "View Factors"
  };

  // Predefined target variables
  char** targets[7] = {
    &modelInfo->databaseTs,
    &modelInfo->frontTs,
    &modelInfo->gebhardtFactorsTs,
    &modelInfo->meshParameterTs,
    &modelInfo->meshTs,
    &modelInfo->solverTs,
    &modelInfo->viewfactorsTs
  };

  // Check which of the targets (if any) should
  // be updated
  for (int i = 0; i < 7; i++) {
    if ( LibFront::ncEqual(target_name, (char*)target_names[i]) ) {
      char*& target = *(targets[i]);
      update_dyna_string(target, ts);
      break;
    }
  }
}


void
Model::setVertexTable(int dim1, int dim2, int* vertex_ids, MatcValueTable& matc_table)
{
  modelData->setVertexTable(dim1, dim2, vertex_ids, matc_table);
}


void
Model::setWindowTitles()
{
  strstream strm;

  strm << "ELMER Front - ";

  // If model exists
  if ( modelInfo->modelName != NULL && modelInfo->modelName[0] != '\0' ) {
    strm << modelInfo->modelName;

    // if problem name defined
    if ( modelInfo->problemName != NULL && modelInfo->problemName[0] != '\0' ) {
      strm << "." << modelInfo->problemName;
    }

  }
  // No model exists
  else {
    strm << "No model name";
  }

  strm << ends;

  theControlCenter->setWindowTitles(strm.str());
}


void
Model::setParameter(ecif_parameterType parameter_type,
                    int pid, int parent_id,
                    char* data_string, char* param_name)
{
  Parameter* parameter = getParameterById(parameter_type, pid);

  // Create a new parameter entry and add to model
  if (parameter == NULL) {
    parameter = createNewParameter( parameter_type, pid, parent_id,
                                    data_string, param_name);
    addParameter(parameter_type, parameter);
  }

  // Update an existing parameter
  else {
    parameter->setName(param_name);
    parameter->setValue(data_string);
  }

  // Mark this parameter updated
  parameter->setUpdateFlag(true);

  UserInterface* gui = theControlCenter->getGui();

  char ts_buffer[64];

  theControlCenter->getCurrentTimestamp(ts_buffer);

  // Update coordinate system info
  if (parameter_type == ECIF_COORDINATE) {

    ParameterField* pf;
    char** data = NULL;

    pf = parameter->getFieldBySifName("Coordinate System");

    if(pf != NULL) 
    {
      data = pf->getDataStrings();

      modelInfo->updateCoordinateType(data[0]);
      modelInfo->updateSimulationDimension(data[0]);

    } else {
      printf("Parameter field is null, something went wrong. Contact <elmerdiscussion@postit.csc.fi>\n");
    }


    pf = parameter->getFieldBySifName("Coordinate Mapping");

    if(pf != NULL) 
    {
      data = pf->getDataStrings();
      modelInfo->updateCoordinateMapping(data[0]);
    } else {
      printf("Parameter field is null, something went wrong. Contact <elmerdiscussion@postit.csc.fi>\n");
    }

    Renderer* renderer = theControlCenter->getRenderer();

    if ( renderer != NULL ) {
      renderer->setSimulationDimension(modelInfo->simulationDimension);
      refreshRenderer();
    }

  }

  // Write mesh parameter ts
  if (parameter_type == ECIF_GRID_PARAMETER) {
    setTimestamp("Mesh_Parameter", ts_buffer);
    gui->setTimestamp(ECIF_GRID_PARAMETER, ts_buffer);
  }

  // NOTE: Change checks do not work anymore, because
  // all parameter are written anew each time parameters
  // are updated (old are deleted and existing are added as new!)

#if 0
  // Check change status
  bool value_changed;
  bool emissivity_changed;

  parameter->getParameterValueState(value_changed);

  // If any parameter's value has changed (potential change for Solver)
  if (value_changed) {
    modelInfo->solverNeedsUpdate = true;
    gui->setNeedsUpdate(EFN_PROGRAM_SOLVER);
  }

  // Check if mesh parameter has changed
  if (parameter_type == ECIF_MESH && value_changed) {
    setTimestamp("Mesh_Parameter", ts_buffer);
    gui->setTimestamp(ECIF_MESH, ts_buffer);
    //modelInfo->meshNeedsUpdate = true;
    //gui->setNeedsUpdate(EFN_PROGRAM_MESH);
  }

  // Check if emissivity boundary condition has changed
  if (parameter_type == ECIF_BOUNDARY_CONDITION) {

    parameter->getParameterFieldValueState(EFN_EMISSIVITY, emissivity_changed);

    if (emissivity_changed) {
      modelInfo->gebhardtFactorsNeedsUpdate = true;
      gui->setNeedsUpdate(EFN_PROGRAM_GEBHARDT_FACTORS);
    }
  }
#endif


}


int
Model::setNewSplitCombineIndex(short shift)
{
  if (shift == 0)
    return modelData->splitCombineInfoIndex;

  int index = modelData->splitCombineInfoIndex + shift;

  if ( index < 0 )
    return modelData->splitCombineInfoIndex;

  // Allocate more space if needed
  if ( index >= MAX_NOF_SPLIT_COMBINE_INFOS - 1 ) {

    int current_size = MAX_NOF_SPLIT_COMBINE_INFOS;

    MAX_NOF_SPLIT_COMBINE_INFOS += 16;

    SplitCombineInfoArray* tmp = new SplitCombineInfoArray(MAX_NOF_SPLIT_COMBINE_INFOS);

    for (int i = 0; i < MAX_NOF_SPLIT_COMBINE_INFOS; i++) {
      if ( i < current_size)
        (*tmp)[i] = (*modelData->splitCombineInfos)[i];
      else
        (*tmp)[i] = NULL;
    }

    delete modelData->splitCombineInfos;

    modelData->splitCombineInfos = tmp;
  }

  modelData->splitCombineInfoIndex = index;

  return modelData->splitCombineInfoIndex;
}


void
Model::setParallelInfo(ParallelInfo& pi)
{
  parallelInfo->nofProcessors = pi.nofProcessors;
}


#if 0
void
Model::sortBoundaryVertices(enum modelGeometryType gtype)
{

  BoundaryVertexList* bvlist;

  // Select vertex list to use
  if (gtype == GEOM_CAD) {
    bvlist = modelData->boundaryVertices;
  } else {
    bvlist = modelData->meshBoundaryVertices;
  }

  int count = 1 + bvlist->size();

  BoundaryVertex** bpoints = new BoundaryVertex*[count];

  for (int i = 0; i < count; i++) {
    bpoints[i] = NULL;
  }

  BoundaryVertex* bp = getFirstBoundaryVertex(gtype);

  while (bp != NULL ) {

    bpoints[bp->id] = bp;

    bp = getNextBoundaryVertex(gtype);
  }

  bvlist->clear();

  for (i = 0; i < count; i++) {
    if ( bpoints[i] != NULL ) {
      bvlist->push_back(bpoints[i]);
    }
  }

  if (gtype == GEOM_CAD) {
    modelStatistics->nofBoundaryVertices = bvlist->size();
  } else {
    modelStatistics->nofMeshBoundaryVertices = bvlist->size();
  }

}
#endif

#if 0
void
Model::sortMeshBoundaryIndices()
{
  int i, j;
  int nof_belems = meshInfo->nofInnerBndrElements + meshInfo->nofOuterBndrElements;
  if (nof_belems == 0)
    return;
  // Sorted indices are stored here
  int** new_table = new int*[nof_belems];
  //
  // Position counter for each (body1,body2)-pair
  // are stored in this table
  int start = 0;
  int** pair_counters = new int*[meshInfo->nofBodies];
  for (i = 0; i < meshInfo->nofBodies; i++) {
    pair_counters[i] = new int[meshInfo->nofBodies];
    for (j = 0; j < meshInfo->nofBodies; j++) {
      pair_counters[i][j] = start;
      start += meshBodyPairTable[i][j];
    }
  }
  // Sort data
  int M = meshInfo->nofBodies; // pair table size
  for (i=0; i < nof_belems; i++) {
    int p1_id = meshBoundaryIndices[i][BELM_PARENT1_ID];
    int p2_id = meshBoundaryIndices[i][BELM_PARENT2_ID];
    int m1 = meshBulkElements[p1_id][ELM_BODY];
    int m2 = meshBulkElements[p2_id][ELM_BODY];
    if (m2 == NO_INDEX)
      m2 = m1;
    // Boundary element ID:
    // pair-table-index + 1(index origo = 1) - lower diag indices
    int bndr_elem_id = (m1 * M + m2) + 1 - ( (m1+1) * ((m1+0)/2) );
    //meshBoundaryIndices[i][BELM_ID] = m1 * M + m2 + 1;
    meshBoundaryIndices[i][BELM_ID] = bndr_elem_id;
    int index = pair_counters[m1][m2];
    new_table[index] = meshBoundaryIndices[i];
    pair_counters[m1][m2]++;
  }

  for (i = 0; i < meshInfo->nofBodies; i++)
    delete[] pair_counters[i];
  delete[] pair_counters;

  delete[] meshBoundaryIndices;
  meshBoundaryIndices = new_table;
}
#endif


// NOTE: Only one boundary element at a time
// can be under splitting !!!
void
Model::splitBoundary(int body1_id, int body2_id)
{
  UserInterface* gui = theControlCenter->getGui();

  Body* body1 = getBodyById(body1_id);
  Body* body2 = getBodyById(body2_id);

  int body1_tag = NO_INDEX;
  int body2_tag = NO_INDEX;

  if ( body1 != NULL ) {
    body1_tag = body1->Tag();
  }

  if ( body2 != NULL ) {
    body2_tag = body2->Tag();
  }

  int nof_selected;
  int source_id;

  // Split source element (boundary)
  BodyElement* split_source = NULL;

  //---Count nof mesh elements in the new body element
  //   Only one boundary at a time!!!
  int index = 0;
  while (true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    nof_selected = be->getNofMeshSelectedElements();
    if (nof_selected > 0) {
      split_source = be;
      source_id = be->Id();
      break;
    }
  }

  //---If nothing was selected
  if (split_source == NULL) {
    gui->showMsg("Nothing selected for splitting!");
    return;
  }

  int nof_source_elements = split_source->getNofMeshElements();

  // If all source elements were selected, split
  // does not make sense!
  if (nof_selected == nof_source_elements) {
    gui->showMsg("All elements were selected. Nothing to split!");
    return;
  }

  if (modelInfo->editingMeshBoundaries == false) {
    startEditMeshBoundaries();
  }

  // Delete possible old info entry and replace with a new
  short idx = modelData->splitCombineInfoIndex;
  delete (*modelData->splitCombineInfos)[idx];
  SplitCombineInfo* sc_info = new SplitCombineInfo;
  (*modelData->splitCombineInfos)[idx] = sc_info;

  // Update index for the next entry
  setNewSplitCombineIndex(+1);

  int body1_lr = split_source->getParentLayer(1);
  int body2_lr = split_source->getParentLayer(2);

  //---Create new bodyelement, add to the model and to the bodies
  BodyElement* new_be = createBodyElement(body1_tag, body1_lr, body2_tag, body2_lr, nof_selected);

  new_be->setParentIds(body1_id, body2_id);
  new_be->checkElementGroupData();

  (*modelData->createdModelElements)[new_be->Id()] = new_be;

  //-Store split info
  sc_info->canRedo = false;
  sc_info->canUndo = true;
  sc_info->splitSourceId = source_id;
  sc_info->splitTargetId = new_be->Id();
  sc_info->nofSplitTargetMeshElements = nof_selected;
  sc_info->splitTargetMeshElementSourceIndices = new int[nof_selected];

  body1->check();

  if (body2 != NULL) {
    body2->check();
  }

  //---Copy selected mesh elements to the new boundary
  //   and remove them from the original boundary
  split_source->setDrawState(DS_NORMAL);
  gui->setBoundarySelectionMode(source_id, false);

  //-Copy all selected
  for (int i = 0; i < split_source->getNofMeshElements(); i++) {

    int elem_id = split_source->getMeshElementId(i);
    short elem_dir = split_source->getMeshElementDir(i);

    if ( !meshData->boundaryElements->selected[elem_id] )
      continue;

    // Set mesh element to the new boundary
    new_be->addMeshElement(elem_id, elem_dir);
    meshData->boundaryElementBoundaryIds[elem_id] = sc_info->splitTargetId;
  }

  //-Remove (selected) elements from the original
  // Store also original source ids for possible redo!!!
  int* removed = sc_info->splitTargetMeshElementSourceIndices;
  split_source->removeSelectedMeshElements(removed);

  //-Update model
  split_source->findMeshBorder();
  new_be->findMeshBorder();

  updateModelStatistics();

  gui->updateBodyData(this);
  gui->updateBoundaryData(this);

  gui->setMeshEdited();

  meshData->boundaryElements->resetSelected();

  refreshRenderer();
}


void
Model::splitCombineBoundariesRedo()
{
  UserInterface* gui = theControlCenter->getGui();

  short cur_index = modelData->splitCombineInfoIndex;

  SplitCombineInfo* sc_info = (*modelData->splitCombineInfos)[cur_index];

  // If there is nothing to undo
  if (sc_info == NULL || !sc_info->canRedo) {
    gui->showMsg("Nothing for redo!");
    return;
  }

  // Update index for the next insert
  int new_index = setNewSplitCombineIndex(+1);

  sc_info->canRedo = false;
  sc_info->canUndo = true;

  //---If we have to REDO a SPLIT
  if (sc_info->splitTargetId != NO_INDEX) {

    BodyElement* be_target = getRemovedBodyElement(sc_info->splitTargetId);

    // This is not a "removed" element anymore
    modelData->removedModelElements->erase(be_target->Id());

    // Add target element (again) to the model
    restoreBodyElement(be_target, true);

    BodyElement* be_source = getBoundaryById(sc_info->splitSourceId);

    // Remove target mesh elements from the source
    // NOTE: They are still stored in the target, no need to
    // add them there again!
    be_source->removeMeshElements(sc_info->nofSplitTargetMeshElements,
                                  sc_info->splitTargetMeshElementSourceIndices);

    // Update moved mesh element boundary ids
    for (int i = 0; i < sc_info->nofSplitTargetMeshElements; i++) {

      int elem_id = be_target->getMeshElementId(i);
      meshData->boundaryElementBoundaryIds[elem_id] = sc_info->splitTargetId;
    }

    be_source->findMeshBorder();
    be_target->findMeshBorder();
  }

  //---If we have to REDO a COMBINE
  else if (sc_info->nofCombineSourceIds > 0) {

    BodyElement* be_target = getRemovedBodyElement(sc_info->combineTargetId);

    // This should not be a "removed" element anymore
    modelData->removedModelElements->erase(be_target->Id());

    // Add target element (again) to the model
    restoreBodyElement(be_target, true);

    // Remove source elements from the model
    for (int i = 0; i < sc_info->nofCombineSourceIds; i++) {
      BodyElement* be_source = getBoundaryById(sc_info->combineSourceIds[i]);
      removeBodyElement(be_source, true, false);
    }

    be_target->findMeshBorder();
  }

  //-Check body data (rebuild element loops etc.)
  checkBodies();

  //-Update model
  updateModelStatistics();

  // Update gui and graphics screen
  gui->updateBodyData(this);
  gui->updateBoundaryData(this);

  refreshRenderer();

#if 0
  // For debugging
  strstream cur_strm;
  strstream new_strm;
  cur_strm << "Cur SplitCombineIndex = " << cur_index << ends;
  new_strm << "New SplitCombineIndex = " << new_index << ends;
  gui->showMsg(cur_strm.str());
  gui->showMsg(new_strm.str());
#endif

}


void
Model::splitCombineBoundariesUndo()
{
  UserInterface* gui = theControlCenter->getGui();

  // For debugging only!
  short cur_index = modelData->splitCombineInfoIndex;

  // Move backwards to undo
  short new_index = setNewSplitCombineIndex(-1);

  SplitCombineInfo* sc_info = (*modelData->splitCombineInfos)[new_index];

  // If there is nothing to undo!
  if (sc_info == NULL || !sc_info->canUndo) {
    setNewSplitCombineIndex(+1);
    gui->showMsg("Nothing for undo!");
    return;
  }

  sc_info->canRedo = true;
  sc_info->canUndo = false;

  //---If we have to UNDO a SPLIT
  if (sc_info->splitTargetId != NO_INDEX) {

    BodyElement* be_target = getBoundaryById(sc_info->splitTargetId);
    BodyElement* be_source = getBoundaryById(sc_info->splitSourceId);

    // Remove target element from the model
    removeBodyElement(be_target, true, false);

    // Add target mesh elements (back) to the source
    for (int i = 0; i < sc_info->nofSplitTargetMeshElements; i++) {

      int elem_id = be_target->getMeshElementId(i);
      short elem_dir = be_target->getMeshElementDir(i);
      int int_index = be_source->addMeshElement(elem_id, elem_dir);
      sc_info->splitTargetMeshElementSourceIndices[i] = int_index;

      meshData->boundaryElementBoundaryIds[elem_id] = sc_info->splitSourceId;
    }

    be_source->findMeshBorder();
  }

  //---If we have to UNDO a COMBINE
  else if (sc_info->nofCombineSourceIds > 0) {

    BodyElement* be_target = getBoundaryById(sc_info->combineTargetId);

    // Remove target element from the model
    removeBodyElement(be_target, true, false);

    // Add source elements (back) to the model
    for (int i = 0; i < sc_info->nofCombineSourceIds; i++) {
      BodyElement* be_source = getRemovedBodyElement(sc_info->combineSourceIds[i]);
      restoreBodyElement(be_source, true);
      be_source->findMeshBorder();
    }

  }

  //-Check body data (rebuild element loops etc.)
  checkBodies();

  //-Update model
  updateModelStatistics();

  // Update gui and graphics screen
  gui->updateBodyData(this);
  gui->updateBoundaryData(this);

  refreshRenderer();

#if 0
  // For debugging
  strstream cur_strm;
  strstream new_strm;
  cur_strm << "cur SplitCombineIndex = " << cur_index << ends;
  new_strm << "New SplitCombineIndex = " << new_index << ends;
  gui->showMsg(cur_strm.str());
  gui->showMsg(new_strm.str());
#endif

}


void
Model::startEditMeshBoundaries()
{
  modelInfo->editingMeshBoundaries = true;

  int body1_id = modelInfo->selectedBody1Id;
  int body2_id = modelInfo->selectedBody2Id;

  if (body1_id == body2_id)
    body2_id = NO_INDEX;

  // Backup all boundaries under (possible) edit
  // We will copy these back in user quit the boundaries
  // edit panel wit CANCEL
  int& nof_boundaries = modelInfo->nofEditableMeshBoundaries;
  BodyElement**& boundaries = modelInfo->editableMeshBoundaries;

  // NOTE: We allocate here editableMeshBoundaries container!!!
  getBoundaries(body1_id, body2_id, nof_boundaries, boundaries);

  for (int i = 0; i < nof_boundaries; i++) {
    boundaries[i]->backupMeshData();
  }

}


void
Model::stopEditMeshBoundaries(bool cancel_edit)
{
  // If nothing was really edited
  if (modelInfo->editingMeshBoundaries == false)
    return;

  modelInfo->editingMeshBoundaries = false;

  modelData->splitCombineInfoIndex = 0;

  // Reset split/combine info data
  for (int i = 0; i < MAX_NOF_SPLIT_COMBINE_INFOS; i++) {
    delete (*modelData->splitCombineInfos)[i];
    (*modelData->splitCombineInfos)[i] = NULL;
  }

  // If editing was cancelled, delete current boundaries
  // and restore the original from the backup
  if (cancel_edit) {
    int i;
    int nof_cur_boundaries;
    BodyElement** cur_boundaries;

    int body1_id = modelInfo->selectedBody1Id;
    int body2_id = modelInfo->selectedBody2Id;

    if (body1_id == body2_id)
      body2_id = NO_INDEX;

    getBoundaries(body1_id, body2_id, nof_cur_boundaries, cur_boundaries);

    bool update_bodies = true;

    for (i = 0; i < nof_cur_boundaries; i++) {
      removeBodyElement(cur_boundaries[i], update_bodies, true);
    }

    // Add backup elements again into the model and restore
    // their mesh data
    for (i = 0; i < modelInfo->nofEditableMeshBoundaries; i++) {

      BodyElement* be = modelInfo->editableMeshBoundaries[i];

      addBodyElement(be, update_bodies);

      // This should not be a "removed" element anymore
      modelData->removedModelElements->erase(be->Id());

      be->restoreMeshDataBackup();
    }

    Body* body1 = getBodyById(body1_id);
    Body* body2 = getBodyById(body2_id);

    body1->check();

    if (body2 != NULL)
      body2->check();

    UserInterface* gui = theControlCenter->getGui();

    gui->updateBodyData(this);
    gui->updateBoundaryData(this);

    meshData->boundaryElements->resetSelected();
    refreshRenderer();
  } // end cancel-edit mode

  // Now it is safe to purge all "removed" elements from the
  // memory
  modelData->purgeRemovedElements();
  modelData->removedModelElements = new BodyElementTable;

  delete[] modelInfo->editableMeshBoundaries;
  modelInfo->editableMeshBoundaries = NULL;
  modelInfo->nofEditableMeshBoundaries = 0;

}


void
Model::storeBoundaryNames()
{
  int index = 0;
  while(true) {
    BodyElement* be = getBoundary(index++);
    if (be==NULL) break;
    be->storeName();
  }
}


void
Model::swapBodyElements(IdArray* ids1, IdArray* ids2, IdArray* relative_dirs)
{
  int index = 0;
  while (true) {
    BodyElementLoop* bel = getBodyElementLoop(index++);
    if (bel==NULL) break;
    bel->swapElements(ids1, ids2, relative_dirs);
  }

}


void
Model::unloadMesh(char* msg)
{
  UserInterface* gui = theControlCenter->getGui();

  if (msg == NULL || msg[0] == '\0')
    gui->showMsg("Removing mesh data from the memory");
  else
    gui->showMsg(msg);

  resetMeshData();

  gui->configureMenuButtons("File", "LoadMesh", 1);
  gui->configureMenuButtons("File", "Mesh", 1);

  setWindowTitles();
}



void
Model::updateMeshDirectoryInfo()
{
  char* dir = NULL;
  char* dir_abs = NULL;
  char* dir_head = NULL;
  char* dir_head_abs = NULL;

  UserInterface* gui = theControlCenter->getGui();

  gui->getMeshDirectoryInfo(dir, dir_abs);

  update_dyna_string(modelInfo->meshDirectory, dir);
  update_dyna_string(modelInfo->meshDirectory_absolute, dir_abs);

  delete[] dir; delete[] dir_abs;
}


void
Model::setMeshFs()
{
  delete[] modelInfo->meshFs;
  modelInfo->meshFs = NULL;

  if ( modelInfo->nofMeshes == 0 )
    return;

  modelInfo->meshFs = new double[modelInfo->nofMeshes];

  // Init
  for (int i = 0; i < modelInfo->nofMeshes; i++ )
    modelInfo->meshFs[i] = 1.0;
}


void
Model::setMeshHs()
{
  delete[] modelInfo->meshHs;
  modelInfo->meshHs = NULL;

  if ( modelInfo->nofMeshes == 0 )
    return;

  modelInfo->meshHs = new double[modelInfo->nofMeshes];


  // For version 4 files we have normally only one
  // model level parameter, take mesh-h from it!
  double mesh_h;
  Parameter* param = getParameter(0, ECIF_GRID_PARAMETER);

  if ( param != NULL && param->getFieldValueBySifName("Mesh H", mesh_h) ) {

  } else {
    mesh_h = calcInitialMeshH();
  }

  // Init with same value
  for (int i = 0; i < modelInfo->nofMeshes; i++ )
    modelInfo->meshHs[i] = mesh_h;

}


void
Model::updateModelDirectoryInfo()
{
  char* dir = NULL;
  char* dir_abs = NULL;

  UserInterface* gui = theControlCenter->getGui();

  gui->getModelDirectoryInfo(dir, dir_abs);

  update_dyna_string(modelInfo->modelDirectory, dir);
  update_dyna_string(modelInfo->modelDirectory_absolute, dir_abs);

  delete[] dir; delete[] dir_abs;
}


void
Model::updateModelNameInfo()
{
  char* model_name = NULL;
  char* problem_name = NULL;

  UserInterface* gui = theControlCenter->getGui();

  gui->getModelNameInfo(model_name, problem_name);

  update_dyna_string(modelInfo->modelName, model_name);
  update_dyna_string(modelInfo->problemName, problem_name);

  delete[] model_name;
  delete[] problem_name;
}


void
Model::updateBodyForceApplyCounts()
{
  modelStatistics->nofBodiesWithBodyForce = 0;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    int param_id = body->getBodyForceId();
    if ( param_id != NO_INDEX ) {
      Parameter* param = getParameterById(ECIF_BODY_FORCE, param_id);
      if ( param != NULL ) {
        modelStatistics->nofBodiesWithBodyForce++;
        param->updateApplyCount(1);
      } else {
        body->setBodyForceId(NO_INDEX);
      }
    }
  }
}


void
Model::updateBoundaryConditionApplyCounts()
{
  modelStatistics->nofInnerBoundariesWithCondition = 0;
  modelStatistics->nofOuterBoundariesWithCondition = 0;
  modelStatistics->nofEdgesWithCondition = 0;
  modelStatistics->nofVerticesWithCondition = 0;

  bool param_found;
  int index = 0;
  while (true) {

    param_found = true;
    BodyElementGroup* beg = getBodyElementGroup(index++);

    if (beg==NULL) break;

    int param_id = beg->getBoundaryConditionId();

    Parameter* param = getParameterById(ECIF_BOUNDARY_CONDITION, param_id);

    if ( param == NULL ) {
      beg->setBoundaryConditionId(NO_INDEX);
      continue;
    }

    for (int i = 0; i < beg->getNofElements(); i++) {

      const BodyElement* be = beg->getElement(i);

      if ( be == NULL ) break;

      // For a virtual group we increse boundary counter
      // only if the element doe not have already an other
      // boundary condition
      //
      if ( beg->isVirtual() ) {

        BodyElementGroup* be_eg = (BodyElementGroup*)be->getElementGroup();

        if ( NO_INDEX != be_eg->getBoundaryConditionId() ) {
          param->updateApplyCount(1);
          continue;
        }
      }

      int bd1_tag = be->getParentTag(1);
      int bd2_tag = be->getParentTag(2);

      // Inner boundary
      if ( bd1_tag != NO_INDEX && bd2_tag != NO_INDEX ) {
        modelStatistics->nofInnerBoundariesWithCondition++;

      // Outer boundary
      } else if ( bd1_tag != NO_INDEX || bd2_tag != NO_INDEX ) {
        modelStatistics->nofOuterBoundariesWithCondition++;

      // Edge in 3D
      } else if ( OT_EDGE == be->getObjectType() ) {
        modelStatistics->nofEdgesWithCondition++;

      // Vertex
      } else  {
        modelStatistics->nofVerticesWithCondition++;
      }

      param->updateApplyCount(1);

    } // each group element

  } // each group
}


void
Model::updateBoundaries()
{
  setBoundaryTags();
}


void
Model::updateEquationApplyCounts()
{
  modelStatistics->nofBodiesWithEquation = 0;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    int eq_id = body->getEquationId();

    if ( eq_id != NO_INDEX ) {
      Parameter* param = getParameterById(ECIF_EQUATION, eq_id);
      if ( param != NULL ) {
        modelStatistics->nofBodiesWithEquation++;
        param->updateApplyCount(1);
      } else {
        body->setEquationId(NO_INDEX);
      }
    }
  }
}


// Update (Matc-dependent) geometry
//
void
Model::updateCadGeometry()
{
  // Update vertex-table points
  //
  VertexTable* vt = modelData->vertexTable;
  const char* def = getMatcString(vt->matcTable, EMF_POINTS);

  if ( vt->dim1 != 0 && def != NULL ) {

    // Evaluate Matc-string for points
    strstream strm;
    char* res = LibFront::evalMatcString(def);

    if ( res != NULL ) {
      strm << res << ends;

      // Loop points
      for (int i = 0; i < vt->dim1; i++) {

        BodyElement* v = getBodyElementById(vt->vertexIds[i]);
        GcPoint* p = (GcPoint*)v->getGeometry();
        double val;

        // Loop point coordinates
        for (int j = 0; j < vt->dim2; j++) {
          strm >> val;
          p->setPos(j, val);
        }
      }
    }
  }

  int index = 0;
  while (true) {
    BodyElement* be = getBodyElement(index++, true);
    if (be==NULL) break;

    // Error!
    if ( !be->updateGeometry() ) {
      return;
    }
  }

  // Check body data (bound boxes etc.
  checkBodies();

  // Update model statistics
  updateModelStatistics();

  // Update gui
  UserInterface* gui = theControlCenter->getGui();
  gui->updateBodyData(this);
  gui->updateBoundaryData(this);

  // Remove old display lists and update geoemtry display
  //
  Renderer* renderer = theControlCenter->getRenderer();
  if ( renderer != NULL ) {
    renderer->removeDisplayLists();
    refreshRenderer();
  }
}


void
Model::updateInitialConditionApplyCounts()
{
  modelStatistics->nofBodiesWithInitialCondition = 0;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    int param_id = body->getInitialConditionId();

    if ( param_id != NO_INDEX ) {
      Parameter* param = getParameterById(ECIF_INITIAL_CONDITION, param_id);
      if ( param != NULL ) {
        modelStatistics->nofBodiesWithInitialCondition++;
        param->updateApplyCount(1);
      } else {
        body->setInitialConditionId(NO_INDEX);
      }
    }
  }
}


bool
Model::updateMatcFile(char* filename, char* mode, int def_count, char** defs)
{
  UserInterface* gui = theControlCenter->getGui();

  // Overwrite mode
  // ==============

  // Overwrite mode, just write user definition into the file
  if ( LibFront::ncEqualPartial("w", mode ) ) {
    fstream matc_file(filename, ios::out | ios::trunc);

    for (int i = 0; i < def_count; i++) {
      matc_file << defs[i] << endl;
    }
    matc_file.close();

    return true;
  }

  // Update/append mode
  // ==================
  MatcValueTable all_defs, old_vars, old_funcs;
  NameList old_names, new_names;

  // First read all old definitions and store also variables and
  // functions in separate tables
  int comment_count = 0;
  char* source = NULL;
  char matc_buffer[10001];
  char name_buffer[256];
  bool is_var, is_func;
  LibFront::readFile(filename, source, false);

  int source_pos = 0;
  int source_len = strlen(source);

  while (source_pos < source_len ) {
    source_pos = LibFront::readMatcExpression(source, source_pos, source_len,
                                              matc_buffer, 10000,
                                              false);
    LibFront::trim(matc_buffer);

    if ( matc_buffer[0] == '\0' ) continue;

    LibFront::getMatcName(matc_buffer, name_buffer, 255, is_var, is_func);

    // Store old name
    // NOTE: Allocate new array for the name!
    char* name;

    if ( name_buffer != NULL && name_buffer[0] != '\0' ) {
      create_dyna_string(name, name_buffer);
    } else {
      strstream strm;
      strm << "comment " << ++comment_count << ends;
      create_dyna_string(name, strm.str());
    }
    old_names.push_back(name);

    // Store value
    // NOTE: Allocate new array for the value!
    char* value;
    create_dyna_string(value, matc_buffer);
    all_defs[name] =value;

    if ( is_var ) {
      old_vars[name] = "1";
    } else if ( is_var )  {
      old_funcs[name] = "1";
    }

  }

  // Next update old-defs by new defs
  for (int i = 0; i < def_count; i++) {
    LibFront::getMatcName(defs[i], name_buffer, 255, is_var, is_func);

    // A new variable cannot be an old function!
    if ( is_var && NULL != old_funcs[name_buffer] ) {
      strstream strm;
      strm << "Cannot update the Matc file!" << "\\\\n"
           << "variable: " << name_buffer << "\\\\n"
           << "already defined as a function in the file!" << ends;
      gui->errMsg(0, strm.str());
      return false;

    // A new function cannot be an old variable!
    } else if ( is_func && NULL != old_vars[name_buffer] ) {
      strstream strm;
      strm << "Cannot update the Matc file!" << "\\\\n"
           << "function: " << name_buffer << "\\\\n"
           << "already defined as a variable in the file!" << ends;
      gui->errMsg(0, strm.str());
      return false;
    }

    // NOTE: Allocate new array for the name!
    char* name;
    create_dyna_string(name, name_buffer);

    // New object: store name
    if ( NULL == all_defs[name_buffer] ) {
      new_names.push_back(name);

    // Old object: delete old value
    } else {
      delete[] all_defs[name];
    }

    // Ok, update old or add new
    // NOTE: Allocate new array for the value
    char* value;
    create_dyna_string(value, defs[i]);
    all_defs[name] = value;
  }

  // Then write all definitions to the file
  // NOTE: If a 'definition' is just the linefeed, it is
  // not actually written to file,  just lf!
  //
  fstream matc_file(filename, ios::out | ios::trunc);

  NameList::iterator itr;

  itr = old_names.begin();
  while ( itr != old_names.end() ) {
    char* nm = (*itr);
    char* def = all_defs[nm];
    if ( strlen(def) == 1 && def[0] == '\n' ) {
      matc_file << def;
    } else {
      matc_file << def << endl;
    }
    itr++;
  }

  itr = new_names.begin();
  while ( itr != new_names.end() ) {
    char* nm = (*itr);
    char* def = all_defs[nm];
    if ( strlen(def) == 1 && def[0] == '\n' ) {
      matc_file << def;
    } else {
      matc_file << def << endl;
    }
    itr++;
  }

  matc_file.close();

  purgeMatcValueTable(all_defs);
  purgeNameList(old_names);
  purgeNameList(new_names);

  return true;
}


void
Model::updateMaterialApplyCounts()
{
  modelStatistics->nofBodiesWithMaterial = 0;

  int index = 0;
  while (true) {
    Body* body = getBody(index++);
    if (body==NULL) break;
    int param_id = body->getMaterialId();

    if ( param_id != NO_INDEX ) {
      Parameter* param = getParameterById(ECIF_MATERIAL, param_id);
      if ( param != NULL ) {
        modelStatistics->nofBodiesWithMaterial++;
        param->updateApplyCount(1);
      } else {
        body->setMaterialId(NO_INDEX);
      }
    }
  }
}


void
Model::updateMinimumEdgeSize(int nof_points, GcPoint** points)
{
  for (int i = 1 ; i < nof_points; i++) {

    Point3* p1 = points[i - 1]->getPoint();
    Point3* p2 = points[i]->getPoint();

    double dist = dist3(*p1, *p2);

    if (dist < modelInfo->minEdgeSize)
      modelInfo->minEdgeSize = dist;
  }
}


void
Model::updateParametersApplyCounts(ecif_parameterType parameter_type)
{
  switch (parameter_type) {
  case ECIF_BODY_FORCE:
    updateBodyForceApplyCounts();
    break;
  case ECIF_BOUNDARY_CONDITION:
    updateBoundaryConditionApplyCounts();
    break;
  case ECIF_EQUATION:
    updateEquationApplyCounts();
    break;
  case ECIF_INITIAL_CONDITION:
    updateInitialConditionApplyCounts();
    break;
  case ECIF_MATERIAL:
    updateMaterialApplyCounts();
    break;
  }
}


// Update parent object info which is read from a emf-file
// Needed ex. for BoundaryConditions, whose parents are mainly
// normal boundaries, but in the model parents are bounadry groups
// (logical or real)
//
void
Model::updateParametersParentId()
{
  updateParametersParentId(ECIF_INITIAL_CONDITION);
  updateParametersParentId(ECIF_BOUNDARY_CONDITION);
  updateParametersParentId(ECIF_MATERIAL);
  updateParametersParentId(ECIF_BODY_FORCE);
  updateParametersParentId(ECIF_GRID_PARAMETER);
  updateParametersParentId(ECIF_GRID_H);
}


void
Model::updateParametersParentId(ecif_parameterType param_type)
{
  int index = 0;
  while (true) {
    Parameter* param = getParameter(index++, param_type);
    if (param==NULL) break;
    param->updateParentId();
  }

}


// NOTE: Used for <=4 version emf-files
//
void
Model::updateParametersParentTags()
{
  Parameter* param;
  int pid;
  int ctag;

  int index = 0;
  while (true) {

    Body* body = getBody(index++);
    if (body==NULL) break;

    pid = body->getBodyForceId();
    param = getParameterById(ECIF_BODY_FORCE, pid);
    if ( param != NULL && NO_INDEX == param->getParentEmfTag() ) {
      param->setParentEmfTag(body->Tag());
      param->setParentEmfType(OT_BODY);
    }

    pid = body->getInitialConditionId();
    param = getParameterById(ECIF_INITIAL_CONDITION, pid);
    if ( param != NULL && NO_INDEX == param->getParentEmfTag() ) {
      param->setParentEmfTag(body->Tag());
      param->setParentEmfType(OT_BODY);
    }

    pid = body->getMaterialId();
    param = getParameterById(ECIF_MATERIAL, pid);
    if ( param != NULL && NO_INDEX == param->getParentEmfTag() ) {
      param->setParentEmfTag(body->Tag());
      param->setParentEmfType(OT_BODY);
    }
  }

  index = 0;
  while (true) {

    BodyElementGroup* beg = getBodyElementGroup(index++);
    if (beg==NULL) break;

    if ( EXPLICIT_GROUP != beg->getGroupType() ) continue;

    pid = beg->getBoundaryConditionId();
    param = getParameterById(ECIF_BOUNDARY_CONDITION, pid);
    if ( param != NULL &&
         ( NO_INDEX == param->getParentEmfTag() ||
           OT_BODY == param->getParentEmfType()
         )
         ) {
      param->setParentEmfTag(beg->Tag());
      param->setParentEmfType(beg->getObjectType());
    }
  }

  index = 0;
  while (true) {

    BodyElement* be = getBodyElement(index++);
    if (be==NULL) break;

    pid = be->getBoundaryConditionId();
    param = getParameterById(ECIF_BOUNDARY_CONDITION, pid);
    if ( param != NULL &&
         ( NO_INDEX == param->getParentEmfTag() ||
           OT_BODY == param->getParentEmfType()
         )
         ) {
      param->setParentEmfTag(be->Tag());
      param->setParentEmfType(be->getObjectType());
    }
  }
}


void
Model::variableNameGuiToSif(const char* gui_name, char* sif_name_buffer)
{
  theControlCenter->getUI()->variableNameGuiToSif(gui_name, sif_name_buffer);
}


void
Model::variableNameSifToGui(const char* sif_name, char* gui_name_buffer)
{
  theControlCenter->getUI()->variableNameSifToGui(sif_name, gui_name_buffer);
}



// **********************
//   STL etc. utilities
// **********************

int
find2(Ids2Set& id_set, int key1)
{
  Ids2Set::iterator pos;
  pos = id_set.begin();
  while (pos != id_set.end()) {
    Ids2 ids = *pos++;
    if (ids.id1 < key1)
      continue;
    else if (ids.id1 == key1)
      return ids.id2;
    else
      return NO_INDEX;
  }

  return NO_INDEX;
}


int
find3(Ids3Set& id_set, int key1, int key2)
{
  Ids3Set::iterator pos;
  pos = id_set.begin();
  while (pos != id_set.end()) {
    Ids3 ids = *pos++;
    if (ids.id1 < key1)
      continue;
    else if (ids.id1 == key1 && ids.id2 < key2 )
      continue;
    else if (ids.id1 == key1 && ids.id2 == key2)
      return ids.id3;
    else
      return NO_INDEX;
  }

  return NO_INDEX;
}


// Get Matc-expression string using a name-key
// NOTE: An empty definition is returned as a NULL-string
//
const char*
getMatcString(MatcValueTable& table, const char* key)
{
  char* val = table[key];

  if ( val == NULL || val[0] == '\0' ) {
    return NULL;
  } else {
    return val;
  }
}


// Store Matc-expression string using a name-key
// NOTE: An empty definition will nullify a possible older
// definition
//
void
storeMatcString(MatcValueTable& table, const char* key, const char* value)
{
  // Delete a possible old definition
  char* old_val = table[key];
  if ( old_val != NULL ) {
    delete[] old_val;
    table.erase(key);
  }

  // Create new definition string if a non-empty
  // matc-definition given
  //
  char* str = NULL;

  // If non-empty value given
  if ( value != NULL && strlen(value) > 1 ) {

    char* new_val;
    const char* work = value;
    
    // Remove possible leading $-sign
    //
    if ( work[0] == '$' ) {
      work++;
    }

    // Allocate str and copy tmp
    create_dyna_string(new_val, work);

    // Store key/value pair
    table[key] = new_val;
  }
}


// Copy any Matc-expression string from one table to an other
//
void
copyMatcValueTable(MatcValueTable& source, MatcValueTable& target)
{
  MatcValueTable::iterator pos = source.begin();
  MatcValueTable::iterator end_pos = source.end();

  while ( pos != end_pos ) {

    // Pick value
    const char* key = (*pos).first.c_str();
    char* val = (*pos).second;

    // Delete possible old value
    char* old_val = target[key];
    if ( old_val != NULL ) {
      delete[] old_val;
      target.erase(key);
    }

    // Create new value
    char* new_val;
    create_dyna_string(new_val, val);

    // Store new value using the key
    target[key] = new_val;

    pos++;
  }
}


// Delete values from the Matc value table and clear it
//
// NOTE: Use this only if values (char*) are allocated with new!!!
//
void
purgeMatcValueTable(MatcValueTable& table)
{
  MatcValueTable::iterator pos = table.begin();
  MatcValueTable::iterator end_pos = table.end();

  while (pos != end_pos) {
    delete[] (*pos).second;
    pos++;
  }
  table.clear();
}


// Delete values from a name list and clear it
//
// NOTE: Use this only if values (char*) are allocated with new!!!
//
void
purgeNameList(NameList& list)
{
  NameList::iterator pos = list.begin();
  NameList::iterator end_pos = list.end();

  while (pos != end_pos) {
    delete[] (*pos);
    pos++;
  }
  list.clear();
}


// Delete values from a name table and clear it
//
// NOTE: Use this only if values (char*) are allocated with new!!!
//
void
purgeNameTable(NameTable& table)
{
  NameTable::iterator pos = table.begin();
  NameTable::iterator end_pos = table.end();

  while (pos != end_pos) {
    delete[] (*pos).second;
    pos++;
  }
  table.clear();
}



// Array reallocate functions
// ==========================

void
reallocate_array(int old_size, int new_size, int*& array, int default_value)
{
  reallocate_array_impl1(old_size, new_size, array, default_value);
}

void
reallocate_array(int old_size, int new_size, char**& array, char* default_value)
{
  reallocate_array_impl2(old_size, new_size, array, default_value);
}

void
reallocate_array(int old_size, int new_size, int**& array, int* default_value)
{
  reallocate_array_impl2(old_size, new_size, array, default_value);
}

void
reallocate_array(int old_size, int new_size, BoundBox**& array)
{
  reallocate_array_impl3(old_size, new_size, array);
}

void
reallocate_array(int old_size, int new_size, BodyElementTable**& array)
{
  reallocate_array_impl3(old_size, new_size, array);
}

void
reallocate_array(int old_size, int new_size, IdList**& array)
{
  reallocate_array_impl3(old_size, new_size, array);
}

void
reallocate_array(int old_size, int new_size, IdArray**& array)
{
  reallocate_array_impl3(old_size, new_size, array);
}


// Implmentation of the template functions
// ---------------------------------------


// Function reallocates an object array and sets a default value for
// new entries
//
template <class T > void
reallocate_array_impl1(int old_size, int new_size, T*& array, T default_value)
{
  int i;
  T* new_array = new T[new_size];

  for (i = 0; i < old_size; i++) {
    new_array[i] = array[i];
  }

  for (i = old_size; i < new_size; i++) {
    new_array[i] = default_value;
  }

  delete[] array;

  array = new_array;
}


// Function reallocates an object array and sets a pointer default value for
// new entries
//
template <class T > void
reallocate_array_impl2(int old_size, int new_size, T**& array, T* default_value)
{
  int i;
  T** new_array = new T*[new_size];

  for (i = 0; i < old_size; i++) {
    new_array[i] = array[i];
  }

  for (i = old_size; i < new_size; i++) {
    new_array[i] = default_value;
  }

  delete[] array;

  array = new_array;
}


// Function reallocates an object array and allocates objects for
// new entries
//
template <class T > void
reallocate_array_impl3(int old_size, int new_size, T**& array)
{
  int i;
  T** new_array = new T*[new_size];

  for (i = 0; i < old_size; i++) {
    new_array[i] = array[i];
  }

  for (i = old_size; i < new_size; i++) {
    new_array[i] = new T;
  }

  delete[] array;

  array = new_array;
}


syntax highlighted by Code2HTML, v. 0.9.1