#!/usr/bin/env perl

# Contributed to GeniusTrader (C) 2000-2004 Raphaël Hertzog, Fabien Fulhaber
# Copyright 2010 ras
# This file is distributed under the terms of the General Public License
# version 2 or (at your option) any later version.

# $Id: Build.PL,v 1.25 2012/07/09 03:10:25 ras Exp ras $

###use strict;
use warnings;
use lib '..';  # to be able to find GeniusTrader.pm

use Data::Dumper;

use Module::Build '--no-use_rcfile';


my $DB_MOD_KV_MSG = join "",
 "DB::module <module to use>\n",
 "       plus any other specific DB module key-value pairs for your prices data.\n",
 "       refer to pod of the GT/DB/<module> being used for details.",
 "\n";
my $FP_KV_MSG = join "",
 "Path::Font::Arial </absolute/path/to/desired/truetype/fontfile>\n",
 "       the <path> need not be the arial font, any truetype font should work.\n\n",
 "       other font face names implemented include:\n",
 "          Path::Font::Courier\n",
 "          Path::Font::Times\n\n",
 "       each supported font face defaults to the one spec'ed for\n",
 "       Path::Font::Arial unless explicitly set in the GT config file.\n",
 "       refer to pod and code of GT/Graphics/Driver.pm for details.\n",
 "\n";

# the fontpath type type checking depneds on the file utility
# and it's output string for a truetype font being "^TrueType font"
#
# if the file on your platform fails to emit that string the verification
# done here will fail.
#
# in order to be portable i also check the file cmd supports the
# -L symlink dereference flag, if not i declare file unavailable.
#
# you can provide a full path in place of 'file' below if the first one
# in your $PATH doesn't support -L ...
#
# note your $PATH is searched for the file cmd. the first one found
# that supports the -L flag is used ... the old old old version
# found in /usr/ucb (on some antique systems) does support -L and
# does emit "^TrueType font" and is therefore an acceptable non-gnu binary.
#
# if you run into difficultly and want to help make this helper script
# or portable contact me (ras at acm dot org) or via a gt mailing list
# and send me details of the problem(s) and how your version of file works.
#
my $FILE_CMD = 'file';    # change to your 'file' cmd if named differently
my $FILE_ARG = '-L';      # symlink dereference flag

my $resp = system( "$FILE_CMD $FILE_ARG $0 >/dev/null 2>&1" );
if ( $resp ) { # if resp is not zero we need to search the path for file
    $FILE_CMD = '';
    foreach my $path_ele ( split /:/, $ENV{PATH} ) {
        my $resp = system( "$path_ele/file $FILE_ARG $0 >/dev/null 2>&1" );
        if ( $resp == 0 ) {
            $FILE_CMD = "$path_ele/file";
            last;
        }
    }

    unless ( $FILE_CMD ) {
        print "oh my! without the \"$FILE_CMD\" cmd i'm unable to validate your GT options file\n";
        print "has fontpaths that actully resolve as truetype font files\n";
        print "\n";
        print "$FP_KV_MSG";
        print "if you have a \"$FILE_CMD\" that supports the -L flag but isn't first in your \$PATH\n";
        print "hack that absolute pathname into this scripts' \$FILE_CMD variable and re-run it.\n";
    }
    else {
    #    print "$0: using \"$FILE_CMD\"\n";
    }
}

( my $prog_name = $0 ) =~ s@^.*/@@;    # lets identify ourself
my $VERSION = (qw$Revision: 1.25 $)[-1];    # and our revision


my @gt_apps = qw(
 select_combination.pl
 anashell.pl
 analyze_backtest.pl
 display_signal.pl
 backtest.pl
 display_system.pl
 manage_portfolio.pl
 backtest_multi.pl
 display_indicator.pl
 scan.pl
 backtest_many.pl
 graphic.pl
);


goto SKIP;

# this results in real number with the following characteristics:
# given that an rcs/cvs? 'revision' number is composeds of these 4 fields
# release, level, branch, and sequence
# the release value will be unchanged
# the remaining fields will be padded with leading zeros to 3 digits
# and then concatenated together form the fractional part
# examples include: 1.1        => 1.001
#                   1.80.1.112 => 1.080001112
#                   1.68.1.55  => 1.068001055
my $version;
my @r;
$version = do {
   @r=(q$Revision: 1.25 $=~/\d+/g); sprintf "%d."."%03d"x$#r,@r
};

