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

use Tk;
use Tk::Balloon;

############################################################################
# Modular level variables
my $lst_tables;                # list of all the table names
my $lst_columns;               # list of all the column names for selected tables
my $txt_sql;                   # SQL statment created
my $win_create_sql;            # this window for creating SQL
my $selected_table = '';       # selected table name(s)
my $selected_columns = '*';    # selected column name(s)
my $tbl_conditions;            # SQL condition(s)


############################################################################
# Create and show the window for creating SQL statements
sub show_create_sql
############################################################################
{
    ### create the window ###
    $win_create_sql = $win_sq_hal->Toplevel;

    $win_create_sql->title("Create SQL - SQ-HAL");

    ### center the window in the screen ###
    my $h = 350;
    my $w = 700;
    my $x = int(($win_create_sql->screenwidth()-$w)/2);
    my $y = int(($win_create_sql->screenheight()-100-$h)/2);
    $win_create_sql->geometry("${w}x${h}+${x}+${y}");

    ### Set the minimu and maximum sizes to be the same ###
    ### so that the user can not resize the window      ###
    $win_create_sql->minsize( $w, $h );
    $win_create_sql->maxsize( $w, $h );

    ########################################################################
    ### define and place window controls ###

    my $tooltip = $win_create_sql->Balloon;

    my $frame1 = $win_create_sql->Frame->pack( -side => "top",
                                           -fill => "x",
                                           -expand => 1);

    my $fra_tables = $frame1->Frame->pack( -side => "left",
                                           -fill => "x",
                                           -expand => 1);

    my $fra_columns = $frame1->Frame->pack( -side => "left",
                                           -fill => "x",
                                           -expand => 1);

    $fra_tables->Label( -text => "Select the table(s)\n from the list:",
                            -anchor => "nw")
                    ->pack( -side => "top",
                            -fill => "x",
                            -expand => 0 );

   ### list of all the table names -----------------------------------------
   $lst_tables = $fra_tables->Scrolled( 'Listbox', -scrollbars => "oe",
                                              -selectmode => "multiple",
                                              -border => 3,
                                              -height => 7)
                                      ->pack( -side => "left",
                                              -padx => 5,
                                              -fill => "y",
                                              -expand => 1);

    $lst_tables->insert("end", get_table_names());

    $tooltip->attach($lst_tables,
                     -msg => "Select one or more tables from this list.");

    $fra_columns->Label( -text => "Select what columns\nyou want to see:",
                            -anchor => "nw")
                    ->pack( -side => "top",
                            -fill => "x",
                            -expand => 0 );

    ### list of all the column names for selected table(s) -----------------
    $lst_columns = $fra_columns->Scrolled( 'Listbox', -scrollbars => "oe",
                                              -selectmode => "multiple",
                                              -border => 3,
                                              -height => 7)
                                      ->pack( -side => "left",
                                              -padx => 5,
                                              -fill => "y",
                                              -expand => 1);

    $tooltip->attach($lst_columns,
                     -msg => "Select one or more column names from this list.");

    ### table use to display various SQL conditions ------------------------
    $tbl_conditions = $fra_columns->Table( -rows => 7,
                                           -scrollbars => "se",
                                           -columns => 2)
                                   ->pack( -side => "right",
                                           -fill => "both",
                                           -expand => 1);

    ### when selecting column names, update the string for the selected ###
    ### column and the new SQL statement                                ###
    $lst_columns->bind("", \&update_selected_columns);

    ### when table name is selected, update the column names list ###
    ### and conditions list                                       ###
    $lst_tables->bind("",
          sub
          {
              update_column_names();
              ### clear the conditions table ###
              for (my $i = 0; $i < $tbl_conditions->totalRows; $i++)
              {
                  for (my $j = 0; $j < $tbl_conditions->totalColumns; $j++)
                  {
                      $tbl_conditions->put($i, $j, "");
                  }
              }
              ### fill the conditons table with new values ###
              for (my $i = 1; $i < $lst_columns->size; $i++)
              {
                  my @txt_conditions;
                  ### insert the column name label to the conditions table ###
                  $tbl_conditions->put($i, 0, $tbl_conditions->Label( -text => $lst_columns->get($i), -anchor => "e"));

                  ### create entry field to enter the condition ###
                  $txt_conditions[$i] = $tbl_conditions->Text( -height => 1, -width => 15);

                  ### insert the condition entry field table ###
                  $tbl_conditions->put($i, 1, $txt_conditions[$i]);

                  ### update the SQL statement every time user type ###
                  ### something in this condition field             ###
                  $txt_conditions[$i]->bind("", \&create_sql);

                  ### tooltip for the condition entry fields ###
                  $tooltip->attach($txt_conditions[$i],
                                   -msg => "Type the condition here.\ne.g. \"\> 100\" or \"= 'Abc'\"");
              }
          });

    $win_create_sql->Label( -text => "SQL statement (or type your own):",
                            -anchor => "nw")
                    ->pack( -side => "top",
                            -fill => "x",
                            -expand => 0 );

    ### SQL statement created ----------------------------------------------
    $txt_sql = $win_create_sql->Text( -height => 5)
                                 ->pack( -side => "top",
                                         -fill => "x",
                                         -expand => 0 );

    $tooltip->attach($txt_sql,
                     -msg => "SQL statement created.  You can edit this or type your own SQL statements.");

    my $fra_buttons = $win_create_sql->Frame->pack( -side => "top" );

    ### OK and Cancel buttons ----------------------------------------------
    my $cmd_ok = $fra_buttons->Button( -text => "OK",
                                       -underline => 0,
                                       -command => \&Update_SQL )
                                ->pack( -fill => "x",
                                        -side => "left",
                                        -ipadx => 30,
                                        -padx => 10,
                                        -pady => 10,
                                        -expand => 0);

    $tooltip->attach($cmd_ok,
                     -msg => "Accept the SQL statement created and close this window.");

    my $cmd_cancel = $fra_buttons->Button( -text => "Cancel",
                                           -underline => 0,
                                           -command => sub { $win_create_sql->destroy(); } )
                                        ->pack( -fill => "x",
                                           -side => "left",
                                           -ipadx => 20,
                                           -padx => 10,
                                           -pady => 10,
                                           -expand => 0);

    $tooltip->attach($cmd_cancel,
                     -msg => "Close this window.");

    ### make the SQ-HAL main window visible when this window get closed ###
    $win_create_sql->bind('', sub{ $win_sq_hal->MapWindow; $win_sq_hal->deiconify; } );

    ### update winodw controls before displaying the window ###
    $win_create_sql->update();

    ### show this window ###
    $win_create_sql->raise();

    ### hide the SQ-HAL main window ###
    $win_sq_hal->UnmapWindow;
}


