#################################################################
#
# iDatabase::SQL
#
# A wrapper around various database types.
#
# Author: Matthew Mecham <matt@ikonboard.com>
#
#################################################################

package iDatabase::SQL;
use strict;
use vars qw(@ISA $error $DRIVER $AUTOLOAD %SUBS %CONNECTED);

#----------------------------------------------------
# sub: new
# Creates a new construct and returns a blessed scalar
#-----------------------------------------------------

sub new {
    my $pkg  = shift;
    my $this = ref $pkg || $pkg;
    my $obj = bless { }, $this;

    my %args = (    "DATABASE"  => "",
                    "IP"        => "",
                    "PORT"      => "",
                    "USERNAME"  => "",
                    "PASSWORD"  => "",
                    "DB_DIR"    => "",
                    "DB_PREFIX" => "",
                    "DB_DRIVER" => "",
                    @_,
               );
    
    # Needs work
    die "Error: No driver specified!" unless $args{DB_DRIVER};
    
    $obj->{database} = $args{DATABASE};
    $obj->{name}     = $args{DB_DRIVER};
    $obj->{base_dir} = $args{DB_DIR};
    $obj->{prefix}   = $args{DB_PREFIX};
               
    # Attempt to load the correct driver
    my $class = "iDatabase::Driver::$args{DB_DRIVER}";
    # Make global
    $DRIVER   = $class;
    {
        local ($@);
        my $r_class = $class;
           $r_class =~ s~::~/~g;
        eval { require "$r_class.pm" };
        if ($@) {
            # Until we do something more elaborate
            die "Cannot load driver:  $args{DB_DRIVER} (Perl says: $@)";
            return;
        }
    }
    
    
    # Get a new SQL connection
    $obj->{driver} = $class->newSQL( \%args );
    # If successful, push the keys & values to our
    # global connected hash.
    for (keys %{$obj->{driver}}) {
        $CONNECTED{ $_ } = $obj->{driver}->{$_};
    }
    
    
    $obj->{driver}->{error}  = undef;
    
    return $obj;
}               

# use AUTOLOAD to forward method calls to the DB driver
# if the sub is not defined here.

sub AUTOLOAD {
    my $obj = $_[0];  # Don't shift
    # Return if it's a destroy method
    return if $AUTOLOAD =~ /::DESTROY$/;
    # Get the method and package name
    my ($pkg, $method) = $AUTOLOAD =~ /^(.*)::([^:]+)$/;
    # If it's a sub to be compiled here, then do so, if not
    # pass it on to the driver module
    if (exists $SUBS{$method}) {
        eval "#line 0 Compile iDatabase::SQL::$method\n$SUBS{$method}";
        if ($@) { die "Unable to compile $pkg::$method $@"; }
        return $iDatabase::SQL::{$method}->( @_ );
    }
    # Still here? forward to the driver then..
    shift @_; # remove this $obj as we need to use $obj->{driver};
    $AUTOLOAD =~ s/^.*:://;
    $obj->{driver}->$AUTOLOAD(@_);
}



sub DESTROY {
    iDatabase::SQL::reset();
}

sub reset {
    undef %CONNECTED;
    # Kludge alert!
    no strict 'refs';
    eval {"$DRIVER::disconnect( \@_ )"};
}

## SUBS TO COMPILE ##

$SUBS{driver} = <<'END_OF_SUB';
sub driver {
    my $obj = shift;
    # Simply returns the name of the currently used driver
    return $obj->{name};
}
END_OF_SUB

$SUBS{prefix} = <<'END_OF_SUB';
sub prefix {
    my $obj = shift;
    # Simply returns the name of the currently used table prefix
    return $obj->{prefix};
}
END_OF_SUB

$SUBS{show_query} = <<'END_OF_SUB';
sub show_query {
    my $obj = shift;
    # Returns the last evaluated parsed query
    return $obj->{driver}->{query};
}
END_OF_SUB

$SUBS{query_count} = <<'END_OF_SUB';
sub query_count {
    my $obj = shift;
    # Returns the number of queries
    return $obj->{driver}->{query_c};
}
END_OF_SUB

$SUBS{matched_records} = <<'END_OF_SUB';
sub matched_records {
    my $obj = shift;
    # Returns the number of records matched via the
    # last query
    return $obj->{driver}->{matched_records};
}
END_OF_SUB

$SUBS{error} = <<'END_OF_SUB';
sub error {
    my $obj = shift;
    # Returns the number of records matched via the
    # last query
    return $obj->{driver}->{error};
}
END_OF_SUB






## DEFAULTS ##
$SUBS{def_select} = <<'END_OF_SUB';
sub select { my $obj = shift; return $obj->{driver}->select( @_ ); }
END_OF_SUB
$SUBS{def_insert} = <<'END_OF_SUB';
sub insert { my $obj = shift; return $obj->{driver}->insert( @_ ); }
END_OF_SUB
$SUBS{def_update} = <<'END_OF_SUB';
sub update { my $obj = shift; return $obj->{driver}->update( @_ ); }
END_OF_SUB
$SUBS{def_query} = <<'END_OF_SUB';
sub query  { my $obj = shift; return $obj->{driver}->query( @_ );  }
END_OF_SUB
$SUBS{def_delete} = <<'END_OF_SUB';
sub delete { my $obj = shift; return $obj->{driver}->delete( @_ ); } 
END_OF_SUB
#+---------------------------------------------------------------------------------------------
1;       # End of Module
#+---------------------------------------------------------------------------------------------