package GO::Object::Tool;

=head1 NAME

GO::Object::Tool       - represents a GO::Object::Tool on the GO tools page

=cut

use strict;
use Data::Dumper;
use Exporter;
use lib '/Users/gwg/go/scratch/tools';
use vars qw(@ISA);
use base qw(GO::Object::Generic); #GO::MiniTests);
use GO::Object::Developer;
use GO::Object::URL;
use GO::TestSet qw(dfv_test);
use Data::FormValidator::Constraints qw(:closures);


sub _specification {
	my $self = shift;
	
	our $list_values = {
#		license => [ 'free_academic', 'proprietary', ],#'other' ],
#		tool_type => [ 'online', 'standalone' ],
#		compatible_os => [ 'win', 'mac', 'unix', 'linux' ],
#		feature => [ 'ont_view', 'annot_view', 'ont_edit', 'annot_edit', 'godb', 'stat', 'sw', 'textmine', 'data', 'id_map', 'other_feature' ],
#		go_data_used => [ 'tree', 'term', 'def', 'synonym', 'relationship', # ontology
#			'assoc', 'evcode', 'ref', 'qual', 'not' ],  # association data

		## Compatible OS
		compatible_os => [
			'win', 'Windows',
			'mac', 'Mac OS X',
			'linux', 'Linux',
			'unix', 'Unix',
		],
		
		## Tool features
		feature => [
			'ont_view', 'ontology viewer / browser',
			'annot_view', 'annotation viewer / browser',
			'ont_edit', 'ontology editor',
			'annot_edit', 'annotation editor', 
			'godb', 'GO database',
			'stat', 'statistical analysis',
			'sw', 'software library',
			'textmine', 'text mining',
			'data', 'data warehouse',
			'id_map', 'ID mapping',
		],
		
		## license
		license => [
			'free_academic', 'free for academic use',
			'proprietary', 'proprietary software',
			'other_license', 'other license',
		],
	
		## GO data
		go_data_used => [
			# ontology data
			'term', 'GO terms',
			'def', 'term definitions',
			'synonym', 'term synonyms',
			'tree', 'ontology tree', 
			'relationship', 'relationships between terms',
			# association data
			'assoc', 'association (annotation) data',
			'evcode', 'evidence codes for annotations',
			'ref', 'references for annotations',
			'qual', 'annotation qualifiers (e.g "contributes to")',
			'not', 'NOT (negative) annotations',
			# gene product data
			'gp_spp', 'gene product species',
			'gp_seq', 'gene product sequences',
			# other stuff
			'mappings', 'mappings to other databases',
		],
	};


	sub get_list_values {
		my $param = shift;
		return if !$list_values->{$param};
		my $n = 0;
		
		return [ grep { $_ if ! ( $n++ % 2 ) } @{$list_values->{$param}} ];
	}
	
	sub get_value_human_name_h {
		my $param = shift;
		return if !$list_values->{$param};
		my %hash = ( @{$list_values->{$param}} );
		return { %hash }
	
	}

	return (
		# required
		{	id => 'name',
			required => 1,
			test => [ dfv_test('is_a_string_p', { this => 1 }), FV_min_length(2), ],
			human_name =>'Tool name',
		},
		{	id => 'url',
			required => 1,
			test => dfv_test('is_an_url_p', { this => 1 }),
			human_name =>'Tool URL',
		},
		{	id => "email",
			required => 1,
			test => email(),
			human_name =>'Contact email for tool',
		},
		{	id => "developer", # id => "developer_list",
			required => 1,
			allow_multiple => 1,
			type => 'GO::Object::Developer',
			test => dfv_test('is_subclass_of_p', { class => 'GO::Object::Developer', this => 1 }, ),
			human_name =>'Tool developer(s)',
		},
		{	id => "license",
			required => 1,
			test => dfv_test('is_in_list_p', { list => get_list_values('license'), this => 1 }),
			human_name =>'License',
			list_values => get_list_values('license'),
			list_values_human_name_h => get_value_human_name_h('license'),
			default => 'free_academic',
		},
		{	id => "description",
			required => 1,
			test => [ qr/\w{3,}/, FV_min_length(50), ],
			human_name =>'Tool description',
		},

		# required, booleans
		{	id => "is_online_tool",
			test => dfv_test('is_true_p'),
			human_name =>'Web-based tool',
		},
		{	id => "is_standalone_tool",
			test => dfv_test('is_true_p'),
			human_name =>'Standalone (downloadable) tool',
		},

		{	id => "compatible_os", # id => "compatible_os_list",
			allow_multiple => 1,
			test => [ dfv_test('is_in_list_p', { list => get_list_values('compatible_os'), this => 1 }) ],
#			dependencies => [ 'is_standalone_tool' ],
			human_name =>'Compatible operating systems (for standalone tools)',
			list_values => get_list_values('compatible_os'),
			list_values_human_name_h => get_value_human_name_h('compatible_os'),
		},

		{	id => "feature", # id => "feature_list",
			required => 1,
			allow_multiple => 1,
			test => [ #qr/ont/, 
							dfv_test('is_in_list_p', { list => get_list_values('feature'), this => 1 }) ],
			human_name =>'Tool feature list',
			list_values => get_list_values('feature'),
			list_values_human_name_h => get_value_human_name_h('feature'),
		},
		
		# optional, list
		{	id => "publication", # id => "publication_list",
			allow_multiple => 1,
			test => [ dfv_test('is_a_string_p', { this => 1 }), FV_min_length(10) ],
			human_name =>'Publication(s) relating to the tool',
#			valid_prefixes => [ 'pmid', 'doi' ],
		},

		# optional, boolean
		{	id => "is_open_source",
			test => dfv_test('is_true_p', { this => 1 }),
			human_name =>'Open-source tool',
		},
		{	id => "url_source",
			test => dfv_test('is_an_url_p', { this => 1 }),
			dependencies => [ 'is_open_source' ],
			human_name =>'URL for tool source code',
		},

	## what GO data is used
		{	id => "go_data_used", # id => "go_data_used_list",
			allow_multiple => 1,
			test => dfv_test('is_in_list_p', { list => get_list_values('go_data_used'), this => 1 }),
			human_name =>'GO data used by the tool',
			list_values => get_list_values('go_data_used'),
			list_values_human_name_h => get_value_human_name_h('go_data_used'),
		},

	## GO data source
		{	id => "go_data_source",
			# should this be an URL?
			test => [ dfv_test('is_a_string_p', { this => 1 }), FV_min_length(5), ],
			human_name =>'Source of GO data',
		},
		
	## GO data update frequency
		{	id => "go_data_update_frequency",
			test => [ dfv_test('is_a_string_p', { this => 1 }), FV_min_length(5), ],
			human_name =>'Frequency at which GO data is updated',
			# daily, weekly, monthly, n_per_week, n_per_month, n_per_year, unknown
		},
		
		{	id => "submission_date", # get this from the CGI
			test => dfv_test('is_a_date_p', { this => 1 }),
		},

		# generated automatically
#		{	id => "name_lc",
#			constructor => 'automatic',
#		},
#		{	id => "name_acronym",
#			constructor => 'automatic',
#			test => dfv_test('is_a_string_p', { this => 1 }),
#			human_name =>'Acronym',
#		},
#		{	id => "name_abbr",
#			constructor => 'automatic',
##			test => dfv_test('is_a_string_p', { this => 1 }),
#			human_name =>'Abbreviated name',
#		},


	);
}



