#################################################################
#
# iDatabase::Drivers::Base
#
# A default driver class for iDatabase::SQL
#
# Author: Matthew Mecham <matt@ikonboard.com>
#
#################################################################

package iDatabase::Driver::Base;
use strict;


#---------------------------------------------------------
# Make hash reference
#---------------------------------------------------------
# Allows you to manipulate the data returned by DBI
# Default behaviour forces column names to uppercase
# Override in your Driver module if this is not the
# desired behaviour


sub make_hash_ref {
    # Routine written by Nurlan ("infection")
	my ($obj, $sth) = @_;
	return undef unless($sth);
    my $result = {};
    $result = $sth->fetchrow_hashref;
	return undef unless($result);
	my %ret;
	foreach(keys %{$result}){
		$ret{uc($_)} = $result->{$_};
	}
	return \%ret;
}

#---------------------------------------------------------
# Parse where statememnt
#---------------------------------------------------------
# Allows you to fine tune your where statement for your
# driver. Default behaviour suits mySQL.

sub parse_where {
    my ($obj, $where) = @_;
    my %ops = ( 'eq' => '=',
                'ne' => '<>',
                '==' => '=',
                '!=' => '<>',
                '=~' => 'REGEXP',
                '!~' => 'NOT REGEXP'
              );
    my %bln = ( 'and' => 'AND',
                'or'  => 'OR',
                '&&'  => 'AND'
              );

    $where =~ s#\s{1,}(eq|ne|==|!=|=~)\s{1,}# $ops{$1} #ig;
    $where =~ s#\s{1,}(and|or|&&)\s{1,}# $bln{$1} #ig;
    # Convert perl / into single quotes...
    $where =~ s#/#'#g;
    return $where;
}


#---------------------------------------------------------
# Parse LIMIT statememnt
#---------------------------------------------------------
# Allows you to fine tune your LIMIT statement for your
# driver. Default behaviour suits mySQL. pgSQL needs to
# use it the other way around for some surreal reason.

sub parse_limit {
    my ($obj, $range) = @_;
    # $range is a string: "0 to 10" (mySQL: LIMIT 0,10)
    my ($from, $to) = split " to ", $range;
    $obj->{limit_from} = $from || undef;
    $obj->{limit_to}   =  $to  || undef;
    my $total = $to - $from + 1;
    my $limit  = " LIMIT";
    $limit    .= " $from," if defined $from;
    $limit    .= " $total";
    return $limit;
}

#---------------------------------------------------------
# Connect: Method of connecting to a database
#---------------------------------------------------------

sub connect    {  return @_; }

#---------------------------------------------------------
# Disconnect: Method of disconnecting from the database
#---------------------------------------------------------

sub disconnect {  return @_; }
    
#+--------------------------------------------------------
#| Create Table: Creates a table
#+--------------------------------------------------------

sub create_table  { return @_; }

#+--------------------------------------------------------
#| Drop Table: Drops a table
#+--------------------------------------------------------

sub drop_table    { return @_; }

#+--------------------------------------------------------
#| Drop Tables: Drops multiple tables
#+--------------------------------------------------------

sub drop_tables   { return @_; }

#+--------------------------------------------------------
#| Drop Database: Drops multiple databases
#+--------------------------------------------------------

sub drop_database { return @_; }

#+--------------------------------------------------------
#| Select: Returns a single row from the database
#+--------------------------------------------------------

sub select  { return @_; }

#+--------------------------------------------------------
#| Query: Returns records based on criteria(s)
#+--------------------------------------------------------

sub query  { return @_; }
    
#+--------------------------------------------------------
#| Insert: Inserts a record row into the table
#+--------------------------------------------------------

sub insert { return @_; }

#+--------------------------------------------------------
#| Delete: Deletes a row based on the Primary Key
#+--------------------------------------------------------

sub delete  { return @_; }

#+--------------------------------------------------------
#| Update: Updates a record(s) based on the Primary Key
#+--------------------------------------------------------

sub update  { return @_; }

#+--------------------------------------------------------
#| Count: Counts the number of rows in a table
#+--------------------------------------------------------

sub count { return @_; }

#+--------------------------------------------------------
#| Back up: Exports a table into a delimeted text file
#+--------------------------------------------------------
    
sub back_up { return @_; }
sub table_import  { return @_; }
sub rebuild_record { return @_; }

#+--------------------------------------------------------
#| Lock Table
#+--------------------------------------------------------
    
sub lock_table { return @_; }

#+--------------------------------------------------------
#| Release lock
#+--------------------------------------------------------
    
sub release_lock { return @_; }

