#!/usr/bin/perl
#
# $Id: ScanSet.pm,v 1.10 2001/11/24 22:28:15 levine Exp $
#
# Copyright (C) 2000  James D. Levine (jdl@vinecorp.com)
#
#
#   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, Inc., 59 Temple Place - Suite 330, Boston, MA 
#   02111-1307, USA.
#
####################################################################

use strict;

use PortScan::ScannedHost;

package PortScan::ScanSet;

sub new
{
    my ($type, $tag, $hosts, $properties, $ports) = @_;

    $hosts = {} if !defined $hosts; 
    $properties = {} if !defined $properties;
    $ports = {} if !defined $ports;

    my $self = 
    {
	tag => $tag,		# identifying tag for the scanset used by DataStore
	properties => $properties, # hash of key to value mappings
	hosts => $hosts,  # hash of IP (dotted-quad text) to ScannedHost mappings
	all_scanned_ports => $ports,  # hash of PortSpec::key_for() to PortSpec mappings
                                      # dummy PortSpecs for all ports scanned
    };

    bless $self, $type;

    return $self;
}

# private util to output a hash
sub hash_to_text
  {
    my $h = shift;
    my $t;
    while (my ($k, $v) = each %$h)
      {
	$t .= "`${k}' -> `${v}'\n";
      }
    $t;
  }

# outputs a ScanSet in human readable form
sub to_text
  {
    my $self = shift;

    return
      "tag: " . $self->{tag} . "\n" 
    . "properties:\n" 
    . hash_to_text($self->{properties}) 
    . "hosts:\n"  
    . hash_to_text($self->{hosts})
      ;
  }

# generic accessor
sub set_or_get
{
    my $field = shift;
    my $self = shift;
    my $val = shift;

    $self->{$field} = $val if defined $val;

    return $self->{$field};
}

# set/get the tag associated with the set
sub tag
{
    return set_or_get('tag', @_);
}

# clones this instance
sub clone_deep
{
    my( $self, $from, $when, $tag1, $tag2 ) = @_;

    my $hosts = {};
    my $properties = {};

    my ($k, $v);
    my $h = $self->hosts();

    while ( ($k, $v) = each %$h )
    {
	$hosts->{$k} = $v->clone();
    }

    my $p = $self->{properties};
    while ( ($k, $v) = each %$p)
    {
	$properties->{$k} = $v;
    }

    return new ScanSet($from, $when, $tag1, $tag2, $hosts, $properties);
}

# set an arbitrary piece of metadata
sub set_property
{
    my( $self, $k, $v ) = @_;
    $self->{properties}->{$k} = $v;
}

# retrieve a piece of metadata by name
sub get_property
{
    my( $self, $k ) = @_;
    $self->{$k};
}

# set/get the hash of hosts in the set
sub hosts { return set_or_get('hosts', @_); }

# set/get the hash of metadata
sub properties { return set_or_get('properties', @_); }

# set/get the hash of all ports scanned
sub all_scanned_ports { return set_or_get('all_scanned_ports', @_); }

# TODO: where is this used??
sub prune
{
    my( $self ) = shift;

    my $hosts = $self->hosts;

    while( my( $name, $host ) = each %$hosts )
    {
	print "------------> prune: processing $name \n";
	    my $portspecs = $host->port_specs();
	    my @ports = keys %$portspecs;
	print "default_state is " . $host->default_state . " \n";
	print "number of ports is $#ports \n";

		if( ( $host->default_state eq "unknown" )  &&
		    ( $#ports == -1 )
		    )
		{
		    print "prune: removing $name \n";
		    $self->remove_host( $name )
	    }
    
    }
}

# adds a PortScan::PortSpec instance to the master set of scanned ports 
sub add_scanned_port 
{
    my( $self, $spec ) = @_;

    $self->all_scanned_ports()->{$spec->key_for()} = $spec;
}

# returns the list of hosts (PortScan::ScannedHost) sorted in IP address order
sub hosts_sorted_list
{
    my $self = shift;
    return PortScan::ScannedHost::sorted_list values %{$self->hosts()};
}


# add a ScannedHost instance 

sub add_host
{
    my( $self, $scanned_host ) = @_;
    $self->hosts()->{ $scanned_host->addr() } = $scanned_host;
    $scanned_host->scan_set($self);
}

# remove a ScannedHost instance identified by its IP address in dotted-quad
# text rep
sub remove_host
{
    my( $self, $addr ) = @_;
    delete $self->hosts()->{$addr};
}


# retrieve a ScannedHost instance identified by its IP address in dotted-quad
# text rep
sub get_host
{
    my( $self, $addr ) = @_;
    $self->hosts()->{$addr};
}

1;




