#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package API::App;

use strict;
use warnings;

use CGI;

use lib '/app/tools/common/lib';
use Common::Assert;

use lib '/app/tools/rps/lib';
use RSApache::RSWebApp;
use base 'RSApache::RSWebApp';

# Map of endpoints based on request type.
# A route may have a route parameter (variable); these are prefixed
# with ":" in the route.  The command can then access the parameter
# using $self->getRouteParam(":someId").
#
my %gCommandMap = (

    '/hello' => {
        'GET' => 'API::Command::Hello',
    },
    '/authenticate' => {
        'POST' => 'API::Command::Authenticate',
    },
    '/logout' => {
        'POST' => 'API::Command::Logout',
    },
    '/user/:userId' => {
        'GET' => 'API::Command::GetUserInfo',
        'PUT' => 'API::Command::PutUserInfo',
    },
    '/user/:userId/client/:clientId/payors' => {
        'GET' => 'API::Command::GetClientPayorInfo',
    },
    '/user/:userId/client/:clientId/runtype/:runTypeId' => {
        'GET' => 'API::Command::GetClientRunInfo',
    },
    '/labels/:userId' => {
        'GET' => 'API::Command::GetLabelsInfo',
    },
    '/client/:clientId' => {
        'GET' => 'API::Command::GetClientInfo',
    },
    '/user/confirm/:invitekey' => {
        'GET'  => 'API::Command::UserInvite',
        'POST' => 'API::Command::Confirm',
    },
    '/label/confirm' => {
        'POST' => 'API::Command::LabelConfirm',
    },
    '/user/forgotpw/:email' => {
        'POST' => 'API::Command::PostForgotPW',
    },
    '/user/recoverpw/:token' => {
        'POST' => 'API::Command::PostRecoverPW',
    },
    '/client/:clientId/runtype/:runTypeId/statement/:statementId' => {
        'GET' => 'API::Command::GetStatementInfo',
    },
    '/client/:clientId/runtype/:runTypeId/statement/:statementId/download' => {
        'GET' => 'API::Command::GetDownloadStatement',
    },
    '/statements/runtype/:runTypeId/current' => {
        'GET' => 'API::Command::GetCurrentStatementInfo',
    },
    '/client/:clientId/runtype/:runTypeId/statement/current/download' => {
        'GET' => 'API::Command::GetDownloadCurrentStatements',
    },
    '/statements/runtype/:runTypeId/historical' => {
        'GET' => 'API::Command::GetHistoricalStatements',
    },
    '/statements/runtype/:runTypeId/historical/download' => {
        'GET' => 'API::Command::GetHistoricalStatements',
    },
);

sub _getCommandMap {
    my ($self) = @_;

    return \%gCommandMap;
}

sub CreateCommand {
    my ( $pkg, $cgi ) = @_;

    assert( defined $cgi );

    my $url = $ENV{REQUEST_URI};

    my $requestMethod = $cgi->request_method();

    my ( $cmdPkg, $routevars ) = $pkg->GetCommandPkg($cgi);

    $cmdPkg = "API::Command::NotFound" if !$cmdPkg;

    Common::Log::Print("API::App - url($url) --> cmd($cmdPkg)") if ( $cmdPkg && $cmdPkg ne 'API::Command::Hello' );


    eval "require $cmdPkg";
    die $@ if $@;

    # If a matching route was found, then routevars will hold the route variables.
    # Any query string parameters will be accessible by the 'params' attribute which
    # can be retrieved via the command's getParams() method (e.g., $commandObj->getParams()).
    my $commandObj = $cmdPkg->new( cgi => $cgi );
    $commandObj->{routevars} = $routevars;

    return $commandObj;
}

# Get the command associated with a matching route; also return
# route parameters (if any)
#
sub GetCommandPkg {
    my ( $pkg, $cgi ) = @_;

    my $self = Common::RSApp::Instance();
    my $map  = $self->_getCommandMap();

    my $requestMethod = $cgi->request_method();
    my $contentType   = $cgi->header();

    my $cmdPkg;

    my %params;

    my $uri = $ENV{REQUEST_URI};

    # Separate locator path (route) from query string
    my ( $path, $qs ) = split( "\\?", $uri );

    my @a = split( '\/', $path );

    shift @a if ( $uri =~ /^\// );    # remove leading (empty) element
    shift @a;                         # remove the app portion of url

    foreach my $route ( keys %$map ) {

        my $match = 1;                # set to 0 if the route doesn't match the URL

        my $i = 0;
        my @b = split( '\/', $route );
        shift @b if ( $route =~ /^\// );

        if ( ( scalar @a ) != ( scalar @b ) ) {
            next;
        }

        # Compare each part of the URL with the route
        foreach my $abit (@a) {
            if ( !$abit ) {
                $i++;
                next;
            }

            if ( $b[$i] =~ /^:/ ) {    # skip variable
                $params{ $b[$i] } = $a[$i];
            } elsif ( $a[$i] ne $b[$i] ) {
                $match = 0;
            }

            $i++;
        }

        if ($match) {
            $cmdPkg = $map->{$route}{$requestMethod};
            last;
        } else {
            undef %params;
        }

    }

    return ( $cmdPkg, \%params );
}

1;
