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

Abstract:   Implementation

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

#include "ecif_body.h"
#include "ecif_bodyLayer.h"
#include "ecif_bodyElement.h"
#include "ecif_bodyElement2D.h"
#include "ecif_bodyElement3D.h"
#include "ecif_bodyElementGroup.h"
#include "ecif_bodyElementLoop.h"
#include "ecif_mesh.h"
#include "ecif_model.h"
#include "ecif_parameter.h"
#include "ecif_parameterField.h"
#include "ecif_renderer.h"
#include "ecif_userinterface.h"

//Initialize static class variables.
int BodyPair::last_tag = 0;
int Body::last_tag = 0;


// BodyPair class
// ==============

BodyPair::BodyPair()
{
  id = NO_INDEX;
  tag = NO_INDEX;
  init();
}


BodyPair::BodyPair( const Body* bd1, const Body* bd2)
{
  id = NO_INDEX;
  tag = NO_INDEX;
  init();

  body1 = bd1;
  body2 = bd2;
}



BodyPair::BodyPair(int int_tag, const Body* bd1, const Body* bd2)
{
  tag = int_tag;

  init();

  body1 = bd1;
  body2 = bd2;

  if (last_tag < tag)
    last_tag = tag;
}


BodyPair::~BodyPair()
{
}


const char*
BodyPair::getName()
{
  strstream strm;
  strm << ((Body*)body1)->getName() << "-" << ((Body*)body2)->getName() << ends;
  return strm.str();
}


void
BodyPair::init()
{
  body1 = NULL;
  body2 = NULL;
}


void
BodyPair::initClass(Model* mdl)
{
  BodyPair::model = mdl;
  BodyPair::last_tag = 0;
}


int
BodyPair::setTag()
{
  tag = ++last_tag;

  return tag;
}


int
BodyPair::setId()
{
  model->addModelObject(this, OT_BODYPAIR);

  return Id();
}




// Body class
// ==========

Body::Body()
{
  tag = ++last_tag;
  init();
}


Body::Body(bodyGmtrType gmtr_type, int ext_tag, char* body_name, colorIndices color_index)
{
  tag = ++last_tag;

  init();

  colorIndex = color_index;
  for (int i = 0; i < 4; i++)
    color[i] = colorValues[colorIndex][i];

  externalTag = ext_tag;

  update_dyna_string(name, body_name);

  gmtrType = gmtr_type;
}



Body::Body(bodyGmtrType gmtr_type, int int_tag, int ext_tag, char* body_name, colorIndices color_index)
{
  tag = int_tag;

  if (last_tag < tag) {
    last_tag = tag;
  }

  init();

  colorIndex = color_index;
  for (int i = 0; i < 4; i++)
    color[i] = colorValues[colorIndex][i];

  externalTag = ext_tag;

  update_dyna_string(name, body_name);

  gmtrType = gmtr_type;
}


Body::Body(ecif_Body_X& tx, bool add_default_layer)
{
  tag = tx.tag;

  if (last_tag < tag) {
    last_tag = tag;
  }

  init(add_default_layer);

  int i;

  if ( tx.has_color ) {
    colorIndex = ef_nodefault;
    for (i = 0; i < 4; i++)
      color[i] = tx.color[i];

  } else {
    colorIndex = DEFAULT_COLOR_INDEX;
  }

  update_dyna_string(name, tx.name);

  bodyForceId = tx.body_force_id;
  bodyParameterId = tx.body_param_id;
  equationId = tx.equation_id;
  initialConditionId = tx.init_cond_id;
  materialId = tx.material_id;

  if (tx.is_checked) {
    status = true;
    checked = true;
  }


  if ( tx.is_open ) {
    tplgType = OPEN_BODY;
  }

  if ( tx.is_bem ) {
    type = BEM_BODY;

  } else if ( tx.is_virtual ) {
    type = VIRTUAL_BODY;
    drawMode = DM_HIDDEN;
  }


}


Body::~Body()
{
  removeLayers();

  removeElementGroups();

  delete boundbox;
  delete boundboxMesh;

  delete[] meshElementIds;
}


// Basic version which just creates the loop of elements without
// checking their orientation or connectivity.
// Used mainly for mesh-based boundaries for which checking is not relevant
// Return true if body is ok, otherwise false.
//
bool
Body::check()
{
  // NOTE: Virtual bodies are checked separately, because their
  // possible pending edges must be inserted into a virtual group!!
  //
  if ( isVirtual() ) {
    return checkVirtual();
  }

  if (nofLayers == 0) return false;

  initName();

  int layer = -1;
  while (true) {

    if (!selectLayer(++layer)) break;

    addAllPendingVertices(layer);
    addAllPendingElements(layer);

    checked = true;

    nofElements[layer] = belements[layer]->size();

    // We do not have yet any elements!
    if (nofElements[layer] == 0 ) {

      // If even no loops, something is really wrong!
      if (nofElementLoops[layer] == 0) {
        status = false;
        return false;

      // Element ids should be in the loops
      } else if ( !addAllLoopElements(layer) ) {
        status = false;
        return false;
      }
    }

    nofElements[layer] = belements[layer]->size();

    // If still no elements, something is wrong!!!
    if (nofElements[layer] == 0 ) {
      status = false;
      return false;
    }

    // NOTE: Currently we don't check the orientation of real loops (like
    // a cube inside a cube !!!***!!!
    // we just put all existing elements to ONE SINGLE LOOP !!!
    //
    // So this is meant for: mesh bodies, open bodies

    // Create (one) new loop from all elements
    // =======================================
    status = false;
    removeElementLoops(layer);

    int nofFreeElements = nofElements[layer];

    while (nofFreeElements > 0) {

      // Create one element loop
      int be_index = 0;

      IdList elementLoop;
      BodyElement* be = getElement(layer, be_index++);

      while (be) {
        nofFreeElements--;
        elementLoop.push_back(be->Id());
        be = getElement(layer, be_index++);
      }

      BodyElementLoop* bel = new BodyElementLoop(&elementLoop, false, OT_BOUNDARY);

      // Store loop in the model
      model->addBodyElementLoop(bel);

      // Store loop info also in the body
      int bid = bel->Id();
      elementLoopIds[layer]->push_back(bel->Id());
      elementLoopTags[layer]->push_back(bel->Tag());
      nofElementLoops[layer]++;
    }

  } // All layers


  status = true;
  return true;
}


bool
Body::checkLayerIndex(int layer)
{
  if ( layer < 0 || layer >= nofLayers ) return false;
  return true;
}


// Basic version which just creates the loop of elements without
// checking their orientation or connectivity.
// Used mainly for mesh-based boundaries for which checking is not relevant
// Return true if body is ok, otherwise false.
//
bool
Body::checkVirtual()
{
  if (nofLayers == 0) return false;

  initName();

  int layer = -1;
  while (true) {

    if (!selectLayer(++layer)) break;

    checked = true;

    addAllPendingVertices(layer);
    addAllPendingElements(layer);

    nofElements[layer] = belements[layer]->size();

    // We do not have yet any elements!
    if (nofElements[layer] == 0 ) {

      // If even no loops, something is really wrong!
      if (nofElementLoops[layer] == 0) {
        status = false;
        return false;

      // Element ids should be in the loops
      } else if ( !addAllLoopElements(layer) ) {
        status = false;
        return false;
      }
    }

    nofElements[layer] = belements[layer]->size();

    // If still no elements, something is wrong!!!
    if (nofElements[layer] == 0 ) {
      status = false;
      return false;
    }

    int be_count = 0;
    int* be_ids = NULL;
    int* be_tgs = NULL;

    getElementIds(layer, be_count, be_ids);
    getElementTags(layer, be_count, be_tgs);

    // Group eleemnt type by th efirst element!
    BodyElement* be = getElement(layer, 0);

    BodyElementGroup* beg = new BodyElementGroup();
    beg->setElementIdsAndTags(be_count, be_ids, be_tgs);
    beg->setType(VIRTUAL_GROUP);
    beg->setElementType(be->getObjectType());
    beg->setParentId(1, id);
    beg->setParentTag(1, tag);
    beg->setName((char*)getName(layer));

    delete[] be_ids;
    delete[] be_tgs;

  } // All layers


  status = true;
  return true;
}


// NOTE: For a virtual body only!
//
bool
Body:: addElementGroupTag(int group_tag)
{
  nofElementGroups += 1;

  elementGroupTags->push_back(group_tag);
  elementGroupIds->push_back(NO_INDEX);

  return true;
}


// NOTE: For a virtual body only!
//
bool
Body:: addElementGroupTags(int nof_groups, int* group_tags)
{
  nofElementGroups += nof_groups;

  for(int i = 0; i < nof_groups; i++) {
    elementGroupTags->push_back(group_tags[i]);
    elementGroupIds->push_back(NO_INDEX);
  }

  return true;
}


bool
Body:: addElementLoopTags(int layer, int nof_loops, int* loop_tags)
{
  if (!checkLayerIndex(layer)) return false;

  nofElementLoops[layer] += nof_loops;

  for(int i = 0; i < nof_loops; i++) {
    elementLoopTags[layer]->push_back(loop_tags[i]);
    elementLoopIds[layer]->push_back(NO_INDEX);
  }

  return true;
}



