#!/usr/bin/env perl

use Getopt::Long;
use IO::Socket::INET;
use Net::Telnet;
use Ham::Reference::QRZ;
use utf8;
use Data::Dumper;
use strict;
use warnings;
use YAML qw ( LoadFile );;

my $callsign;
my $client_address;
my $client_socket;
my $cluster_data;
my $cluster_report;
my $config;
my $config_file;
my $dxcc;
my $key;
my $listing;
my $local_host;
my $local_login;
my $local_port;
my $local_telnet;
my $mode;
my $pota;
my $qrz;
my $qrz_data;
my $qrz_cc;
my $qrz_state;
my $qrz_password;
my $qrz_query;
my $qrz_username;
my $remarks;
my $session;
my $socket;
my $spot;
my $spot_data;
my $spot_datum;
my $value;

$Data::Dumper::Sortkeys = 1;

# auto-flush on socket
$| = 1;

$qrz_query = 1;
 
$config_file = "cluster_server.yml";

$config = LoadFile ( $ config_file );


$local_login       = 'k5lrk-4';

$local_host = 'localhost';
$local_port = 6600;
$local_telnet  = new Net::Telnet ( Timeout => 30,
                                   telnetmode => 0,
                                   Errmode => 'return',
                                   Input_log => "local_data.log",
                                   Port => 6600
                                 );
$local_telnet->open ( $local_host );
$local_telnet->waitfor ( '/ogin:/i' );
$local_telnet->print ( $local_login ); 
local_flush ( );

# Creating a listening socket
   $socket = new IO::Socket::INET (
    LocalHost => '0.0.0.0',
    LocalPort => '7777',
    Proto => 'tcp',
    Listen => 5,
    Reuse => 1
);
die "Cannot create socket $!\n" unless $socket;

$SIG{INT} = sub { $socket->close(); exit 0; };
if ( $qrz_query )
{
    $qrz_password = $config -> { 'qrz_password' };
    $qrz_username = $config -> { 'qrz_username' };
    $qrz_password = trim ( $qrz_password );

    printf "qrz_password: %s\n", $qrz_password;
    printf "qrz_username: %s\n", $qrz_username;
}

while ( 1 )
{
    $client_socket = $socket->accept();

    # Get information about a newly connected client
    $client_address = $client_socket->peerhost();

    # Read up to 1024 characters from the connected client
    $spot = "";
    $client_socket->recv($spot, 1024);

    utf8::encode ( $spot );
    
    @$spot_data = split /:/, $spot, 5;

    for $spot_datum ( @$spot_data )
    {
      ( $key, $value ) = split /=/, $spot_datum, 2;
      $cluster_data -> { $key } = $value;
    }
    $mode = get_mode ( $cluster_data -> { spot_frequency } );

    if ( $qrz_query )
    {
        $qrz_data = get_qrz_data ( $cluster_data -> { spot_callsign } );

        $qrz_cc = $qrz_data -> { dxcc } -> { ccc };
        if ( $qrz_data -> { listing } -> { state } )
        {
          $qrz_state = $qrz_data -> { listing } -> { 'state' };
        }
        else
        {
          $qrz_state = "__";
        }
    }
    else
    {
        $qrz_cc = "??";
        $qrz_state = "??";
    }
    $remarks = $cluster_data -> { spot_remarks };

    if ( $remarks =~ /\[-POTA-\]/ )
    {
      $remarks =~ s/\[-POTA-\]//;
      $pota = 'p';
    }
    else
    {
      $pota = " ";
    }

    $cluster_data -> { spot_remarks } = sprintf "%s/%s/%s/%s %s %s", 
                                                 $qrz_cc,
                                                    $qrz_state,
                                                       $mode,
                                                          $pota,
                                                             $cluster_data -> { spotter_callsign },
                                                                  $remarks;

    $cluster_report = sprintf "DX %s %s %s\n",
                                  $cluster_data -> { spot_frequency },
                                     $cluster_data -> { spot_callsign },
                                        $cluster_data -> { spot_remarks };
    local_flush ( );
    utf8::encode ( $cluster_report );
    printf "cluster_report: %s", $cluster_report;
    $local_telnet -> print ( $cluster_report );
}
#
sub local_flush
{
    my $returned;

    $returned = $local_telnet -> get ( Timeout => 0 );
}

