#
############################################################################
# File   : database.pl                                                     #
# Author : Supun Ruwanpura                                                 #
# Date   : 19-10-2000                                                      #
############################################################################
use strict;

use Tk;
use DBI;

############################################################################
# Modular level variables
my $dbh;      # database handle
my $parent;   # parent window

############################################################################
# try to establish a connection to the database
sub connect_to_db
############################################################################
{
    my ($dbType, $dbSource, $dbUser, $dbPwd) = @_;

    if ( $win_splash ) {
        $parent = $win_splash;
    }
    else  {
        $parent = $win_config;
    }

    ### if database type is known then try connect  ###
    ### to the database using theinformation given. ###
    if (($dbType ne "Don't know") && ($dbType ne "Other"))
    {
        print "Establishing connection to DBI:$dbType:$dbSource ...\n";

        eval ### try connecting to the database ###
        {
            $dbh = DBI->connect( "DBI:$dbType:$dbSource", $dbUser, $dbPwd, { PrintError => 1, RaiseError => 1 } )
        };
        if ( $@ )   ### connection failed ###
        {
            ### display the error message to the user ###
            $parent->messageBox( -title => "Connection ERROR",
                                  -message => "Can not connect to the ${dbType} database '${dbSource}'.\n\n$@\n",
                                  -type => "OK");
            return 0;
        };
    }

    ### if the user does not know what type of database    ###
    ### s/he using, then try all available drivers until   ###
    ### a suitable driver is found.    ### i.e. connection ###
    ### with out error                                     ###
    elsif ($dbType eq "Don't know")
    {
        print "Searching for a valid database driver...\n";

        my $valid_db_driver = 0;

        ### try all the available drivers until a valid database connection is established ###
        my @db_drivers = get_db_drivers();
        foreach ( @db_drivers )
        {
            $dbType = $_;
            eval
            {
                print "Trying the connection \"DBI:${dbType}:${dbSource}\" ...\n";
                $dbh=DBI->connect( "DBI:${dbType}:${dbSource}", $dbUser, $dbPwd, { PrintError => 1, RaiseError => 1 });
            };
            if (! $@ )    ### if not an error then valid dbType ###
            {
                $valid_db_driver = 1;
                last;    ### exit the foreach loop ###
            }
        }
        if (! $valid_db_driver)  ### valid database driver is not found ###
        {
            ### display the error message to the user ###
            $parent->messageBox( -title => "Connection ERROR!",
                                 -message => "Can not connect to the database '${dbSource}'\n\nNo matching database driver is found or invalid password.\n",
                                 -type => "OK");
            return 0;
        }
    }

    else   # for case "Other"
    {
        ### display the error message to the user ###
        $parent->messageBox( -title => "Connection ERROR!",
                             -message => "Can not connect to the database '${dbSource}'\n\nYou don't have the proper database drivers installed.\n",
                             -type => "OK");
            return 0;
    }

    ### successful connection ###
    return 1;
}


############################################################################
# disconnect the current database connection
sub disconnect_from_db
############################################################################
{
    print "Disconnecting from the database...\n";
    eval
    {
        ### try to disconnect from the database ###
        $dbh->disconnect
            or warn "Disconnection Failed: $DBI::errstr\n";
    };
}