sub _dfv_data {
	return {
		'require_some' => {
			tool_type_group => [ 1, 'is_standalone_tool', 'is_online_tool' ],
		},
		'dependency_groups' => {
			standalone_os_group => [ 'is_standalone_tool', 'compatible_os' ],
		},
	};
}


sub transform_parsed_data {
	my $self = shift;
	my $arg_h = shift;
	my $data_h = $arg_h->{data};
	my $spec_h;

	## do any transformations here
#	if ($data_h->{developer_list})
	if ($data_h->{developer})
	{	my $temp;
		if (!$spec_h->{dev_spec})
		{	$spec_h->{dev_spec} = GO::Object::Developer->get_spec();
			$spec_h->{dev_dfv_profile} = GO::Object::Developer->dfv_profile();
		}
#		foreach (@{$data_h->{developer_list}})
		foreach (@{$data_h->{developer}})
		{	my $dev_h;
			($dev_h->{url}, $dev_h->{fn}) = split(" ", $_, 2);
			if ($dev_h->{fn} =~ /^\s*\"(.*)\" ?(.*?)$/)
			{	$dev_h->{fn} = $1;
				my $rest = $2;

				#	split up 'rest' by ;\s
				my @rest_parts = split('; ', $rest);
				foreach (@rest_parts)
				{	if (/^\s?(.*?):\s?(.+)\s?$/)
					{	$dev_h->{$1} = $2;
					}
				}
			}
			
			# create a developer object 
			my $results = GO::Object::Developer->new({ data => $dev_h,
				object_spec => $spec_h->{dev_spec},
				dfv_profile => $spec_h->{dev_dfv_profile},
				check_input => $arg_h->{check_input} || undef,
				return_as => 'success_hash',
			});
			if ($results->{SUCCESS})
			{	# put the object into the temp list
				push @$temp, $results->{OBJECT};
			}

			if ($results->{ERROR_LIST})
			{	$self->add_message($results->{ERROR_LIST});
			}
		}
		delete $data_h->{developer};
		$data_h->{developer} = $temp if $temp && @$temp;
#		delete $data_h->{developer_list};
#		$data_h->{developer_list} = $temp if $temp && @$temp;
	}
}


sub add_developer {
	my $self = shift;
	my $arg_h = shift;
	if (! ref $arg_h)
	{	# we have a string as the argument
		$arg_h = { data => { name => $arg_h } };
	}
	
	my $results = GO::Object::Developer->new({
		%$arg_h,
		return_as => 'success_hash',
	});

	if ($results->{SUCCESS})
	{	# hurrah!
		if (!$arg_h->{add_as})
#		{	$arg_h->{add_as} = 'developer_list';
		{	$arg_h->{add_as} = 'developer';
		}
		push @{$self->{ $arg_h->{add_as} }}, $results->{OBJECT};
	}
	
	if ($results->{ERROR_LIST})
	{	$self->add_message($results->{ERROR_LIST});
	}
}


sub name_lc {
	my $self = shift;
	return $self->{name_lc} if $self->{name_lc};
	
	my $name_lc = lc($self->{name}) || return;
	$name_lc =~ s/\W/_/g; # convert non-alphanum characters into _
	$self->{name_lc} = $name_lc;
	return $self->{name_lc};
}

sub email_id {
	my $self = shift;
	my $email = $self->email;
	(my $id = $email) =~ s/\@.+//;
	return $id;
}

sub email_place {
	my $self = shift;
	my $email = $self->email;
	(my $place = $email) =~ s/.+\@//;
	return $place;
}


1;