package Sleepycat::DbXml;

use strict;
use warnings;

our $VERSION = '0.10';

our $strict_txn = 1 ;

sub import
{
    my $this = shift ;
    my $opt = shift ;

    $strict_txn = 0 
        if defined $opt && $opt eq 'simple' ;

    require Sleepycat::Db; Sleepycat::Db->import($strict_txn ? () : 'simple');
}

package DbXml;

use 5.006001;
use strict;
use warnings;
use Carp;

require Exporter;
use AutoLoader;


our @ISA = qw(Exporter);

#our %EXPORT_TAGS = ( 'all' => [ qw(
#	
#) ] );
#
#our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );


sub LEVEL_NONE;
sub LEVEL_DEBUG;
sub LEVEL_INFO;
sub LEVEL_WARNING;
sub LEVEL_ERROR;
sub LEVEL_ALL;


sub CATEGORY_NONE;
sub CATEGORY_INDEXER;
sub CATEGORY_QUERY;
sub CATEGORY_OPTIMIZER;
sub CATEGORY_DICTIONARY;
sub CATEGORY_CONTAINER;
sub CATEGORY_ALL;

sub metaDataName_uri_id;
sub metaDataName_uri_default;
sub metaDataNamespace_uri;
sub metaDataNamespace_prefix;
sub metaDataName_id;
sub metaDataName_name;
sub metaDataName_content;
sub metaDataName_default;
sub metaDataNamespace_prefix_debug;


sub DBXML_VERSION_MAJOR;
sub DBXML_VERSION_MINOR;
sub DBXML_VERSION_PATCH;
sub DBXML_VERSION_STRING;	


our @EXPORT = qw();
	 

sub AUTOLOAD {
    # This AUTOLOAD is used to 'autoload' constants from the constant()
    # XS function.

    my $constname;
    our $AUTOLOAD;
    #($constname = $AUTOLOAD) =~ s/.*:://;
    $constname = $AUTOLOAD;
    croak "&DbXml::constant not defined" if $constname eq 'constant';
    my ($error, $val) = DbXml::constant($constname);
    if ($error) { croak $error; }
    {
	no strict 'refs';
	# Fixed between 5.005_53 and 5.005_61
#XXX	if ($] >= 5.00561) {
#XXX	    *$AUTOLOAD = sub () { $val };
#XXX	}
#XXX	else {
	    *$AUTOLOAD = sub { $val };
#XXX	}
    }
    goto &$AUTOLOAD;
}

require XSLoader;
XSLoader::load('Sleepycat::DbXml', $VERSION);

{

    my @txnids = (
	    [ 'XmlContainer', 'exists',		0, 1],
	    [ 'XmlContainer', 'open', 		0, 3],
	    [ 'XmlContainer', 'rename',		1, 2],
	    [ 'XmlContainer', 'remove',		0, 1],
	    [ 'XmlContainer', 'putDocument',	1, 4],
	    [ 'XmlContainer', 'getDocument',	1, 3],
	    [ 'XmlContainer', 'updateDocument',	1, 3],
	    [ 'XmlContainer', 'parseXPathExpression',1, 3],
	    [ 'XmlContainer', 'setIndexSpecification',1, 2],
	    [ 'XmlContainer', 'getIndexSpecification',0, 1],
	    [ 'XmlContainer', 'addIndex',	3, 4],
	    [ 'XmlContainer', 'deleteIndex',	3, 4],
	    [ 'XmlContainer', 'replaceIndex',	3, 4],
	    [ 'XmlContainer', 'modifyDocument',	1, 4],

	    );
	
    foreach (@txnids)
    {
	my ($pkg, $name, $from, $to) = @{ $_ } ;

        my $sub = <<'EOM' ;
            sub PACKAGE::NAME
            {
                my $THIS = shift ;
    
                croak "PACKAGE::NAME needs between FROM and TO parameters\n" 
                    if @_ < FROM || @_ > TO;
    
                ($Db::_filename, $Db::_line) = (caller)[1,2];
    
                if ($Sleepycat::DbXml::strict_txn
		    || @_ && !defined $_[0] 
		    || ref $_[0] && UNIVERSAL::isa($_[0], "DbTxn")) {
                    $THIS->_NAME(@_) ;	    
                }
                else {
                    $THIS->_NAME(undef, @_) ;	    
                }	   
            }
EOM

        $sub =~ s/PACKAGE/$pkg/g ;
        $sub =~ s/NAME/$name/g ;
        $sub =~ s/FROM/$from/g ;
        $sub =~ s/TO/$to/g ;
        eval $sub;
    }

}