// Add all elements from all bodyelement loops in the body
// NOTE: This should be used only when elements are not
// added directly to the body.
// Returns true if success
bool
Body::addAllLoopElements(int layer)
{
  if (!checkLayerIndex(layer)) return false;

  UserInterface* gui = (UserInterface*)model->getGui();

  IdList::iterator id_beg = elementLoopIds[layer]->begin();
  IdList::iterator id_end = elementLoopIds[layer]->end();

  IdList::iterator tg_beg = elementLoopTags[layer]->begin();
  IdList::iterator tg_end = elementLoopTags[layer]->end();

  IdList::iterator id_itr;
  IdList::iterator tg_itr;

  DirectedBodyElement d_be;

  bool is_first_loop = true;

  // All body element loops
  for (id_itr=id_beg,tg_itr=tg_beg; id_itr != id_end; id_itr++,tg_itr++) {

    int bel_id = *id_itr;
    int bel_tg = *tg_itr;

    bel_id = (bel_id < 0) ? -bel_id : bel_id;

    BodyElementLoop* bel = model->getBodyElementLoopById(bel_id);

    if ( bel == NULL ) {

      strstream strm1, strm2;
      strm1 << "***ERROR in geometry for the body " << tag << ":" << ends;
      strm2 << "---Element loop " << bel_tg << " not defined in the input!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str(), 1);

      return false;
    }


    // All elements in the loop
    int index =0;
    while (true) {

      bel->getElement(index++, d_be);
      BodyElement* be = d_be.element;

      if (be==NULL) break;

      bool add = true;

      // If element already in the body
      if ( NULL != getElementById(layer, be->Id()) ) {

        // Outermost loop cannot contain multiple elements
        if ( is_first_loop ) {
          strstream strm1, strm2;
          strm1 << "***ERROR in geometry for the body " << tag << ":" << ends;
          strm2 << "---Element " << be->Tag() << " included more than once!" << ends;
          gui->showMsg(strm1.str());
          gui->showMsg(strm2.str(), 1);
          return false;

        // Inner loops could introduce same elements many times, but these
        // must be inner boundaries and they are not accepted
        } else {
          removeElement(layer, be);
          add = false;
        }
      }

      if ( add ) {
        addElement(layer, be);
      }

    } // all elements in the loop

    is_first_loop = false;

  } // all loops

  return true;
}


// Add all pending element ids
// Returns nof elements added
int
Body::addAllPendingElements(int layer)
{
  if (!checkLayerIndex(layer)) return false;

  int nof_elements = 0;

  for (int i = 0; i < pendingElementTags[layer]->size(); i++) {

    // Read and remove last element
    int be_tag = (*pendingElementTags[layer])[i];

    BodyElement* be = model->getBoundaryByTag(be_tag);

    if (be != NULL) {
      addElement(layer, be);
      nof_elements++;
    }
  }

  pendingElementTags[layer]->clear();

  return nof_elements;
}


// NOTE: Take care that bodies are
// checked (method check()) after calling
// this method (before body is really used) !!!
//
// Otherwise body's state is not ok. Especially
// element is NOT yet inserted to any bodyElement
// loop here!!!
//
int
Body::addElement(int layer, BodyElement* be)
{
  if (!checkLayerIndex(layer)) return 0;

  BodyElementTable* elements = belements[layer];

  RangeVector rv;

  (*elements)[be->Id()] = be;

  nofElements[layer]++;

  if ( !be->getRangeVector(rv) )
    return 0;

  updateBoundBox(layer, rv);

  return 0;
}


// "Add" layer by allocating more space to layer-related arries
int
Body::addLayer(ecif_BodyLayer_X& tx)
{
  int old_count = nofLayers++;

  reallocate_array(old_count, nofLayers, layerIds, NO_INDEX);
  reallocate_array(old_count, nofLayers, boundboxes);
  reallocate_array(old_count, nofLayers, belements);
  reallocate_array(old_count, nofLayers, pendingElementTags);
  reallocate_array(old_count, nofLayers, pendingVertexGroups);
  reallocate_array(old_count, nofLayers, pendingVertexTags);
  reallocate_array(old_count, nofLayers, elementLoopIds);
  reallocate_array(old_count, nofLayers, elementLoopTags);
  reallocate_array(old_count, nofLayers, nofElements, 0);
  reallocate_array(old_count, nofLayers, nofElementLoops, 0);
  reallocate_array(old_count, nofLayers, nofInnerBoundaries, 0);
  reallocate_array(old_count, nofLayers, nofOuterBoundaries, 0);

  // Create new model object layer
  BodyLayer* lr = new BodyLayer(tx);

  // If body is declared open, all layers must
  // be open!
  //
  if ( isOpen() ) {
    lr->setTplgType(OPEN_LAYER);
  }

  layerIds[nofLayers-1] = lr->Id();

  return nofLayers;
}


int
Body::addMeshElements(int nof_new_elements, int* new_element_ids)
{
  int new_size = nofMeshElements + nof_new_elements;

  // Allocate new table
  int* new_ids = new int[new_size];

  // Copy old ids
  for (int i = 0; i < nofMeshElements; i++)
    new_ids[i] = meshElementIds[i];

  // Add new ids
  for (int j = 0; j < nof_new_elements; j++)
    new_ids[nofMeshElements + j] = new_element_ids[j];

  // Update info
  nofMeshElements = new_size;
  delete[] meshElementIds;
  meshElementIds = new_ids;

  return nofMeshElements;
}


// NOTE: Take care that pending elements tags are
// finally added as element ids to the body
//
int
Body::addPendingElement(int layer, int element_tag)
{
  if (!checkLayerIndex(layer)) return 0;

  pendingElementTags[layer]->push_back(element_tag);

  return 0;
}


// NOTE: Take care that pending vertices are
// finally added as an element to the body
//
int
Body::addPendingVertex(int layer, int layer_id, int vertex_tag)
{
  if (!checkLayerIndex(layer)) return 0;

  pendingVertexGroups[layer]->push_back(layer_id);
  pendingVertexTags[layer]->push_back(vertex_tag);

  return 0;
}


ecif_modelStatus
Body::checkStatus()
{
  ecif_modelStatus body_status = STATUS_OK;

  int equationId = getEquationId();
  int materialId = getMaterialId();

  if (equationId == NO_INDEX) {
    body_status |= BODY_EQUATION_MISSING;
  }

  if (materialId == NO_INDEX) {
    body_status |= BODY_MATERIAL_MISSING;
  } else {
    Parameter* material = model->getParameterById(ECIF_MATERIAL, materialId);
    if (material != NULL) {
      body_status |= material->checkStatus();
    }
  }
  return body_status;
}


bool
Body::convertTags2Ids()
{
  UserInterface* gui = (UserInterface*)model->getGui();
  strstream strm1, strm2;

  int i,j;

  IdList::iterator id_itr;
  IdList::iterator tg_itr;

  // Layer level data
  //
  for (i = 0; i < nofLayers; i++) {

    // Element loop tags to ids
    id_itr = (elementLoopIds[i])->begin();
    tg_itr = (elementLoopTags[i])->begin();

    for (j = 0; j < nofElementLoops[i]; j++, id_itr++,tg_itr++) {

      int bel_tag = *tg_itr;

      int sign = (bel_tag < 0)?-1:1;

      BodyElementLoop* bel = model->getBodyElementLoopByTag(sign * bel_tag);

      // Tags are stored unsigned!
      *tg_itr = sign * bel_tag;

      // Ids are stored signed!
      if ( bel != NULL ) {
        *id_itr = sign * bel->Id();
      } else {
        *id_itr = NO_INDEX;
        strm1 << "***ERROR in geometry for the body " << tag << ":" << ends;
        strm2 << "---Edge loop " << bel_tag << " not defined in the input!" << ends;
        gui->showMsg(strm1.str());
        gui->showMsg(strm2.str(), 1);
        return false;
      }
    }

  } // all layers


  // Element grops (virtual body stuff)
  //
  id_itr = elementGroupIds->begin();
  tg_itr = elementGroupTags->begin();

  for (i = 0; i < nofElementGroups; i++, id_itr++,tg_itr++) {

    int eg_tag = *tg_itr;

    BodyElementGroup* eg = model->getBodyElementGroupByTag(eg_tag);

    if ( eg != NULL ) {
      *id_itr = eg->Id();

      // ERROR if this is not a virtual group
      if ( !eg->isVirtual() ) {
        strm1 << "***ERROR in geometry for the virtual body " << tag << ":" << ends;
        strm2 << "---Edge group " << eg_tag << " should be virtual (Type=Virtual)!" << ends;
        gui->showMsg(strm1.str());
        gui->showMsg(strm2.str(), 1);
        return false;
      }

      // Set parent body info
      eg->setParentId(1, id);
      eg->setParentTag(1, tag);

    } else {
      *id_itr = NO_INDEX;
      strm1 << "***ERROR in geometry for Body " << tag << ":" << ends;
      strm2 << "---Edge group " << eg_tag << " not defined in the input!" << ends;
      gui->showMsg(strm1.str());
      gui->showMsg(strm2.str(), 1);
      return false;
    }
  } // all element groups

  return true;
}