############################################################################
# execute the SQL statement and display the results in the main window
sub execute_sql
############################################################################
{
    my $sSQL = $_[0];   ### SQL statment to be executed ###

    eval   ### trap any errors ###
    {
        ### only execute SELECT statements ###
        unless ( $sSQL =~ m/select/i )  ### not a SELECT statement ###
        {
            ### print error message ###
            $win_sq_hal->messageBox( -title => "Invalid SELECT query!",
                                     -message => "Can not execute any queries other than \"SELECT\" queries",
                                     -type => "OK");
            return 0;
        }

        ### prepare the sql statement for execution ###
        my $sth = $dbh->prepare( $sSQL );

        ### execute the sql statement ###
        $sth->execute();

        ### update the status bar text ###
        $status_text = "Formatting data to be displayed...";
        $win_sq_hal->update();

        my @rows;     ### returned row containing number of columns ###
        my $i = 1;

        ### count number of columns in the results ###
        my $columns_count = $sth->{NUM_OF_FIELDS};

        my @col_type;     ### type of column data ###

        ### clear the existing results table (in the SQ-HAL main window ###
        for (my $i = 0; $i < $results_table->totalRows; $i++)
        {
            for (my $j = 0; $j < $results_table->totalColumns; $j++)
            {
                $results_table->put($i, $j, "");
            }
        }
        $win_sq_hal->update();

        ### add column names to the array ###
        for (my $j = 0; $j < $columns_count; $j++)
        {
            ### create headings for the results table              ###
            ### these headings are the column names in the results ###
            $results_table->put(0, $j,
                          $results_table->Label( -text => $sth->{NAME}->[$j] ,
                                                 -anchor => "nw",
                                                 -relief => "groove",
                                                 -borderwidth => 5));

            ### get the data type of the current column ###
            $col_type[++$#col_type] = $sth->{TYPE}->[$j];
        }

        ### read each row from the table ###
        while (@rows = $sth->fetchrow_array())
        {
            my $j = 0;
            my $align;  ### data alignment in the table ###

            ### read each column in the row ###
            foreach( @rows )
            {
               if ($col_type[$j] == 1)  ### data type is string ###
               {
                   $align = "nw";       ### align left ###
               }
               else                     ### data type is not string ###
               {
                   $align = "ne";       ### align right ###
               }
               ### insert data to the results table ###
               ### in the row i and coloum j        ###
               $results_table->put($i, $j++,
                         $results_table->Label( -text => "  $_  " ,
                                                -anchor => $align,
                                                -relief => "groove",
                                                -borderwidth => 2));
            }
            $i++;
            if ( $i > $rows_displayed )   ### maximum number or rows reached ###
            {
                last;   ### exit this while loop ###
            }
        }
    };
    if ( $@ )   ### execution failed ###
    {
        ### display an error message ###
        $win_sq_hal->messageBox( -title => "SQL ERROR!",
                                 -message => "Can not execute the SQL statement.\n\n$@.\n",
                                 -type => "OK");
    }
}


############################################################################
# get all the table names in the database
sub get_table_names
############################################################################
{
    my @table_names;

    eval
    {
        ### Create a statement handle to fetch table information ###
        my $tabsth = $dbh->table_info();

        ### read only the table names to the table names array ###
        while ( my ($qual, $owner, $name, $type, $remarks) =
            $tabsth->fetchrow_array() )
        {
            $table_names[++$#table_names] = $name;
        }
    };
    if ( $@ )  ### error reading table names ###
    {
        ### print a warning message ###
        warn "Can not read table information.\n";
    }

    ### retun the array containing table names ###
    return @table_names;
}


############################################################################
# Get column names for a particular table
sub get_column_names
############################################################################
{
    my $table = $_[0];    ### table name for which the column names to be found ###
    my @column_names;

    eval
    {
        ### create sql statement to fecth data from the table ###
        my $statement = "SELECT * FROM $table";

        ### prepare and execute the statement ###
        my $sth = $dbh->prepare( $statement );
        $sth->execute();

        ### count number of columns belongs to the table ###
        my $columns_count = $sth->{NUM_OF_FIELDS};

        ### add column names to the array ###
        for (my $i =0; $i < $columns_count; $i++)
        {
            $column_names[++$#column_names] = $sth->{NAME}->[$i];
        }
    };
    if ( $@ )  ### error reading column names ###
    {
        ### print a warning message ###
        warn "Can not read column names for the table ${table}\n";
    }

    ### retun the array containing column names ###
    return @column_names;
}


############################################################################
# Get all the available database drivers
sub get_db_drivers
############################################################################
{
    ### retrive and return all the available database drivers ###
    ### installed in the current system                       ###
    return DBI->available_drivers();
}


############################################################################
# return the data sources for a given database driver
sub get_db_sources
############################################################################
{
    eval
    {
        return DBI->data_sources( $_[0] )
            or warn "No data sources found!\n";
    };
}

1;    ### so the 'do' command succeeds ###