#!/usr/bin/perl -w

# Movable Type (r) (C) Six Apart Ltd. All Rights Reserved.
# This code cannot be redistributed without permission from www.sixapart.com.
# For more information, consult your Movable Type license.
#
# $Id$

package MT::Tool::Upgrade;
use strict;
use warnings;
use utf8;
use Carp qw(confess);
use FindBin;
use lib ( "$FindBin::Bin/../lib", "$FindBin::Bin/../extlib" );
use base qw( MT::Tool );
use Encode;
use MT::Upgrade;

sub usage {"\$ $0 [--dryrun] [--sql] [--name <name>]"}

sub help {
    return <<'HELP'
  Installs or upgrades a database to the current MT schema.
  --quiet          Stop progress reports.
  --dryrun         Determine the upgrade steps required without
                   executing any changes.
  --sql            Report the SQL that would be performed instead
                   of executing it.
  --name <name>    The author as whom to perform the upgrade steps.
                   Required when performing an upgrade (not at
                   initial install).

  At initial install, these parameters are all required. All values
  must be URI escaped.

  --username <name>

  --password <pass>

  --nickname <name>

  --email <name>

  --use_system_email [0 or 1]

  --preferred_language [ja|de|en-us|es|fr|nl]
HELP
}

my ( $quiet, $dryrun, $name, $sqlonly );
my ($username,   $password,         $nickname,
    $email,      $use_system_email, $preferred_language,
);

sub options {
    return (
        'quiet'   => \$quiet,
        'dryrun!' => \$dryrun,
        'sql!'    => \$sqlonly,
        'name=s'  => \$name,

        "username=s"           => \$username,
        "password=s"           => \$password,
        "nickname=s"           => \$nickname,
        "email=s"              => \$email,
        "use_system_email=n"   => \$use_system_email,
        "preferred_language=s" => \$preferred_language,
    );
}

sub _error {
    my $msg = shift;
    $msg ||= 'An error occurred!';
    if ( Encode::is_utf8($msg) ) {
        $msg = Encode::encode_utf8($msg);
    }
    $msg .= "\n" unless $msg =~ /\n$/;
    print STDERR $msg;
    exit 1;
}

sub main {
    my $class = shift;
    my ($verbose) = $class->SUPER::main(@_);

    if ($sqlonly) {
        $dryrun = 1;
        MT->add_callback( 'MT::Upgrade::SQL', 1, undef, \&sql_cb );
    }
    else {
        print
            "upgrade -- A command line tool for upgrading the schema for Movable Type.\n"
            unless $quiet;
        print "(Non-destructive mode)\n" if $dryrun && !$quiet;
    }

    my $install;
    my $driver = MT::Object->driver;
    if ( !$driver || !$driver->table_exists('MT::Author') ) {
        $install = 1;
    }

    unless ( $install || $name ) {
        print
            "Please set username to set superuser at upgrading.  cf: upgrade --name Melody\n"
            unless $quiet;
        exit;
    }

    my $author_id;
    if ( !$install && $name ) {
        require MT::BasicAuthor;
        my $a = MT::BasicAuthor->load( { name => $name } )
            or die "Not found user $name:" . MT::BasicAuthor->errstr;
        $author_id = $a->id;
    }

    if ($install) {
        $MT::Upgrade::Installing = 1;
    }

    local $SIG{__WARN__} = sub { __PACKAGE__->trace( $_[0] ) };

    if ($install) {

        # Strict parameter check for initial install
        _error "--username is required for initial install" unless $username;
        _error "--password is required for initial install" unless $password;
        require MT::App;
        my $password_error
            = MT::App::verify_password_strength( 'MT', $username, $password );
        _error $password_error if $password_error;
        _error "--nickname is required for initial install" unless $nickname;
        _error "--email is required for initial install"    unless $email;
        _error "--preferred_language is required for initial install"
            unless $preferred_language;

        my $new_user = {
            user_name     => $username,
            user_nickname => $nickname,
            user_password => $password,
            user_email    => $email,
            user_lang     => $preferred_language,
        };

        my $updated = MT::Upgrade->do_upgrade(
            App       => __PACKAGE__,
            DryRun    => $dryrun,
            Install   => 1,
            SuperUser => $author_id,
            CLI       => 1,
            User      => $new_user,
        );
        exit( $updated ? 0 : 1 ) if $dryrun;
        if ($use_system_email) {
            MT->config->set_internal( EmailAddressMain => $email, 1 );
            MT->config->save_config;
        }
        print "Installation complete.\n" unless $quiet;

        exit( $updated ? 0 : 1 );
    }
    else {
        my $updated = MT::Upgrade->do_upgrade(
            App       => __PACKAGE__,
            DryRun    => $dryrun,
            Install   => 0,
            SuperUser => $author_id,
            CLI       => 1,
        );

        print "Upgrade complete!\n" if !$dryrun && $updated && !$quiet;
        print "Your schema is up to date already.\n"
            if defined $updated && !$updated && !$quiet;
        exit 0;
    }

}

sub progress {
    my $pkg = shift;
    my $msg = shift;
    print "\t* "
        . Encode::encode( MT->config->PublishCharset || 'UTF-8', $msg ) . "\n"
        unless $quiet;
}

sub error {
    my $pkg = shift;
    my $err = shift;
    confess Encode::encode( MT->config->PublishCharset || 'UTF-8', $err )
        unless $quiet;
}

sub sql_cb {
    my $cb = shift;
    my ( $upgrade, $stmt ) = @_;
    print "$stmt\n" unless $quiet;
}

sub trace {
    my $pkg = shift;
    print "[warn] >> \t"
        . Encode::encode( MT->config->PublishCharset || 'UTF-8', $_[0] )
        . "\n"
        unless $quiet;
}

sub config {
    MT->config;
}

__PACKAGE__->main() unless caller;

1;