print "\nhello, my rcs based version value is $version\n";

# epoch based version value
$version = time();

print "world! my epoch based version value is $version\n\n";

#goto SKIP;

print "i'd really prefer a release numbering scheme based on major minor and bug_fixes\n";
print "   where major means expect incompatibilities with prior major versions\n";
print "   where minor means different features and capabilities\n";
print "   where no new features or capabilities, just bug fixes\n";
print "\n";
print "this really means that we have been just two releases:\n";
print "the trunk say as 0.0.... and the exp branch say as 0.1....\n";
print "\n\n";
print "\n";

#SKIP:

# major minor/branch bugfix based on rcs/cvs $Revision string
my $major;
my $minor;
my $bugfix;
$version = do {
  ($major,$minor,$bugfix)=(q$Revision: 1.25 $=~/\d+/g);sprintf "%d."."%03d"x$#r,@r
};
$version = ( $major  ? "$major" : "0" ) . "."
         . ( $minor  ? "$minor" : "0" ) . "."
         . ( $bugfix ? "$bugfix" : "0" );


SKIP:

my $gt_version = "not available";
if ( eval { require GeniusTrader } ) {
  import GeniusTrader;
  $gt_version = $GeniusTrader::VERSION;
}

print "$prog_name release: $VERSION\n";
print "GT release is: $gt_version\n\n";

print "Module::Build release is: $Module::Build::VERSION\n\n";

print <<"eohd";

Aloha $ENV{USER}.

The intent of this utility is to assess your platforms perl installation and
add-on modules with respect to the needs of GT and the primary perl modules
GT depends on. It is in no way intended to be a complete dependency
installer for GT and its' dependencies dependencies.  Its output should be
used as a guide, along with information on the various webpages
(http://geniustrade.org) for you to determine what prerequisites might still
be missing and to manually install them yourself.

There are very good, but never-the-less complex dependency discussions in
the Install & Setup page and in the Users Wiki pages. All shoould be at
least looked at, if not studied carefully, with respect to your platform,
your perl, how you plan to provide/manage market price data for GT and how
you plan to display GT results. All play a role in the dependencies you will
need for a successful GT setup.

While it was never the intent that this utility be able to automagically
install missing dependencies, if it does that so much the better. Instead,
it was created to aid you in identifying what you have already and what
might be still missing. Armed with this information you can then use
whatever your standard installation method is to install them.

The last parts of this script will take a look at your GT configuration file
(\$HOME/.gt/options) and check to see if it contains the minimal required
entries and that they are, to the extent possible, correct and valid.

The final part will, under your consent, tweak each GT script app sharpbang
line to be consistent with your perls' notion of it (usually not
necessary).  Lastly it will create symlinks to these scripts if your
platform groks symlinks.


eohd


( my $cwd = `pwd` ) =~ s@^.*/@@;
unless ( $cwd =~ m/^Scripts$/o ) {
    print "$prog_name: error: current working dir is \"$cwd\"\n";
    print "$prog_name requires cwd to be gt \"Scripts\"\n";
    print "it also expects the gt toolkit dir \"GT\" to be ../ relative to Scripts.\n";
    print "\n";
    print "usage example: (presumes $prog_name has exec bit set)\n";
    print "\$  pushd your/gt_top_level/Scripts\n";
    print "\$  $prog_name\n";
    print "\n";
    print "$prog_name takes no arguments, although Module::Build args are probably\n";
    print "implicitly accepted (and might interfer) with this hack\n";
    print "\n";
    print "for more try perldoc -t $prog_name\n";
    exit 1;
}
my $is_scripts_dir_writable = (stat ".")[2] & 00200;

#
# we assume that the gt install is like this:
#   gt_tld/
#      Scripts/
#      GT/
#
# if there isn't a ../GT dir we puke ...
#
my $gt_dir = "../GT";
my $is_there_a_gt_dir = (stat "$gt_dir")[2];
#printf "stat[2] ../GT returns: %04o\n", $is_there_a_gt_dir;
unless ( $is_there_a_gt_dir && $is_there_a_gt_dir & 07777 ) {
    print <<"eohd";

$prog_name:  error: gt installation directory hierarchy
  we assume that the gt install is like this:
    gt_tld/
       Scripts/
       GT/
we could not stat $gt_dir

if you want help subscribe the gt-devel mailing list and send
a note including all of this output as part of the message text.

it would also be helpful to describe how/where on your filesystem
you installed it, plus the platform(ppc,intel,cray), and the os
(linux,hpux,solaris) you are using.

eohd
    exit 1;
}



