#!/usr/bin/env perl

use strict;
use warnings;

# fix lib paths, some may be relative
BEGIN {
    require File::Spec;
    my @libs = (
        "lib", 
        "local/lib",
        "../libcif/lib", # in case we're in -dev mode
        "../libcif-dbi/lib", # in case we're in -dev mode
        "../cif-router/lib", # in case we're in -dev mode
        "../cif-smrt/lib", # in case we're in -dev mode

    );
    my $bin_path;

    for my $lib (@libs) {
        unless ( File::Spec->file_name_is_absolute($lib) ) {
            unless ($bin_path) {
                if ( File::Spec->file_name_is_absolute(__FILE__) ) {
                    $bin_path = ( File::Spec->splitpath(__FILE__) )[1];
                }
                else {
                    require FindBin;
                    no warnings "once";
                    $bin_path = $FindBin::Bin;
                }
            }
            $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib );
        }
        unshift @INC, $lib;
    }
}

use Cikl::Client::Factory;
use Getopt::Long;
use JSON::XS;
use Cikl qw/debug/;

use Cikl::Report::QueryResultsReport;
use Cikl::Report::CSVFormatter;
use Cikl::Report::TableFormatter;
require Cikl::Models::QueryAddress;
use Config::Simple;

our $debug       = 0;

# config opts
my $config_file      = $ENV{'HOME'}.'/.cikl';
my $outfile;
my @queries;

# query options
my $nolog       = 0;
my $confidence;
my $group;
my $limit;

# plugin opts
my $plugin      = 'Table';
my $fields;
my $help = 0;

Getopt::Long::Configure ("bundling");
GetOptions(
  'config|C=s' => \$config_file,
  'outfile|O=s' => \$outfile,
  'debug|d|v+' => \$debug,
  'query|q=s' => \@queries,
  'nolog|n' => \$nolog,
  'confidence|c=i' => \$confidence,
  'group|g=s' => \$group,
  'limit|l=i' => \$limit,

  'plugin|p=s' => \$plugin,
  'fields|f=s' => \$fields,
  'help|h' => => \$help 
) or die($!);


die usage() if($help);

sub usage {
    return <<EOF;
Usage: perl $0 -q xyz.com

Standard Options:
    -h  --help:             this message
    -C  --config:           specify cofiguration file, default: $config_file
    
Query Options:
    -q  --query:            query string
    -n  --nolog:            perform a "silent" query (no log query), default: $nolog
    -l  --limit:            set the default result limit (queries only), default is set on server, usually around 500.
    -c  --confidence:       lowest tolerated confidence (0.00 -- 100.00), default $confidence
    
Format Options:
    -p  --plugin:           output plugin ('Table','Csv'), default: Table
    -f  --fields:           set default output fields for default table display
    -g  --group:             filter by a specific group name, ex: group1.example.com
    
Nonstandard Options:

Example Queries:

    \$> perl $0 -q 1.2.3.4
    \$> perl $0 -q 1.2.3.0/24
    \$> perl $0 -q f8e74165fb840026fd0fce1fd7d62f5d0e57e7ac
    \$> perl $0 -q hut2.ru
    \$> perl $0 -q hut2.ru,f8e74165fb840026fd0fce1fd7d62f5d0e57e7ac
    \$> perl $0 hut2.ru
    
    \$> perl $0 -q malware
    \$> perl $0 -q malware
    \$> perl $0 -q infrastructure/botnet -p csv 
    \$> perl $0 -q domain/malware -p bindzone -c 95
    \$> perl $0 -q domain -c 40
    
    \$ $0 -d -q example.com -e search

Configuration:

    configuration file ~/.cikl should be readable and look something like:

    [client]
    apikey = xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    driver = 'http'
    
    # table_nowarning = 1
    # csv_noseperator = 1
    
    [client_http]
    host = https://example.com:443/api
    timeout = 60
    
    # add this if you have a self signed cert
    verify_tls = 0
    
    # proxy settings
    # proxy = https://localhost:5555

EOF
}


$plugin = lc($plugin);
my $formatter;
if ($plugin eq 'csv') {
  $formatter = Cikl::Report::CSVFormatter->new();
} elsif ($plugin eq 'table') {
  $formatter = Cikl::Report::TableFormatter->new();
}

if (!defined($formatter)) {
    print usage();
    print "ERROR: Unknown formatter ($plugin) specified.\n";
    exit(0);
}

my $config = Config::Simple->new($config_file) or die("Failed to open config file $config_file: " . $!);
my $err;
my $client_config = $config->get_block('client');
#$client_config->{global_config} = $config;


my $cli = Cikl::Client::Factory->instantiate($client_config);


# else we're doing query
if($outfile){
    open(F,">",$outfile) || die($!);
}
my %args;

if ($limit) {
  $args{limit} = $limit;
}

if ($group) {
  $args{group} = $group;
}

if ($confidence) {
  $args{confidence} = Cikl::Models::QueryRange->new(min => $confidence);
}

my @address_criteria;
foreach my $query (@queries) {
  my @query_parts = split(':', $query, 2);
  if (!defined($query_parts[1])) {
    die("Invalid query: $query");
  }

  push(@address_criteria, Cikl::Models::QueryAddress->new(
      operator => $query_parts[0],
      value => $query_parts[1] 
    ));
}
$args{address_criteria} = \@address_criteria;

use Time::HiRes qw/tv_interval gettimeofday/;
my $start = [gettimeofday];
my $query_results = $cli->query(%args);
my $runtime = tv_interval($start);
debug("Query round trip: $runtime seconds");
$cli->shutdown();


if($err){
    print 'ERROR: '.$err."\n";
    exit(-1);
}
unless($query_results){
    debug('no results...') if($debug);
    exit(0);
}

debug('formatting as '.ucfirst($plugin).'...');

$fields = [ split(/,/,$fields) ] if($fields);

my @text;


my $output = *STDOUT;

if($outfile){
  $output = *F;
}

my $report = Cikl::Report::QueryResultsReport->new($query_results);
$formatter->generate_report($report, $output);

if ($outfile) {
  close(F);
}
