
use strict;
use warnings;

use Test::More tests => 31 ;
BEGIN { use_ok('Sleepycat::DbXml', 'simple') };
BEGIN { use_ok('File::Path') };

my @Strategies = qw(
    none-none-none-none-none
    node-element-presence-none
    node-attribute-presence-none
    node-element-equality-string
    node-element-equality-number
    node-element-substring-string
    node-attribute-equality-string
    node-attribute-equality-number
    node-attribute-substring-string
    edge-element-presence-none
    edge-attribute-presence-none
    edge-element-equality-string
    edge-element-equality-number
    edge-element-substring-string
    edge-attribute-equality-string
    edge-attribute-equality-number
    edge-attribute-substring-string
    );

sub indexCompare
{
    my $index = shift ;
    my @expected = ();
    foreach (@_)
    {
	if (ref $_ && ref $_ eq 'ARRAY')
	  { push @expected, @$_ }
	else
	  { push @expected, $_ }
    }

    my %got = map { $_, 1 } split m#\s+#, $index;
    my @bad = ();

    foreach (@expected)
    {
        if ($got{$_})
	  { delete $got{$_} }
	else
	  { push @bad, $_ }
    }

    return (keys %got == 0 && ! @bad) ;

}

#sub readAll
#{
#    my $index = shift ;
#
#    my ($U, $N, $I);
#    my %got = () ;
#
#    # record what is actually stored in dbxml
#    $index->reset() ;
#    while ($index->next($U, $N, $I))
#    {
#        push @{ $got{$U}{$N} }, split /\s+/, $I ;
#    }
#
#    return %got ;
#
#}

eval 
{

    my %Index = () ;

    my $tmp_dir = "tmp" ;

    if (-d $tmp_dir)
    {
        rmtree($tmp_dir);
    }
    
    mkdir $tmp_dir, 0777 ;
    
    my $doc ;
    
    $doc = new XmlDocument(); 
    
    ok defined $doc, "Document object created ok" ;
    
    is $doc->getID(), 0, "Doc ID should be 0 before it has any content" ;
    
    my $title = '<title>Knowledge Discovery in Databases.</title>';
    my $content = "<book>$title</book>";
    $doc->setContent($content);
    
    my $container_name = "$tmp_dir/fred.dbxml" ;
    my $x = new XmlContainer($container_name); 
    ok $x, "new XmlContainer returned object" ;
    
    
    my $indexSpec = new XmlIndexSpecification();

    my $Uri = "http://xyz.com/";
    my $Name = "dummy";
    my $Index = $Strategies[1];

    push @{ $Index{$Uri}{$Name} } , $Strategies[1] ;
    $indexSpec->addIndex($Uri, $Name, $Strategies[1]);

    
    my $get_index ;
    ok $indexSpec->find($Uri, $Name, $get_index), "find found $Name" ;
    is $get_index, $Strategies[1], "found index '$Strategies[1]'";
    
    push @{ $Index{$Uri}{$Name} } , $Strategies[2] ;
    $indexSpec->addIndex($Uri, $Name , $Strategies[2]);

    ok $indexSpec->find($Uri, $Name, $get_index), "find found $Name" ;
    ok indexCompare($get_index, $Index{$Uri}{$Name}), "does [$get_index] match [@{ $Index{$Uri}{$Name} }]";

    my ($U, $N, $I);
    ok $indexSpec->next($U, $N, $I), "next is true";

    is $U, $Uri;
    is $N, $Name ;
    ok indexCompare($I, $Index{$Uri}{$Name}), "does [$get_index] match [@{ $Index{$Uri}{$Name} }]";

    ok ! $indexSpec->next($U, $N, $I), "next is false";

    pop @{ $Index{$Uri}{$Name} };
    $indexSpec->deleteIndex($Uri, $Name , $Strategies[2]);
    ok $indexSpec->find($Uri, $Name, $get_index), "find found $Name" ;
    ok indexCompare($get_index, $Index{$Uri}{$Name}), "does [$get_index] match [@{ $Index{$Uri}{$Name} }]";

    $Index{$Uri}{$Name} = [ $Strategies[3] ];
    $indexSpec->replaceIndex($Uri, $Name , $Strategies[3]);
    ok $indexSpec->find($Uri, $Name, $get_index), "find found $Name" ;
    ok indexCompare($get_index, $Index{$Uri}{$Name}), "does [$get_index] match [@{ $Index{$Uri}{$Name} }]";

    pop @{ $Index{$Uri}{$Name} };
    $indexSpec->deleteIndex($Uri, $Name , $Strategies[3]);
    ok ! $indexSpec->find($Uri, $Name, $get_index), "not find found $Name" ;

    push @{ $Index{$Uri}{$Name} } , $Strategies[1] ;
    $indexSpec->addIndex($Uri, $Name, $Strategies[1]);


    {
        # setIndexSpecification -- unopened container throws CONTAINER_CLOSED exception
        
        eval { $x->setIndexSpecification($indexSpec) ; } ;
    
        if (my $E = catch XmlException)
        {
            ok 1, "setIndexSpecification on unopened container throws an exception";
            is $E->getExceptionCode(), XmlException::CONTAINER_CLOSED, "exception is CONTAINER_CLOSED";
    
        }
        else
        {
	    print $@;
            ok 0, "setIndexSpecification on unopened container throws an exception";
	    ok 0;
        }
    
    }
    
    $x->open(Db::DB_CREATE); 
    
    ok $x->isOpen(), "isOpen returns true on open container";
    
    
    {
        # setIndexSpecification -- opened container without docs is ok
        
        my $uri ;
        my $name ;
        my $index ;
    
        my $ix = $x->getIndexSpecification(); 
    
        ok !$ix->next($uri, $name, $index), 
            "next returns false";
    
        eval { $x->setIndexSpecification($indexSpec) ; } ;
    
        if (my $E = catch XmlException)
        {
            ok 0, "setIndexSpecification on opened container is ok";
	    warn "# exception says: " . $E->what() ;
    
        }
        else
        {
            ok 1, "setIndexSpecification on opened container is ok";
        }
    
        $ix = $x->getIndexSpecification(); 
    
        ok $ix->next($uri, $name, $index), 
            "next returns true";
    
        is $index, $Index, "next index 1 is '$Index'";
        is $name, $Name, "next name is '$Name'";
        is $uri, $Uri, "next uri is '$Uri'";
    
        ok ! $ix->next($uri, $name, $index), 
            "next 1 returns false";
    
    }
    
    my $id = $x->putDocument($doc);
    
    
    {
        # setIndexSpecification -- container with doc does not throw exception
        
        my $uri = "http://xyz.com/";
        my $name = "dummy";
        my $index = "node-attribute-presence";
    
        eval { $x->setIndexSpecification($indexSpec) ; } ;
    
        if (my $E = catch XmlException)
        {
        ok 0, "setIndexSpecification on un-empty container does not throw an exception";

        }
        else
        {
            ok 1, "setIndexSpecification on un-empty container does not throw an exception";
        }
    
    }


    $x->close();
    
    ok ! $x->isOpen(), "isOpen returns false on closed container";


} ;

if (my $E = catch std::exception)
{
        print "# Unexpected Exception - " . $E->what(). "\n";
}
elsif ($@)
{
        print "# Unexpected Exception - $@\n";
}