my $build = Module::Build->new(
    license     => 'gpl',
    dist_author => 'ras <ras@acm.org>',

    dist_name   => 'GeniusTrader',
    #dist_version => $VERSION,
    # dist_version should be the value of $VERSION from
    # tld/GeniusTrader.pm
    dist_version   => "$gt_version",

    build_requires => {
        Test::More        => '',
        Test::Differences => '',
    },

    script_files => "Scripts/",

    pod_files => {
        'gt_files.pod'        => '../GT/Docs/gt_files.pod',
        'gt_sig-sys-desc.pod' => '../GT/Docs/gt_sig-sys-desc.pod',
        'object_aliases.pod'  => '../GT/Docs/object_aliases.pod',
        'how_to_spec+debug_a_system.pod' =>
                                 '../GT/Docs/how_to_spec+debug_a_system.pod',
        'pod_guidelines.pod'  => '../GT/Docs/pod_guidelines.pod',
        'indicator_signal_system_modules.pod' =>
                                 '../GT/Docs/indicator_signal_system_modules.pod',
    },

    pm_files => {
        'GeniusTrader.pm' => '../GeniusTrader.pm',
        'Conf.pm'         => '../GT/Conf.pm',
        'Eval.pm'         => '../GT/Eval.pm',
    },

    build_requires => {
        'Module::Build'         => '',
#        'missing::build_prereq' => '',
    },

    auto_features => {

        # which databases are available for use
        dbi_support => {
            description => "support for DBI",
            requires    => { 'DBI' => 0, },
        },

        beancounter => {
            description => "beancounter database and application",
            requires    => { 'Finance::BeanCounter' => 0, },
        },

        beancounter_support => {
            description => "beancounter support modules ",
            requires    => {
                'DBI'                     => 0,
                'Finance::YahooQuote'     => 0,
                'Finance::BeanCounter'    => 0,
                'Text::ParseWords'        => 0,
                'Statistics::Descriptive' => 0,
            },
        },

        pg_support => {
            description => "Interface with Pg (postgresql) databases",
            requires    => { 'DBD::Pg' => 0, },
        },

        mysql_support => {
            description => "Interface with mysql based db engine",
            requires    => { 'DBD::mysql' => 0, },
        },

        sqlite_support => {
            description => "Interface with SQLite based db engine",
            requires    => { 'DBD::SQLite' => 0, },
        },

        sqlite2_support => {
            description => "Interface with SQLite2 based db engine",
            requires    => { 'DBD::SQLite2' => 0, },
        },

        sql_file_support => {
            description => "Interface with file based db engine",
            requires    => { 'DBD::File' => 0, },
        },

        odbc_support => {
            description => "Interface using generic ODBC driver",
            requires    => { 'DBD::ODBC' => 0, },
        },

    },    # end auto_features

    requires => {
        Compress::Zlib => '',
        Cwd            => '',
        Data::Dumper   => '',
        Date::Calc     => '',
        Date::Manip    => '>= 5.44, != 5.45, != 5.46',
###        Date::Manip    => '>= 5.44, != 5.45, != 5.46, < 6.0',
        DBI            => '',
        File::Find     => '',
        File::Spec     => '',
        Getopt::Long   => '',
        HTML::Mason    => '',
        IO::Handle     => '',
        List::Util     => '',    # alternate is Scalar::List::Utils
        LWP            => '',
        Math::Trig     => '',
        POSIX          => '',
        Pod::Simple    => '',
        Pod::Usage     => '',
        Storable       => '',
#        NOT_REAL       => '',

        # 'another::missing' => '',

        # in general GD is required for graphic image output
        # graphic.pl can be coerced to use one of the four
        # GD, SVG, PostScript::Simple or Image::Magick but
        # as of this writing backtest.pl only uses GD
        # this could be changed, but it hasn't so far.
        'GD' => '',

    }, # end requires

    recommends => {

        # in general GD is required for graphic image output
        # but graphic.pl can use one of the following instead
        'SVG'              => '',
        PostScript::Simple => '',
        Image::Magick      => '',

        Pod::Parser => '',
        XML::LibXML => '',
        Time::Local => '',    # only needed for DB/CSV.pm
        Log::Log4perl  => '', # only needed for gt internal debug

        YAML => '',           # yaml comes and goes, mostly gone right now

#        # these are commented out in ../GT/Analyzers/Process.pm
#        # but might be activated to provide serious enhancements
#        # to gt analytical reporting
#        R                 => '',
#        R::Wrapper        => '',
#        RReferences       => '',
#        PGPLOT            => '',
#        Chart::Math::Axis => '',

#        'recommend'          => '',
#        'recommend::missing' => '',
    }, # end recommends

); # end Module::Build->new



