#
# DESCRIPTION:
#   Plesk communicate interface. Static methods for managing user accounts.
# AUTHORS:
#   Pavel Odintsov (nrg) <pavel.odintsov@gmail.com>
#
#========================================================================

package API::Plesk::Accounts;

use strict;
use warnings;

use API::Plesk::Methods;
use Data::Dumper;

our $VERSION = '1.00';

=head1 NAME

API::Plesk::Accounts - extension module for the management of user accounts.

=head1 SYNOPSIS

Directly not used, calls via API::Plesk.

 use API::Plesk;
 
 my $plesk_client = API::Plesk->new(%params);
 # See documentations for API::Plesk

 my $res1 = $plesk_client->Accounts->get(
    id => 36341
 );


=head1 DESCRIPTION

The module provides full support operations with accounts.

=head1 EXPORT

None by default.

=cut

# Elements of %template_data: 
# required - 1 / optional - 0
# min length, max length,
# accepted values

my %template_data = (
    cname   => [0, 0, 60 ], # company name 
    pname   => [1, 1, 60 ],
    login   => [1, 1, 60 ],
    passwd  => [1, 5, 14 ],
    status  => [0, 0, 3, [0, 16]],   
    # status: 
    # 0 - active, 
    # 4 - under backup / restore, 
    # 16 - disabled,
    # 256 Expired, 
    # 64 - disabled by admin.
    phone   => [0, 0, 30  ],
    fax     => [0, 0, 30  ],
    email   => [0, 0, 255 ],
    address => [0, 0, 255 ],
    city    => [0, 0, 50  ],
    state   => [0, 0, 50  ], # For US only
    pcode   => [0, 0, 10  ], # zip code, US only
    country => [0, 2, 2   ], # RU
    locale  => [0, 0, 255 ],
);

=head1 METHODS

=over 3

=item create(%params)
 	
Creates a user account on the basis of the template.

Params:
general_info -- hashref with user data
template-name or template-id

Return: response object with created account id in data filed.

=cut

# Create element
# STATIC (%hash)
# 1) general_info -- hashref with user data (it format in source)
# 2) template-name or template-id -- template identificators
sub create {
    my %params = @_;

    if (ref ($_ = $params{'general_info'}) eq 'HASH') {
        if (client_add_gen_info_check(%{ $params{'general_info'} })) {

            my $template = '';
        
            if ($params{'template-name'}) {
                
                $template = create_node('template-name', 
                    $params{'template-name'});

            } elsif ($params{'template-id'}) {
                
                $template = create_node('template-id', 
                    $params{'template-id'});
            
            } else {
                return ''; # template required
            }
            return construct_request_xml( 'client', 'add', 
                generate_info_block('gen_info', select_only_allowed_fields($params{'general_info'}) ), 
                    $template);
        } else {
            return ''; # not enought data
        }
    } else {
        return '';  # not enought data
    }
}

# Return only allowed fields
# STATIC
sub select_only_allowed_fields {
    my $hashref = shift;

    return map {
        $hashref->{$_} ? ($_, $hashref->{$_}) : ( );
    } sort keys %template_data
}

# Parse XML response
# STATIC (xml_response)
# return hashref if one result block
# return arref of hashref if multiple errors 
sub create_response_parse {
    my $xml_from_server = shift; 

    return '' unless $xml_from_server;

    return abstract_parser('add', $xml_from_server, ['status']);
}

=item modify(%params)

Changes the parameters account.

Params:
limits, permissions, new_data -- hashref`s with corresponding blocks.

And also one of the following options:

all   => 1      - for all accounts.
login => 'name' - for a given login.
id    => 123    - for a given id 

=cut

# Modify element
# STATIC
sub modify {
    my %params = @_;

    my $filter;

    $params{'limits'} ||= '';
    $params{'permissions'} ||= '';
    $params{'new_data'} ||= '';

    my $limits_block = ref $params{'limits'} eq 'HASH' &&  %{$params{'limits'}}?
        generate_settings_block('limit' ,%{ $params{'limits'} }) : '';  
 
    my $permissions_block = ref $params{'permissions'} eq 'HASH' && %{$params{'limits'}} ?
        generate_settings_block( 'permission', %{ $params{'permissions'} }) : '';   

    my $gen_info_block = ref $params{'new_data'} eq 'HASH' && %{$params{'new_data'}} ?
        generate_info_block('gen_info', %{ $params{'new_data'} }) : '';

    if ($params{'all'}) {
        $filter =  create_filter(login_field_name => 'login', all => 1);  # warning: modify all !!
    } elsif ($params{'id'} || $params{'login'}) {
        $filter = create_filter(login_field_name => 'login', %params);
    } else {
        $filter = '';
    }

    if ($filter && ($limits_block || $permissions_block || $gen_info_block)) {

        return construct_request_xml( 'client', 'set', $filter, 
            create_node(
                'values', $gen_info_block . $limits_block . $permissions_block
            )
        );
    } else {

        return '';

    }
}


# SET response handler
# STATIC
sub modify_response_parse {
    my $xml_from_server = shift; 

    return '' unless $xml_from_server;

    return abstract_parser('set', $xml_from_server, ['status']);
}

=item delete(%params)

Delete accounts.

Params:
limits, permissions, new_data -- hashref`s with corresponding blocks.

