#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

#use Smart::Comments;
use FindBin;
use lib "$FindBin::Bin/../lib";
use OpenResty::Dispatcher;
use OpenResty::Limits;
use Getopt::Std;

my $cmd = lc(shift) || $ENV{OPENRESTY_COMMAND};

if ($ENV{REQUEST_URI}) {
    if (!$cmd) {
        $cmd = 'fastcgi';
        $ENV{OPENRESTY_COMMAND} = $cmd;
    }
}

$cmd ||= '';

eval {
    OpenResty::Dispatcher->init;
};
warn $@ if $@;

if ($cmd eq 'fastcgi') {
    require OpenResty::FastCGI;
    while (my $cgi = new OpenResty::FastCGI) {
        eval {
            OpenResty::Dispatcher->process_request($cgi);
        };
        if ($@) {
            warn $@;
            print "HTTP/1.1 200 OK\n";
            # XXX don't show $@ to the end user...
            print qq[{"success":0,"error":"$@"}\n];
        }
    }
    exit;
} elsif ($cmd eq 'cgi') {
    require CGI::Simple;
    my $cgi = CGI::Simple->new;
    OpenResty::Dispatcher->process_request($cgi);
    exit;
} elsif ($cmd eq 'start') {
    my %opts;
    getopts('p:', \%opts);
    my $port = $opts{p} || 8000;

    require OpenResty::Server;
    my $server = OpenResty::Server->new;
    $server->port($port);
    $server->run;
    exit;
}

my $error = $OpenResty::Dispatcher::InitFatal;
if ($error) {
    die $error;
}
my $backend = $OpenResty::Backend;

if ($cmd eq 'adduser') {
    my $user = shift or
        die "No user specified.\n";
    if ($backend->has_user($user)) {
        die "User $user already exists.\n";
    }
    eval "use Term::ReadKey;";
    if ($@) { die $@; }
    #local $| = 1;

    my $password;
    print "Enter the password for the Admin role: ";

    ReadMode(2);
    my $key;
    while (not defined ($key = ReadLine(0))) {
    }
    ReadMode(0);

    $key =~ s/\n//s;
    print "\n";

    my $saved_key = $key;
    #warn "Password: $password\n";
    OpenResty::check_password($saved_key);

    print "Re Enter the password for the Admin role: ";

    ReadMode(2);
    while (not defined ($key = ReadLine(0))) {
    }
    ReadMode(0);

    $key =~ s/\n//s;
    print "\n";

    if ($key ne $saved_key) {
        die "2 passwords don't match.\n";
    }
    $password = $key;

    $OpenResty::Backend->add_user($user, $password);
    my $machine = $OpenResty::Backend->has_user($user);
    if ($machine) {
        warn "User $user created on node $machine.\n";
    }
} elsif ($cmd eq 'deluser') {
    my $user = shift or
        die "No user specified.\n";
    if ($backend->has_user($user)) {
        $OpenResty::Backend->drop_user($user);
    } else {
        die "User $user does not exist.\n";
    }
} elsif ($cmd eq 'upgrade') {
    my $user = shift;
    if ($user) {
        if ($backend->has_user($user)) {
            $backend->set_user($user);
            my $base = $backend->get_upgrading_base;
            if ($base >= 0) {
                $backend->upgrade_local_metamodel($base);
            } else {
                warn "User $user is already up to date.\n";
            }
        } else {
            die "User $user does not exist.\n";
        }
    } else {
        $backend->upgrade_all;
    }
} elsif ($cmd eq '' or $cmd eq 'shell') {
    run_shell();
} else {
    die "Unknown command: $cmd\n";
}

sub run_shell {
    local $| = 1;

    #BEGIN{ $ENV{PERL_RL} = 'GNU' };	# Do not test TR::Gnu !
    eval "use Term::ReadLine;";
    if ($@) { die "No Term::ReadLine::Gnu found.\n" };
    my $backend_name = $OpenResty::BackendName;
    my $version = OpenResty->version;
    print <<"_EOC_";
Welcome to openresty $version, the OpenResty interactive terminal.

Type:  \\copyright for distribution terms
       \\a <account> to set the current account
       \\do <sql> to do sql query using xdo
       \\q to quit
       <sql> to do sql query using xquery

_EOC_
    eval { $backend->set_user('_global'); };
    if ($@) { warn $@; }
    my $term = new Term::ReadLine 'Simple Perl calc', \*STDIN, \*STDOUT;
    my $features = $term->Features;
    my $prompt = "$backend_name>";
    while ( defined ($_ = $term->readline($prompt, "")) ) {
        #eval "use Data::Dumper";
        my $cmd = $_;
        #my $cmd = <STDIN>;
        trim($cmd);
        if (lc($cmd) eq '\\q') {
            last;
        }
        elsif (lc($cmd) eq '\\copyright') {
            print <<'_EOC_';
Copyright (c) 2007-2008 by Yahoo! China EEEE Works, Alibaba Inc.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
_EOC_
        }
        elsif ($cmd eq '') { next }
        elsif ($cmd =~ s/^\\[au]\s*//) {
            my $user = $cmd;
            trim($user);
            my $res;
            eval {
                if (my $machine = $backend->has_user($user)) {
                    warn "Switching to account $user on node $machine\n";
                    $res = $backend->set_user($user);
                } else {
                    die "Account \"$user\" not found.\n";
                }
            };
            if ($@) { warn $@ }
            if (defined $res) {
                print $res, "\n";
            }
        }
        elsif ($cmd =~ s/^\\do\s*//) {
            my $sql = $cmd;
            trim($sql);
            my $res;
            eval { $res = $backend->do($sql); };
            if ($@) { warn $@ }
            print $res;
        }
        elsif ($cmd =~ /^\\\S+/) {
            warn "Unknown command: $&\n";
        }
        elsif (lc($cmd) eq 'quit' or lc($cmd) eq 'exit') {
            last;
        }
        else {
            my $res;
            eval {
                $res = $backend->select($cmd, { use_hash => 1 });
            };
            if ($@) { warn $@ }
            if (defined $res) {
                print YAML::Syck::Dump($res);
            }
        }
    } continue {
        $term->addhistory($_) if /\S/ && !$features->{autohistory};
    }
}

sub trim {
    $_[0] =~ s/^\s+|\s+$//gs;
}