# messin' with auto features listed
if ( $build->feature('dbi_support') ) {
    print <<'eohd';

yea! you have the perl module DBI, which is absolutely needed for GT if you
intend to use any sql based price database. let's see which DBI/DBD drivers
you have available ...
eohd
    my %gt_supported_dbd_drivers = (
        mysql   => 0,
        Pg      => 0,
        SQLite  => 0,
        SQLite2 => 0,
        CSV     => 0,
        ODBC    => 0,
    );

    use DBI;
MOD:foreach my $module ( keys %gt_supported_dbd_drivers ) {
        foreach my $driver ( DBI->available_drivers ) {
            if ( $module =~ m/^${driver}$/i ) {
                $gt_supported_dbd_drivers{$module} = 1;
                next MOD;
            }
        }
    }

    foreach my $module ( keys %gt_supported_dbd_drivers ) {
        print "$module, " if $gt_supported_dbd_drivers{$module};
    }
    print "\n\n";
}
else {
    print <<'eohd';

with the state of perl datebase modules all you can use is the Text based
files database.  refer to the pod in module GT/DB/Text.pm (perldoc
GT/DB/Text.pm) for configuration details.

if you intend to use a sql based prices databases with GT you must have 
the perl module DBI and at least one of these perl modules/packages:

    DBD::Pg, DBD::mysql, DBD::SQLite2, DBD::SQLite, DBD::ODBC

Finance::BeanCounter will provide a functional prices database for each of
these database interfaces if you don't plan on using a custom sql database or
the MetaStock file base price data.
eohd

}


if ( $build->feature('beancounter') ) {
    print <<'eohd';

BeanCounter
  OK! you have beancounter installed and ready to go refer to the pod in
  module GT/DB/bean.pm (e.g. perldoc GT/DB/bean.pm) for configuration details.
eohd
}
elsif ( $build->feature('beancounter_support') ) {
    print <<'eohd';

beancounter support
  humm! you have the modules beancounter needs, but not BeanCounter itself.
  install Finance::BeanCounter and rerun this script.
eohd
}

if ( $build->feature('sql_file_support') ) {
    print <<'eohd';

CSV
  humm: you have perl modules needed to use the GT CSV driver.
  THIS IS TOTALLY EXPERIMENTAL that means that you are on your own with this
  -- refer to pod in GT/DB/CSV.pm.
eohd
}

if ( $build->feature('pg_support') ) {
    print <<'eohd';

Posgresql support
  well well: you have the perl modules needed for postgresql db support so a
  beancounter installation could run on a postgresql database repository.
eohd
}

if ( $build->feature('mysql_support') ) {
    print <<'eohd';

MySQL
  facinating! it is nice that you have perl modules needed to use a mysql
  based database so a beancounter installation could run on a mysql db.
eohd
}

if ( $build->feature('sqlite_support') ) {
    print <<'eohd';

SQLite
  ok! you have the perl modules needed for sqlite db support, so a beancounter
  installation could run on this sqlite db.
eohd
}

if ( $build->feature('sqlite2_support') ) {
    print <<'eohd';

SQLite2
  ok! you have the perl modules needed for sqlite2 db support, so a beancounter 
  installation could run on this sqlite2 db
eohd
}

if (   $build->feature('pg_support')
    || $build->feature('mysql_support')
    || $build->feature('sqlite_support')
    || $build->feature('sqlite2_support')
    || $build->feature('odbc_support') )
{
    print <<'eohd';

genericdb
  humm: you have perl modules needed to use any sql database with GT if you
  can define the necessary sql statments needed to query the database for
  prices (open, high, low, close, volume and date tuples are needed per
  symbol), plus optionally the securities name.  for more details refer
  to the pod in GT/DB/genericdb.pm.
eohd
}