And also one of the following options:

all   => 1      - all accounts.
login => 'name' - account with a given login.
id    => 123    - account with a given id 

=cut

# Delete element
# STATIC( %args )
# login => 'userlogin' or id => 12312 or all => 1
sub delete {
    my %params = @_;

    my $filter = '';

    if ($params{'all'}) {
        $filter =  create_filter(login_field_name => 'login', all => 1); # warning: delete all !!
    } elsif ($params{'id'} || $params{'login'}) {
        $filter =  $params{'id'} ?
            create_filter( login_field_name => 'login', id    => $params{'id'}) :
            create_filter( login_field_name => 'login', login => $params{'login'});
    } else {
        $filter = '';
    }
  
    return $filter ? construct_request_xml('client', 'del', $filter) : '';
}


# DEL response handler
# STATIC
sub delete_response_parse {
    my $xml_from_server = shift;

    return '' unless $xml_from_server;

    return abstract_parser('del', $xml_from_server, ['status']);
}


=item get(%params)

Get account detailf from Plesk.

Params:

One of the following options:

all   => 1      - for all accounts.
login => 'name' - for account with a given login.
id    => 123    - for account with a given id 

=cut


# Get all element data
# STATIC( %args )
# login => 'userlogin', id => 12312, all => 1
sub get {
    my %params = @_;

    my $filter = '';

    if ($params{'all'}) {
        $filter =  create_filter(login_field_name => 'login', all => 1); # warning: get all !!
    } elsif ($params{'id'} || $params{'login'}) {
        $filter = $params{'id'} ?
            create_filter( login_field_name => 'login', id    => $params{'id'}) :
            create_filter( login_field_name => 'login', login => $params{'login'});
    } else {
        $filter = '';
    }
    
    return construct_request_xml('client', 'get', $filter, 
        create_node ('dataset', create_node('gen_info')));
}


# GET response handler 
# STATIC
sub get_response_parse {
    my $xml_from_server = shift;

    return '' unless $xml_from_server;
    
    my $parse_result = abstract_parser('get', $xml_from_server, ['status']);
    return '' unless $parse_result;
        
    if (ref $parse_result eq 'HASH') {
        if ($parse_result->{'data'}) {

            $parse_result->{'data'} = xml_extract_values(
                    ( $parse_result->{'data'} 
                        =~ m#<gen_info>(.*?)</gen_info>#sio)[0]);

            return '' unless $parse_result->{'data'};
        } 
    } elsif (ref $parse_result eq 'ARRAY'){ # multiple blocks
        foreach my $element (@$parse_result) {

            if ($element->{'data'}) {
                $element->{'data'} = xml_extract_values(( $element->{'data'} 
                    =~ m#<gen_info>(.*?)</gen_info>#sio )[0]);

                return '' unless $element->{'data'};
            } 
        }
    } else {
        return ''; 
    }

    return $parse_result;
}


# Input data control for create sub
# STATIC
sub client_add_gen_info_check {
    my %params = @_;

    foreach my $key (keys %template_data) { 

        if ($_ = $params{$key}) {
            return '' unless ( 
                                length $_ >= $template_data{$key}->[1]  && 
                                length $_ <= $template_data{$key}->[2] 
            );
        } else {                                    # value not defined
            return '' if $template_data{$key}->[0]; # if required => error 
        }

    }   
    return 1; # all ok
}


1;
__END__
=head1 SEE ALSO

Mention other useful documentation such as the documentation of
related modules or operating system documentation (such as man pages
in UNIX), or any relevant external documentation such as RFCs or
standards.

If you have a mailing list set up for your module, mention it here.

If you have a web site set up for your module, mention it here.

=head1 AUTHOR

Odintsov Pavel E<lt>nrg[at]cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2008 by NRG

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.


=cut
