/* modification.cc */

#include "modification.h"
#include "component.h"
#include "root.h"
#include "element.h"

dc_modification::dc_modification( cstring hpath, dc_node *parent )
  : hash_path( hpath ) {
  set_both( string( "~modification#%d~", next_tag() ), parent );
  //  set_dormant( true );
  set_visible( false );
  mod_list_ptr = root.mod_list.append( this );
  done = false;
}

dc_modification::~dc_modification( void ) { 
  //clear_mods();
  root.mod_list.del( mod_list_ptr );
}

void dc_modification::clear_mods( void ) {
  while( !child_list.empty() ) {
    dc_label *mod = child_list.inf( child_list.first_item() );
    delete( mod );
  }
}

int dc_modification::modify( void ) {
  dc_node *parent = get_parent();
  if( done || ( parent && parent->sub_type() == Component_t && 
      ( ( dc_component * )parent )->is_dormant() ) ) {
    //cerr << "SKIPPING MODIFY OF " << hash_path << " FROM " << parent->full_type() << "\n";
    return 0;
  }

  dc_component *c = ( dc_component * )t_search( hash_path, Component_t, 
						get_parent(), false );

  if( c == nil ) {
    dc_trace( TRACE_ERROR ) {
      cerr << "dc_modification::modify -- could not locate \"" << hash_path 
	   << "\" from " 
	   << ( get_parent() ? get_parent()->full_type() : string( "root" ) )
	   << "\n";
    }
    return 1;
  }

  //cerr << "MODIFYING " << c->full_type() << " FROM " << parent->full_type() << "\n";

  int nerrors = 0;

  if( replacement_template.length() ) {
    c->set_template( replacement_template );
  }

  dic_item di;
  forall_items( di, child_list ) {
    dc_label *mod = child_list.inf( di );

    dc_label *l = c->lookup_child( mod->local_label() );
    if( l ) delete( l );

    dc_label *dupe = mod->duplicate( c );
    dupe->set_templated( true );
    if( dupe == nil ) {
      nerrors++;
    } 
  }

  c->inherit_u_types( uts );

  if_trc( nerrors != 0, TRACE_ERROR ) {
    cerr << "dc_modification -- " << nerrors << " error " 
	 << ( nerrors != 1 ? "s" : "" )  << " modifying " 
	 << c->full_type() << "\n";
  }

  done = true;
  
  return nerrors;
}

/* duplicate children as dormant unless */
void dup_child_dormant( dc_label *child, void *dupe ) {
  dc_label *dupe_child = child->duplicate( ( dc_node * )dupe );
  if( dupe_child ) {
    dupe_child->set_templated( true );
    switch( dupe_child->sub_type() ) {
    case Component_t : case Modification_t : case GA_t :
      ( ( dc_component * )dupe_child )->set_dormant( true );
      break;
    case Element_t :
      ( ( dc_element * )dupe_child )->set_dormant( true );
      break;
    default :;
    }
  } else {
    dc_trace( TRACE_ERROR ) {
      cerr << "dc_modification::duplicate -- failed to duplicate child " 
	   << child->full_type() << "\n";
    }
  }
}

dc_label *dc_modification::duplicate( dc_node *parent ) const {
  /*cerr << "COPYING MODIFICATION \"" << local_label() << "\" OF " << hash_path 
       << " TO " << parent->full_type() << "\n";*/
  dc_modification *dupe = new dc_modification( hash_path, parent );

  dupe->set_replacement_template( replacement_template );

  dupe->uts = uts;
  
  /* duplicate sub-elements and sub-components */
  for_children( dup_child_dormant, ( void * )dupe, true );

  return ( dc_label * )dupe;
}

void dc_modification::child_init( dc_label *child ) {
  dc_component::child_init( child ); 
  switch( child->sub_type() ) {
  case Component_t : case Modification_t : case GA_t :
    ( ( dc_component * )child )->set_dormant( true );
    break;
  case Element_t :
    ( ( dc_element * )child )->set_dormant( true );
    break;
  default :;
  }
}