void
Body::deleteMeshElements()
{
  delete[] meshElementIds;
  meshElementIds = NULL;
  nofMeshElements = 0;
}


void
Body::calcMeshBox()
{
  MeshElementTable* bulks = model->getMeshBulkElements();
  Point3* nodes = model->getMeshNodeData();

  RangeVector rv;
  rv[0] = rv[2] = rv[4] = MAX_RANGE;
  rv[1] = rv[3] = rv[5] = MIN_RANGE;

  // Loop all mesh elements
  for (int i = 0; i < nofMeshElements; i++) {
    int elem_id = meshElementIds[i];

    // Pick mesh element nodes
    meshElementCode elem_code = bulks->getElementCode(elem_id);
    const int* node_ids = bulks->getNodeIds(elem_id);
    short nof_nodes = MeshElementDesc[elem_code][DESC_NOF_NODES];

    // Loop all nodes in the mesh element
    for (short j = 0; j < nof_nodes; j++) {
      int node_id = node_ids[j];
      double* point = nodes[node_id];
      double x = point[0];
      double y = point[1];
      double z = point[2];
      if (x < rv[0])
        rv[0] = x;
      if (x > rv[1])
        rv[1] = x;
      if (y < rv[2])
        rv[2] = y;
      if (y > rv[3])
        rv[3] = y;
      if (z < rv[4])
        rv[4] = z;
      if (z > rv[5])
        rv[5] = z;
    }
  }

  // If no cad geometry, use mesh dimensions
  // body's boundbox
  if (gmtrType == MESH_BODY) {
    boundbox->extendByRange(rv);
  }

  boundboxMesh->extendByRange(rv);
}


bool
Body::canHaveZeroVelocityElements()
{
  int equationId = getEquationId();

  if ( equationId == NO_INDEX ) {
    return false;
  }

  Parameter* eq = model->getParameterById(ECIF_EQUATION, equationId);

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

  ParameterField* pf = eq->getFieldBySifName("Navier-Stokes");

  if ( pf != NULL ) {
    char** data = pf->getDataStrings();

    if ( LibFront::ncEqual((char*)data[0], "true") ) {
      return true;
    }
  }

  return false;
}


bool
Body::checkElements()
{
  BodyElementList devided_elements;
  BodyElementList covering_elements;
  IdList covering_ids;

  int layer = 0;

  if (!selectLayer(layer)) return false;

  while (true) {

    // First check outer boundaries which
    // have "hanging" components to be created
    int be_index = 0;
    BodyElement* be = getElement(layer, be_index++);

    while (be) {

      if ( !(be->getStatus() & BE_DEVIDED) ) {
        be = getElement(layer, be_index++ );
        continue;
      }

      devided_elements.push_back(be);

      covering_ids.clear();

      if ( !model->getCoveringElementList(be->Id(), covering_ids) ) {
        be = getElement(layer, be_index++);
        continue;
      }

      while (!covering_ids.empty()) {

        int ce_id = covering_ids.front();
        covering_ids.pop_front();

        ce_id = ( ce_id < 0)?-ce_id:ce_id;

        BodyElement* ce = model->getBodyElementById(ce_id);

        if ( ce != NULL ) {
          covering_elements.push_back(ce);
        }
      }

      be = getElement(layer, be_index++);
    }

    while (!devided_elements.empty()) {
      removeElement(layer, devided_elements.front() );
      devided_elements.pop_front();
    }

    while ( !covering_elements.empty() ) {
      addElement(layer, covering_elements.front() );
      covering_elements.pop_front();
    }

    if (!selectLayer(++layer)) break;
  }

  return true;
}


void
Body::draw(Renderer* renderer, flagName geometry_type, objectDrawingMode dmode)
{
  if ( isVirtual() ) return;

  int i, idx;

  // Check if this body is possibly excluded from meshing
  int layer = 0;

  if (!selectLayer(layer)) return;

  bool mesh_excluded = isExcludedFromCurrentMesh(layer);

  // Draw bulk elements' mesh
  if ( geometry_type == DRAW_SOURCE_MESH &&
       model->getFlagValue(DRAW_TARGET_BODIES) &&
       !mesh_excluded
     ) {
    drawMesh(renderer);
    return;
  }

  renderer->name_save(id);

  // Draw all bodyelements of the body in counter-clock-wise order.
  // This is how OpenGL thinks.
  // NOTE: originally elements are thought to be in ccw
  // If body is stored in ccw-order, then *loopDirection* = 1 (cw = -1).
  // So the way we read *edgeLoop* depends on attribute *loopDirection*.
  // If it is negative, then bodyelements are in cw-direction in the elementloop
  // and we must start from the end of loop.    !!!***!!!
  int loopDirection;
  DirectedBodyElement d_be;

  for (layer = 0; layer <  nofLayers; layer++) {

    IdList::iterator beg = (elementLoopIds[layer])->begin();
    IdList::iterator end = (elementLoopIds[layer])->end();

    BodyLayer* lr = getLayer(layer);

    if ( lr == NULL ) continue;

    int lid = lr->Id();

    renderer->name_save(lid);

    int disp_list_id = OBJECT_DISPLAY_LIST_BASE + lid;

    bool creating_display_list = false;

    bool drawing_cad_body = geometry_type == DRAW_SOURCE_CAD &&
                            !lr->isOpen() &&
                            dmode == DM_NORMAL;

    // Set display list stuff
    //
    if ( drawing_cad_body ) {

      if ( renderer->hasDisplayList(disp_list_id) ) {
        renderer->useDisplayList(disp_list_id);
        //renderer->name_delete(id);
        //return;

      } else {
        renderer->startDisplayList(disp_list_id);
        creating_display_list = true;
      }
    }

    // If body starts with a multi-geometry element, we have to draw each component
    // as separate 'body'!
    //
    BodyElementLoop* bel = getElementLoop(layer, 0);

    if ( bel == NULL )continue;

    BodyElement* be = bel->getElement(0);

    if ( be == NULL ) continue;

    int cmp_count = be->getNofComponents();

    for ( idx = 0; idx < cmp_count; idx++) {

      if ( drawing_cad_body ) {
        renderer->startDrawingCadBody();
      }

      // Loop all body element loops in the body layer
      //
      bool is_first_loop = true;

      for (IdList::iterator itr = beg; itr != end; itr++) {

        int bel_id = *itr;

        if ( bel_id < 0 )
          loopDirection = -1;
        else
          loopDirection = 1;

        BodyElementLoop* bel = model->getBodyElementLoopById(loopDirection * bel_id);

        // Pre-loop processing
        //
        if ( drawing_cad_body ) {
          renderer->startDrawingCadBodyElementLoop(is_first_loop);
        }

        // Draw all elements in the loop
        //
        int be_index;
        if ( loopDirection == 1 ) {
          be_index = 0;
        } else {
          be_index = bel->getNofElements() - 1;
        }

        while (true) {

          if ( loopDirection == 1 ) {
            bel->getElement(be_index++, d_be);
          } else {
            bel->getElement(be_index--, d_be);
          }

          BodyElement* be = d_be.element;
          bool mode_changed = false;

          if (be==NULL) break;

          // Let's make the final decision concerning bodyelement's ccw-direction
          // If it is in ccw-direction, we set: sign = 1.
          int direction = loopDirection * d_be.direction;

          objectDrawingMode be_dm = be->getDrawMode();

          if ( be_dm == DM_HIDDEN ) continue;

          // If wireframe mode is needed for this layer
          if ( !drawing_cad_body ||
               lr->isOpen() ||
               (geometry_type == DRAW_SOURCE_MESH && mesh_excluded)
             ) {

            objectDrawingState be_ds = be->getDrawState();

            if ( be_ds != DS_SELECTED ) {
              mode_changed = true;
              be->setDrawMode(DM_WIREFRAME);
            }
          }

          // Draw one body element
          //
          // If a 'mid' element has multi-geometry, we havet to draw them all
          // here (this is possible because their 'inner' components are not
          // visible at this level (they would be visible only ig tje element
          // were the first in the body)!
          //
          if ( cmp_count > 1 ) {
            be->draw(idx, renderer, geometry_type, id, direction, is_first_loop);

          } else {
            int  ccount = be->getNofComponents();
            for (i = 0; i < ccount; i++) {
              be->draw(i, renderer, geometry_type, id, direction, is_first_loop);
              if ( drawing_cad_body && i < ccount - 1 ) {
                renderer->stopDrawingCadBodyElementLoop();
                renderer->startDrawingCadBodyElementLoop(is_first_loop);
              }
            }
          }

          // Restore the original mode if changed for wireframe
          if ( mode_changed ) {
            be->setDrawMode(be_dm);
          }

        } //-All elements in the loop

        is_first_loop = false;

        // Post-loop processing
        if ( drawing_cad_body ) {
          renderer->stopDrawingCadBodyElementLoop();
        }

      } //-All loops in the layer

      if ( drawing_cad_body ) {
        renderer->stopDrawingCadBody();
      }

    } // By geometry component

    if ( creating_display_list ) {
     renderer->stopDisplayList(disp_list_id);
    }

    renderer->name_delete(lid);

  } //-All layer in the body

  renderer->name_delete(id);
}


