#!/usr/bin/perl
#  Copyright (C) 2002  Stanislav Sinyagin
#
#  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.

# Stanislav Sinyagin <ssinyagin@k-open.com>

use strict;
use warnings;
BEGIN { require '/usr/share/torrus/conf_defaults/torrus-config.pl'; }

use Getopt::Long;

use Torrus::Log;
use Torrus::ConfigTree;
use Torrus::SiteConfig;
use Torrus::ConfigBuilder;

exit(1) unless Torrus::SiteConfig::verify();

my $tree;
my $help_needed;
my $verbose = 0;

my $outfile = 'snapshot.xml';

my $filter_param;
my $filter_value;
my $filter_op = '=';

my %filterTokens;

my $creator = "Torrus version 2.09\n" .
    "This file was generated by command:\n" .
    $0 . " \\\n";
foreach my $arg ( @ARGV )
{
    if( $arg =~ /^--/ )
    {
        $creator .= ' ' . $arg . ' ';
    }
    else
    {
        $creator .= "\'" . $arg . "\'\\\n";
    }
}
$creator .= "\nOn " . scalar(localtime(time));

my $ok = GetOptions('tree=s'   => \$tree,
                    'out=s'    => \$outfile,
                    'param=s'  => \$filter_param,
                    'value=s'  => \$filter_value,
                    'op=s'     => \$filter_op,
                    'verbose'  => \$verbose,
                    'help'     => \$help_needed);

if( not $ok or not $tree or $help_needed or
    ( defined($filter_param) + defined($filter_value) == 1 ) or
    ( $filter_op ne '=' and $filter_op ne 'eq' and $filter_op ne 're' ) or
    scalar(@ARGV) > 0 )
{
    print STDERR "Usage: $0 --tree=NAME [options...]\n",
    "Options:\n",
    "  --tree=NAME     tree name\n",
    "  --out=filename  output file [".$outfile."]\n",
    "  --param=PARAM --value=VALUE \n",
    "                  filter the output by leaves with specified value\n",
    "  --op=OP         filter operation [=|eq|re], default: [=]\n",
    "  --verbose       print extra information\n",
    "  --help          this help message\n";
    exit 1;
}

if( $verbose )
{
    Torrus::Log::setLevel('verbose');
}

if( not Torrus::SiteConfig::treeExists( $tree ) )
{
    Error('Tree ' . $tree . ' does not exist');
    exit 1;
}

&Torrus::DB::setSafeSignalHandlers();

my $filter_match = sub {return $_[0] == $filter_value};

if(defined($filter_param))
{
    if( $filter_op eq 'eq' )
    {
        $filter_match = sub {return $_[0] eq $filter_value};
    }
    elsif( $filter_op eq 're' )
    {
        $filter_match = sub {return $_[0] =~ $filter_value};
    }
}

{
    my $config_tree = new Torrus::ConfigTree( -TreeName => $tree, -Wait => 1 );
    if( not defined( $config_tree ) )
    {
        exit 1;
    }
    
    my $cb = new Torrus::ConfigBuilder;
    
    $cb->addCreatorInfo( $creator );
    
    # We don't collect views, since they are in defaults.xml which is always
    # included
    
    collect_monitors( $config_tree, $cb );
    collect_tokensets( $config_tree, $cb );
    collect_definitions( $config_tree, $cb );
    collect_datasources( $config_tree, $cb );

    $ok = $cb->toFile( $outfile );
    if( $ok )
    {
        Verbose('Wrote ' . $outfile);
    }
    else
    {
        Error('Cannot write ' . $outfile . ': ' . $!);
    }
}

exit($ok ? 0:1);

sub collect_monitors
{
    my $config_tree = shift;
    my $cb = shift;

    my $monitorsNode = $cb->startMonitors();

    foreach my $action ( $config_tree->getActionNames() )
    {
        &Torrus::DB::checkInterrupted();
        
        my $params = $config_tree->getParams( $action );
        $cb->addMonitorAction( $monitorsNode, $action, $params );
    }

    foreach my $monitor ( $config_tree->getMonitorNames() )
    {
        &Torrus::DB::checkInterrupted();
        
        my $params = $config_tree->getParams( $monitor );
        $cb->addMonitor( $monitorsNode, $monitor, $params );
    }
    return;
}