print "\n";


#$build->create_gt_options_file;

#$build->create_build_script;

my @graphic_drivers = qw( GD SVG PostScript::Simple Image::Magick );
my $missing_gd      = @graphic_drivers;
my @missing_graphic_drivers;

my $gd_missing  = 0;
my $svg_missing = 0;
my $ps_missing  = 0;
my $im_missing  = 0;

my $failures = $build->prereq_failures;
while ( my ( $type, $list ) = each %$failures ) {
    while ( my ( $name, $hash ) = each %$list ) {

        if ( $type eq 'recommends' ) {
            ++$svg_missing if $name =~ m/SVG/;
            ++$ps_missing  if $name =~ m/PostScript::Simple/;
            ++$im_missing  if $name =~ m/Image::Magick/;

            if ( $name =~ m/SVG|PostScript::Simple|Image::Magick/o ) {
                --$missing_gd;
                push @missing_graphic_drivers, grep m/$name/, @graphic_drivers;
            }
        }
        if ( $type eq 'requires' ) {

            ++$gd_missing if $name =~ m/GD/;

            if ( $name =~ m/GD/o ) {
                --$missing_gd;
                push @missing_graphic_drivers, grep m/$name/, @graphic_drivers;
            }
        }
    }
}

if ( $gd_missing && $missing_gd == code0 ) {
    print "\nwhoa! you don't seem to have any graphic driver package";
    print " installed\nthat gt can use to generate graphic images\n";

}
elsif ( $gd_missing && $missing_gd > 0 ) {
    print "\nOOPS! you don't have the GD perl module installed. GD is the\n";
    print "primary (default) image package used by gt.  it it HIGHLY";
    print " recommended\nthat you take to time to install it.\n";

    print "\nthe perl module GD also requires the c library libgd known";
    print " as gd-2...\nversions from gd-2.0.33 up are known to work.\n";

    print "\nsince you have";
    print $svg_missing ? " no svg" : " SVG";
    print $ps_missing  ? " no ps"  : " PostScript::Simple";
    print $im_missing  ? " no im"  : " Image::Magick";
    print " modules\n";
    print "you can at use one of them, but be sure to set the\n";
    print "\"Graphics::Driver\" key to whatever driver you intend to use\n";
    print "in your \$HOME/.gt/options file.\n";
    print "\notherwise you will have to set option\n";
    print "  --driver=your_driver\n";
    print "on the graphic.pl gt application command line.\n";

    print "\nnote that gt application backtest.pl only supports GD based";
    print "graphic output.\n";
}



#
# check users' gt configuration file
#
my $options_file = "$ENV{HOME}/.gt/options";
#my $options_file = "$ENV{HOME}/.gt/options_file_test3";
#my $options_file = "$ENV{HOME}/.gt/options_file_test2";
#my $options_file = "$ENV{HOME}/.gt/options_file_test1";

print "\n\nchecking on $ENV{USER}'s GT configuration file\n \"$options_file\"\n\n\n";

my $arial = 0;            # arial font ok? false to start
my $bad_path = 0;         # (count of) bad font paths or files false to start
my $bad_db_config = 0;    # flag for a bad config file false to start
my $line;                 # config file line number

# misc work arrays
my @fps;
my @dbmods;
my @config_keys;



unless ( -s $options_file && -T $options_file ) {
    print "\nohmygod! you don't seem to have a GT configuration file";
    print " installed.\n";
    print "      \$HOME/.gt/options\n\n";
    print "this file is required and must set at least these two configuration keys:\n\n";
    print join "", "    1) ", "$DB_MOD_KV_MSG";
    print "\n";
    print join "", "    2) ", "$FP_KV_MSG";
    print "refer to http://geniustrader.org/first_use.html for options file details\n";
    print "\n\n";

    ++$bad_db_config;

    goto OPT_DONE;
}