sub trim
{
    my $s = shift;
    $s =~ s/^\s+|\s+$//g;
    return $s
}

########################################################################

sub get_qrz_data
{
  my $callsign = shift;

  my $qrz_data;

  eval
  {
    $qrz = Ham::Reference::QRZ->new
    (
      username => $qrz_username,
      password => $qrz_password
    );
  };
  if ( $qrz->is_error( ) )
  {
    print $qrz->error_message;
    print "\n";
    eval
    {
      $qrz = Ham::Reference::QRZ->new
      (
        username => $qrz_username,
        password => $qrz_password
      );
    }
  }

  $qrz -> set_callsign ( $callsign );
 
  $qrz_data -> { listing }      = $qrz -> get_listing ;
  $qrz_data -> { dxcc }         = $qrz -> get_dxcc ;

  #$qrz_data -> { session }      = $qrz -> get_session ;

  return ( $qrz_data );
}

sub get_mode
{
  my $frequency = shift;

  my $band;
  my $band_limits;
  my $bands;
  my $mhz;
  my $mode;
  my $voice;


  $bands =
  {
    '1mhz'   => '160_meter',
    '3mhz'   => '80_meter',
    '5mhz'   => '60_meter',
    '7mhz'   => '40_meter',
    '10mhz'  => '30_meter',
    '14mhz'  => '20_meter',
    '18mhz'  => '17_meter',
    '21mhz'  => '15_meter',
    '24mhz'  => '12_meter',
    '28mhz'  => '10_meter',
    '29mhz'  => '10_meter',
    '50mhz'  => '6_meter',
    '51mhz'  => '6_meter',
    '52mhz'  => '6_meter',
    '53mhz'  => '6_meter'
  };

  $band_limits =
  {
    '160_meter' =>
    {
      'bottom' => 1800,
      'voice'  => 1800,
      'top'    => 2000
    },
    '60_meter' =>
    {
      'bottom' => 5300,
      'voice'  => 5300,
      'top'    => 5400
    },
    '40_meter' =>
    {
      'bottom' => 7000,
      'voice'  => 7125,
      'top'    => 7300
    },
    '30_meter' =>
    {
      'bottom' => 10100,
      'voice'  => 10100,
      'top'    => 1015
    },
    '20_meter' =>
    {
      'bottom' => 14000,
      'voice'  => 14150,
      'top'    => 14350
    },
    '17_meter' =>
    {
      'bottom' => 18068,
      'voice'  => 18110,
      'top'    => 18168
    },
    '15_meter' =>
    {
      'bottom' => 21000,
      'voice'  => 21200,
      'top'    => 21450
    },
    '12_meter' =>
    {
      'bottom' => 24890,
      'voice'  => 24930,
      'top'    => 24990
    },
    '10_meter' =>
    {
      'bottom' => 28000,
      'voice'  => 28300,
      'top'    => 29700
    },
    '6_meter' =>
    {
      'bottom' => 50000,
      'voice'  => 50100,
      'top'    => 54000
    }
  };


  $mhz = sprintf "%smhz", int ( ( $frequency / 1000 ) );
  if ( $bands  -> { $mhz } )
  {
    $band = $bands  -> { $mhz };
    $voice = $band_limits -> { $band } -> { voice };

    if ( $frequency < $voice )
    {
      $mode = "d";
    }
    else
    {
      $mode = "v";
    }
  }
  else
  {
    $mode = "?";
  }

  return $mode;
}