void
Body::drawMesh(Renderer* renderer)
{
  if (nofMeshElements == 0) return;

  renderer->setLightUndirected();

  renderer->name_save(id);
  renderer->name_save(0); // Space for possible fem element id

  const Point3* node_data = model->getMeshNodeData();
  MeshElementTable* bt = model->getMeshBulkElements();
  //MeshElementTable* et = model->getMeshBulkElementEdges();

  int index;
  bool selected;

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

    index = meshElementIds[i];

    selected = false;

    if (drawState == DS_SELECTED && bt->selected[index]) {
      selected = true;
    }

    // Bulk elements are always drawn as wireframe!
    bt->drawEdges(renderer, node_data, index, selected);
  }

  renderer->name_delete(0);
  renderer->name_delete(id);

  renderer->setLightDirected();
}


#if 0
void
Body::drawMesh(Renderer* renderer)
{
  if (nofFemElements == 0)
    return;

  renderer->name_save(id);
  renderer->name_save(0);

  MeshBulkElementTable* elements = model->getMeshBulkElements();
  Point3* node_data = model->getMeshNodeData();

  for (int i = 0; i < nofFemElements; i++) {
    int index = femElementIds[i];
    int elem_code = elements->element_codes[index];
    int elem_type = MeshElementDesc[elem_code][DESC_ELEM_CODE];
    int* elem_nodes = elements->node_ids[index];

    // If body is selected, we store also
    // fem element ids
    if (drawMode == SELECTED) {
      renderer->name_replace(index);
    }

    objectDisplayMode display_mode;
    if ( elements->selected[index] )
      display_mode = HIGHLITED;
    else
      display_mode = NORMAL_DISPLAY;

    renderer->drawMeshBulkElement(elem_type, elem_nodes,
                                  display_mode, node_data);
  }

  renderer->name_delete(0);
  renderer->name_delete(id);
}
#endif


int
Body::getBodyForceId()
{
  return bodyForceId;
}


BodyLayer*
Body::getBodyLayer(int layer)
{
  if (!checkLayerIndex(layer)) return NULL;

  return model->getBodyLayerById(layerIds[layer]);
}


BoundBox*
Body::getBoundBox(int layer)
{
  if (!checkLayerIndex(layer)) return NULL;

  return boundboxes[layer];
}

// Int color coding
void
Body::getColor(Color4& clr)
{
  for (int i = 0; i < 4; i++)
    clr[i] = color[i];
}

// Float color coding
void
Body::getColor(Color4f& clr)
{
  for (int i = 0; i < 4; i++)
    clr[i] = float(color[i])/MAX_NOF_COLOR_LEVELS;
}


int
Body::getDirectedElementLoopId(int layer, int index)
{
  if (!checkLayerIndex(layer)) return 0;

  if ( index >= elementLoopIds[layer]->size() ) return 0;

  IdList::iterator itr = elementLoopIds[layer]->begin();

  for (int i = 0; i < index; i++, itr++);

  return *itr;
}


int
Body::getDirectedElementLoopTag(int layer, int index)
{
  if (!checkLayerIndex(layer)) return 0;

  int directed_id = getDirectedElementLoopId(layer, index);

  if ( directed_id == 0 ) return 0;

  int sign = (directed_id < 0)?-1:1;

  ModelObject* obj = model->getModelObjectById(sign * directed_id);

  if ( obj != NULL )
    return sign * obj->Tag();
  else
    return 0;
}


BodyElement**
Body::getElementArray()
{
  int tot_count = getElementCount();

  if (tot_count == 0) return NULL;

  BodyElement** be_array = new BodyElement*[tot_count];

  int index = 0;
  int pos = 0;
  while (true) {
    BodyElement* be = getElement(index++);
    if (be==NULL) break;
    be_array[pos++] = be;
  }

  return be_array;
}


BodyElement**
Body::getElementArray(int layer)
{
  if (!checkLayerIndex(layer)) return NULL;

  int row;

  int be_count = getElementCount(layer);

  if ( be_count == 0 ) return NULL;

  BodyElement** be_array = new BodyElement*[be_count];

  int be_index = 0;

  BodyElement* be = getElement(layer, be_index++);
  row = 0;
  while (be != NULL) {
    be_array[row++] = be;
    be = getElement(layer, be_index++);
  }

  return be_array;
}


int
Body::getElementCount()
{
  int count = 0;

  for (int i = 0; i < nofLayers; i++)
    count += nofElements[i];

  return count;
}


int
Body::getElementCount(int layer)
{
  if (!checkLayerIndex(layer)) return 0;

  return nofElements[layer];
}


// Get body element group id by index
//
int
Body::getElementGroupId(int index)
{
  if (index >= elementGroupIds->size()) return NO_INDEX;

  IdList::iterator itr = elementGroupIds->begin();

  for (int i = 0; i < index; i++, itr++);

  int eg_id = *itr;

  return eg_id;
}


// Get all body element groups ids
//
void
Body::getElementGroupIds(int& nof_groups, int*& group_ids)
{
  nof_groups = getNofElementGroups();
  group_ids = NULL;

  if ( nof_groups == 0 ) return;

  group_ids = new int[nof_groups];

  int counter = 0;

  for (int i = 0; i < nof_groups; i++) {
    group_ids[counter++] = getElementGroupId(i);
  }
}


// Get body element group tag by layer and index
//
int
Body::getElementGroupTag(int index)
{
  if (index >= getNofElementGroups() ) return NO_INDEX;

  IdList::iterator itr = elementGroupTags->begin();

  for (int i = 0; i < index; i++, itr++);

  int eg_tag = *itr;

  return eg_tag;
}


// Get all body element groups tags
//
void
Body::getElementGroupTags(int& nof_groups, int*& group_tags)
{
  nof_groups = getNofElementGroups();
  group_tags = NULL;

  if ( nof_groups == 0 ) return;

  group_tags = new int[nof_groups];

  int counter = 0;

  for (int i = 0; i < nof_groups; i++) {
    group_tags[counter++] = getElementGroupTag(i);
  }

}


// Get all (unsigned) body element ids in loop order
//
void
Body::getElementIds(int& nof_elements, int*& element_ids)
{
  nof_elements = getElementCount();
  element_ids = new int[nof_elements];

  int index = 0;

  int layer = -1;
  while (true ) {

    if (!checkLayerIndex(++layer)) break;

    // If loops created (normal bodies)
    //
    if ( getNofElementLoops(layer) > 0 ) {
      int bel_index = 0;
      BodyElementLoop* bel = getElementLoop(layer, bel_index++);

      while ( bel != NULL ) {

        for (int i = 0; i < bel->getNofElements(); i++) {
          element_ids[index++] = bel->getElementId(i);
        }

        bel = getElementLoop(layer, bel_index++);
      }

    // If no loops created (virtual bodies)
    //
    } else {
      int be_index = 0;
      while (true) {
        BodyElement* be = getElement(layer, be_index++);
        if (be == NULL ) break;
        element_ids[index++] = be->Id();
      }
    }
  }

}


// Get all (unsigned) layer element ids in loop order
//
void
Body::getElementIds(int layer, int& nof_elements, int*& element_ids)
{
  nof_elements = 0;
  element_ids = NULL;

  if (!checkLayerIndex(layer)) return;

  nof_elements = nofElements[layer];

  if ( nof_elements == 0 ) return;

  element_ids = new int[nof_elements];

  // If loops created (normal bodies)
  //
  if ( getNofElementLoops(layer) > 0 ) {

    int bel_index = 0;
    BodyElementLoop* bel = getElementLoop(layer, bel_index++);

    int index = 0;

    while ( bel != NULL ) {

      for (int i = 0; i < bel->getNofElements(); i++) {
        element_ids[index++] = bel->getElementId(i);
      }

      bel = getElementLoop(layer, bel_index++);
    }

  // If no loops created (virtual bodies)
  //
  } else {
    int index = 0;
    int be_index = 0;
    while (true) {
      BodyElement* be = getElement(layer, be_index++);
      if (be == NULL ) break;
      element_ids[index++] = be->Id();
    }
  }
}


// Get all (unsigned) body element tags in loop order
//
void
Body::getElementTags(int& nof_elements, int*& element_tags)
{
  nof_elements = getElementCount();
  element_tags = new int[nof_elements];

  int index = 0;

  int layer = -1;

  while (true ) {

    if (!checkLayerIndex(++layer)) break;

    // If loops created (normal bodies)
    //
    if ( getNofElementLoops(layer) > 0 ) {
      int bel_index = 0;
      BodyElementLoop* bel = getElementLoop(layer, bel_index++);

      while ( bel != NULL ) {

        for (int i = 0; i < bel->getNofElements(); i++) {
          element_tags[index++] = bel->getElementTag(i);
        }

        bel = getElementLoop(layer, bel_index++);
      }

    // If no loops created (virtual bodies)
    //
    } else {
      int be_index = 0;
      while (true) {
        BodyElement* be = getElement(layer, be_index++);
        if (be == NULL ) break;
        element_tags[index++] = be->Tag();
      }
    }
  }

}