############################################################################
# Update the SQL statement are in the main window and close this window
sub Update_SQL
############################################################################
{
    ### make this window busy by changing the mouse icon ###
    $win_create_sql->Busy;

    ### update the SQL statment area in the main window ###
    $results = $txt_sql->get("1.0", "end");
    $txt_output->delete("1.0", "end");
    $txt_output->insert("end", $results);

    ### execute the newly created SQL statement and ###
    ### update the SQL results table                ###
    show_data();

    ### close this window ###
    $win_create_sql->destroy();
}


############################################################################
# Update the column names list with the column names for the selected table(s)
# and update the SQL statement created
sub update_column_names
############################################################################
{
    eval    ### ignore any errors ###
    {
        ### get the indexes of the currently selected tables ###
        my @table_indexes = $lst_tables->curselection;

        $lst_columns->delete(0, "end");
        $lst_columns->insert("end", "All columns");

        $selected_table = "";

        ### for each of the index in the table names selection ... ###
        foreach (@table_indexes)
        {
            ### get the table name ###
            my $table = $lst_tables->get($_);

            ### update the string for the selected table names in the SQL ###
            $selected_table .= "${table}, ";

            if ($#table_indexes == 0) ### if there is only one table selected ###
            {
                ### get the column names for the selected table ###
                ### and insert to the column names list         ###
                $lst_columns->insert("end", &get_column_names($table));
            }
            else  ### if more than one table is selected ###
            {
                ### get the column names for the selected tables ###
                ### and insert to the column names list          ###
                ### the column name need to be updated to        ###
                ### . format            ###
                $lst_columns->insert("end", split(":", "${table}.".(join(":${table}.", (&get_column_names($table))))));
            }
        }

        ### remove the last "' " characters from selected_tables string ###
        chop($selected_table);
        chop($selected_table);

        ### default selected columns is "*" - all columns ###
        $selected_columns = "*";

        ### create the SQL statement using the new values ###
        create_sql();
    };
}


############################################################################
# Get the selected column names and update the SQL statement created
sub update_selected_columns
############################################################################
{
    eval    ### ignore any errors ###
    {
        ### if the list item "All columns" is selected ###
        if ($lst_columns->selectionIncludes(0))
        {
            $selected_columns = "*";
            create_sql();
        }
        else  ### not all the columns, only the selected column names ###
        {
            ### get the indexes of the current selection ###
            my @columns = $lst_columns->curselection;
            my @column_names;

            foreach ( @columns )
            {
                ### Get the column names of the selection ###
                $column_names[++$#column_names] = $lst_columns->get($_);
            }

            ### update the column names string
            $selected_columns = join( ", ", @column_names);

            ### create the SQL statement using the new values ###
            create_sql();
        }
    };
}


############################################################################
# Create the SQL statement using the selected table names and column names
sub create_sql
############################################################################
{
    ### insert the SQL statement to the statement display area ###
    $txt_sql->delete("1.0", "end");
    $txt_sql->insert("end", "SELECT $selected_columns\nFROM $selected_table\n");

    ### create and append SQL conditions ###
    my $condition = "";

    ### get the selected table names to an array ###
    my @tbls = split(", ", $selected_table);

    ### append all the table relationships between each pair of tables ###
    ### to the SQL conditions                                          ###
    if ($#tbls)
    {
        for (my $i= 0; $i < $#tbls; $i++)
        {
            for (my $j = $i+1; $j <= $#tbls; $j++)
            {
                ### if table relationship is defined between the selected tables ###
                ### append it the SQL condtions string                           ###
                if ( my $relationship = $table_relationships{$tbls[$i]}{$tbls[$j]} )
                {
                    if ($condition)  ### the condition string already contains some condtions ###
                    {
                        $condition .= "\n\tAND $relationship";
                    }
                    else  ### the conditions string is empty ###
                    {
                        $condition .= $relationship;
                    }
                }
            }
        }
    }

    ### add other user entered conditions ###
    for (my $i = 1; $i < $tbl_conditions->totalRows; $i++)
    {
       ### get the entered condition for each entry ###
       my $entry = $tbl_conditions->get($i, 1)->get("1.0", "end");
       chomp($entry);

       ### if the condition entry is not empty then ###
       ###  append it to the condtions string       ###
       if ($entry)
       {
            if ($condition)
            {
                $condition .= "\n\tAND "
            }
            $condition .=  $tbl_conditions->get($i, 0)->cget( '-text' ) . " ${entry}";
       }
    }

    ### append the condition to the end of the SQL statement ###
    if ($condition)
    {
        $txt_sql->insert("end", "WHERE $condition\n");
    }

    ### update the SQL statment field ###
    $win_create_sql->update();
}

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