else {
    open( OPTIONS, "<", $options_file );
    my @options = <OPTIONS>;
    close OPTIONS;

    #
    # checking on Path::Font::Arial and other entries
    #
    $line = @options + 1;
    foreach my $kv ( reverse @options ) {
        --$line;
        #next if $kv =~ m@^#*$@io;
        next unless $kv =~ m@^Path::Font::@io;
        chomp $kv;
        my ( $key, $fpath ) = split /\s+/, $kv, 2;
        
        next if grep { m@^$key@i } @fps;
        my $bad_pathname = 0;

        unless ( (stat "$fpath")[2] ) {
            print "file $options_file: line $line:\n";
            print "    path \"$fpath\" not found\n\n";
            ++$bad_pathname;
        }

        if ( $FILE_CMD && ! $bad_pathname ) {
            my $ftype = `$FILE_CMD $FILE_ARG $fpath 2>/dev/null`;
            unless ( $ftype =~ m@TrueType font@io ) {
                print "file $options_file: line $line:\n";
                print "    $key pathname is not a TrueType font file.\n";
                print "    $FILE_CMD reports:\n";
                print "       $ftype\n\n";
                ++$bad_pathname;
            }
        }

        unless ( $bad_pathname ) {
            push @fps, $key, $fpath;
            ++$arial if $arial < 1 && $key =~ m@^Path::Font::Arial@io;
        }
        else {
            ++$bad_path;
        }
    } # end foreach

#print "\nsummary: arial is $arial, bad_path==$bad_path\n\n";

    unless ( $arial == 1 ) {
        print "\nyikes! -- your GT options file does not have the required arial font face entry.\n";
        print "    $FP_KV_MSG";
        print "you must correct this before attempting to use any GT GD graphic app.\n";
        print "refer to http://geniustrader.org/first_use.html\n\n";
    }

    if ( @fps && $arial == 1 ) {
        print "\nCongrats!!! you have correctly configured these font faces:\n";
        foreach my $fp ( @fps ) {
            print "$fp\n" if $fp =~ m@^Path::Font::@io;
        }
        print "\n";
    }

    if ( $bad_path > 0 ) {
        print "\noh boy -- as noted above, your GT options file has $bad_path bad font file ";
        print "pathnames\nthat do not appear to be TrueType font files.\n";
        print "\nyou might want to correct these entries before attempting to use GT.\n\n";
    }


    #
    # checking for DB::Module related entries
    #
    $line = @options + 1;
    #my @dbmods;
    opendir( DB_DIR, "../GT/DB" );
    my @dbmodules = grep { /^.*\.pm$/io && s@\.pm@@io } map { lc } readdir DB_DIR;
    closedir DB_DIR;

    foreach my $kv ( reverse @options ) {
        --$line;
        next unless $kv =~ m@^DB::Module\s@io;
        chomp $kv;
        my ( $key, $dbmodule ) = split /\s+/, $kv, 2;

        if ( $dbmodule =~ m/^metastock$/io ) {
            print "Notice: the MetaStock.pm module is depreciated in favor of the\n";
            print "        MetaStockReader.pm module. see the pod in both modules\n";
            print "        for the details and discussion\n";
            push @dbmods, $dbmodule;
            next;
        }

        unless ( grep { $dbmodule } @dbmodules ) {
            print "ERROR: the $dbmodule module is not a valid prices datebase module.\n";
            print "";
            print "   $DB_MOD_KV_MSG\n";
            print "\n\n";
            next;
        }
        else {
            push @dbmods, $dbmodule;
            next;
        }

     } # end foreach DB::Module entry
     #
     # now using each dbmodule (from @dbmods)
     # scan the config file and select lines matching
     #  '^DB::$dbmodule(::.*\s|\s)'
     #
     #my @config_keys;
     foreach my $module ( @dbmods ) {
         my $line;
         foreach my $kv ( @options ) {
            ++$line;
            next unless $kv =~ m@^DB::$module(::.*\s|\s)@i;
            chomp $kv;
            my ( $key, $config, $residual ) = split /\s+/, $kv, 3;

            if ( $config =~ m/^['"].+['"]$/io ) {
                print "warning: values should NOT be quoted (with '\") unless the quote\n";
                print "characters are actually part of the value. verify the entry at line $line \n";
                print "is correct:\n";
                print "      $key $config $residual\n";
                print "\n";
            }

            if ( grep { /^$key$/i } @config_keys ) {
                print "Notice: you have multiple settings for key:\n";
                print "      $key\n";
                print "    this may be fine, but be aware only the last key-value will be used.\n";
                print "\n";
            }

            push @config_keys, [ $key, $config ];

         } # end foreach DB::Module entry
     } # end foreach @dbmods entry

     if    ( @dbmods <= 0 ) {
        print "ooops! you don't have a correctly configured prices database module\n";
        print "   in your gt configuration file.\n";
        print "\n";
        print "This must be corrected, without it, gt will be unable to access price data.\n";
        print "\n";
        print "$DB_MOD_KV_MSG\n";
        print "\n";
     }
     elsif ( @dbmods > 1 ) {
        print "error! it seems you have tried to configure ", scalar @dbmods, "\n";
        print "   prices database modules. The last one ( $dbmods[0] ) will used\n";
        print "   These will be ignored: $dbmods[1]";
        foreach ( my $i = 2; $i <= $#dbmods; ++$i ) {
            print ", $dbmods[$i]";
        }
        print "\n";
        print "\n";
        print "You should check the gt configuration file carefully.\n";
        print "\n";
        print "$DB_MOD_KV_MSG\n";
        print "\n";
     }
     else {
        print "\nyou are configured for the $dbmods[0] prices database module.\n";
        print "with these database module key settings:\n";
        foreach my $kv ( @config_keys ) {
            if ( @$kv[0] =~ m/password|dbpasswd|passwd/io ) {
                my $hidden = '*' x length @$kv[1];
                print "    @$kv[0] $hidden (password not printed)\n";
            }
            else {
                print "    @$kv[0] @$kv[1]\n";
            }
        }
        print "\n";
     }

} # end else unless ( -s $options_file && -T $options_file )

OPT_DONE:
unless ( $bad_path > 0 || $bad_db_config > 0 ) {
    print "\nyour GT configuration file looks ok\n\n\n\n";
}
else {
    print "\n--->>>your GT configuration file needs some attention\n\n\n\n";
}


OPT_SKIP:


unless ( $is_scripts_dir_writable ) {

    print <<'eohd';

oh sorry! your scripts dir is not writable so i'm unable to reset your
gt script app sharpbang lines to match your perls' config flavor or to
create symlinks for the gt script apps (assuming your platform even knows
about such exotic filesystem entities.

so with that i'll bid you good day!

eohd

exit 0;
}


#
# checking users perl sharpbang setting vice the gt default
#
my $shebangline = $build->config("sharpbang") . $build->config("perlpath");
my $sb_regex =
 $build->config("sharpbang") . '\s*' . $build->config("perlpath") . '.*$';

#print "regex \'$sb_regex\'\n";

my @bad_shebangs;
foreach my $app (@gt_apps) {
    open APP, "<", "$app"
     or print "humm, could not open \"$app\" for reading\n";
    while (<APP>) {
        chomp;
        unless ( $_ =~ m{^$sb_regex} ) {
            push @bad_shebangs, $app;
        }
        last;
    }
    close APP;
}

if (@bad_shebangs) {
    my $app_count = @bad_shebangs;
    print <<"eohd";

the distribution uses a shebang line that differs from your perl config version.
to upgrade the gt perl app scripts you can simply insert the following line

$shebangline

as the first line of each of the following $app_count files:
eohd

    my @bad_files = @bad_shebangs;
    while ( my $file = shift @bad_shebangs ) {
        print "  $file\n";
    }

    print "\nif you want i will do it for you automagically? y/[n] ";
    my $resp = <>;
    unless ( $resp =~ m/^y.*$/io ) {
        print "fine! be that way, i really don't care, but you could be heading";
        print " for trouble.\n";
    }
    else {
        print "great! i'll fix the files in place, by prepending your perls'";
        print " shebang line\n";
       FILE: while ( my $file = shift @bad_files ) {
            print "$file .";
            open FILE, "<", "$file"
             or print
             " wtf!? opening \'$file\' for reading failed, skipping it.\n"
             and next FILE;
            my @lines = <FILE>;

            open FILE, "+>", "$file"
             or print " oh crap! reopening \'$file\' for trunc'ed write failed, skipping it.\n"
             and next FILE;
            print FILE "$shebangline\n\n", @lines;
            close FILE;
            print ".. done.\n";
        }
    }
}


#
# if supported offer user to create gt script apps as symlinks
# without the .pl extension
#
my $can_mksymlink = eval { symlink( "", "" ); 1 };
if ($can_mksymlink) {

    print <<'eohd';

excellent! your platform supports symlinks, so if you want i can create
symlinks for each of the gt application scripts without that damned .pl
extension ... it saves a bit of typing the command lines.

eohd
    print "do you want the symlinks? y/[n] ";
    my $resp = <>;

   SYMLINKS:
    my $c = 0;
    if ( $resp =~ m/^y.*$/io ) {
        print "ok, making symlink for\n";
       FILE: foreach my $file (@gt_apps) {
            ( my $symlink = $file ) =~ s/\.pl$//;
            if ( -f "$file" ) {
                if ( -f "$symlink" || -l "$symlink" ) {
                    print "file $symlink already exists, so i'm skipping it.\n"
                     if -f "$symlink";
                    print "symlink $symlink already exists, so i'm skipping it.\n"
                     if -l "$symlink";
                    next FILE;
                }
                else {
                    symlink( "./$file", "$symlink" );
                    print "symlink( \"./$file\", \"$symlink\" ) failed.\nerror $@\n"
                     if $@;
                }    # end if ( -f "$symlink" || -l "$symlink" )

                print "  $symlink ok\n" if -l "$symlink";
            }    # end if ( -f "$file" )
        }    # end FILE:foreach
    }    # end symlinks

}

unless ( $bad_path || $bad_db_config ) {
    exit 0;
}
else {
    exit 1;
}

=pod

=head1 Build.PL - analyzes the users system and (interactively) configures GeniusTrader (GT) for it

=head1 SYNOPSIS

perl Build.PL

=head1 DESCRIPTION

gathers information about the users system and configures GT for it.

information gathered includes checking for perl and the prerequisite
perl modules required by GT. there is some hueristics
about inter-dependencies between alternative methods for the stock
pricing data and graphical output forms, but not a lot.

looks for and evaluates users $HOME/.gt/options file for one of two
critically required key-value pairs:

  * Path::Font::Arial <truetype font file path>
  * DB::Module <prices database module to use>

configuration consists of (interatively) re-setting the GT
application scripts shebang lines suitable for the users system and
perl installation.

Build.PL also offers to create symlinks (if user platform supports
them) for the GT application scripts without the rather annoying .pl
extension.

in addition, (un-implemented as of 16mar11) creates the gt options
configuration file (e.g. $HOME/.gt/options)

=head1 OPTIONS

none

=head1 USAGE

Build.PL is interactive in terns of it's output; in other
words without user approval it will not change or create nothing.

In use it resembles typical perl Build.PL (or the older perl Makefile.PL),
but it is rather verbose in typical ras hack fashion.
It checks for perl usability and Build.PL prerequisites and then checks 
for the perl modules GT requires or can optionally use if available.

Based on these collected information (informata?) Build.PL reports
the users basic options regarding GT use on this system.

  as of 6jul2012 looks for and evaluates users $HOME/.gt/options file
  for correct setting of Path::Font::Arial key-value pair.
    -- checks that value is a truetype file using *nix util file.
    -- checks all other Path::Font::* key-values for valid file path
       and truetype file.
    -- checks for a valid "DB::module <module_name>"
    -- lists the associated DB::module key value settings

  [ currently unsupported and unimplemented ]
    the various collected data along with extensive user interaction
    create the initial users gt options file
     -- difficult without a lot of user interaction ...
      o setup key-value data needed to access stock prices database
      o configure graphic driver [checking now implemented]

Build.PL uses the perl configuration data to verify if the default
GT application script shebang line is suitable for the users system.
If there is a mis-match Build.PL offers to make the correction
automatically. The user must accept the recommendation affirmatively
or nothing will be changed.

Build.PL also offers to create symlinks for the GT application scripts
without the rather annoying .pl extension. The user must accept the
offer affirmatively or nothing will be changed.

=head1 BUGS-DEVELOPMENT

=over

=item file utility

in order to validate the file type your fontpath keys refer to the
*nix file utility is used.
it is required to support the -L symlink deference flag
(gnu versions do as does the old ucb version).
in addition the id string is required to be "^truetype font"
case not significant. if you have trouble with fontpath messages
see the code for commentary on how to help yourself.

=item as of 16mar11

seems to only evaluate for BeanCounter and the various supported
SQL database backends.

=item

should also report on default graphic driver GD (perl GD.pm and c libgd)
and the various optional (but less capable graphics drivers): svg,
image-magick (gnu graphics-magick) and postscript.

=item as of 8jul12

might also he helpful to check that at least the TFS and TFS[]
global aliases are defined in config file, so the myriad examples
will work ...

=back

=cut