// Get all (unsigned) layer element tags in loop order
//
void
Body::getElementTags(int layer, int& nof_elements, int*& element_tags)
{
  nof_elements = 0;
  element_tags = NULL;

  if (!checkLayerIndex(layer)) return;

  nof_elements = nofElements[layer];

  if ( nof_elements == 0 ) return;

  element_tags = new int[nof_elements];

  // If loops created (normal bodies)
  //
  if ( getNofElementLoops(layer) > 0 ) {

    int bel_index = 0;
    BodyElementLoop* bel = getElementLoop(layer, bel_index++);

    int index = 0;

    while ( bel != NULL ) {

      for (int i = 0; i < bel->getNofElements(); i++) {
        element_tags[index++] = bel->getElementTag(i);
      }

      bel = getElementLoop(layer, bel_index++);
    }

  // If no loops created (virtual bodies)
  //
  } else {
    int be_index = 0;
    int index = 0;
    while (true) {
      BodyElement* be = getElement(layer, be_index++);
      if (be == NULL ) break;
      element_tags[index++] = be->Tag();
    }
  }

}


int
Body::getElementLoopId(int index)
{
  int count = 0;
  int old_count;

  for (int i = 0; i < nofLayers; i++) {
    old_count = count;
    count += elementLoopIds[i]->size();

    if ( index < count )
      return getElementLoopId(i, index-old_count);
  }

  return NO_INDEX;
}


int
Body::getElementLoopId(int layer, int index)
{
  if (!checkLayerIndex(layer)) return NO_INDEX;

  if (index >= elementLoopIds[layer]->size()) return NO_INDEX;

  IdList::iterator itr = elementLoopIds[layer]->begin();

  for (int i = 0; i < index; i++, itr++);

  int bel_id = *itr;

  return ( bel_id < 0 )?-bel_id:bel_id;
}


int
Body::getElementLoopTag(int index)
{
  int count = 0;
  int old_count;

  for (int i = 0; i < nofLayers; i++) {
    old_count = count;
    count += elementLoopTags[i]->size();

    if ( index < count ) {
      return getElementLoopTag(i, index-old_count);
    }
  }

  return NO_INDEX;
}


int
Body::getElementLoopTag(int layer, int index)
{
  if (!checkLayerIndex(layer)) return NO_INDEX;

  if (index >= elementLoopTags[layer]->size()) return NO_INDEX;

  IdList::iterator itr = elementLoopTags[layer]->begin();

  for (int i = 0; i < index; i++, itr++);

  int bel_tag = *itr;

  return bel_tag;
}



int
Body::getEquationId()
{
  return equationId;
}


BodyElement*
Body::getElement(int index)
{
  int count = 0;
  int old_count;

  for (int i = 0; i < nofLayers; i++) {
    old_count = count;
    count += belements[i]->size();

    if ( index < count )
      return getElement(i, index-old_count);
  }

  return NULL;
}


BodyElement*
Body::getElement(int layer, int index)
{
  if (!checkLayerIndex(layer)) return NULL;

  if (index >= belements[layer]->size()) return NULL;

  BodyElementTable::iterator itr = belements[layer]->begin();

  for (int i = 0; i < index; i++, itr++);

  return (*itr).second;
}


BodyElement*
Body::getElementById(int be_id)
{
  BodyElement* be;

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

    be = getElementById(i, be_id);

    if ( be != NULL )
      return be;
  }

  return NULL;
}


BodyElement*
Body::getElementById(int layer, int be_id)
{
  if (!checkLayerIndex(layer)) return NULL;

  BodyElementTable* elements = belements[layer];

  BodyElement* be = NULL;

  if ( elements != NULL ) {
    be = (*elements)[be_id];
  }

  return be;
}


BodyElementLoop*
Body::getElementLoop(int index)
{
  int count = 0;
  int old_count;

  for (int i = 0; i < nofLayers; i++) {
    old_count = count;
    count += nofElementLoops[i];

    if ( index < count )
      return getElementLoop(i, index-old_count);
  }

  return NULL;
}


BodyElementLoop*
Body::getElementLoop(int layer, int index)
{
  if (!checkLayerIndex(layer)) return NULL;

  if (index >= nofElementLoops[layer]) return NULL;

  int bel_id = getElementLoopId(layer, index);

  return model->getBodyElementLoopById(bel_id);
}


BodyLayer*
Body::getLayer(int layer)
{
  if (!checkLayerIndex(layer)) return NULL;

  return model->getBodyLayerById(layerIds[layer]);
}


int
Body::getLayerId(int layer)
{
  if (!checkLayerIndex(layer)) return NO_INDEX;

  return layerIds[layer];
}


int
Body::getLayerIndexById(int layer_id)
{
  for (int i = 0; i < nofLayers; i++) {
    if (layerIds[i] == layer_id) {
      return i;
    }
  }

  return NO_INDEX;
}


int
Body::getLayerIndexByTag(int layer_tag)
{
  for (int i = 0; i < nofLayers; i++) {
    if ( layer_tag == getLayerTag(i) ) {
      return i;
    }
  }

  return NO_INDEX;
}


int
Body::getLayerTag(int layer)
{
  if (!checkLayerIndex(layer)) return NO_INDEX;

  return model->getModelObjectTagById(layerIds[layer]);
}


int
Body::getLayerTagById(int layer_id)
{
  return model->getModelObjectTagById(layer_id);
}


int
Body::getInitialConditionId()
{
  return initialConditionId;
}


int
Body::getMaterialId()
{
  return materialId;
}


int
Body::getMeshElementId(int index)
{
  if (index < 0 || index >= nofMeshElements) {
    return NO_INDEX;
  }

  return meshElementIds[index];
}

// Get mesh density (H) value for a layer
bool
Body::getMeshDensityValue(int layer, int mesh_index, char& dtype, double& dvalue)
{
  if (!checkLayerIndex(layer)) return false;

  if ( mesh_index < 0 || mesh_index >= model->getNofMeshes() )
    return false;

  dtype = ' ';
  dvalue = 0;

  BodyLayer* bl = model->getBodyLayerById(layerIds[layer]);

  if (bl == NULL ) return false;

  return bl->getMeshDensityValue(mesh_index, dtype, dvalue);
}


// Get boundary meshing N for a body layer
// If layer not 'griddable' return 0
int
Body::getMeshQuadGridN(int layer, int mesh_index, int element_id)
{
  if (!checkLayerIndex(layer)) return 0;

  BodyLayer* bl = model->getBodyLayerById(layerIds[layer]);

  if (bl == NULL ) return 0;

  return bl->getMeshQuadGridN(mesh_index, element_id);
}


// Body level name
const char*
Body::getName()
{
  if ( name == NULL || name[0] == '\0' ) {
    strstream strm;
    strm << "Body" << tag << ends;
    return strm.str();

  } else {
    return name;
  }
}


// Body layer name
const char*
Body::getName(int layer)
{
  if (!checkLayerIndex(layer)) return NULL;

  const char* nm = model->getModelObjectNameById(layerIds[layer]);

  if ( nm == NULL || nm[0] == '\0' ) {
    strstream strm;
    strm << "Body" << tag << "-L" << 1 + layer << ends;
    return strm.str();

  } else {
    return nm;
  }
}


int
Body::getNofBoundaries(int layer, elementType type)
{
  if (!checkLayerIndex(layer)) return 0;

  switch (type) {
  case INNER_ELEMENT:
    return nofInnerBoundaries[layer];
    break;
  case OUTER_ELEMENT:
    return nofOuterBoundaries[layer];
    break;
  default:
    return nofInnerBoundaries[layer] + nofOuterBoundaries[layer];
    break;
  }
}


int
Body::getNofElementGroups()
{
  return nofElementGroups;
}


int
Body::getNofElementLoops(int layer)
{
  if (!checkLayerIndex(layer)) return 0;

  return nofElementLoops[layer];
}


int
Body::getNofMifLayers()
{
  int count = 0;

  for (int i = 0; i < nofLayers; i++) {
    BodyLayer* bl = model->getBodyLayerById(layerIds[i]);
    if ( bl == NULL ) break;
    count += bl->getNofMifLayers(elementLoopIds[i]);
  }

  return count;
}


// Check if the body layer is inside a layer of an other body
bool
Body::hasInside(int layer, Body* other_body, int other_body_layer)
{
  BoundBox* box1 = getBoundBox(layer);
  BoundBox* box2 = other_body->getBoundBox(other_body_layer);

  if ( !box1->contains(box2) ) {
    return false;
  }

  int o_bel_index = 0;
  BodyElementLoop* o_bel = other_body->getElementLoop(other_body_layer, o_bel_index);

  BodyElement* o_be = o_bel->getElement(0);

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

  BodyElement* o_se = o_be->getSubElement(0);

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

  // Pick one vertex from other body element
  BodyElement* o_v;

  if ( model->getDimension() == ECIF_2D ) {
    o_v = o_se;
  } else {
    o_v = o_se->getSubElement(0);
  }

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

  //---Calculate intersection from the vertex
  //  with all elements of this body layer
  GcPoint* vp = (GcPoint*)o_v->getGeometry();
  double vp_x = vp->Pos(X);

  //-Pick first (outermost is enough!) loop from this body layer
  int bel_index = 0;
  BodyElementLoop* bel = getElementLoop(layer, bel_index++);

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

  bool negative_on_left;

  Point3List hit_points;

  Point3* p1;
  Point3* p2;

  Point3List::iterator itr1;
  Point3List::iterator itr2;

  //-Add intersections with this element to the total count
  int index = 0;
  while (true) {

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

    if (be==NULL) break;

    RayHit* be_hits =  be->isectionsWithXdir(vp, negative_on_left);

    if ( be_hits != NULL && !isEqual(vp_x, be_hits->min_value) ) {

      for (itr1 = hit_points.begin(); itr1 != hit_points.end(); itr1++) {
          p1 = *itr1;
        for (itr2 = be_hits->points.begin(); itr2 != be_hits->points.end(); itr2++) {
          p2 = *itr2;

          if ( !isZero(dist3(*p1, *p2)) ) {
            hit_points.push_front(p2);
          }
        }
      }
    }
  }

  //--Non-zero and even number of intersections --> point is inside
  if ( 1 == hit_points.size() % 2 ) {
    return true;

  //--Otherwise it is outside
  } else {
    return false;
  }
}