sub printVersionInfo
{
    my ($major, $minor, $patch) = (0,0,0) ;
    print "perl  : $]\n" ;
    print "dbxml : " . dbxml_version($major, $minor, $patch) . "\n" ;
    print "db    : " . DbEnv::version($major, $minor, $patch) . "\n";
    print "xerces: " . xerces_version() . "\n";

}

package XmlResults ;

use Carp;


sub next
{
    my $THIS = shift ;

    unless ($Sleepycat::DbXml::strict_txn ||
        (! defined $_[0] || ref $_[0] && UNIVERSAL::isa($_[0], "DbTxn")))
        {
           unshift @_, undef ;
        
        }

    croak "XmlResults::next needs between 1 and 3 parameters\n" 
        if @_ < 1 || @_ > 3;

    if (@_ == 2)
    {
        if (ref $_[1] && UNIVERSAL::isa($_[1], "XmlValue")) {
            $THIS->_next1(@_) ;
        }
	else {
            $THIS->_next2(@_) ;
        }
    }
    else
    {
        $THIS->_next3(@_) ;
    }
}

package XmlContainer ;

use Carp;

sub new
{
    my $CLASS = shift ;
    unshift @_, undef 
        unless ! defined $_[0] || ref $_[0] && UNIVERSAL::isa($_[0], "DbEnv");
    _XmlContainer::new($CLASS, @_);
}

sub queryWithXPath
{
    my $THIS = shift ;

    unless ($Sleepycat::DbXml::strict_txn ||
        (! defined $_[0] || ref $_[0] && UNIVERSAL::isa($_[0], "DbTxn")))
        {
	    unshift @_, undef ;
	    #if (ref $_[0] && UNIVERSAL::isa($_[0], "XmlQueryExpression")) || 
	    #   (ref $_[1] && UNIVERSAL::isa($_[1], "XmlQueryContext"))  ;
        
        }

    croak "XmlContainer::queryWithXPath needs between 1 and 4 parameters\n" 
        if @_ < 1 || @_ > 4;


    if (ref $_[1] && UNIVERSAL::isa($_[1], "XmlQueryExpression")) {
        $THIS->_queryWithXPath_2(@_) ;
    }
    else {
        $THIS->_queryWithXPath_1(@_) ;	    
    }	   
}

sub deleteDocument
{
    my $THIS = shift ;

    unless ($Sleepycat::DbXml::strict_txn ||
        (! defined $_[0] || ref $_[0] && UNIVERSAL::isa($_[0], "DbTxn")))
        {
           unshift @_, undef ;
        
        }

    croak "deleteDocument needs between 1 and 3 parameters\n" 
        if @_ < 1 || @_ > 3;


    if (ref $_[1] && UNIVERSAL::isa($_[1], "XmlDocument")) {
        $THIS->deleteDocument_1(@_) ;
    }
    else {
        $THIS->deleteDocument_2(@_) ;	    
    }	   
}

sub load
{
    my $THIS = shift ;
    if (@_ == 1)
    {
	my $line = 0;
        $THIS->_load(@_, $line, 0);	    
    }
    else
    {
        $THIS->_load(@_);	    
    }
}

package XmlException ;

our @ISA = qw(std::exception);

*AUTOLOAD = \&DbXml::AUTOLOAD;

sub INTERNAL_ERROR;
sub CONTAINER_OPEN;
sub CONTAINER_CLOSED;
sub CONTAINER_PASSED_WRONG_OBJECT;
sub INDEXER_PARSER_ERROR;
sub DATABASE_ERROR;
sub XPATH_PARSER_ERROR;
sub DOM_PARSER_ERROR;
sub XPATH_EVALUATION_ERROR;
sub NO_VARIABLE_BINDING;
sub LAZY_EVALUATION;
sub DOCUMENT_NOT_FOUND;
sub CONTAINER_EXISTS;
sub UNKNOWN_INDEX;
sub INVALID_VALUE;
sub VERSION_MISMATCH;

