#!/usr/bin/perl

use strict;
use warnings;
use Slinke::Foundation;

my $TRUE=1; my $FALSE = 0;

sub interpretType($$$) {
    my ($typeNumber, $typeR, $messageDataLengthR) = @_;

    if ($typeNumber eq $END_OF_PORT_MESSAGE_TYPE) {
        $$typeR = 'EndOfPortMessage';
    } elsif ($typeNumber eq $CONTROL_TYPE) {
        $$typeR = 'Control';
    } else {
        $$typeR = 'PortMessageData';
        $$messageDataLengthR = $typeNumber;
    }
}



sub reportControlCommand($) {
    my ($port) = @_;

    read(STDIN, my $byte1, 1);

    my $actionCode = ord($byte1);
   
    my $commandType = 
      Slinke::Foundation::commandTypeFromActionCode($actionCode, $port);
    
    if (defined($commandType)) {
        print("0x" . unpack("H*", chr($actionCode)) . " $commandType ");
        
        my $datalen = $COMMAND_TYPE{$commandType}->{'DATALEN'};
        
        if ($datalen > 0) {
            print("Args: ");
            read(STDIN, my $args, $datalen);

            print(unpack('H*', $args));
            if (length($args) < $datalen) {
                print("EOF IN MIDDLE OF ARGUMENTS");
            }
            print " ";
        }
    } else {
        print("UNKNOWN COMMAND TYPE.  ASSUMING NO ARGUMENTS.");
    }
}



sub reportWholePortMessage($$) {
    my ($port, $portMessageStatusR) = @_;

    my $length = length($portMessageStatusR->{CURRENT_MSG_DATA})/2;

    print("===> Whole port message sent on Port $port: $length bytes\n");
}



sub reportPortMessageData($$) {
    my ($messageDataLength, $portMessageStatusR) = @_;

    read(STDIN, my $messageDataPacked, $messageDataLength);

    my $messageData = unpack('H*', $messageDataPacked);

    print("   $messageData");

    if (length($messageData) < $messageDataLength) {
        print(" EOF IN MIDDLE OF DATA");
    }
    print("\n");
            
    $portMessageStatusR->{CURRENT_MSG_DATA} .= $messageData;
}



sub reportOneCommand($$) {
    my ($portMessageStatusR, $eofR) = @_;

    read(STDIN, my $byte0, 1);

    if (length($byte0) < 1) {
        $$eofR = $TRUE;
    } else {
        my $portAndTypeNumber = ord($byte0);

        my $portNumber = $portAndTypeNumber >> 5;
        my $port = $PORTNAME{$portNumber};

        my $typeNumber = $portAndTypeNumber & 0x1f;

        interpretType($typeNumber, \my $type, \my $messageDataLength);

        print("0x" . unpack('H*', $byte0) . " " . 
              substr("$port        ", 0, 8) . " ");

        if ($type eq 'Control') {
            print("Control Cmd:  ");

            reportControlCommand($port);

            print("\n");

        } elsif ($type eq 'EndOfPortMessage') {
            print("End Of Port Message\n");
            
            reportWholePortMessage($port, $portMessageStatusR->{$port});

            $portMessageStatusR->{$port}->{CURRENT_MSG_DATA} = '';
        } elsif ($type eq 'PortMessageData') {
            print("Port Msg Data: $messageDataLength bytes\n");
            
            reportPortMessageData($messageDataLength, 
                                  $portMessageStatusR->{$port});
        }
    }
}



###############################################################################
#                             MAINLINE
###############################################################################

my $eof;

my %portMessageStatus;

foreach my $port (keys(%PORTNUMBER)) {
    
    $portMessageStatus{$port}->{'CURRENT_MSG_DATA'} = '';
}


$eof = $FALSE;

while (!$eof) {
    reportOneCommand(\%portMessageStatus, \$eof);
}