void
Body::initClass(Model* mdl)
{
  Body::last_tag = 0;
}


void
Body::init(bool add_default_layer)
{
  int i;

  model->addModelObject(this, OT_BODY);

  name = NULL;

  bodyParameterId = NO_INDEX;
  boundbox = new BoundBox;
  boundboxMesh = new BoundBox;
  checked = false;

  colorIndex = DEFAULT_COLOR_INDEX;

  for (i = 0; i< 4; i++) {
    color[i] = colorValues[DEFAULT_COLOR_INDEX][i];
  }

  drawMode = DM_NORMAL;
  drawState = DS_NORMAL;
  externalTag = NO_INDEX;
  maxNofMeshElements = 0;

  nofMeshElements = 0;
  meshElementIds = NULL;

  nofLayers = 0;
  layerIds = NULL;

  bodyParameterId = NO_INDEX;
  initialConditionId = NO_INDEX;
  bodyForceId = NO_INDEX;
  equationId = NO_INDEX;
  materialId = NO_INDEX;

  boundboxes = new BoundBox*[nofLayers];
  belements = new BodyElementTable*[nofLayers];
  pendingElementTags = new IdArray*[nofLayers];
  pendingVertexGroups = new IdArray*[nofLayers];
  pendingVertexTags = new IdArray*[nofLayers];
  elementLoopIds = new IdList*[nofLayers];
  elementLoopTags = new IdList*[nofLayers];

  nofElements = new int[nofLayers];
  nofElementLoops = new int[nofLayers];
  nofInnerBoundaries = new int[nofLayers];
  nofOuterBoundaries = new int[nofLayers];

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

    layerIds[i] = NO_INDEX;

    boundboxes[i] = new BoundBox;
    belements[i] = new BodyElementTable;
    pendingElementTags[i] = new IdArray;
    pendingVertexGroups[i] = new IdArray;
    pendingVertexTags[i] = new IdArray;
    elementLoopIds[i] = new IdList;
    elementLoopTags[i] = new IdList;

    nofElements[i] = 0;
    nofElementLoops[i] = 0;
    nofInnerBoundaries[i] = 0;
    nofOuterBoundaries[i] = 0;
  }

  nofElementGroups = 0;
  elementGroupIds = new IdList;
  elementGroupTags = new IdList;

  separateFlag = false;
  status = false;

  type = NORMAL_BODY;
  if (model->modelHasCadGeometry()) {
    gmtrType = GEOM_BODY;
  } else {
    gmtrType = MESH_BODY;
  }

  tplgType = CLOSED_BODY;

  // Add default layer
  if (add_default_layer) {
    ecif_BodyLayer_X bl;
    init_trx_data(bl);
    addLayer(bl);
  }

}


void
Body::initName()
{

  if ( name == NULL || name[0] == '\0' ) {
    strstream strm;
    strm << "Body" << tag << ends;

    update_dyna_string(name, strm.str());
  }
}


void
Body::incrBndrCount(int layer, elementType type)
{
  if (!checkLayerIndex(layer)) return;

  switch (type) {
  case INNER_ELEMENT:
    nofInnerBoundaries[layer]++;
    break;
  case OUTER_ELEMENT:
    nofOuterBoundaries[layer]++;
    break;
  }
}


// If body is excluded from the currently drawn mesh
bool
Body::isExcludedFromCurrentMesh()
{
  int mesh_index = model->getCurrentMeshIndex();

  return isExcludedFromMesh(mesh_index);
}



// If body layer is excluded from the currently drawn mesh
bool
Body::isExcludedFromCurrentMesh(int layer)
{
  int mesh_index = model->getCurrentMeshIndex();

  return isExcludedFromMesh(layer, mesh_index);
}


// If body is excluded from the given mesh
bool
Body::isExcludedFromMesh(int mesh_index)
{
  if (mesh_index == NO_INDEX) return false;

  int layer = -1;
  while (true) {

    if (!selectLayer(++layer)) break;

    BodyLayer* bl = model->getBodyLayerById(layerIds[layer]);

    if (bl == NULL ) continue;

    // Body is 'included' if even one of the layers is active!!!
    if ( !bl->isExcludedFromMesh(mesh_index) ) {
      return false;
    }
  }

  return true;
}


// If body layer is excluded from the currently drawn mesh
bool
Body::isExcludedFromMesh(int layer, int mesh_index)
{
  if (!checkLayerIndex(layer)) return true;

  if (mesh_index == NO_INDEX) return false;

  BodyLayer* bl = model->getBodyLayerById(layerIds[layer]);

  if (bl == NULL ) return false;

  return bl->isExcludedFromMesh(mesh_index);
}


// Is this a 'decent' body?
bool
Body::isOk()
{
  if (!checked)
    status = check();
  return status;
}


bool
Body::isSeparable(int layer)
{
  if (!checkLayerIndex(layer)) return false;

  int be_index = 0;
  BodyElement* be = getElement(layer, be_index++);

  while ( be != NULL ) {

    if ( be->isInnerBoundary() ) {
      return true;
    }

    be = getElement(layer, be_index++);
  }

  return false;
}


void
Body::markActiveMeshObjects(int mesh_index, bool*& active_object_flags)
{

  // Mark body active
  active_object_flags[id] = true;

  int layer = -1;
  while (true) {

    if (!selectLayer(++layer)) break;

    BodyLayer* bl = model->getBodyLayerById(layerIds[layer]);

    if (bl == NULL ) continue;;

    if ( !bl->isExcludedFromMesh(mesh_index) ) {

      // Mark all body related elements active
      int be_index = 0;
      BodyElement* be = getElement(layer, be_index++);

      while ( be != NULL ) {

        if ( !be->isActive() ) {
          be = getElement(layer, be_index++);
          continue;
        }

        active_object_flags[be->Id()] = true;

        be->markActiveMeshObjects(active_object_flags);

        be = getElement(layer, be_index++);
      }
    }
  }
}


void
Body::markActiveObjects()
{
  int layer = 0;
  if (!selectLayer(layer)) return;

  while (true) {

    int bel_index = 0;
    BodyElementLoop* bel = getElementLoop(layer, bel_index++);
    while (bel != NULL) {
      int bel_id = bel->Id();
      model->markObjectActive(bel_id);
      bel = getElementLoop(layer, bel_index++);
    }

    if (!selectLayer(++layer)) break;
  }
}


ostream&
Body::output_emf(ostream& out, short indent_size, short indent_level)
{
  char* QM = "\"";
  short is = indent_size;
  short il = indent_level;

  int i;

  const short nof_parameter_ids = 5;

  const char* param_names[nof_parameter_ids] = {
    "Body Parameter", "Body Force", "Equation", "Initial Condition", "Material"
  };

  int param_ids[nof_parameter_ids] = {
    bodyParameterId, getBodyForceId(), getEquationId(), getInitialConditionId(), getMaterialId()
  };

  // Header
  LibFront::output_scalar(out, is, il, EMF_BODY, NULL, tag);

  // Type
  if ( isOpen() ) {
    LibFront::output_scalar(out, is, il + 1, EMF_TYPE, NULL, "Open");
  } else if ( isBemBody() ) {
    LibFront::output_scalar(out, is, il + 1, EMF_TYPE, NULL, "Bem");
  } else if ( isVirtual() ) {
    LibFront::output_scalar(out, is, il + 1, EMF_TYPE, NULL, "Virtual");
  }

  // Body name
  LibFront::output_scalar(out, is, 1 + il, EMF_NAME, NULL, name);

  // We do not print size-info for the color vector
  LibFront::output_vector(out, is, 1 + il, EMF_COLOR, NULL, 4, color, false);

  // Parameter (equation,body force etc.)ids
  for (i = 0; i < nof_parameter_ids; i++) {
    if (param_ids[i] != NO_INDEX) {
      LibFront::output_scalar(out, is, 1 + il, param_names[i], NULL, param_ids[i]);
    }
  }

  if ( isVirtual() ) {
    int eg_count = getNofElementGroups();

    if ( eg_count > 0 ) {

      int* eg_tags = new int[eg_count];
      for (int i = 0; i < eg_count; i++) {
        eg_tags[i] = getElementGroupTag(i);
      }

      LibFront::output_vector(out, is, il + 1, "Element Groups", NULL, eg_count, eg_tags, false);

      delete[] eg_tags;
    }

    return out;
  }


  int layer, nof_ids;
  int* mids;
  int* gids;

  // Loop all layers
  // ===============
  layer = -1;
  int lr_tag_prev = NO_INDEX;

  while (true) {

    if (!selectLayer(++layer)) break;

    int lr_id = layerIds[layer];

    BodyLayer* bl = model->getBodyLayerById(lr_id);

    if ( bl == NULL ) continue;

    int lr_tag = bl->Tag();

    // Store directed element loop and element group tags into an arries
    //
    int bel_count = elementLoopTags[layer]->size();
    int* bel_tags = new int[bel_count];
    for (i = 0; i < bel_count; i++) {
      bel_tags[i] = getDirectedElementLoopTag(layer, i);
    }

    //--Header and tag
    if ( EXPLICIT_LAYER == bl->getLayerType() && lr_tag != lr_tag_prev ) {
      lr_tag_prev = lr_tag;
      LibFront::output_scalar(out, is, 1 + il, EMF_LAYER, NULL, lr_tag);

      // If name given explicitely
      if ( bl->hasName() ) {
        LibFront::output_scalar(out, is, 1 + il, EMF_LAYER_NAME, NULL, bl->getName());
      }
    }

    //--Directed element loop tags and gridparameter ids etc. from layer.
    //
    int ill = il;

    if ( EXPLICIT_LAYER == bl->getLayerType() )
      ill += 2;
    else
      ill += 1;

    if ( bel_count > 0 ) {
      LibFront::output_vector(out, is, ill, "Element Loops", NULL, bel_count, bel_tags, false);
    }

    bl->output_emf(out, is, ill);

    delete[] bel_tags;

  } // All Layers

  return out;
}


