# HISTORY :
#	BB Dec 1 1998

require HashObject ;
require MDL_data ;

require bb_misc ;


#**************************************************************************#
package MDL_sdf_data_field ; 
#**************************************************************************#
# A data field starts with >
$[ = 1 ; #The index of the 1st el in a array is 1 ( and not 0)
	@ISA = qw( HashObject );

	@fields_names = (
		'field_name',  #ex. <melting point>
		'field_number', #ex DTn where n is a number assigned to a field in the database
		'data', #one or more line of max 200 chars, ends with a empty line
		'external_registry_number',  #Opt.  ex (MD-08974), needs parentheses
		'internal_registry_number',   #Opt. a number
		'rest' #Opt
	# either field_name or field_number must be present
	);

	eval( ${HashObject'new_SubClass_String} ) ;


#--------------------------------------------------------------------------#
	
	sub readFromInput
	{
		my $class = shift ;
		my $self = new($class) ;
		
		local $_ = <STDIN> ;
		
		if(! /^>/ )
		{
			return undef() ;
		}
		s/^>\s*//;
		if( s/<([^>]+)>/ /){ ($self->{'field_name'}) = $1  ;}

		if( s/\bDT(\d+)\b/ / ){
		($self->{'field_number'}) =  $1;}

		
		if( s/\((.+)\)/ / ){
		($self->{'external_registry_number'}) =  $1;}

		
		if(s/\b(\d+)\b/ / ){
		($self->{'internal_registry_number'}) =  $1;}
		
		s/^\s+//;
		s/\s+$// ;
		
		if(! /^\s*$/) {
		$self->{'rest'} = $_ ;}
		
			
		while( <STDIN> )
		{
			#To avoid a warning
			if(! defined $self->{'data'} )
			{$self->{'data'} = '' ;}
			
			/^\s*$/ && last ;
			/^\${4}\s*$/ && last ;
			$self->{'data'} = $self->{'data'} . $_ ;
		}		
		
		#Clean : remove trailing blanks
		$self->{'data'} =~ s/\s+$//;
		return $self ;
		
	}

#--------------------------------------------------------------------------#
sub write	{
	my $self = shift ;

	defined $self->{'data'} || return $self ;
	
	print("> ") || die "Write error";
	defined $self->{'field_name'} && printf( " <%s>", $self->{'field_name'}) ;
	defined $self->{'external_registry_number'} && printf( " (%s)", $self->{'external_registry_number'}) ;
	defined $self->{'field_number'} && printf( " DT%d", $self->{'field_number'}) ;
	defined $self->{'internal_registry_number'} && printf( " %s", $self->{'internal_registry_number'}) ;
	defined $self->{'rest'} && printf( " %s", $self->{'rest'}) ;
	print("\n") || die "Write error";
	print($self->{'data'}) || die "Write error";
	print("\n\n") || die "Write error";
	

}
#**************************************************************************#
package MDL_sdf_data_fields ; 
#**************************************************************************#
$[ = 1 ; #The index of the 1st el in a array is 1 ( and not 0)
	@ISA = qw( HashObject );

	@fields_names = (
		'fields'  #ref array of MDL_sdf_data_field		
	);

	eval( ${HashObject'new_SubClass_String} ) ;

#--------------------------------------------------------------------------#
	
sub readFromInput {
	my $class = shift ;
	my $self = new($class) ;
	
	my @fields = () ;
	my $data_field =  MDL_sdf_data_field->readFromInput() ;
	
	while( $data_field  )
	{
		push( @fields, $data_field);
		$data_field =  MDL_sdf_data_field->readFromInput() ;
	}


	$self->{'fields'} = \@fields ;
	
	return $self;
}
#--------------------------------------------------------------------------#
sub init
{
	my $self = shift ;
	
	$self->{'fields'} =[] ;
	
	return $self ;
}
#--------------------------------------------------------------------------#
sub write	{
	my $self = shift ;
	
	
	my @fields = @{$self->{'fields'}} ;
	
	defined @fields || return $self ;
	
	foreach $f (@fields)
	{
		$f -> write() ;
	}
	
	return $self ;
}

#--------------------------------------------------------------------------#
#returns the data (value) associated with the argument (key)
sub data_for_field_name
{
	my $self = shift ;
	my $field_name = shift ;
	
	main'is_array_ref( $self->{'fields'}) || die" Assertion failed: \@fields is undefined";
	my @fields = @{$self->{'fields'}} ;
	
	
	foreach $sdf_field (@fields)
	{
		defined $sdf_field || die" Assertion failed: \$sdf_field is undefined";
		if( $sdf_field->{'field_name'} eq $field_name )
		{
			return $sdf_field->{'data'} ;
		}
	}

	
	return undef ;
}
#--------------------------------------------------------------------------#
sub at_fieldName_put_data
{
	my $self = shift ;
	my $field_name = shift ;
	my $data_string = shift ;
	
	defined $self || die" Assertion failed: \$self is undefined";
	main'is_array_ref($self->{'fields'} ) || die " Assertion failed: fields";
	
	
	foreach $sdf_field (@{$self->{'fields'}})
	{
		defined $sdf_field || die" Assertion failed: \$sdf_field is undefined";
		if( $sdf_field->{'field_name'} eq $field_name )
		{
			$sdf_field->{'data'} = $data_string;
			return $sdf_field;
		}
	}
	my $new_data_field = new MDL_sdf_data_field ;
	$new_data_field->{'field_name'} = $field_name ;
	$new_data_field->{'data'} = $data_string ;
	
	push(@{$self->{'fields'}},$new_data_field ) ;
	
	return 	$new_data_field ;

}

#--------------------------------------------------------------------------#
#Remove all entries that match the argument

sub remove_fieldName
{
	my $self = shift ;
	my $field_name = shift ;
	
	defined $self || die" Assertion failed: \$self is undefined";
	main'is_array_ref($self->{'fields'} ) || die " Assertion failed: fields";
	
	my @new_fields = () ;
	foreach $sdf_field (@{$self->{'fields'}})
	{
		defined $sdf_field || die" Assertion failed: \$sdf_field is undefined";
		if( $sdf_field->{'field_name'} ne $field_name )
		{
			push(@new_fields, $sdf_field) ;
		}
	}

	$self->{'fields'} = \@new_fields; 
	
	
	return 	$self ;

}

#--------------------------------------------------------------------------#
#Remove all entries

sub removeAll
{
	my $self = shift ;
	defined $self || die" Assertion failed: \$self is undefined";
	main'is_array_ref($self->{'fields'} ) || die " Assertion failed: fields";

	my @new_fields = () ;

	$self->{'fields'} = \@new_fields; 
	
	
	return 	$self ;

}

#**************************************************************************#
package MDL_sdf ; #One structure data entry
#**************************************************************************#
$[ = 1 ; #The index of the 1st el in a array is 1 ( and not 0)
	@ISA = qw( HashObject );

	@fields_names = (
		'molecule' ,
		'fields'  # MDL_sdf_data_fields		
	);

	eval( ${HashObject'new_SubClass_String} ) ;
#--------------------------------------------------------------------------#
sub init
{
	my $self = shift;
	$self->{'molecule'} = undef;
	$self->{'fields'} = MDL_sdf_data_fields->new() ;
	$self->{'fields'}->init() ;
	
	$self ;
}
#--------------------------------------------------------------------------#
	
sub readFromInput {
	my $class = shift ;
	my $self = new($class) ;
	
	$self->init() ;
	
	$mol = MDL_molecule->readFromInput() ;
	
	if(! defined $mol )
	{
		return undef ;
	}
	
	$self->{'molecule'}  = $mol ;
	if( ! /^\$\$\$\$/ )
	{
		$self->{'fields'}  = MDL_sdf_data_fields->readFromInput() ;
	} #else no data fields
	
	
	return $self;
}

#--------------------------------------------------------------------------#
sub write	{
	my $self = shift ;
	
	defined $self->{'molecule'} || return $self ;
	($self->{'molecule'}) -> write() ;
	
	if( defined $self->{'fields'})
	{
		( $self->{'fields'} ) -> write() ;
	}
	
	print( '$$$$', "\n") || die "write error";
	
	return $self ;
}
#--------------------------------------------------------------------------#
#answer the data for the first line of the molecule
#( some programs store the entry id there)

sub line1
{
	my $self = shift ;
	
	defined $self->{'molecule'} || die "Undefined molecule" ;
	
	return ($self->{'molecule'})->{'line1'} ;
	

}
#--------------------------------------------------------------------------#
#answer the data for a key in the  MDL_sdf_data_fields
#answer undef if not found

sub data_for_field_name
{
	my $self = shift ;
	my $field_name = shift ;
	
	defined $self->{'fields'} || die "Undefined \@fields" ;
	
	return ($self->{'fields'})->data_for_field_name($field_name) ;
	

}
#--------------------------------------------------------------------------#
#add/replace values in  MDL_sdf_data_fields
#The argument type is  hash ref

sub addReplaceProperties
{
	my $self = shift ;
	my $dict_ref_hash = shift ;
	
	(ref($dict_ref_hash ) eq 'HASH') || die "Argument to addReplaceProperties() must be a reference to a hash table";
	
	defined $self->{'fields'} || die "Undefined \@fields" ;

	while(($key, $value) = each( %$dict_ref_hash))
	{
		($self->{'fields'})->at_fieldName_put_data($key, $value);
	}


	return $self ;
}
#--------------------------------------------------------------------------#
#Remove all fields with a given name

sub remove_fieldName
{
	my $self = shift ;
	my $fieldname = shift ;
	
	defined($fieldname) || die "Assertion failed: field name is undefined" ;
	
	defined $self->{'fields'} || die "Undefined \@fields" ;

	$self->{'fields'}->remove_fieldName( $fieldname) ;

	return $self ;

}
#--------------------------------------------------------------------------#
#Remove all fields 

sub remove_all_fields
{
	my $self = shift ;
	defined $self->{'fields'} || die "Undefined \@fields" ;
	
	$self->{'fields'}->removeAll() ;
	
	return $self ;
}



#**************************************************************************#
package  MDL_sdf_non_parsed_molecule; #One structure data entry
#**************************************************************************#
$[ = 1 ; #The index of the 1st el in a array is 1 ( and not 0)
	@ISA = qw( MDL_sdf );

	@fields_names = (
	
	);

	eval( ${HashObject'new_SubClass_String} ) ;

#--------------------------------------------------------------------------#
	
sub readFromInput {
	my $class = shift ;
	my $self = new($class) ;
	$self->init() ;
	
	$mol = MDL_non_parsed_molecule->readFromInput() ;
	
	if(! defined $mol )
	{
		return undef ;
	}
	
	$self->{'molecule'}  = $mol ;
	if( ! /^\$\$\$\$/ )
	{
		$self->{'fields'}  = MDL_sdf_data_fields->readFromInput() ;
	} #else no data fields
	
	
	return $self;
}

#--------------------------------------------------------------------------#



1;
