#!/usr/bin/perl

use File::Copy;
use File::Compare;
use File::Glob ':glob';
use DBI;

use blib;
use lib '.';

BEGIN {
   require 'PApp/Config.pm';
   require "./config.pl";
}

use PApp;
use PApp::Admin;
use PApp::SQL;
use PApp::I18n;

$|=1;

*CFG = \%PApp::Config;

my $lib = $CFG{LIBDIR};

sub crdir {
   local $_ = shift;
   print "making directory $_... ";
   if (-d $_) {
      print "[skipped] ";
   } else {
      mkdir $_, 0777 or die "$!\n";
   }
   chown $CFG{PAPP_UID}, $CFG{PAPP_GID}, $_;
   print "ok\n";
}

sub install($$) {
   my ($s, $d) = @_;
   if (compare($s, $d)) {
      copy($s, "$d~") or die "copy($s,$d~): $!\n";
      chown $CFG{PAPP_UID}, $CFG{PAPP_GID}, "$d~";
      chmod ((stat $s)[2] & 07777, "$d~");
      rename "$d~", $d or die "rename($d~,$d): $!\n";
      0;
   } else {
      chown $CFG{PAPP_UID}, $CFG{PAPP_GID}, $d;
      chmod ((stat $s)[2] & 07777, $d);
      1;
   }
}

crdir $lib;
crdir $CFG{I18NDIR};

for my $dir (qw(macro widget apps demo style eg)) {
   crdir "$lib/$dir";

   for my $app (bsd_glob "$dir/*.{papp,xsl,pxsl}",
                                 GLOB_ERR|GLOB_NOSORT|GLOB_BRACE) {
      $app =~ s/.*?([^\/]+)$/$1/;
      print "$dir/$app => $lib/$dir...";
      print "[skipped] " if install "$dir/$app", "$lib/$dir/$app";
      print "ok\n";
   }
}

print <<EOF;

This program (papp-install) initializes the database and library
directories used by PApp. It assumes that the DBD driver understands the
"func" method. MySQL currently does this.

You can re-run ./papp-install from the (configured) installation directory
to reset the database and re-install the library directry as often as you
want.

EOF

print "trying to open state database... ";

$DBH =
   DBI->connect($CFG{STATEDB}, $CFG{STATEDB_USER}, $CFG{STATEDB_PASS},
                { RaiseError => 0, PrintError => 1 });

if (!$DBH) {
   print "failed\n";
   $CFG{STATEDB} =~ /DBI:([^:]+):([^:]+).*?(?:host=([^;]*))?/i or die "unable to parse database name ($CFG{STATEDB})\n";

   my ($driver, $db, $host) = ($1, $2, $3||"'localhost'");
   print "trying to create $driver-database '$db' on host $host\n";
   print "(might only work for mysql)... ";

   $drh = DBI->install_driver($driver) or die "unable to find DBI driver $driver\n";
   $drh->func("createdb", $db, "localhost", $CFG{STATEDB_USER}, $CFG{STATEDB_PASS}, "admin");

   $DBH = DBI->connect($CFG{STATEDB}, $CFG{STATEDB_USER}, $CFG{STATEDB_PASS}, { RaiseError => 0, PrintError => 1 });
   $DBH or die "unable to create database $CFG{STATEDB}, please create it manually and re-run papp-install\n";

   print "seems to have worked\n";
} else {
   print "already exists (good)\n";
}

$PApp::SQL::DBH = $DBH;

$installed_version = eval { sql_fetch "select value from env where name = ?", "PAPP_VERSION" };

print <<EOF;

Now creating tables (that do not already exist). existing tables will
_not_ be dropped, so if you want to upgrade to a new & incompatible
version you have to drop the database manually.

EOF

$DBH->do(<<SQL);
   create table env (
     name varchar(255) binary not null,
     value longblob not null,
     primary key (name)
   )
SQL

$DBH->do(<<SQL);
   create table msgid (
     nr mediumint(6) unsigned not null auto_increment,
     id mediumtext not null,
     domain varchar(30) not null,
     lang varchar(16) not null,
     context text not null,
     primary key (nr),
     index (id(64))
   )
SQL

$DBH->do(<<SQL);
   create table msgstr (
     nr mediumint(6) unsigned default '0' not null,
     lang varchar(16) not null,
     flags set('valid','fuzzy','unused') not null,
     msg mediumtext not null,
     unique nr (nr,lang)
   )
SQL

$DBH->do("drop table state") if $installed_version < 0.12;
$DBH->do(<<SQL);
   create table state (
     id int(10) unsigned not null auto_increment,
     ctime timestamp(14),
     previd int(10) unsigned default '0' not null,
     alternative mediumint(8) unsigned default '0' not null,
     userid int(10) unsigned default '0' not null,
     sessid int(10) unsigned default '0' not null,
     state mediumblob default '' not null,
     primary key (id),
     key (alternative, previd)
   ) delay_key_write=1