sub catch
{
    return $@
        if (ref($@) && UNIVERSAL::isa($@, "XmlException"));

    return undef ;
}	

#package std::exception ;
#
#sub catch
#{
#    return $@
#        if (ref($@) && UNIVERSAL::isa($@, "std::exception"));
#
#    return undef ;
#}	

package XmlDocument ;

use Carp;

*AUTOLOAD = \&DbXml::AUTOLOAD;

sub setContent
{
    my $THIS = shift ;

    croak "setContent needs 1 parameters\n" unless @_ == 1 ;

    if (ref $_[3] && UNIVERSAL::isa($_[3], "Dbt")) {
        $THIS->_setContent_dbt(@_) ;	    
    }
    else {
        $THIS->_setContent_string(@_) ;	    
    }	   
}

sub setMetaData
{
    my $THIS = shift ;

    croak "setMeta needs 4 parameters\n" unless @_ == 4 ;

    if (ref $_[3] && UNIVERSAL::isa($_[3], "XmlValue")) {
        $THIS->_setMetaData_XmlValue(@_) ;	    
    }
    else {
        $THIS->_setMetaData_Dbt(@_) ;	    
    }	   
}

sub getMetaData
{
    my $THIS = shift ;

    croak "getMeta needs 3 parameters\n" unless @_ == 3 ;

    if (ref $_[2] && UNIVERSAL::isa($_[2], "XmlValue")) {
        return $THIS->_getMetaData_XmlValue(@_) ;	    
    }
    else {
        return $THIS->_getMetaData_Dbt(@_) ;	    
    }	   
}

sub queryWithXPath
{
    my $THIS = shift ;

    croak "XmlDocument::queryWithXPath needs between 1 and 2 parameters\n" 
        if @_ < 1 || @_ > 2;


    if (ref $_[0] && UNIVERSAL::isa($_[0], "XmlQueryExpression")) {
        $THIS->_queryWithXPath_2(@_) ;
    }
    else {
        $THIS->_queryWithXPath_1(@_) ;	    
    }	   
}

package XmlQueryContext;

*AUTOLOAD = \&DbXml::AUTOLOAD;

sub ResultDocuments;
sub ResultValues;
sub CandidateDocuments;
sub ResultDocumentsAndValues;
	
sub Eager;
sub Lazy;

package XmlValue ;

use Carp;

sub NONE;
sub STRING;
sub NUMBER;
sub BOOLEAN;
sub DOCUMENT;
sub NODE;
sub VARIABLE;
sub BINARY;

*AUTOLOAD = \&DbXml::AUTOLOAD;

sub getTypeName
{
    my $THIS = shift ;
    my @types = qw( NONE STRING NUMBER BOOLEAN DOCUMENT NODE VARIABLE BINARY);
    my $type = $THIS->getType(@_);
    return $types[$type] ;
}

sub dump
{
    my $THIS = shift ;
    my $type = $THIS->getType(@_);
    my $name = $THIS->_getTypeName();
    print "Type is $name ($type)" ;

    if ($type == XmlValue::BOOLEAN  || 
	$type == XmlValue::NUMBER   || 
	$type == XmlValue::STRING   || 
	$type == XmlValue::NODE     || 
	$type == XmlValue::DOCUMENT  )
        { print ", value is '". $THIS->asString . "'\n" }
    else
        { print "\n" }
	
}

package XmlModify;

*AUTOLOAD = \&DbXml::AUTOLOAD;
use Carp;

sub InsertAfter;
sub InsertBefore;
sub Append;
sub Update;
sub Remove;
sub Rename;
sub Empty;

sub Element;
sub Attribute;
sub Text;
sub ProcessingInstruction;
sub Comment;
sub None;
		
sub new
{
    my $CLASS = shift ;

    croak "XmlModify::new needs between 5 and 7 parameters\n" 
    	unless @_ >=5 && @_ <= 7  ;

    if (ref $_[0] && UNIVERSAL::isa($_[0], "XmlQueryExpression")) {
        return _XmlModify1::new($CLASS, @_);
    }
    else {
        return _XmlModify2::new($CLASS, @_);
    }	   
}


package DbtPtr;

use Carp;
our @ISA = qw(Dbt);

sub DESTROY
{
    my $class = shift ;

}


package DbXml ;

1;
__END__
