$| = 1;
require ESL;
use WWW::Google::Translate;
use JSON;
use Data::Dumper;
use POSIX qw(strftime);
use URL::Encode qw(url_encode);
use Math::Round;

$DIALOGFLOW = 0;

sub translate($$$) {
  my $from = shift;
  my $to = shift;
  my $s = shift;

  
  my $wgt = WWW::Google::Translate->new(
				      {   key            => 'AIzaSyDyMknoy98t7N_PlpuFYsTB9px8psARVEk',
					  default_source => $from,
					  default_target => $to,
				      }
				       );

  my $r = $wgt->translate( { q => $s } );
  my $o = "";
  
  for my $trans_rh (@{ $r->{data}->{translations} })
    {
      $o .= $trans_rh->{translatedText};
    }

  return $o;
}

my $TRANSLATE = 0;
my $ITALIAN = "it-IT-Standard-C";
my $VOICE = "en-US-Wavenet-B";
#my $VOICE = "en-GB-Standard-D";
our $TINY = 0;
our $CID;
our $DICTATE = 0;
our $FUNNY = 0;
our $CAPTION = 0;
our $UUID;
our $MYNAME = "franklin";

my $track_uuid = shift;
my $room = shift || die "need slack channel";
my $conf_name = "";

if ($track_uuid =~ /^conf:(.*)$/) {
  $conf_name = $1;
}

top:

#ESL::eslSetLogLevel(7);
my $con = new ESL::ESLconnection("127.0.0.1", "8021", "ClueCon");

my @members = ();

if ($conf_name) {
  my $list = $con->api("conference", "$conf_name json_list");
  my $json;

  eval {
    $json = decode_json $list->getBody();
  };

  if ($json) {
    foreach (@{$json->[0]->{members}}) {
      $con->api("uuid_setvar", "$_->{uuid} fire_asr_events true");
      push @members, $_->{uuid};
    }
  }
} else {
  push @members, $track_uuid;
  $con->api("uuid_setvar", "$track_uuid fire_asr_events true");
}

sub onInput {
  my $event = shift;

  my $type = $event->getHeader("Speech-Type");

  if ($type ne "detected-speech" && $type ne "detected-partial-speech") {
    return;
  }
  
  my $test = $event->serialize();
  my $jtxt = $event->getBody();

  my $json = decode_json $jtxt;

  #print $jtxt;
  #print Dumper $json;

  if ($TINY) {
    my $tiny = $json->{engine_data}[0]->{results}[1]->{alternatives}[0]->{transcript};
  
    if ($tiny) {
      $LAST_TEXT = $tiny;
    }
  } else {
    if ($DIALOGFLOW) {
      $LAST_TEXT = $json->{engine_data}->{query_result}->{query_text};
    } else {
      $LAST_TEXT = $json->{text};
    }
  }


  if ($LAST_TEXT) {
    $LAST_TEXT_TIME = time;
  }


  return $LAST_TEXT;

}