#+--------------------------------------------------------
#| Rebuild Record: Returns hash ref of data entry split on delimeter
#+--------------------------------------------------------

sub rebuild_record {
    my $obj = shift;
    my $IN = {  
                "TABLE"   => "",
                "STRING"  => "",
                "VALUES"  => {},
                @_
             };
             

    $obj->load_cfg($IN->{'TABLE'});
    
    my $record = $obj->decode_record($IN->{STRING});
    # Override the column values from the string with those
    # given to us by the accessing script.
    if ($IN->{VALUES}) {
        for my $k (keys %{ $IN->{VALUES} }) {
            $record->{$k} = $IN->{VALUES}->{$k};
        }
    }
    return $record;
}

#+--------------------------------------------------------
#| Join Record: Returns a string of a joined hash ref keys
#+--------------------------------------------------------

sub join_record {
    my $obj = shift;
    my $IN = {  
                "TABLE"   => "",
                "STRING"  => "",
                "VALUES"  => {},
                @_
             };
             

    $obj->load_cfg($IN->{'TABLE'});
    my $record = $obj->encode_record($IN->{VALUES});
    return $record;
}

#+--------------------------------------------------------
#| DECODE_RECORD: Decode a record entry
#+--------------------------------------------------------

sub decode_record {
    my ($obj, $record) = @_;
    my $return = {};
    chomp $record;
    my @Tmp = split (/\Q|^|\E/, $record);
    for my $i (0 .. $obj->{'total_cols'}) {
        $Tmp[$i] =~ s!^\s+!!g;
        $Tmp[$i] =~ s!\s+$!!g;
        $Tmp[$i] =~ s!\$!&#36!g;
        $Tmp[$i] =~ s!\\n!\n!g;
        $return->{ $obj->{'col_name'}->[$i] } = $Tmp[$i];
        
    }
    return $return;
}
 
#+--------------------------------------------------------
#| ENCODE_RECORD: Encode a record entry
#+--------------------------------------------------------

sub encode_record {
    my ($obj, $values) = @_;
    my ($return, $cnt);
    for my $i (0 .. $obj->{'total_cols'}) {
        $values->{$obj->{'col_name'}->[$i]}  =~ s!^\s+!!g;
        $values->{$obj->{'col_name'}->[$i]}  =~ s!\s+$!!g;
        $values->{$obj->{'col_name'}->[$i]}  =~ s!\r!!g;
        $values->{$obj->{'col_name'}->[$i]}  =~ s!\n!\\n!g;
        $return .= $values->{$obj->{'col_name'}->[$i]}."|^|";
    }
  $return =~ s!\Q|^|\E\Z!!g;
  return $return;
}

#+--------------------------------------------------------
#| LOAD_CFG: Load and set up the configuration file.
#+--------------------------------------------------------

sub load_cfg  {
    my ($obj, $cfg) = @_;
    die "Invalid Number of ARGVS" unless @_ == 2;
    $obj->{'cur_p_key'} = undef;
    do $obj->{'base_dir'}.'config/'.$cfg.'.cfg' or die "Cannot open file : $cfg.cfg ($!)";

    $obj->{'cur_table'}  = $IMPORT::STRING->{'TABLE'};
    $obj->{'cur_p_key'}  = $IMPORT::STRING->{'P_KEY'};
    $obj->{'cur_method'} = $IMPORT::STRING->{'MTD'};
    $obj->{'cur_update'} = $IMPORT::STRING->{'UPDATE'} || 'bottom';
    $obj->{'cur_ID'}     = $IMPORT::STRING->{'ID'};
    $obj->{'cur_DBID'}   = $IMPORT::STRING->{'DBID'};
    $obj->{'cur_INDEX'}  = $IMPORT::STRING->{'INDEX'};
    $obj->{'all_cols'}   = $IMPORT::COLS;
    $obj->{'total_cols'} = 0;
    $obj->{'col_name'}   = [];
    foreach (sort { $obj->{'all_cols'}->{$a}[0] <=> $obj->{'all_cols'}->{$b}[0] } keys %{$obj->{'all_cols'}} ) {
        push @{$obj->{'col_name'}}, $_;
        ++$obj->{'total_cols'};
    }
    $obj->{'total_cols'}--;
    undef $IMPORT::STRING;
}

#+---------------------------------------------------------------------------------------------
#| Index routines
#+---------------------------------------------------------------------------------------------

sub update_index { return @_; }
sub create_index { return @_; }
sub drop_index   { return @_; }

#+---------------------------------------------------------------------------------------------
1;       # End of Module
#+---------------------------------------------------------------------------------------------