package UPC;

use strict;
use warnings;

use WWW::Mechanize;
use HTML::TokeParser;

use Date::Parse;

use UPC::Config;

sub new {
    my $type = shift;
    my %opts = @_;
    my $self = {};

    $opts{ipaddr} ||= '192.168.1.1';
    $opts{username} ||= '';

    # default password is blank, so this probably works
    $opts{password} ||= '';

    my $ua = new WWW::Mechanize( env_proxy => 0, timeout => 10 );
    $ua->credentials( $opts{ipaddr} . ':80',
                      'Cisco',
                      $opts{username},
                      $opts{password} );

    $self->{ua} = $ua;
    $self->{ipaddr} = $opts{ipaddr};
    $self->{username} = $opts{username};
    $self->{password} = $opts{password};

    return bless $self, $type;
}

=pod
 reset() - reset the modem. returns 0 on failure, 1 on success.

=cut

sub reset {
    my $self = shift;

    my $c = $self->_getpage( 'restart.asp' );
    if ( $c ) {
        my $res = $self->{ua}->submit();
        if ( $res->is_success()) {
            return 1;
        }
    }
    return 0;
}

sub _getconfig {
    my $self = shift;

    my $c = $self->_getpage( 'filename.gwc' );
    if ( $c ) {
        $self->{_config} = new UPC::Config();
        $self->{_config}->parsetext( $c );
    }

    return $c;
}

sub _system {
    my $self = shift;

    my $data = {
                Date => scalar( gmtime( time ))
               };

    my $c = $self->_getpage( 'system.asp' );
    if ( $c ) {
        my $p = new HTML::TokeParser( \$c );
        my $label = "";
        while( my $t = $p->get_token( "td" )) {
            my $text = $p->get_trimmed_text( "/td" );
            if ( $text !~ /^[[:print:]]/ ) {
                $text =~ s/^.\s*//;
                $data->{$label} = $text;
                # cheap hack
                last if $label eq "Software Revision";
            } else {
                $text =~ s/^.*\. //;
                $label = $text;
            }
        }
    } else {
        $data->{'Cable Modem Status'} = 'Admin Interface not responding';
    }

    $data;
}

sub _network {
    my $self = shift;

    my $c = $self->_getpage( 'RgSetup.asp' );

    my $data = {
                Date => scalar( gmtime( time ))
               };

    if ( $c ) {
        my $p = new HTML::TokeParser( \$c );
        while ( my $t = $p->get_tag( "input" )) {
            if ( $t->[1]{name} ) {
                $data->{$t->[1]{name}} = $t->[1]{value};
            }
        }

        # reset parser, and pull the plain text
        $p = new HTML::TokeParser( \$c );
        while ( my $t = $p->get_tag( "tr" )) {
            my ( $key, $value ) = ( undef, "" );
            my $col = 0;
            while ( my $t1 = $p->get_tag( "td", "/tr" )) {
                last if $t1->[0] eq "/tr";
                $col++;
                next if $col == 1;
                my $text = $p->get_trimmed_text( "/td" );
                if ( $col == 2 ) {
                    if ( $text !~ /^[[:print:]]/ ) {
                        $text = 'IPv4 DNS Servers';
                        $value = $data->{$text};
                    }
                    $key = $text;
                } else {
                    if ( $value ) {
                        $value = join( ", ", $value, $text );
                    } else {
                        $value = $text;
                    }
                }
            }
            next unless defined($key) and defined($value);
            $key =~ s/:$//;
            $data->{$key} = $value;
        }
    }

    # data fiddling
    my $leaselength = $data->{Duration};
    my $leaseexpires = $data->{Expires};
    $data->{LeaseTime} = time;

    if ( $leaselength and $leaseexpires ) {
        my $exp = str2time( $leaseexpires );
        my %len = split( /:?\s+/, $leaselength );

        # now backtrack, not wholly accurate
        if ( $exp ) {
            $data->{LeaseTime} =
              $exp
                - $len{S}
                  - ( 60 * $len{M} )
                      - ( 60 * 60 * $len{H} )
                        - ( 24 * 60 * 60 * $len{D} );
        }
    }

    $data;
}

sub _getpage {
    my $self = shift;
    my $page = shift;

    my $res = $self->{ua}->get( 'http://' . $self->{ipaddr} . '/' . $page );
    my $c;
    if ( $res->is_success()) {
        $c = $self->{ua}->content();
    } else {
        $c = "";
    }
    return $c;
}

1;