SQL

$DBH->do(<<SQL);
   create table user (
     id int(10) unsigned not null auto_increment,
     ctime timestamp(14),
     prefs blob not null,
     user varchar(100) not null,
     pass varchar(14) not null,
     comment text not null,
     primary key (id),
     key user (user)
   )
SQL

$DBH->do(<<SQL);
   create table grp (
     id int(10) unsigned not null auto_increment,
     name varchar(100) not null,
     comment text not null,
     primary key (id)
   )
SQL

$DBH->do(<<SQL);
   create table usergrp (
     userid int(10) unsigned default '0' not null,
     grpid int(8) unsigned default '0' not null,
     primary key (userid,grpid)
   )
SQL

$DBH->do(<<SQL);
   create table app (
     id smallint(6) unsigned not null auto_increment,
     name varchar(255) binary default '' not null,
     appset smallint(5) unsigned default '0' not null,
     path varchar(255) binary default '' not null,
     mountconfig mediumtext default '' not null,
     config mediumtext default '' not null,
     primary key (id),
     unique (name)
   )
SQL

$DBH->do(<<SQL);
   create table appset (
     id smallint(5) unsigned not null auto_increment,
     name varchar(255) default '' not null,
     primary key (id),
     unique (name)
   )
SQL

$DBH->do(<<SQL);
   create table pkg (
     id varchar(255) default '' not null,
     ctime timestamp(14),
     config mediumblob default '' not null,
     code longblob default '' not null,
     primary key (id)
   )
SQL

$DBH->do(<<SQL);
   create table locks (
     id varchar(255) binary default '' not null,
     breaktime int(10) unsigned default '0' not null,
     data varchar(255) binary default '' not null,
     primary key (id)
   )
SQL

$DBH->do("drop table error") if $installed_version < 0.13;
$DBH->do(<<SQL);
   create table error (
     id mediumint(6) unsigned not null auto_increment,
     ctime timestamp(14),
     data blob default '' not null,
     comment text default '' not null,
     primary key (id)
   )
SQL

$DBH->do(<<SQL);
  CREATE TABLE ssluser (
    userid int(10) unsigned NOT NULL default '0',
    cert blob NOT NULL,
    KEY idx_userid (userid),
    KEY idx_cert (cert(20))
  )
SQL


$DBH->do("delete from pkg");
   # if $PApp::Config::VERSION != $installed_version;

print <<EOF;

Now populating tables (that hopefully do exist now). Any errors in this
section are supposedly fatal(!!).

EOF

eval {
   $DBH->do("insert into appset values (1, 'default')")
   or die;
};

print "creating admin user and admin group... ";
eval {
   my $pass = crypt "public", "xx";
   $DBH->do("insert into user values (1, NULL, '', 'admin', '$pass', 'Main Administrator')")
   and $DBH->do("insert into grp values (1, 'admin'      , 'hyperuser access rights')")
   and $DBH->do("insert into grp values (2, 'poedit'     , 'general translator access')")
   and $DBH->do("insert into grp values (3, 'poedit_*'   , 'translator access for all apps')")
   and $DBH->do("insert into grp values (4, 'poedit_papp', 'translator access for papp itself')")
   and $DBH->do("insert into usergrp values (1, 1)")
   and $DBH->do("insert into usergrp values (1, 2)")
   and $DBH->do("insert into usergrp values (1, 3)")
   or die;
   print <<EOF;
ok

********* the admin user is named 'admin'           *********
********* and has the initial password 'public'     *********
********* please change this ASAP using             *********
********* papp-admin -u admin --password <password> *********

EOF
};
if ($@) {
   print "failed (or already exists)\n";
}

$DBH->do("delete from env where name='PAPP_VERSION'");
$DBH->do("insert into env (name, value) values ('PAPP_VERSION', '$PApp::Config::VERSION')");

my $umask = umask 077;
install("config.pl", "$lib/config.pl");
chmod 0600, "$lib/config.pl"; # just to be sure
umask $umask;

print "\nimporting i18n tables\n";
for my $domain (qw(papp bench dbedit demo iso639 iso3166)) {
   PApp::Admin::import_po 0, "i18n/$domain.po", 1;
   print "exporting $domain to $CFG{I18NDIR}/$domain\n";
   PApp::I18n::export_dpo $domain, "$CFG{I18NDIR}/$domain", $CFG{PAPP_UID}, $CFG{PAPP_GID};
}

print "\n$lib/config.pl is chmod 600, better chown or chgrp it to the group
your webserver or trusted user is running under.\n\n";


