#!/usr/bin/perl

###################################################
#
#  Copyright 2005-2010 Christian Jodar
#
#  This file is part of GCstar.
#
#  GCstar is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  GCstar is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with GCstar; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#
###################################################

use strict;
use utf8;

my $initTime;
$ENV{GCS_PROFILING} = 0 if ! exists $ENV{GCS_PROFILING};
if ($ENV{GCS_PROFILING} > 0)
{
    eval 'use Time::HiRes';
    eval '$initTime = [Time::HiRes::gettimeofday()]';
}

my $VERSION = '1.7.1';

my $MULTI_PROCESS = ((!exists $ENV{GCS_PROFILING}) || ($ENV{GCS_PROFILING} == 0));

use Getopt::Long;
use File::Path;
use File::Spec;
use FindBin qw($RealBin);
use POSIX qw(locale_h);

$ENV{GCS_BIN_DIR} = $RealBin;
($ENV{GCS_LIB_DIR} = $ENV{GCS_BIN_DIR}) =~ s/bin\/?$/lib\/gcstar/;
($ENV{GCS_SHARE_DIR} = $ENV{GCS_BIN_DIR}) =~ s/bin\/?$/share\/gcstar/;
use lib File::Spec->canonpath("$RealBin/../lib/gcstar");
if (exists $ENV{PAR_TEMP})
{
    unshift @INC, "$RealBin/../lib/gcstar";
}

# For win32, redirect all the output to files
if ($^O =~ /win32/i)
{
    my $logdir = $ENV{'APPDATA'};
	$logdir =~ s/\\/\//g;
    mkpath $logdir;
    close(STDOUT);
    close(STDERR);
    open(STDOUT, ">$logdir/gcstar.log");
    open STDERR, ">&STDOUT";
    select STDERR; $| = 1;
}

#XDG stuff
my $home = $ENV{'HOME'};
$home = $ENV{'APPDATA'} if ($^O =~ /win32/i);
$home =~ s/\\/\//g if ($^O =~ /win32/i);

$ENV{XDG_CONFIG_HOME} = $home.'/gcstar/config' if ($^O =~ /win32/i);
$ENV{XDG_CONFIG_HOME} = $home.'/.config' if ! exists $ENV{XDG_CONFIG_HOME};

$ENV{XDG_DATA_HOME} = $home.'/gcstar' if ($^O =~ /win32/i);
$ENV{XDG_DATA_HOME} = $home.'/.local/share' if ! exists $ENV{XDG_DATA_HOME};

$ENV{GCS_CONFIG_HOME} = $ENV{XDG_CONFIG_HOME}.'/gcstar';
$ENV{GCS_CONFIG_HOME} = $ENV{XDG_CONFIG_HOME} if ($^O =~ /win32/i);

# Migrate settings from old windows data path if required
if (($^O =~ /win32/i) && !(-d $ENV{XDG_DATA_HOME}))
{
    if (-d $RealBin.'/../config')
    {	
        print ("Need to migrate settings from old gcstar data store\n");
		mkpath $ENV{XDG_CONFIG_HOME};
        mkpath $ENV{XDG_DATA_HOME};
		my $winRealBin = $RealBin;
		$winRealBin =~ s/\//\\/g;
		my $winXDGConfig = $ENV{XDG_CONFIG_HOME};
		$winXDGConfig =~ s/\//\\/g;
		my $winXDGData = $ENV{XDG_CONFIG_HOME};
		$winXDGData =~ s/\//\\/g;
		system "xcopy /Y \"".$winRealBin."\\..\\config\" \"".$winXDGConfig."\"";
		system "xcopy /Y \"".$winRealBin."\\..\\data\" \"".$winXDGData."\"";
    } 
}

mkpath $ENV{XDG_CONFIG_HOME};
mkpath $ENV{XDG_DATA_HOME};

mkdir $ENV{GCS_CONFIG_HOME};
mkdir $ENV{GCS_CONFIG_HOME}.'/GCModels/';
$ENV{GCS_CONFIG_FILE} = $ENV{GCS_CONFIG_HOME}.'/GCstar.conf';
$ENV{GCS_DATA_HOME} = $ENV{XDG_DATA_HOME}.'/gcstar';
$ENV{GCS_DATA_HOME} = $ENV{XDG_DATA_HOME} if ($^O =~ /win32/i);
mkdir $ENV{GCS_DATA_HOME};

use GCOptions;
my $options = new GCOptionLoader($ENV{GCS_CONFIG_FILE}, 1);

my $lang = $options->getFullLang;
$ENV{LANG} = $lang;
$ENV{LANGUAGE} = $lang;
$ENV{LC_ALL} = $lang;
$ENV{LC_CTYPE} = $lang;
setlocale(LC_ALL, $lang);

sub usage
{
    print "Usage: $0 [-u UPDATE-OPTIONS] [-x EXECUTE-OPTIONS] [FILENAME]

Launch GCstar, a personal collection manager. Without any option, it will open
FILENAME if specified or the previously opened file.

Update options:

  -u, --update                 Tell GCstar to look for available updates
  -a, --all                    Update all components
  -c, --collection             Update collection models
  -w, --website                Update plugins to download information
  -i, --import                 Update plugins to import data
  -e, --export                 Update plugins to export data
  -l, --lang                   Update translations
  -n, --noproxy                Don't ask for a proxy

Execute options:

  -x, --execute                Enter non-interactive mode
  -c, --collection MODEL       Specify the collection type
  -w, --website PLUGIN         Specify the plugin to use to download information
  -i, --import PLUGIN          Specify the plugin to use to import a collection
  -e, --export PLUGIN          Specify the plugin to use to export the collection
  -f, --fields FILENAME        File containing fields list to use for import/export
  -o, --output FILENAME        Write output in FILENAME instead of standard output
  --download TITLE             Search for the item with TITLE as name
  --importprefs PREFERENCES    Preferences for the import plugin
  --exportprefs PREFERENCES    Preferences for the export plugin
  --list-plugins               List all the plugins available to download information

  Preferences for import/export plugins are specified using this schema:
    \"Key1=>Value1,Key2=>Value2\"

Environment variables:

  \$HOME                        Used to define following variables if needed
  \$XDG_CONFIG_HOME             Where configuration files should be stored
                                  If not defined: \$HOME/.config
  \$XDG_DATA_HOME               Where some data will be stored
                                  If not defined: \$HOME/.local/share

Bugs reporting:

  To report bugs, please use this forum:
    http://forums.gcstar.org/viewforum.php?id=4
  
";
}