ostream&
Body::output_mif(ostream& out)
{
  char* QM = "\"";

  int i;
  char value_buffer[1 + 128];

  // Read bodylevel ghrid info from the first layer
  //
  BodyLayer* bl = getBodyLayer(0);
  if ( bl == NULL ) return out;
  int mesh_index = model->getCurrentMeshIndex();
  int pid = bl->getGridParameterId(mesh_index);
  Parameter* grid_param = model->getParameterById(ECIF_GRID_PARAMETER, pid);

  // Body id
  // -------
  indent(out, 0) << "BodyId: " << tag << endl;

  // Element order (common for all layers)
  // -------------
  indent(out, 2) << "ElementOrder: ";

  if ( grid_param != NULL &&
       grid_param->getFieldValueBySifName("Mesh Element Order", 128, value_buffer)
     )
    out << value_buffer;
  // Default
  else
    out << "Linear";
  out << endl;

  // Nof layers
  // ----------
  indent(out, 2) << "Layers: " << getNofMifLayers() << endl;

  int next_layer_id = 1;

  // Output data for each Layer
  // ==========================
  int layer = -1;
  while (true) {

    if (!selectLayer(++layer)) break;

    BodyLayer* bl = getBodyLayer(layer);

    if ( bl == NULL ) break;

    bl->output_mif(out, next_layer_id, elementLoopIds[layer]);

  } // All body Layers

  return out;
}


#if 0
ostream&
Body::output_mif(ostream& out)
{
  char* QM = "\"";

  int i;
  char value_buffer[1 + 128];

  int mesh_index = model->getCurrentMeshIndex();

  int layer = -1;

  // Output data for each Layer
  // ==========================
  while (true) {

    if (!selectLayer(++layer)) break;

    Parameter* grid_param = NULL;

    BodyLayer* bl = getBodyLayer(layer);

    if ( bl == NULL ) continue;

    int pid = bl->getGridParameterId(mesh_index);

    grid_param = model->getParameterById(ECIF_GRID_PARAMETER, pid);

    // ----------------------------------------
    // Output body level data based on 1. layer
    // ----------------------------------------

    if ( layer == 0 ) {

      // Body id
      // -------
      indent(out, 0) << "BodyId: " << tag << endl;

      // Element order (common for all layers)
      // -------------
      indent(out, 2) << "ElementOrder: ";

      if ( grid_param != NULL &&
           grid_param->getFieldValueBySifName("Mesh Element Order", 128, value_buffer)
         )
        out << value_buffer;
      // Default
      else
        out << "Linear";
      out << endl;

      // Nof layers
      // ----------
      indent(out, 2) << "Layers: " << nofLayers << endl;

    }

    char dtype;
    double dvalue;
    bool dgiven = getMeshDensityValue(layer, mesh_index, dtype, dvalue);

    bool is_quadGrid;
    // Check if Quadrilateral elements
    if ( grid_param != NULL &&
         grid_param->getFieldValueBySifName("Mesh Element Type", 128, value_buffer) &&
         LibFront::ncEqual(value_buffer, "Quad")
       ) {
      is_quadGrid = true;
    } else {
      is_quadGrid = false;
    }

    // Layer id
    // --------
    indent(out, 4) << "LayerId: " << layer + 1 << endl;

    // Layer mesh density value
    // ------------------------
    if ( dgiven && dvalue > 0 )
      indent(out, 4) << dtype << ": " << dvalue << endl;

    // Layer type (meshing method)
    // ---------------------------
    indent(out, 6) << "LayerType: ";

    //-Structured grid
    if ( is_quadGrid ) {
      out << "QuadGrid";

      indent(out, 6) << "GridSize: ";
      grid_param->getFieldValueBySifName("Mesh Quadgrid N1", 128, value_buffer);
      out << value_buffer << " ";
      grid_param->getFieldValueBySifName("Mesh Quadgrid N2", 128, value_buffer);
      out << value_buffer << endl;

    //-Triangles
    } else if ( grid_param != NULL &&
                grid_param->getFieldValueBySifName("Mesh Layer Type", 128, value_buffer)
              ) {
      out << value_buffer;

    //-Default
    } else {
      out << "MovingFront";
    }

    out << endl;

    // Background mesh stuff
    // ---------------------
    if ( !is_quadGrid ) {

      //-Fixed nodes
      indent(out, 6) << "FixedNodes: " << 0 << endl;  // NOTE: Currently always 0!, MVe 16.02.00

      //-Background mesh type
      indent(out, 6) << "BGMesh: ";

      //--Background mesh method specified
      if ( grid_param != NULL &&
           grid_param->getFieldValueBySifName("Mesh Bg Mesh", 128, value_buffer)
         ) {

        //-External bg-mesh file
        if ( LibFront::in(value_buffer, "External") ) {

          //-File name given
          if ( grid_param->getFieldValueBySifName("Mesh Bg Mesh File", 128, value_buffer) &&
               value_buffer != NULL && value_buffer[0] != '\0'
             ) {
            out << "External " << QM << value_buffer << QM;

          //-File name missing, use default method!
          } else {
            out << "Delaunay";
          }

        //-Some of the predefined methods selected by the user
        } else {
          out << value_buffer;
        }

      //--Use default method (no bg mesh)
      } else {
        out << "Delaunay";
      }

      out << endl;

      // Mesh seed (optional)
      // --------------------
      if ( grid_param != NULL &&
           grid_param->getFieldValueBySifName("Mesh Seed Type", 128, value_buffer)
         ) {

        // Only Implicit seed currently supported, MVe 16.02.99
        if ( LibFront::ncEqual(value_buffer, "Implicit") &&
             grid_param->getFieldValueBySifName("Mesh Seed Edge", 128, value_buffer)
           ) {
          indent(out,6) << "Seed: Implicit" << endl;
          indent(out,8) << "Edge: " << value_buffer << endl;
        }
      }
    }

    // Layer element loops
    // -------------------
    indent(out, 6) << "Loops: " << nofElementLoops[layer] << endl;
    for (i = 0; i < nofElementLoops[layer]; i++) {

      int did = getDirectedElementLoopId(layer, i);
      int direction = (did < 0 )?-1:1;

      BodyElementLoop* bel = model->getBodyElementLoopById(direction * did);

      if ( bel == NULL )
        continue;

      // Print positions before and after printing fixed data
      // (for getting the indent size for ids)
      int pos1, pos2;

      indent(out, 8) << "LoopId: " << bel->Tag() << endl;
      indent(out, 10) << "Direction: " << direction << endl;

      pos1 = out.tellp();
      indent(out, 10) << "Edges: " << bel->getNofElements() << "  ";
      pos2 = out.tellp();

      bel->outputDirectedElementTags(out, pos2 - pos1);
      out << endl;
    }

  } // All body Layers

  return out;
}
#endif


