#!/usr/bin/perl -w
############################################################
#
# $Id: graph-set-attributes,v 1.7 2011/02/17 04:54:49 rsat Exp $
#
# Time-stamp: <2003-07-04 12:48:55 jvanheld>
#
############################################################

## use strict;

=pod

=head1 NAME

graph-set-attributes

=head1 DESCRIPTION

Set attributes of selected nodes to a given value.

=head1 AUTHORS

=over

=item Jacques.van-Helden\@univ-amu.fr

=head1 CATEGORY

graph analysis

=head1 USAGE
    
graph-set-attributes [-i graph_file] -nodes node_file -attr key1 value1 
   [-attr key2 value2 ...] [-o outputfile] [-v #] [...]

graph-set-attributes [-i graph_file] -all -attr key1 value1 
   [-attr key2 value2 ...] [-o outputfile] [-v #] [...]

=head1 INPUT FORMAT

See convert-graph for a description of the supported input and output
formats.

=head1 OUTPUT FORMAT

=cut


BEGIN {
    if ($0 =~ /([^(\/)]+)$/) {
	push (@INC, "$`lib/");
    }
}
require "RSA.lib";
require RSAT::Graph;

################################################################
## Main package
package main;
{

    ################################################################
    ## Initialise parameters
    local $start_time = &RSAT::util::StartScript();

    @seed_names = (); ## Names of the seed nodes
    @seed_nodes = (); ## Seed node objects
    @unknown_nodes = (); ## Names of the unidentified nodes
    $all_seeds = 0; ## Use all nodes as seeds

    ################################################################
    ## Initialize the graph
    $graph = new RSAT::Graph();
    $graph->set_attribute("label", "graph");

    ## Columns of the tab-delimited graph file
    local $source_col = 1;
    local $target_col = 2;
    local $weight_col = 0;


    ## Output formats
    %supported_output_format =(
			       dot=>1,
			       gml=>1,
			       gdl=>1,
    );
    $supported_output_formats = join (",", keys %supported_output_format);
    local $output_format = "gml";

    %main::infile = ();
    %main::outfile = ();

    $main::verbose = 0;
#    $main::in = STDIN;
    $main::out = STDOUT;

    ################################################################
    ## Read argument values
    &ReadArguments();

    ################################################################
    ## Check argument values

    ################################################################
    ## Open output stream
    $main::out = &OpenOutputFile($main::outfile{output});

    ################################################################
    ## Read input graph
    $graph->read_from_table($infile{graph}, $source_col, $target_col, $weight_col);


    ################################################################
    ## Build the list of seed nodes

    ## Use all nodes as seeds
    if ($all_seeds) {
      @seed_nodes = $graph->get_nodes();
      &RSAT::message::TimeWarn("Using all",scalar(@seed_nodes), "nodes of the graph as seeds") if ($main::verbose >= 2);
      ## Put the name of each node in the list
      @seed_names = ();
      foreach my $node (@seed_nodes) {
	my $name = $node->get_attribute("label");
	push @seed_names, $name;
      }
    } else {

      ## Read seed nodes from a file
      if ($infile{seeds}) {
	my $l = 0;
	&RSAT::message::TimeWarn("Reading seed nodes from file", $infile{seeds}) if ($main::verbose >= 2);
	my ($seed_handle) = &OpenInputFile($infile{seeds});
	while (my $line = <$seed_handle>) {
	  $l++;
	  next if ($line =~ /^\#/); ## Skip header lines
	  next if ($line =~ /^--/); ## Skip comment lines
	  next if ($line =~ /^;/); ## Skip comment lines
	  next unless ($line =~ /\S/); ## Skip empty lines
	  chomp($line);
	  my @fields = split /\s+/, $line;
	  my $name =  $fields[0];
	  if ($name) {
	    push @seed_names,$name;
	  } else {
	    &RSAT::message::Warning("Line", $l, "starts with space. Skipped.");
	  }
	}
	close $seed_handle;
      }

      ## Identify seed nodes in the graph
      &RSAT::message::TimeWarn("Identifying",scalar(@seed_names), "seed nodes in the graph") if ($main::verbose >= 2);
      foreach my $name (@seed_names) {
	my $node = $graph->node_by_id($name);
	if ($node) {
	  push @seed_nodes, $node;
	  &RSAT::message::Info("Identified node with name", $name, $node->get_attribute("id")) if ($main::verbose >= 3);
	} else {
	  push @unknown_nodes, $name;
	  &RSAT::message::Warning("The graph does not contain any node with name", $name);
	}
      }
    }

    ################################################################
    ## Print verbose
    &Verbose() if ($main::verbose);

    ## Print the output graph
    print $out $cluster_graph->to_text($output_format);

    ################################################################
    ## Close output stream
    my $exec_time = &RSAT::util::ReportExecutionTime($start_time);
    print $main::out $exec_time if ($main::verbose >= 1);
    close $main::out if ($main::outfile{output});

    exit(0);
}

################################################################
################### SUBROUTINE DEFINITION ######################
################################################################


################################################################
## Display full help message 
sub PrintHelp {
    system "pod2text -c $0";
    exit()
}

################################################################
## Display short help message
sub PrintOptions {
    &PrintHelp();
}

################################################################
## Read arguments 
sub ReadArguments {
    my $arg;
    my @arguments = @ARGV; ## create a copy to shift, because we need ARGV to report command line in &Verbose()
    while (scalar(@arguments) >= 1) {
      $arg = shift (@arguments);
	## Verbosity
=pod

=head1 OPTIONS

=over 4

=item B<-v #>

Level of verbosity (detail in the warning messages during execution)

=cut
	if ($arg eq "-v") {
	    if (&IsNatural($arguments[0])) {
		$main::verbose = shift(@arguments);
	    } else {
		$main::verbose = 1;
	    }

	    ## Help message
=pod

=item B<-h>

Display full help message

=cut
	} elsif ($arg eq "-h") {
	    &PrintHelp();

	    ## List of options
=pod

=item B<-help>

Same as -h

=cut
	} elsif ($arg eq "-help") {
	    &PrintOptions();

	    ## Graph file
=pod

=item B<-i graphfile>

If no graph file is specified, the standard input is used.  This
allows to use the command within a pipe.

=cut
	} elsif ($arg eq "-i") {
	    $main::infile{graph} = shift(@arguments);

	    ## Source column
=pod

=item B<-scol>

Source column. Column containing the source nodes in the tab-delimited
graph file.

=cut
	} elsif ($arg eq "-scol") {
	    $source_col = shift (@arguments);
	    unless (&IsNatural($source_col) && ($source_col > 0)) {
		&RSAT::error::FatalError(join("\t", $source_col, "Invalid value for the source column. Must be a strictly positive natural number"));
	    }

	    ## Target column
=pod

=item B<-tcol>

Target column. Column containing the target nodes in the tab-delimited
graph file.

=cut
	} elsif ($arg eq "-tcol") {
	    $target_col = shift (@arguments);
	    unless (&IsNatural($target_col) && ($target_col > 0)) {
		&RSAT::error::FatalError(join("\t", $target_col, "Invalid value for the target column. Must be a strictly positive natural number"));
	    }

	    ## Weight column
=pod

=item B<-wcol>

Weight column. Column containing the weight nodes in the tab-delimited
graph file.

=cut
	} elsif ($arg eq "-wcol") {
	    $weight_col = shift (@arguments);
	    unless (&IsNatural($weight_col) && ($weight_col > 0)) {
		&RSAT::error::FatalError(join("\t", $weight_col, "Invalid value for the weight column. Must be a strictly positive natural number"));
	    }


=pod

=item B<-nodes node_file>

Node file. The node file specifies a list of nodes by their name/id.

Node file format: the first word of each row specifies one node. The
rest of the row is ignored.

=cut
	} elsif ($arg eq "-seedf") {
	    $main::infile{seeds} = shift(@arguments);

=pod

=item B<-all>

Set the attribute vlaues for all the nodes of the input graph. 

=cut
	} elsif ($arg eq "-all") {
	    $all_seeds = 1;

=pod

=item B<-node node>

Specify one node. This option can be used iteratively to specify
several seed nodes.

=cut
	} elsif ($arg eq "-seed") {
	    push @seed_names, shift(@arguments);


	    ## Output file
=pod

=item	B<-o outputfile>

If no output file is specified, the standard output is used.  This
allows to use the command within a pipe.

=cut
	} elsif ($arg eq "-o") {
	    $main::outfile{output} = shift(@arguments);

	    ### Output format  
=cut

=item B<-out_format output_format>

See convert-graph for a list of supported output formats.

=cut 
	} elsif ($arg eq "-out_format") {
	    $output_format = shift(@arguments);
	    &RSAT::error::FatalError("$output_format\tInvalid output format. Supported: $supported_output_formats")
		unless ($supported_output_format{$output_format});


	} else {
	    &FatalError(join("\t", "Invalid option", $arg));

	}
    }


=pod

=back

=cut

}

################################################################
#### verbose message
sub Verbose {
    print $main::out "; graph-neighbnours ";
    &PrintArguments($main::out);
    if (%main::infile) {
	print $main::out "; Input files\n";
	while (my ($key,$value) = each %main::infile) {
	    print $main::out ";\t$key\t$value\n";
	}
    }
    if (%main::outfile) {
	print $main::out "; Output files\n";
	while (my ($key,$value) = each %main::outfile) {
	    print $main::out ";\t$key\t$value\n";
	}
    }

    ## Report graph size
    my ($nodes, $arcs) = $graph->get_size();
    print $out "; Graph size\n";
    print $out ";\tnodes\t",$nodes,"\n";
    print $out ";\tarcs\t",$arcs,"\n";

    ## Report seed nodes
    print $out "; Seed nodes\t",scalar(@seed_names),"\n";
    if (@unknown_nodes) {
      print $out ";\tidentified\t",scalar(@seed_nodes),"\n";
      print $out ";\tunknown nodes\t",scalar(@seed_names) - scalar(@seed_nodes),"\n";
      foreach my $name (@unknown_nodes) {
	print $out join ("\t", ";\t", "unknown", $name), "\n";
      }
    }
}


__END__

=pod

=head1 SEE ALSO

=cut
