package Net::Indosoft::Voicebridge;

use warnings;
use strict;
use Data::Dumper;
use SOAP::Lite;

our $AUTOLOAD;
our $DEBUG = 1;

=head1 NAME

Net::Indosoft::Voicebridge - Interface to Indosoft Voicebridge API

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';

=head1 SYNOPSYS

  use Net::Indosoft::Voicebridge;

  my $handle = Net::GlobalPOPs::MediaServicesAPI->new(
    'url'    => 'http://your_tag.kanobe.net:8080/vbsoap/voicebridgeAPI.php',
  );

=head1 METHODS

=head2 new

Creates a new Net::Indosoft::Voicebridge object.

=cut

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self = ref($_[0]) ? shift : { @_ };

#  my $soap = new SOAP::Lite (
#    'service' => $URL.'?wsdl',
#  );
#  $self->{soap} = $soap;

  bless($self, $class);
}

#ideally this could be retreived from the WSDL, but hey
# or at least derived from the method name?
our %requestobj = (
  'addAccount'       => 'Account',
  'modifyAccount'    => 'Account',
  'addClient'        => 'Client',
  'modifyClient'     => 'Client',
  'addConference'    => 'Conference',
  'modifyConference' => 'Conference',
);

#this is think they're just on crack.  returnning a string to parse inside
#a ton of XML?  somehow that misses the point.
our %returnparse = (
  'addAccount'       => [ qw( account_id ) ],
  'modifyAccount'    => [ qw( account_id ) ],
  'addClient'        => [ qw( client_id  ) ],
  'modifyClient'     => [ qw( client_id  ) ],
  'addConference'    => [ qw( conference_id moderator_pin participant_pin ) ],
  'modifyConference' => [ qw( conference_id ) ],
);

sub AUTOLOAD {
  my $self = shift;

  $AUTOLOAD =~ /(^|::)(\w+)$/ or die "unparsable AUTOLOAD: $AUTOLOAD";
  my $function = $2;
  return if $function eq 'DESTROY';

  my $uri = "voicebridgeAPI/$function";


  my $soap = SOAP::Lite
#    -> readable(1)
    -> proxy($self->{url})
#    -> on_action( sub { join '/', @_ } ) #according to the wsdl, right?
#    -> on_action( sub { "urn:voicebridgeAPI/$function" } )
    -> autotype(0)
#    -> default_ns("urn:voicebridgeAPI")
  ;

  my $request;
  my $obj = $requestobj{$function};
  if ( $obj ) {

    my $opts = ref($_[0]) ? shift : { @_ };
    if ( $DEBUG > 1 ) {
      warn "$_: ". $opts->{$_}. "\n" foreach keys %$opts;
    }

    $request = SOAP::Data->name( $obj =>
      \SOAP::Data->value(
        map SOAP::Data->name( $_ )->value( $opts->{$_} ), keys %$opts
      )
    );

  } else {

    $request = shift;

  }

  my $som = $soap->call( $function, $request );

  die $som->faultstring if $som->fault;
  return { 'error' => $som->faultdetail } if $som->fault;

  warn Dumper($som->body) if $DEBUG > 1;

  my $return = $som->valueof("//${function}Response/return");

  if ( $return =~ /^<errors/i ) {
    my $rsom = SOAP::Deserializer->deserialize($return);
    my @errors = $rsom->valueof('//errors/error');
    return { 'error' => join(' / ', @errors ) } if @errors;
  }

  if ( $function =~ /^delete/ && $return !~ /Deleted Success?fully/i ) {
    return { 'error'  => 'Deletion unsuccessful',
             'return' => $return,
           };
  }

  my %return = ( 'return'=>$return );
  foreach my $rp ( @{ $returnparse{$function} || [] } ) {
                              #are they always numeric?
    $return =~ /\W$rp\s*=\s*(\d+)/ and $return{$rp} = $1;
  }

  return \%return;
}

=head2 addAccount

Pass a list of key=>value pairs or a hash reference:

i.account_name: Required Field: Alpha Numeric 
ii.account_desc: Alpha Numeric
iii.account_addr: Alpha Numeric
iv.account_city: Alpha Numeric
v.account_state: Alpha Numeric
vi.account_country: Alpha Numeric
vii.account_zip: Alpha Numeric
viii.account_phone: Required Field: Alpha Numeric Ex: 123-123-1234
ix.account_fax: Alpha Numeric
x.account_email: Required Field, have to be in valid email format
xi.account_password: Required Field: Alpha Numeric

Returns a hash reference with one element, either 'error' for error conditions,
or 'account_id' if the account is created sucessfully.

=head2 modifyAccount

Pass a list of key=>value pairs or a hash reference:

xiv.account_id: Required Field (Provided when the account was created) 
xv.account_name: Required Field
xvi.account_desc 
xvii.account_addr 
xviii.account_city 
xix.account_state 
xx.account_country 
xxi.account_zip 
xxii.account_phone: Required Field 
xxiii.account_fax
xxiv.account_email: Required Field
xxv.account_password: Required Field

Returns a hash reference with one element, either 'error' for error conditions,
or 'account_id' if the account is modified sucessfully.

=head2 addClient

Pass a list of key=>value pairs or a hash reference:

account_id: Required Field Alpha Numeric 
client_contact_name: Required Field Alpha Numeric
client_contact_addr Alpha Numeric
client_contact_city Alpha Numeric
client_contact_state Alpha Numeric
client_contact_country Alpha Numeric
client_contact_zip Alpha Numeric
client_contact_phone: Required Field Alpha Numeric
client_contact_fax Alpha Numeric
client_contact_email: Required Field Alpha Numeric
client_contact_password: Required Field Alpha Numeric

Returns a hash reference with one element, either 'error' for error conditions,
or 'client_id' if the account is created sucessfully.

=head2 modifyClient

Pass a list of key=>value pairs or a hash reference:

client_id: Required Field
account_id: Required Field
client_contact_name: Required Field
client_contact_addr
client_contact_city
client_contact_state
client_contact_country
client_contact_zip
client_contact_phone: Required Field
client_contact_fax
client_contact_email: Required Field
client_contact_password: Required Field

Returns a hash reference with one element, either 'error' for error conditions,
or 'client_id' if the account is modified sucessfully.

=head2 addConference

Pass a list of key=>value pairs or a hash reference:

client_id: Required Field Alpha Numeric (Required to associate conference to client, client ID provided when new client is added)
conference_name: Required Field Alpha Numeric
conference_desc Alpha Numeric
start_time: Required Field Alpha Numeric
moderated_flag: 
1 ż Presentation mode 
0 ż Conversation Mode
entry_ann_flag: Integer
0 ż None
1 -  Tone
2 - Name 
record_flag: Integer
0 ż Stop Recording
1 ż Start Recording
moh_flag: Integer
0 ż Stop MOH
1 ż Start MOH
talk_detect_flag
play_user_cnt_flag: Integer
1- Announce number of conference members currently in conference
0 ż no Announcement
wait_for_admin_flag: Integer
1 - Only start conference once admin enters
0 ż all users without admin
stop_on_admin_exit_flag: Integer
1 - End conference when admin exits:
0 - No
second_pin_flag: Integer
1 - Prompt conference members for a second pin/password when logging in?
0 - No Extra conference PIN
secondary_pin: Integer
If second_pin_flag is 1 also pass the PIN
allow_sub_conf: Integer
1 ż Allow sub conference for this conference
0 ż Donot Allow sub conference
duration: Integer
Duration in minutes e.g 30 for 30 minutes
conference_type: reservationless/reserved

On errors, returns a hash reference with one element, 'error', otherwise
returns a hash reference with the following keys: conference_id, moderator_pin
and participant_pin.

=head2 modifyConference

Pass a list of key=>value pairs or a hash reference:

conference_id: Required Field
client_id: Required Field
conference_name: Required Field
conference_desc
start_time: Required Field
moderated_flag: 
1 ż Presentation mode 
0 ż Conversation Mode
entry_ann_flag: Integer
0 ż None
1 -  Tone
2 - Name 
record_flag: Integer
0 ż Stop Recording
1 ż Start Recording
moh_flag: Integer
0 ż Stop MOH
1 ż Start MOH
play_user_cnt_flag: Integer
1- Announce number of conference members currently in conference
0 ż no Announcement
wait_for_admin_flag: Integer
1 - Only start conference once admin enters
0 ż all users without admin
stop_on_admin_exit_flag: Integer
1 - End conference when admin exits:
0 - No
second_pin_flag: Integer
1 - Prompt conference members for a second pin/password when logging in?
0 - No Extra conference PIN
secondary_pin: Integer
If second_pin_flag is 1 also pass the PIN
allow_sub_conf: Integer
1 ż Allow sub conference for this conference
0 ż Donot Allow sub conference
duration: Integer
Duration in minutes e.g 30 for 30 minutes

Returns a hash reference with one element, either 'error' for error conditions,
or 'conference_id' if the conference is modified sucessfully.

=head2 deleteAccount

Pass a list of key=>value pairs or a hash reference:

i.account_id: Required Field

On errors, should returns a hash reference with one element, 'error'.

=head2 deleteClient

Pass a list of key=>value pairs or a hash reference:

ii.client_id: Required Field

On errors, should returns a hash reference with one element, 'error'.

=head2 deleteConference

Pass a list of key=>value pairs or a hash reference:

iii.conference_id: Required Field

On errors, should returns a hash reference with one element, 'error'.

=head1 The services below are not yet documented/online

=head2 addConferencePIN

=head2 modifyConferencePIN

=head2 deleteConferencePIN

=head2 addDNIS

=head2 modifyDNIS

=head2 deleteDNIS

=head1 AUTHOR

Ivan Kohler, C<< <ivan-voicebridge at freeside.biz> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-net-indosoft-voicebridge at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Net-Indosoft-Voicebridge>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Net::Indosoft::Voicebridge

You can also look for information at:

=over 4

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-Indosoft-Voicebridge>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/Net-Indosoft-Voicebridge>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/Net-Indosoft-Voicebridge>

=item * Search CPAN

L<http://search.cpan.org/dist/Net-Indosoft-Voicebridge>

=back

=head1 ACKNOWLEDGEMENTS

This module was developed by Freeside Internet Services, Inc.
If you need a complete, open-source web-based application to manage your
customers, conferences, billing and trouble ticketing, please visit
http://freeside.biz/

Development sponsored by NxxTcom Conferencing.  If you need a cost-effective
voice, web or video conference, please visit http://www.nxxtcom.net/

=head1 COPYRIGHT & LICENSE

Copyright (c) 2009 Freeside Internet Services, Inc. <http://freeside.biz/>
All rights reserved.

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

=cut

1;