sub prime($) {
  my $uuid = shift;
  my @list;

  if ($uuid) {
    push @list, $uuid;
  } else {
    push @list, @members;
  }
  
  foreach (@list) {
    my $target_uuid = $_;
    print "prime $target_uuid\n";

    if (!$uuid) {
      $con->execute("detect_speech", "stop", $target_uuid);
    }


    
    #$con->execute("detect_speech", "stop", $target_uuid);
    #$con->api("uuid_denoise" ,"$target_uuid start m=3 th=1 sh=20 ng=200 nl=3000 db=1");
    #$con->api("uuid_denoise" ,"$target_uuid start");
    $con->api("uuid_denoise" ,"$target_uuid stop");
    
    $con->execute("detect_speech", "param hint $MYNAME", $target_uuid);
    $con->execute("detect_speech", "param hint Hey $MYNAME", $target_uuid);
    $con->execute("detect_speech", "param hint Yo $MYNAME", $target_uuid);
    $con->execute("detect_speech", "param hint $MYNAME toggle video", $target_uuid);
    $con->execute("detect_speech", "param hint $MYNAME play video", $target_uuid);
    $con->execute("detect_speech", "param hint $MYNAME tell", $target_uuid);
    $con->execute("detect_speech", "param hint $MYNAME what", $target_uuid);
    $con->execute("detect_speech", "param hint $MYNAME slack", $target_uuid);
    $con->execute("detect_speech", "param hint jerris", $target_uuid);
    $con->execute("detect_speech", "param hint cluecon", $target_uuid);
    $con->execute("detect_speech", "param hint signalwire", $target_uuid);
    
    $con->execute("detect_speech", "param automatic-punctuation true", $target_uuid);

    if ($DIALOGFLOW) {
      $con->execute("detect_speech", "gcloud_dialogflow default default default", $target_uuid);
      $con->execute("detect_speech", "param project-id tony-testing-210612", $target_uuid);
      $con->execute("detect_speech", "param channel-uuid " .. $target_uuid, $target_uuid);
    } else {
      $con->execute("detect_speech", "gcloud_speech default default default", $target_uuid);
    }
    
    $con->execute("detect_speech", "param start-input-timers true", $target_uuid);
    $con->execute("detect_speech", "param no-input-timeout 60000", $target_uuid);
    $con->execute("detect_speech", "param speech-timeout 60000", $target_uuid);
    $con->execute("detect_speech", "param language en-US", $target_uuid);
    $con->execute("detect_speech", "param confidence-threshold .8", $target_uuid);
    $con->execute("detect_speech", "param partial true", $target_uuid);
    $con->execute("detect_speech", "param channel-uuid $target_uuid", $target_uuid);
    $con->execute("detect_speech", "start-input-timers", $target_uuid);



  }
}



sub say($;$) {
  my $txt = shift;
  my $voice = shift or $VOICE;
  print "SAY: $txt\n";
  $txt =~ s/\n/ /g;

  $con->api("conference", "$conf_name say {tts_engine=gcloud,tts_voice=$voice}<speak>$txt</speak>");

}

my $cmdhash = {};


sub weather($) {
  my $where = shift;
  $where = url_encode($where);
  my $json = `wget 'http://api.openweathermap.org/data/2.5/weather?q=${where}&APPID=74157ae77efbf579ad73035835245f7b' -qO-`;
  my $weather = decode_json $json;
}

sub fortune {
  my $fortune = `/usr/games/fortune`;
  say("$fortune")
}

sub joke {
  my $joke_txt = `wget "https://official-joke-api.appspot.com/random_joke" -qO-`;
  my $joke = decode_json $joke_txt;

  say("$joke->{setup} <break time=\"2s\"/> $joke->{punchline}");
}
     

$cmdhash{toggle} = sub {
  my $what = shift;

  if ($what eq "mute") {
    $con->api("conference", "$conf_name tmute uuid=$UUID");
  }

  if ($what eq "video") {
    $con->api("conference", "$conf_name tvmute uuid=$UUID");
  }

};

$cmdhash{dictate} = $cmdhash{dictation} = sub {
  my $allcmd = join(" ", @_);

  if ($allcmd =~ /on/) {
    say("Dictation mode on");
    $DICTATE = 1;
  } else {
    say("Dictation mode off");
    $DICTATE = 0;
  }
};

$cmdhash{funny} = sub {
  my $allcmd = join(" ", @_);

  if ($allcmd =~ /on/) {
    say("Funny mode on");
    $FUNNY = 1;
  } else {
    say("funny mode off");
    $FUNNY = 0;
  }
};

$cmdhash{status} = sub {
  my $allcmd = join(" ", @_);

  if ($allcmd =~ /report/) {
    my $o = $con->api("conference", "$conf_name count");
    my $count = $o->getBody();
    say("There are currently $count callers in the conference");
  }
};

