#!/usr/bin/perl

use strict;
use warnings;
use File::Copy qw( copy move );

my $test_device = shift || undef;
my $test_filter = shift || undef;

my $hfile = "/opt/pos/etc/hid.txt";

my @devices = ();

if (! defined $test_device && open(F, "< $hfile")) {
  while (<F>) {
    chop;
    push @devices, $_ if $_;
  }
  close(F);
}

# this will be a test, forget configured devices
if (defined $test_device) {
  if (defined $test_filter) {
    @devices = ( $test_device . "#" . $test_filter );
  }
  else {
    @devices = ( $test_device );
  }
}


if (! scalar @devices) {
  die "Can't find any device inside $hfile\n";
}

my @children = ();
my $i = 0;

if (defined $test_device) {
  $i = 1;
  my $full_str = "";

  my $name = $devices[0];
  my $rc = child($i, $name, 10);
  print "$rc" if $rc;

  if ($rc) {
    open(F, ">> /tmp/miguel");
    print F "$rc";
    close(F);
  }

  $rc = child($i, $name, 1);
  print "$rc" if $rc;
  if ($rc) {
    open(F, ">> /tmp/miguel");
    print F "$rc";
    close(F);
  }

  $rc = child($i, $name, 1);
  print "$rc" if $rc;
  if ($rc) {
    open(F, ">> /tmp/miguel");
    print F "$rc";
    close(F);
  }

  exit(0);
}

foreach my $name (@devices) {
  $i++;
  my $pid = fork();

  if ($pid) {
    #If $pid is non zero, then the parent is running
    print STDERR "PID $pid forked\n";
    push(@children, $pid);

  }
  else {
    # Else we are a child process ($pid == 0)
    my $rc = child($i, $name);
    $rc ||= "";
    print $rc."\n" if $rc;

    #$rc = child($i, $name);
    #$rc ||= "";
    #print $rc."\n" if $rc;

    #if ($rc) {
    #  $rc = child($i, $name);
    #  $rc ||= "";
    #  print $rc."\n" if $rc;
    #}

    exit(0);
  }
}

foreach my $n (@children) {
  my $pid = waitpid($n,0); # waitpid returns the pid that finished, see perldoc -f waitpid
  my $rc = $? >> 8; # remove signal / dump bits from rc
  print "PID $pid finished with rc $rc\n";
}

#
# functions
#

sub child {
  my ($arg, $name, $timeout) = @_;
  #print "$arg: start > $name\n";

  $timeout ||= 10;

  my $filter = "";
  my @t = split /#/, $name;

  if (scalar @t == 1) {
    $name = $t[0];
  }
  else {
    $name = $t[0];
    $filter = $t[1];
  }

  my $DEV = &find_reader_device($name);

  if (! defined $DEV) {
    print STDERR "$arg: error > Can't find hidraw device - $name\n";
  }
  else {
    print STDERR "DEVICE: $DEV\n";
    &disable_device_xorg($name);

    while(1) {
      if (defined $test_device) {
        local $SIG{ALRM} = sub { die "alarm\n" };
        alarm($timeout);
      }

      my $barcode = barcode_read($DEV);

      my $write = 1;

      if ($filter) {
        if ($filter =~ /^\d+,\d+$/) {
          my @t = split /,/, $filter;
          if (scalar @t == 2) {
            if ($t[0] < length($barcode)) {
              $barcode = substr($barcode, $t[0], $t[1]);
            }
          }
        }
        else {
          $write = $filter && $barcode !~ /$filter/ ? 0 : 1;
        }
      }

      my $tmp = "/opt/pos/common/tmp/".$$.".txt";
      my $final = "";

      if (defined $test_device) {
        return $barcode."\n";
        #print $barcode."\n";
        #print $barcode."\n";
        #$final = "/opt/pos/common/tmp/barcode_test.txt";
        #print STDERR "BARCODE: $barcode\n";
        #open(F, "> $tmp");
        #print F $barcode."\n";
        #close(F);
        #&move( $tmp, $final );
      }
      else {
        $final = "/opt/pos/common/tmp/barcode.txt";

        if ($write) {
          print STDERR "BARCODE: $barcode\n";
          open(F, "> $tmp");
          print F $barcode."\n";
          close(F);

          &move( $tmp, $final );
        }
      }

      if (defined $test_device) {
        exit(0);
      }
    }
  }

  #print "$arg: end > $name\n";
  return 1;
}

sub find_reader_device {
  my $find = shift;
  my $out = "";

  if (defined $find) {
    my $cmd = "dmesg | grep hidraw | grep \"$find\" | tail -1";
    $out = `$cmd`;
  }
  else {
    $out = `dmesg | grep hidraw | grep "GIGA-TMS MagStripe Card Reader" | tail -1`;

    if (! $out) {
      $out = `dmesg | grep hidraw | grep 1667 | grep 0009 | tail -1`;
    }
  }

  return unless $out;
  chop($out);

  my( $num ) = $out =~ /input,hidraw(\d+)/;

  if (defined $num) {
    return "/dev/hidraw" . $num;
  }

  return;
}

sub disable_device_xorg {
  my $find = shift;
  my $out = "";

  if (defined $find) {
    $out = `xinput  --list | grep "$find"`;
  }
  else {
    $out = `xinput  --list | grep "GIGA-TMS MagStripe Card Reader"`;

    if (! $out) {
      $out = `xinput  --list | grep 1667 | grep 0009`;
    }
  }

  return unless $out;
  chop($out);


  my( $id ) = $out =~ /id=(\d+)/;

  if (defined $id) {
    print STDERR "DISABLED XINPUT DEVICE: $id\n";
    `xinput set-int-prop $id "Device Enabled" 8 0`;
  }
}

sub barcode_read {
  my $dev = shift;

  my $barcode = "";

  open(F, "< $dev") or die "Can't open $dev - $!\n";
  binmode(F);

  my $continue = 1;

  while ($continue) {
    my $cnt = "";
    sysread(F, $cnt, 80);

    my @c = split //, $cnt;

    foreach my $c (@c) {
      my $j = ord($c);
      next unless $j;

      if ($j == 0x1E || $j == 89) {
        $barcode .= 1;
      }
      elsif ($j == 0x1F || $j == 90) {
        $barcode .= 2;
      }
      elsif ($j == 0x20) {
        $barcode .= 3;
      }
      elsif ($j == 0x21) {
        $barcode .= 4;
      }
      elsif ($j == 0x22) {
        $barcode .= 5;
      }
      elsif ($j == 0x23) {
        $barcode .= 6;
      }
      elsif ($j == 0x24) {
        $barcode .= 7;
      }
      elsif ($j == 0x25) {
        $barcode .= 8;
      }
      elsif ($j == 0x26) {
        $barcode .= 9;
      }
      elsif ($j == 0x27) {
        $barcode .= 0;
      }
      elsif ($j == 0x28) {
        close(F);
        $continue = 0;
      }
    }
  }

  return $barcode;
}

