/*
    Copyright (C) 1998  Dennis Roddeman
    email: dennis.roddeman@uibk.ac.at

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.


    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation 
    59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA
*/

#include "tochnog.h"

#define EPS_DELETE 1.e-12

void delete_element( long int element, long int version )

{
  long int idat=0, data_class=0, swit=0;

  swit = set_swit(-1,-1,"delete_element");
  if ( swit ) pri( "In routine DELETE_ELEMENT" );

  for ( idat=0; idat<MDAT; idat++ ) {
    data_class = db_data_class( idat );
    if ( data_class==ELEMENT && db_version(idat,version) ) 
      db_delete_index( idat, element, version );
  }

  if ( swit ) pri( "Out routine DELETE_ELEMENT" );

}

void delete_node( long int inod, long int version )

{
  long int idat=0, data_class=0, swit=0;

  swit = set_swit(-1,-1,"delete_node");
  if ( swit ) pri( "In routine DELETE_NODE" );

  for ( idat=0; idat<MDAT; idat++ ) {
    data_class = db_data_class( idat );
    if ( data_class==NODE && db_version(idat,version) ) 
      db_delete_index( idat, inod, version );
  }

  if ( swit ) pri( "Out routine DELETE_NODE" );

}

void delete_geom( long int task )

{
  long int element=0, max_element=0, inol=0, nnol=0, inod=0, length=0,
    all_in_geometry=0, in_geometry=0, max_node=0, any_element_deleted=0,
    name=0, node_boundary=-YES, swit=0, icontrol=0,
    ldum=0, idum[1], control_delete_geometry[2], nodes[MNOL], el[MNOL+1];
  double element_volume=0., old_element_volume=0., 
    element_delete_factor=1., time_old=0., time_current=0.,
    time_new=0., rdum=0., ddum[MDIM], coord[MDIM], diff_coord[MDIM], 
    node_start_refined[MDIM], projection[MDIM];

  db( ICONTROL, 0, &icontrol, ddum, ldum, VERSION_NORMAL, GET );
  if ( db_active_index( CONTROL_MESH_DELETE_GEOMETRY, icontrol, VERSION_NORMAL )  ) {

    swit = set_swit(-1,-1,"delete_geom");
    if ( swit ) pri( "In routine DELETE_GEOM" );

    db( CONTROL_MESH_DELETE_GEOMETRY, icontrol, control_delete_geometry, 
      ddum, ldum, VERSION_NORMAL, GET );
    db_version_copy( VERSION_NORMAL, VERSION_TMP );
    db_max_index( ELEMENT, max_element, VERSION_NORMAL, GET );
    if ( task==ELEMENT_DELETE_FACTOR && db_active_index( TIME_OLD, 0, VERSION_NORMAL ) ) {
      db_delete( ELEMENT_DELETE_FACTOR, VERSION_NEW );
      db( TIME_CURRENT, 0, idum, &time_current, ldum, VERSION_NEW, GET );
      db( TIME_OLD, 0, idum, &time_old, ldum, VERSION_NORMAL, GET );
      db( TIME_NEW, 0, idum, &time_new, ldum, VERSION_NORMAL, GET );
      if ( scalar_dabs(time_new-time_old)>EPS_DELETE ) {
        element_delete_factor = 1. - (time_current-time_old)/(time_new-time_old);
        if ( element_delete_factor<1.e-6 ) element_delete_factor = 1.e-6;
      }
    }

      // delete elements totally in geometry
    for ( element=0; element<=max_element; element++ ) {
      if ( db_active_index( ELEMENT, element, VERSION_NORMAL ) ) {
        db( ELEMENT, element, el, ddum, length, VERSION_NORMAL, GET );
        nnol = length - 1; array_move( &el[1], nodes, nnol );
        all_in_geometry = 1;
        for ( inol=0; inol<nnol; inol++ ) {
          inod = nodes[inol];
          geometry( inod, ddum, control_delete_geometry, in_geometry, rdum, ddum, rdum,
            ddum, NODE_START_REFINED, PROJECT_ON_EDGE, VERSION_NORMAL );
          if ( !in_geometry ) all_in_geometry = 0;
        }
        if ( all_in_geometry ) {
          if ( task==ELEMENT_DELETE_FACTOR ) {
            length = 1;
            db( ELEMENT_DELETE_FACTOR, element, idum, &element_delete_factor, 
              length, VERSION_NEW, PUT );
          }
          else {
            assert( task==ELEMENT );
            delete_element( element, VERSION_NORMAL );
            any_element_deleted = 1;
          }
        }
      }
    }
      // move remaining nodes in geometry to edges
    if ( any_element_deleted ) {
      db_max_index( NODE, max_node, VERSION_NORMAL, GET );
      for ( inod=0; inod<=max_node; inod++ ) {
        if ( db_active_index( NODE, inod, VERSION_NORMAL ) ) {
          geometry( inod, ddum, control_delete_geometry, in_geometry, rdum, ddum, rdum,
            projection, NODE_START_REFINED, PROJECT_ON_EDGE, VERSION_NORMAL );
          if ( in_geometry) {
            db( NODE_START_REFINED, inod, idum, node_start_refined, 
              ldum, VERSION_NORMAL, GET );
            db( NODE_START_REFINED, inod, idum, projection, 
              ndim, VERSION_NORMAL, PUT );
            db( NODE, inod, idum, coord, ldum, VERSION_NORMAL, GET );
            array_subtract( projection, node_start_refined, diff_coord, ndim );
            array_add( coord, diff_coord, coord, ndim );
            db( NODE, inod, idum, coord, ndim, VERSION_NORMAL, PUT );
            length=1; db( NODE_BOUNDARY, inod, &node_boundary, ddum, 
              length, VERSION_NORMAL, PUT );
          }
        }
      }
       // delete too small elements (collapsed because of moving nodes to edge)
      for ( element=0; element<=max_element; element++ ) {
        if ( db_active_index( ELEMENT, element, VERSION_NORMAL ) ) {
          db( ELEMENT, element, el, ddum, length, VERSION_NORMAL, GET );
          name = el[0];
          if ( name==-BAR2 || name==-TRIA3 || name==-TET4 ) {
            nnol = length - 1; array_move( &el[1], nodes, nnol );
            element_volume_set( nodes, VERSION_NORMAL, element_volume );
            element_volume_set( nodes, VERSION_TMP, old_element_volume );
            if ( element_volume<EPS_VOLUME*old_element_volume ) 
              delete_element( element, VERSION_NORMAL );
          }
        }
      }
    }
    db_version_delete( VERSION_TMP );
    mesh_has_changed( VERSION_NORMAL );

    if ( swit ) pri( "Out routine DELETE_GEOM" );

  }

}