sub version
{
    print "GCstar $VERSION\n";
}

Getopt::Long::Configure ('bundling');
my ($help, $version, $update, $toBeUpdated, $noProxy, $listPlugins) = (0, 0, 0, {}, 0);
my ($collection, $website, $import, $export) = (undef, undef, undef, undef);
my ($execute, $title, $output, $inPrefs, $outPrefs, $fields) = (0, '', '', '', '', '');
(usage, exit 1) if !GetOptions("h|help" => \$help,
                               "v|version" => \$version,
                               "u|update" => \$update,
                               "x|execute" => \$execute,
                               "a|all" => \$toBeUpdated->{all},
                               "c|collection:s" => \$collection,
                               "w|website:s" => \$website,
                               "i|import:s" => \$import,
                               "e|export:s" => \$export,
                               "l|lang" => \$toBeUpdated->{lang},
                               "n|noproxy" => \$noProxy,
                               "download=s" => \$title,
                               "o|output=s" => \$output,
                               "importprefs=s" => \$inPrefs,
                               "exportprefs=s" => \$outPrefs,
                               "f|fields=s" => \$fields,
                               "list-plugins" => \$listPlugins,
                               );

my $atLeastOne = 0;
foreach (keys %$toBeUpdated)
{
    $atLeastOne = 1 if $toBeUpdated->{$_};
}
(usage, exit 1) if $help || ($atLeastOne && !$update);
(version, exit 0) if $version;

if ($update)
{
    eval '
        use GCUpdater;
        use GCLang;
        ';
    my $langContainer = $GCLang::langs{$options->lang};
    $toBeUpdated->{all} = 1 if !$atLeastOne;
    $toBeUpdated->{models} = defined($collection);
    $toBeUpdated->{plugins} = defined($website);
    $toBeUpdated->{import} = defined($import);
    $toBeUpdated->{export} = defined($export);
    my $updater = new GCTextUpdater($langContainer,
                                    $ENV{GCS_LIB_DIR},
                                    $toBeUpdated,
                                    $noProxy,
                                    $VERSION);
    $updater->update;
    exit 0;
}
elsif ($execute)
{
    use GCCommandLine;
    
    my $execution = new GCCommandExecution($options,
                                           $collection,
                                           $website,
                                           $import,
                                           $export,
                                           $output);
    if ($listPlugins)
    {
        if ($collection)
        {
            $execution->listPlugins;
            exit 0;
        }
        else
        {
            print "A kind of collection should be specified (with -c) when using --list-plugins\n";
            exit 1;
        }
    }

    if ($ARGV[0])
    {
        if ($import)
        {
            $execution->import($ARGV[0], $inPrefs);
        }
        else
        {
            $execution->open($ARGV[0]);
        }
    }
    $execution->setFields($fields) if $fields;
    $execution->load($title) if $title;
    if ($export)
    {
        $execution->export($outPrefs);
    }
    else
    {
        $execution->save;
    }
    exit 0;
}
if ($ARGV[0])
{
    # We have to make it absolute if needed
    my $file = $ARGV[0];
    $file = File::Spec->rel2abs($file)
        if (!File::Spec->file_name_is_absolute($file));
    $options->file($file);
}

my $pid;
if ($MULTI_PROCESS)
{
    pipe(RCOMMAND, WCOMMAND);
    pipe(RDATA, WDATA);
    if ($^O !~ /win32/i)
    {
        if (!($pid = fork))
        {
            use GCPlugins;
            close WCOMMAND;
            close RDATA;
            my $searchJob = new GCPluginJob(\*RCOMMAND, \*WDATA);
        
            $searchJob->run;
        }
    }
}

use Gtk2;
use GCMainWindow;

my %searchJob = ();

if ($MULTI_PROCESS)
{
    close RCOMMAND;
    close WDATA;
    %searchJob = (
        pid => $pid,
        command => \*WCOMMAND,
        data => \*RDATA
    );
    
    if ($^O =~ /win32/i)
    {
        close WCOMMAND;
        close RDATA;
    }
}
Gtk2->init;
my $window = new GCFrame($options, $VERSION, \%searchJob);

#Gtk2->set_locale;
Gtk2->main;

if ($^O =~ /win32/i)
{
    # We store the language in .bat file if possible

    my $batch = 'gcstar.bat';
    if (-w $batch)
    {
        local $/ = undef;
        open BATCH, "<$batch";
        my $lang = $options->lang;
        my $bat = <BATCH>;
        $bat =~ s/LANG=.*$/LANG=$lang/m;
        close BATCH;
        open BATCH, ">$batch" or die "Cannot open .bat to save language\n";
        print BATCH $bat;
        close BATCH;
    }
    close(STDOUT);
    close(STDERR);
}

if ($ENV{GCS_PROFILING} > 0)
{
    my $elapsed;
    eval '$elapsed = Time::HiRes::tv_interval($initTime)';
    print "Elapsed : $elapsed\n";
}

0;