sub collect_tokensets
{
    my $config_tree = shift;
    my $cb = shift;

    my $tsetsNode = $cb->startTokensets();

    foreach my $tset ( $config_tree->getTsets() )
    {
        &Torrus::DB::checkInterrupted();
        
        my $params = $config_tree->getParams( $tset );
        my $name = $tset;
        $name =~ s/^S//;
        $cb->addTokenset( $tsetsNode, $name, $params );
    }
    return;
}


sub collect_definitions
{
    my $config_tree = shift;
    my $cb = shift;

    my $definitionsNode = $cb->startDefinitions();

    foreach my $defName ( sort $config_tree->getDefinitionNames() )
    {
        &Torrus::DB::checkInterrupted();

        my $value = $config_tree->getDefinition( $defName );
        $cb->addDefinition( $definitionsNode, $defName, $value );
    }

    my $propsNode = $cb->startParamProps();
    my $props = $config_tree->getParamProperties();

    &Torrus::DB::checkInterrupted();

    foreach my $prop ( sort keys %{$props} )
    {
        foreach my $param ( sort keys %{$props->{$prop}} )
        {
            $cb->addParamProp( $propsNode, $param, $prop,
                               $props->{$prop}{$param} );
        }
    }
    return;
}




sub collect_datasources
{
    my $config_tree = shift;
    my $cb = shift;
    
    my $topNode = $cb->getTopSubtree();
    my $topToken = $config_tree->token('/');
    
    my $params = prepare_params( $config_tree, $topToken );
    $cb->addParams( $topNode, $params );

    if( defined($filter_param) )
    {
        $filterTokens{$topToken} = apply_filter( $config_tree, $topToken );
    }
    
    collect_subtrees( $config_tree, $cb, $topToken, $topNode );
    return;
}
        


sub apply_filter
{
    my $config_tree = shift;
    my $token = shift;

    $filterTokens{$token} = 0;
    
    foreach my $ctoken ( $config_tree->getChildren( $token ) )
    {
        &Torrus::DB::checkInterrupted();
        
        if( $config_tree->isSubtree( $ctoken ) )
        {
            $filterTokens{$token} += apply_filter( $config_tree, $ctoken );
        }
        elsif( $config_tree->isLeaf( $ctoken ) )
        {
            my $val = $config_tree->getNodeParam( $ctoken, $filter_param );
            if( defined($val) and &{$filter_match}($val) )
            {
                $filterTokens{$ctoken} = 1;
                $filterTokens{$token}++;
            }                
        }
    }

    return $filterTokens{$token};
}
        


sub collect_subtrees
{
    my $config_tree = shift;
    my $cb = shift;
    my $token = shift;
    my $parentNode = shift;
    
    foreach my $ctoken ( $config_tree->getChildren( $token ) )
    {
        &Torrus::DB::checkInterrupted();
        
        if( not defined($filter_param) or $filterTokens{$ctoken} )
        {
            my $childName =
                $config_tree->nodeName( $config_tree->path($ctoken) );
            my $params = prepare_params( $config_tree, $ctoken );
        
            if( $config_tree->isSubtree( $ctoken ) )
            {
                my $subtreeNode =
                    $cb->addSubtree( $parentNode, $childName, $params );
                collect_subtrees( $config_tree, $cb, $ctoken, $subtreeNode );
            }
            elsif( $config_tree->isLeaf( $ctoken ) )
            {
                $cb->addLeaf( $parentNode, $childName, $params );
            }
            
            foreach my $aliasToken ( $config_tree->getAliases( $ctoken ) )
            {
                $cb->addAlias( $parentNode,
                               $config_tree->path( $aliasToken ) );
            }
        }
    }
    return;
}


sub prepare_params
{
    my $config_tree = shift;
    my $token = shift;
    
    my $params = $config_tree->getParams( $token, 1 );

    # Remove linebreaks
    while( my( $param, $value ) = each %{$params} )
    {
        $value =~ s/\s+/ /gm;
        $params->{$param} = $value;
    }

    return $params;
}

# Local Variables:
# mode: perl
# indent-tabs-mode: nil
# perl-indent-level: 4
# End:
