#!/usr/bin/perl
#
# gnview 2ch BBS Viewer installation script
#
#=======================================================

use utf8;
use strict;
use POSIX qw/ locale_h strftime /;
use Encode qw/ encode from_to decode /;
use Encode::Guess qw/ euc-jp shiftjis /;
use File::Copy;
use File::Path;
use Data::Dumper;

#=======================================================
my $stepflg = 1;
my @gnReqLibs = ("Compress::Zlib",	"Config",		"Data::Dumper",	"Encode",
                         "Encode::Guess",	"File::Basename",	"File::Copy",		"File::Path",
                         "Glib",		"Gtk2",		"Gtk2::GladeXML",	"Gtk2::Pango",
                         "HTML::Entities",	"HTML::TokeParser","HTTP::Cookies",	"HTTP::Date",
                         "LWP::MediaTypes",	"LWP::UserAgent",	"List::Util",		"POSIX",
                         "Thread::Queue",	"Time::HiRes",	"Time::Local",		"URI::file",
                         "threads",		"threads::shared",	"utf8");
my $gnUserLang;
my $gnPerlpath;
my $binpath = &gnGetBinPath;
my $sharepath = &gnGetLibPath;
my $manpath = $sharepath . "man\/";

for(;;) {
# Step 1 (日本語が出力可能であることをチェック)=======================
   if($stepflg == 1) {
      $gnUserLang = $ENV{'LANG'};
      $gnUserLang = &env_locale_to_encstr($gnUserLang);
      if($gnUserLang eq "ascii") {
         print "I\'m sorry, but this script says some japanese.\n" .
                "Please set your environment variables to some japanese value.\n";
         exit(1);
      }else{
         &gnprint("==================================\n" .
                    "gnviewをインストールします\(\<Ctrl\>\+Cで中断\)\n");
         $stepflg++;
      }
   }

# Step 2 (使用するperlのパスをチェック)=============================
   if($stepflg == 2) {
      &gnprint("==================================\ngnviewで使用するperlを指定します\n");
      
#      my @pl = `which -a perl 2\>/dev/null`;
      my @pl = &gnWhich(); 
      my $b=0;
      foreach my $a (@pl) {
         chomp($a);
         &gnprint("\t\[$b\] $a\n");
         $b++;
      }
      &gnprint("使用するperlを選択するか、\nperlへのパスをフルパスで入力してください\: ");
      $gnPerlpath = <STDIN>; chomp($gnPerlpath);
      my $flg1 = substr($gnPerlpath,0,1);
      if($flg1 =~ /[0-9]/) {
         my $c = $pl[$flg1];
         my @d = `$c -v`;
         $c = $d[1]; chomp($c);
         &gnprint("$c\n");
         $gnPerlpath = $pl[$flg1]; chomp($gnPerlpath);
         $stepflg++;
      }elsif($flg1 eq "\/") {
         if(-e $gnPerlpath) {
            $stepflg++;
         }else{
         &gnprint("\n\[ERROR\]指定されたパスは存在しません\n\n");
         }
      }else{
         &gnprint("\n\[ERROR\]有効ではない選択肢です\n\n");
      }
   }
   
# Step 3 (Step2で選択したperlが必要条件を満たしているかをチェック)=========
   if($stepflg == 3) {
      my $cnt3_1 = 0;

      # ithreadsサポートのチェック
      my @gnPerlopts = `$gnPerlpath -V`;
      foreach my $line (@gnPerlopts) {
         chomp($line);
         if($line =~ /useithreads=define/) {
          #print "$line\n";
          $cnt3_1++;
         }
      }
      if($cnt3_1 == 0) {
         &gnprint("\[ERROR\]指定されたperlはithreadsをサポートしていません\n");
         &gnprint("\[ERROR\]gnviewの動作にはithreadsに対応したperlを用意する必要があります\n");
         $stepflg--;
      }else{
      
         # ライブラリのチェック
#      my @gnview_modules = `cat *.pl | grep -E "^use"|sort|uniq`;
         my $str = 'echo "foreach \$a(@INC) {print \"\$a\\n\";}"';
         my @gnINCs = `$str|$gnPerlpath`;
      #print "incs:\n" . Dumper(@gnINCs);
         my $cnt3_3 = 0;
         foreach my $eachmodule (@gnReqLibs) {
            chomp($eachmodule);
         #print "modules\t$eachmodule\n";
#         $eachmodule =~ s/^use\s+//;
#         $eachmodule =~ /;/; $eachmodule = $`;
#            print "\tmodules\t$eachmodule";
            my ${cnt3_2} = 0;
            my $modpath;
            foreach my $inc1(@gnINCs) {
               chomp($inc1);
               $modpath = $eachmodule;
               $modpath =~ s/::/\//;
               $modpath = $inc1 . "\/" . $modpath . ".pm";
            #print "\t$modpath\n";
               if(-e $modpath) {
                  ${cnt3_2}++;
               #print "\t\t\t$modpath\n";
               }
            }
            if(${cnt3_2} == 0) {
               print "\tmodules\t$eachmodule\t\tNOT FOUND\n";
            }else{
               #print "\t\tfound\(${cnt3_2}\)\n";
               $cnt3_3++;
            }
         
         }
         my $nummods = @gnReqLibs;
         print "required-modules: $nummods,\tfound: $cnt3_3\n";
         if($nummods == $cnt3_3) {
            &gnprint("動作に必要なモジュールが揃っていることを確認しました。次のステップに進みます\n");
            $stepflg++;
         }else{
            &gnprint("\[ERROR\]動作に必要なモジュールが足りません。\n\[ERROR\]上記の出力を参照の上で必要なモジュールを追加してください\n");
            $stepflg--;
         }
      }
   }
# Step 4 (gnviewのインストールパスを指定)=========
   if($stepflg == 4) {
         for(;;) {
            &gnprint("\n以下のようにgnviewをインストールします\n");
            &gnprint("インストールパスを確認してください\(インストールパスは変更可能です\)\n");
            &gnprint("実行ファイルパス\(${binpath}\)\:\n");
            &gnprint("\tgnview \(実行プログラム\)\n");
            &gnprint("共有ライブラリパス\(${sharepath}gnview\/\)\:\n");
            &gnprint("\tgnview_firstrun.pl gnview_env.pl \(実行プログラム\)\n");
            &gnprint("\t1pix.png 1pix_glay.png gnview.png \(実行プログラムで参照する画像ファイル\)\n");
            &gnprint("\tgnview.glade gikoNavi.ini url.ini sent.ini \(実行プログラムで参照する設定ファイル\)\n");
            &gnprint("システム共有パス\(${sharepath}applications\/\)\:\n");
            &gnprint("\tgnview.desktop \(GUIメニュー用設定ファイル\)\n");
            &gnprint("システム共有パス\(${sharepath}pixmaps\/\)\:\n");
            &gnprint("\tgnview.png \(GUIメニュー用画像ファイル\)\n");
            &gnprint("マニュアルパス\(${manpath}man1\/\)\:\n");
            &gnprint("\tgnview.1.gz \(マニュアルファイル\)\n");
            &gnprint("ドキュメントパス\(${sharepath}doc/gnview\/\)\:\n");
            &gnprint("\tAUTHORS  COPYING  ChangeLog  NEWS  README  TODO \(ドキュメントファイル\)\n");
            
            &gnprint("\n以上の内容でインストールを行います。よろしいですか？\[yes\/NO\/beforestep\] ");
            my $yesno = <STDIN>; chomp($yesno);
            $yesno = substr($yesno,0,1);
            $yesno = lc($yesno);
            if($yesno eq "y") {
               $stepflg++;
               last;
            }elsif($yesno eq "b"){
               $stepflg -= 2;
               last;
            }else{
               &gnprint("実行ファイルパスを指定してください\[${binpath}\] ");
               my ${newbinpath} = <STDIN>; chomp(${newbinpath});
               if($newbinpath ne "") {
                  $binpath = $newbinpath;
               }
               my $aaa = substr($binpath,-1,1);
               if($aaa ne "\/") { $binpath = $binpath . "\/"; }
               &gnprint("共有ライブラリパスを指定してください\[${sharepath}\] ");
               my ${newsharepath} = <STDIN>; chomp(${newsharepath});
               if($newsharepath ne "") {
                  $sharepath = $newsharepath;
               }
               $aaa = substr($sharepath,-1,1);
               if($aaa ne "\/") { $sharepath = $sharepath . "\/"; }
               &gnprint("マニュアルパスを指定してください\[${manpath}\] ");
               my ${newmanpath} = <STDIN>; chomp(${newmanpath});
               if($newmanpath ne "") {
                  $manpath = $newmanpath;
               }
               $aaa = substr($manpath,-1,1);
               if($aaa ne "\/") { $manpath = $manpath . "\/"; }
            }

            
         }
   
   }

# Step 5 (gnviewファイルをコピー)===================================
   if($stepflg == 5) {

      # bin/gnview先頭行のperlパスを指定した物に変更
      my $cnt = 0;
      open(gnMOD, ">gnview.pl.modyfied");
      open(gnBIN, "gnview");
         while(<gnBIN>) {
            my $ln = $_; #chomp($ln);
            if($cnt == 0) {
               $ln =~ s/\/usr\/bin\/perl/$gnPerlpath/;
               print gnMOD $ln;
            }else{
               print gnMOD $ln;
            }
         }
      close(gnBIN);
      close(gnMOD);
      system("mv gnview.pl.modyfied gnview");

      my $uninstinfo = $ENV{'HOME'} . "\/.gnview.uninstinfo";
      open(gnUN, ">$uninstinfo");
#      my $cmd;
      my $dir;
      my $dirret;
      my @instfile;
#      $cmd = "install -D -d $binpath"; system("$cmd");
      $dir = $binpath;
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0755 gnview ${binpath}gnview"; system("$cmd");
      @instfile = ("gnview");
      &gnInstall(@instfile, "0755", $dir);
      print gnUN "${binpath}gnview\n";
      
#      $cmd = "install -D -d ${sharepath}applications"; system("$cmd");
      $dir = "${sharepath}applications";
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0644 gnview.desktop ${sharepath}applications"; system("$cmd");
      @instfile = ("gnview.desktop");
      &gnInstall(@instfile, "0644", $dir);
      print gnUN "${sharepath}applications\/gnview.desktop\n";

#      $cmd = "install -D -d ${sharepath}pixmaps"; system("$cmd");
      $dir = "${sharepath}pixmaps";
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0644 gnview.png ${sharepath}pixmaps"; system("$cmd");
      @instfile = ("gnview.png");
      &gnInstall(@instfile, "0644", $dir);
      print gnUN "${sharepath}pixmaps\/gnview.png\n";

#      $cmd = "install -D -d ${sharepath}doc\/gnview"; system("$cmd");
      $dir = "${sharepath}doc\/gnview";
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0644 AUTHORS  COPYING  ChangeLog  NEWS  README  TODO ${sharepath}doc\/gnview"; system("$cmd");
      @instfile = ("AUTHORS", "COPYING", "ChangeLog", "NEWS", "README", "TODO");
      &gnInstall(@instfile, "0644", $dir);
      print gnUN "${sharepath}doc\/gnview\n";

#      $cmd = "install -D -d ${sharepath}gnview"; system("$cmd");
      $dir = "${sharepath}gnview";
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0644 gnview_firstrun.pl gnview_env.pl ${sharepath}gnview"; system("$cmd");
#      $cmd = "install -m 0644 1pix.png 1pix_glay.png gnview.png ${sharepath}gnview"; system("$cmd");
#      $cmd = "install -m 0644 gnview.glade gikoNavi.ini url.ini sent.ini ${sharepath}gnview"; system("$cmd");
      @instfile = ("gnview_firstrun.pl", "gnview_env.pl", "1pix.png", "1pix_glay.png", "gnview.png",
                      "gnview.glade", "gikoNavi.ini", "url.ini", "sent.ini");
      &gnInstall(@instfile, "0644", $dir);
      print gnUN "${sharepath}gnview\n";

#      $cmd = "install -D -d ${manpath}man1"; system("$cmd");
      $dir = "${manpath}man1";
      $dirret = &gnMkdir($dir, "0755");
      if($dirret>2) {
         &gnprint("継続不可能なエラーが発生しました。インストールを中断します\n");
         exit(1);
      }
#      $cmd = "install -m 0644 gnview.1.gz ${manpath}man1"; system("$cmd");
      @instfile = ("gnview.1.gz");
      &gnInstall(@instfile, "0644", $dir);
      print gnUN "${manpath}man1\/gnview.1.gz\n";
      
      close(gnUN);
      
      &gnprint("\nインストールが完了しました\n");
      
      $stepflg++;
   }


if($stepflg > 5) {
   last;
}
};
# 内部関数 ================================================

sub gnGetBinPath {
   # 実行ファイルパスをチェック
   #
   # 引数:      なし
   # 返り値: 1: 実行ファイルへのフルパス
   my $gnBinPath;
      if($ENV{'PATH'}) {
         my @dvars = split(/:/, $ENV{'PATH'});
         foreach my $dvar(@dvars) {
            chomp($dvar);
            $gnBinPath = $dvar;
            if(-e "$gnBinPath\/perl") {
               return($gnBinPath);
            }
         }
      }
      my @dvars = ('/usr/local/bin/', '/usr/bin/');
      foreach my $dvar(@dvars) {
         chomp($dvar);
         $gnBinPath = $dvar;
         if(-e "$gnBinPath\/perl") {
            return($gnBinPath);
         }
      }
      return($gnBinPath);
}

sub gnGetLibPath {
   # ライブラリパスをチェック
   #
   # 引数:      なし
   # 返り値: 1: ライブラリへのフルパス
   
   my $gnLibPath;
   if ($^O eq "MSWin32") {
      # "perl -V"の"osname"がMSWin32の場合は
      # 実行環境がWindowsであると判断
      $gnLibPath = "$ENV{'APPDATA'}" . "\\gnview\\";
   }else{
      if($ENV{'XDG_DATA_DIRS'}) {
         my @dvars = split(/:/, $ENV{'XDG_DATA_DIRS'});
         foreach my $dvar(@dvars) {
            chomp($dvar);
            $gnLibPath = $dvar;
            if(-d "$gnLibPath\/applications") {
               return($gnLibPath);
            }
         }
      }
      my @dvars = ('/usr/local/share/', '/usr/share/');
      foreach my $dvar(@dvars) {
         chomp($dvar);
         $gnLibPath = $dvar;
         if(-d "$gnLibPath\/applications") {
            return($gnLibPath);
         }
      }
   }
      return($gnLibPath);
   
}

sub gnWhich {
   # 環境変数からperlバイナリの場所を特定する関数
   # 返り値=配列(ここの要素は文字列。perlへのフルパス)
   my @path;
   my @retpath;
   @path = split(/:/, $ENV{'PATH'});
   foreach my $pt(@path) {
      if(-e "$pt\/perl") {
         push(@retpath, "$pt\/perl");
      }
   }
   return(@retpath);
   
}

sub gnMkdir {
   # ディレクトリを作成する関数
   # 引数=文字列(作成するディレクトリ)
   # 引数2=文字列(パーミッション。半角数字4文字を想定)
   # 返り値=integer(1=成功、2=失敗:既にある、3=失敗:作成に失敗)
   my $dir = $_[0];
   my $perm = $_[1];
      if(!(-d $dir)) {
          my $flg;
          $flg = mkpath($dir, 0, oct($perm));
          if ($flg == 0) {
             &gnprint("ディレクトリの作成に失敗しました: $dir\n");
             return(3);
            }else{
               &gnprint("ディレクトリを作成しました: $dir\n");
               return(1);
            }
      }else{
         &gnprint("ディレクトリは既に存在します: $dir\n");
         return(2);
       }
}

sub gnInstall {
    # 引数1=配列(ここの要素は文字列。コピーするファイル名が入っていると想定)
    # 引数2=文字列(Permission。ファイルをコピーしたのちにこのパーミッションを割り当てる)
    # 引数3=文字列(path。コピー先のディレクトリ)
    my @mykeys = @_;
    my $destdir = pop(@mykeys);
    my $perm = pop(@mykeys);
    foreach my $fls(@mykeys) {
       copy($fls, $destdir);
       my $uname = $ENV{'LOGNAME'};
       my ($login, $pass, $uid, $gid) = getpwnam($uname);
       chown($uid, $gid, "${destdir}\/${fls}");
       chmod(oct($perm), "${destdir}\/${fls}");
       &gnprint("${fls}\t=\> ${destdir}\/${fls}\n");
    }    
}

sub gnprint {
    # ロケール名に合わせて文字コードを変換し標準出力に出力する
    # 引数=文字列
    my $gnPrintStr = $_[0];
    $gnPrintStr = Encode::encode($gnUserLang, $gnPrintStr);
    print $gnPrintStr;
}

sub env_locale_to_encstr {
    # ロケール名からEncodeモジュールが解釈できる
    # 文字エンコード名を返す関数
    # 引数=文字列(ロケール名)
    
    # ロケール名を取得
    my $myLocVal = $_[0];

    # Windowsでは"Japanese_Japan"という文字列が使われているので
    # 一括変換しやすいように"ja_JPと置換"
    $myLocVal =~ s/Japanese_Japan/ja_JP/g;
    
    # "ja_JP.eucJP"の"ja_JP"部はいらないので切り取る
    my @myLocStr  = split(/\./, $myLocVal);

    # 後ろの"eucJP"の部分は小文字に置き換える
    # (実際にも大文字・小文字を区別しないよう推奨されている)
    if($myLocStr[1]) {
       $myLocStr[1] = lc($myLocStr[1]);
    }else{
        # SolarisでLocaleの２番目がなかったらeucに決めうち
       if($^O eq 'solaris') {
          push(@myLocStr, "eucjp");
        }
     }
    
    # あとはパターンマッチ
    if    ($myLocStr[1] eq "932") {    return('shiftjis');
    }elsif($myLocStr[1] eq "pck") { return('shiftjis');
    }elsif($myLocStr[1] eq "sjis") { return('shiftjis');
    }elsif($myLocStr[1] eq "20932") { return('euc-jp');
    }elsif($myLocStr[1] eq "eucjp") { return('euc-jp');
    }elsif($myLocStr[1] eq "euc") { return('euc-jp');
    }elsif($myLocStr[1] eq "ujis") { return('euc-jp');
    }elsif($myLocStr[1] eq "iso-2022-jp") { return('7bit-jis');
    }elsif($myLocStr[1] eq "utf-8") { return('utf8');
    }else                           { return('ascii'); # エンコードが判別できなかったらシングルバイトエンコード(単なるバイト列)として解釈する
    }

    
}