$cmdhash{translate} = sub {
  my $allcmd = join(" ", @_);

  my $say = $allcmd;
  $say =~ s/(['])/\\$1/g;
  $say = translate('en', 'it', $say);
  say($say, $ITALIAN);

};

$cmdhash{caption} = sub {
  my $allcmd = join(" ", @_);

  if ($allcmd =~ /on/) {
    say("Caption mode on");
    $CAPTION = 1;
  } else {
    say("Caption mode off");
    $CAPTION = 0;
  }
};

$cmdhash{tell} = sub {
  my $allcmd = join(" ", @_);

  if ($allcmd =~ /joke/i) {
    &joke;
  }

  elsif ($allcmd =~ /fortune/i) {
    &fortune;
  }

};

$ENV{TZ} = 'America/Los_Angeles';

$cmdhash{what} = $cmdhash{whats} = sub {
  my $allcmd = join(" ", @_);

  my $subcmd = shift;
  
  if ($subcmd =~ /time/i) {
    #say("time to get back to work, master");
    my $datestring = strftime "%I %M %p", localtime;
    say("Current Time: $datestring ");
  }
  
  my $w;
  my $where;
  
  if ($allcmd =~ /weather.*?in (.*)/i) {
    $where = $1;
  } elsif ($allcmd =~ /weather/i) {
    $where = "Menlo Park";
  }

  if ($where) {
    $w = weather($where);
  }

  if ($w) {
    my $temp = round($w->{main}->{temp} * (9/5) - 459.67);
    my $conditions = $w->{weather}->[0]->{description};
    say("current conditions in $where: $conditions, current temperature: $temp");
  }
  

};


$cmdhash{message} = sub {
  my $room = shift;

  if ($room eq "hashtag" || $room eq "pound") {
    $room = shift;
  }
  
  my $full_msg = join(" ", @_);
  print "SLACK $room [$full_msg]\n";

  my $j = {};
  if ($full_msg && $room && $CID) {
    my $cmd = "/usr/bin/slack chat send -ch \"$room\" -ti \"$CID\" -cl \"#eb396d\" --compact -tx \"$full_msg\"";
    eval {
      $j = decode_json `$cmd`;
      #print Dumper $j;
    };
  } else {
    $j->{error} = "I didn't understand what to tell them in slack.";
  }

  if ($j->{ok}) {
    say("consider it done sir.");
  } else {
    say("terribly sorry sir, something went wrong: $j->{error}");
  }
};

$cmdhash{call} = sub {

  my $arg = shift;

  my ($number) = $arg =~ /(\d[\d-]+\d)/;
  
  if ($conf_name && $number) {
    say("right away master, dialing $number now");
    $number =~ s/[^\d]//g;

    $con->api("bgapi", "originate {origination_caller_id_name=SignalWire,origination_caller_id_number=16503820000}sofia/gateway/flowroute/1${number} conference:$conf_name inline");
  } else {
    say("something has gone terribly wrong master, I do apoligize");
  }
  
};


$cmdhash{execute} = sub {
  print Dumper \@_;

  my $subcmd = shift;
  my $arg = join(" ", @_);
  my $num;
  
  if ($subcmd =~ /order/i) {
    $arg =~ s/(\d)\s/$1/g;
    $arg =~ s/[^\w\d\s]//g;

    if ($arg =~ /^([\d\s]+)/) {
      $arg = $1;
    } 
    
    if (!$arg) {
      print "can't find clip\n";
      return;
    }
    
    print "clip $arg\n";
    my $reply = `grep -i "$arg" /mnt/freeswitch/clipeeze/00-index.txt`;
    ($num) = $reply =~ /(\d+)/;
    #print "$num $reply";

    if ($num) {

      my $msg = "/bin/slack chat send \"ClipeeZe $num\" -im https://cantina.signalwire.com/clipeeze/gif/$num.gif -ch $room >/dev/null 2>&1 &";
      #print O $msg . "\n";
      #system($msg);
    
      if ($conf_name) {
	$con->api("conference", "$conf_name play /mnt/freeswitch/clipeeze/$num.mp4");
      }
    } else {
      print "not found\n";
      say("terribly sorry master, I can't find that one\n");
    }

  }

};

sub parse_command($) {
  my $cmdline = lc shift;
  my @data = split(" ", $cmdline);

  my $cmd = shift @data;
  $cmd =~ s/[']//g;
  print "EXEC CMD $cmd\n";
  
  if ($cmdhash{$cmd}) {
    $cmdhash{$cmd}->(@data);
  } else {
    print "CMD $cmd not found\n";
  }

}


prime(undef);

$con->events("plain", "DETECTED_SPEECH");
$con->events("plain", "custom conference::maintenance");

say("$MYNAME at your service");

while ($con->connected()) {
  my $e = $con->recvEvent();
  
  my $uuid = $e->getHeader("Channel-Call-UUID");
  my $this_conf_name = $e->getHeader("variable_conference_name") || $e->getHeader("Conference-Name");
  my $action = $e->getHeader("Action");
  $CID = $e->getHeader("Caller-Orig-Caller-ID-Name") . " (" . $e->getHeader("Caller-Orig-Caller-ID-Number") . ")";
  $UUID = $uuid;
  
  #print $e->serialize();

  my $conf_match = ($this_conf_name && $conf_name && $this_conf_name eq $conf_name);
  
  next if ($action && $action !~ /-member/);
  
  #print "u: $uuid c: $this_conf_name a: $action\n";
  


  if ($conf_match) {
    if ($action eq "add-member") {
      print "ADD $uuid\n";
      push @members, $uuid;
      $con->api("uuid_setvar", "$uuid fire_asr_events true");
      prime($uuid);
    } elsif ($action eq "del-member") {
      print "DEL $uuid\n";
      @members = grep { $_ != $uuid } @members;
    }
  }

  if ($action) {
    print Dumper \@members;
    next;
  }
  
  foreach (@members) {
    my $target_uuid = $_;
    
    if ($target_uuid eq $uuid || $conf_match) {
      my $bod = $e->getBody();

      my $st = $e->getHeader("Speech-Type");

      next if ($st eq "closed" || $st eq "begin-speaking");
      
      #if ($st ne "detected-partial-speech") {
	#print $e->serialize();
      #}

      my $partial = 0;
      
      if ($st eq "detected-partial-speech") {
	$partial = 1;
      }
      
      if ($st eq "detected-speech" || $partial) {
	my $text = onInput $e;	

	unless($text =~ /\S+/) {
	  $text = undef;
	}
	
	if ($text) {

	  if ($partial) {
	    printf "\rPARTIAL: [$text]";
	  } else {
	    printf "\nFINAL: [$text]\n";
	  }
	  

	  if ($CAPTION) {
	    #my $say = ucfirst $text;
	    my $say = $text;
	    $say =~ s/(['])/\\$1/g;
	    #$say .= ".";

	    if (!$partial) {
	      $say = translate('en', 'it', $say);
	    }
	    
	    $con->api("conference", "$conf_name vid-banner uuid=$UUID '$say'");

	    if ($partial) {
	      $say = "+$say";
	    }

	    my $o = $con->api("conference", "$conf_name captionmember uuid=$UUID '$say'");
	    #print $o->getBody();
	  }

	  if (!$partial) {
	    if ($text =~ /$MYNAME[,\s]+(.*)/i) {
	      print "COMMAND TEXT $text\n";
	      parse_command($1);
	    } else {

	      if ($FUNNY) {
		if ($text =~ /jerris|Jairus|jarvis</i) {
		  $con->api("conference", "$conf_name play /mnt/freeswitch/clipeeze/117.mp4");
		}
	      
		$twss = `/usr/src/twss/twss2.py "$text" | grep TWSS`;
		chomp $twss;

		if ($twss eq "TWSS") {
		  $con->api("conference", "$conf_name play /mnt/freeswitch/clipeeze/090.mp4");
		}

		if ($text =~ /money/i) {
		  $con->api("conference", "$conf_name play /mnt/freeswitch/clipeeze/000.mp4");
		}

		if ($text =~ /canada/i) {
		  $con->api("conference", "$conf_name play /mnt/freeswitch/clipeeze/123.mp4");
		}
	      }

	      if ($DICTATE) {
		my $full_msg = $text;
		print "SLACKING SPEECH\n";
		my $cmd = "/usr/bin/slack chat send -ch \"$room\" -ti \"$CID\" -cl \"#eb396d\" --compact -tx \"$full_msg\" >/dev/null 2>1";
		system $cmd;
	      }
	    }
	  }
	}
	  
	if (!$text || !$partial) {
	  $con->execute("detect_speech", "stop", $uuid);
	  prime($uuid);
	}
      }

    }
  }
}

print "Disconnected, Retrying in 5s\n";
sleep(5);

goto top;