ostream&
Body::output_sif(ostream& out, short indent_size, short indent_level)
{
  // NOTE: If no equation defined, the body is not output to sif!!!
  //
  if ( NO_INDEX == getEquationId() ) {
    return out;
  }

  char* QM = "\"";
  short is = indent_size;
  short il = indent_level;

  int nof_parameter_ids = 4;
  const char* names[4] = { SIF_BODY_FORCE, SIF_EQUATION, SIF_INITIAL_CONDITION, SIF_MATERIAL};
  int ids[4] = { getBodyForceId(), getEquationId(), getInitialConditionId(), getMaterialId()};

  // Body header and id
  LibFront::output_scalar(out, is, il, SIF_BODY, NULL, tag);

  // Name (typed and in quotes)
  if ( model->getSolverKeywordTypeGiven(SIF_BODY, "Name") ) {
    LibFront::output_scalar(out, is, il + 1, "Name =", NULL, name, true);
  } else {
    LibFront::output_scalar(out, is, il + 1, "Name = String", NULL, name, true);
  }
  out << endl;

  // Body parameters
  if ( bodyParameterId != NO_INDEX ) {
    Parameter* p = model->getParameterById(ECIF_BODY_PARAMETER, bodyParameterId);

    if ( p != NULL ) {

      SifOutputControl soc;
      soc.outputId = false;
      soc.outputName = false;
      soc.outputType = false;
      soc.outputAll = false;
      soc.sectionName = SIF_BODY;

      p->output_sif(out, indent_size, indent_level, soc);
    }
  }

  // Parameter ids
  for (short i = 0; i < nof_parameter_ids; i++) {

    strstream strm;

    // NOTE: Equation is an exception: id = -1 is output!
    // This mainly for convenience, so that the euquation can be
    // nicely turned on/off when using sif-file directly
    //
    //
    if ( 0 == strcmp(SIF_EQUATION, names[i]) || ids[i] != NO_INDEX ) {

      strm << names[i] << " =";
      if ( !model->getSolverKeywordTypeGiven(SIF_BODY, names[i]) ) {
        strm << " Integer" << ends;
      }
      strm << ends;
      LibFront::output_scalar(out, is, 1 + il, strm.str(), NULL, ids[i]);
    }
  }

  return out;
}


bool
Body::selectLayer(int layer)
{
  return checkLayerIndex(layer);
}


// NOTE: Take care that bodies are
// checked (method check()) before they are
// used, when any elements have been removed!!!
int
Body::removeElement(int layer, BodyElement* be)
{
  if (!checkLayerIndex(layer)) return 0;

  belements[layer]->erase(be->Id());
  nofElements[layer]--;

  return 0;
}


// NOTE: We cannot remove the group object themselves, because
// they could be in use somewhere else!
//
void
Body::removeElementGroups()
{
  nofElementGroups = 0;

  delete elementGroupIds;
  delete elementGroupTags;
}


void
Body::removeElementLoops(int layer)
{
  if (!checkLayerIndex(layer)) return;

  if (nofElementLoops[layer] > 0 ) {

    IdList::iterator beg = elementLoopIds[layer]->begin();
    IdList::iterator end = elementLoopIds[layer]->end();

    for (IdList::iterator itr = beg; itr != end; itr++) {

      int bel_id = *itr;

      if (bel_id < 0)
        bel_id = -1 * bel_id;

      //model->removeBodyElementLoop(bel_id);
    }

    elementLoopIds[layer]->clear();
    elementLoopTags[layer]->clear();
    nofElementLoops[layer] = 0;
  }
}


// Remove all layer data from body
//
// NOTE: Layers themselves are removed as model object by the model!
//
//
void
Body::removeLayers()
{
  for (int i = 0; i < nofLayers; i++) {

    delete belements[i];
    delete boundboxes[i];
    delete elementLoopIds[i];
    delete elementLoopTags[i];
    delete pendingElementTags[i];
    delete pendingVertexGroups[i];
    delete pendingVertexTags[i];
  }

  nofLayers = 0;

  delete[] belements;
  delete[] elementLoopIds;
  delete[] elementLoopTags;
  delete[] layerIds;
  delete[] nofElements;
  delete[] nofElementLoops;
  delete[] nofInnerBoundaries;
  delete[] nofOuterBoundaries;
}


int
Body::removeMeshElements(bool* remove_flags)
{
  int counter, i;

  //--Count nof remaining ids
  counter = 0;
  for (i = 0; i < nofMeshElements; i++) {

    if (remove_flags[meshElementIds[i]])
      continue;

    counter++;
  }

  //--Allocate new table
  int* new_ids = new int[counter];

  //--Copy new ids
  counter = 0;
  for (i = 0; i < nofMeshElements; i++) {

    if (remove_flags[meshElementIds[i]])
      continue;

    new_ids[counter] = meshElementIds[i];
    counter++;
  }

  //--Update vars
  nofMeshElements = counter;
  delete[] meshElementIds;
  meshElementIds = new_ids;

  return nofMeshElements;
}


// fix this!!!***!!!
void
Body::separate(bool* duplicated_object_flags)
{
  int layer = 0;

  if (!selectLayer(layer)) return;

  IdArray ids1, ids2;

  BodyElementLoop* bel = model->getBodyElementLoopById( getElementLoopId(layer, 0) );

  int index = 0;
  while (true) {

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

    if (be==NULL) break;

    if ( !be->isInnerBoundary() ) {
      continue;
    }

    int neighbor_id;

    if ( id == be->getParentId(1) ) {
      neighbor_id = be->getParentId(2);

    } else {
      neighbor_id = be->getParentId(1);
    }

    Body* neighbor = model->getBodyById(neighbor_id);

    if ( neighbor->getSeparateFlag() ) {
      continue;
    }

    int neighbor_tag = neighbor->Tag();

    BodyElement* new_be = be->duplicate(duplicated_object_flags);

    if ( new_be != NULL ) {

      ids1.push_back(be->Id());
      ids2.push_back(new_be->Id());

      new_be->setParentIds(id, NO_INDEX);
      new_be->setParentTags(tag, NO_INDEX);

      be->setParentIds(neighbor_id, NO_INDEX);
      be->setParentTags(neighbor_tag, NO_INDEX);

      removeElement(layer, be);
      addElement(layer, new_be);
    }
  }

  if ( 0 < ids1.size() ) {
    bel->swapElements(&ids1, &ids2);
  }
}


void
Body::setBodyParameterId(int pid)
{
  //model->updateParameterApplyCounts(A_BODY, id, ECIF_BODY_PARAMETER, bodyParameterId, pid);
  bodyParameterId = pid;
}


void
Body::setColor(Color4& bd_color)
{
  for (int i = 0; i< 4; i++)
    color[i] = bd_color[i];

  colorIndex = ef_nodefault;
}


void
Body::setColorIndex(colorIndices color_index)
{
  // Set color index
  colorIndex = color_index;
  // Set actual color
  for (int i = 0; i< 4; i++) {
    color[i] = colorValues[color_index][i];
  }
}


void
Body::setElementLoops(int layer, int nof_loops, int* loop_ids, int* loop_tags)
{
  if (!checkLayerIndex(layer)) return;

  nofElementLoops[layer] = nof_loops;

  delete elementLoopIds[layer];
  delete elementLoopTags[layer];

  elementLoopIds[layer] = new IdList;
  elementLoopTags[layer] = new IdList;

  for(int i=0; i < nofElementLoops[layer]; i++) {
    elementLoopIds[layer]->push_back(loop_ids[i]);
    elementLoopTags[layer]->push_back(loop_tags[i]);
  }

}



void
Body::setMeshElements(int nof_elements, int* element_ids)
{
  delete[] meshElementIds; meshElementIds = NULL;

  nofMeshElements = nof_elements;

  meshElementIds = element_ids;
}


void
Body::setLayerTag(int layer, int tag)
{
  if (!checkLayerIndex(layer)) return;

  model->setModelObjectTagById(layerIds[layer], tag);
}


void
Body::swapBodyElements(int layer, BodyElement* be1, BodyElement* be2)
{
  if (!checkLayerIndex(layer)) return;

  if (be1 == be2) {
    return;
  }

  be1->addStatus(BE_SWAPPED);

  removeElement(layer, be1);
  addElement(layer, be2);
}


// Method updates body's:
//  -bounding box

// Update must be done only after when all elements
// have been read into the model
void
Body::updateBoundBox()
{
  int i;
  int direction;
  RangeVector rv;

  int layer = -1;

  // Each Layer
  while (true) {

    if (!selectLayer(++layer)) break;

    IdList::iterator end = elementLoopIds[layer]->end();

    for (IdList::iterator itr = elementLoopIds[layer]->begin(); itr != end; itr++) {

      int bel_id = *itr;

      direction = (bel_id < 0)?-1:1;

      BodyElementLoop* bel = model->getBodyElementLoopById(direction * bel_id);

      if (bel == NULL) continue;

      int index = 0;
      while (true) {
        BodyElement* be = bel->getElement(index++);
        if (be==NULL) break;
        if ( be->getRangeVector(rv) ) {
          updateBoundBox(layer, rv);
        }
      }
    }

  } // Each layer
}


void
Body::updateBoundBox(int layer, RangeVector rv)
{
  boundbox->extendByRange(rv);

  if (!checkLayerIndex(layer)) return;

  boundboxes[layer]->extendByRange(rv);
}


void
Body::updateBodyElementMeshH(int layer, int updateMode)
{
  if (!checkLayerIndex(layer)) return;

  int nof_meshes = model->getNofMeshes();

  int be_index = 0;
  BodyElement* be = getElement(layer, be_index++);

  while(be != NULL) {

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

      //double mesh_h = getMeshH(i);

      //be->setMeshH(i, mesh_h, updateMode);
    }

    be = getElement(layer, be_index++);
  }
}
