#!/usr/bin/perl

use 5.24.0;
use strict;
use warnings;
use Carp qw/croak/;

# use YAML qw(LoadFile) # only needed for converting yaml to perl syntax TODO cleanup
use Data::Dumper qw(Dumper);
use Cwd qw(cwd);
use File::Path;
use File::Copy;

# NOTE to generate
#my $printers = LoadFile("printers.yml");
#print Dumper $printers;
#my $models = LoadFile("models.yml");
#print Dumper $models;

## DATA ##

my $printers = {
    'copy4b' => {
        'model'    => 'TA5007ci',
        'location' => 'Building B, 4th floor'
    },
    'copy3a' => {
        'model'    => 'TA4505ci',
        'location' => 'Building A, 3th floor kitchen'
    },
    'lj5c' => {
        'model'    => 'hp-laserjet-600',
        'location' => 'Building C, 5th floor, next to copy'
    },
    'copy5b' => {
        'model'    => 'TA5007ci',
        'location' => 'Building B, 5th floor'
    },
    'lj-b010' => {
        'location' => 'Building B, groundfloor, Building Management'
    },
    'lj4c' => {
        'location' => 'Building C, 4th floor, next to copy',
        'model'    => 'hp-laserjet-600'
    },
    'lj4p' => {
        'model'    => 'hp-laserjet-p4015x',
        'location' => 'Building B, 4th floor, next to copy'
    },
    'lj4a' => {
        'model'    => 'hp-laserjet-600',
        'location' => 'Building A, 4th floor kitchen'
    },
    'copy4a' => {
        'location' => 'Building A, 4th floor kitchen',
        'model'    => 'TA4505ci'
    },
    'copy2a' => {
        'model'    => 'TA4505ci',
        'location' => 'Building A, 2nd floor kitchen'
    },
    'lj3a' => {
        'location' => 'Building A, 3th floor kitchen',
        'model'    => 'hp-laserjet-600'
    },
    'lj2a' => {
        'model'    => 'hp-laserjet-600',
        'location' => 'Building A, 2nd floor kitchen'
    },
    'copy5c' => {
        'model'    => 'TA4505ci',
        'location' => 'Building C, 5th floor'
    },
    'lj3b' => {
        'model'    => 'hp-laserjet-p4515x',
        'location' => 'Building B, 3th floor, kitchen'
    },
    'lj-a302' => {
        'location' => 'Building A, 3th floor A302 LaSArIS',
        'model'    => 'hp-laserjet-600'
    },
    'copy4c' => {
        'model'    => 'TA4505ci',
        'location' => 'Building C, 4th floor'
    },
    'lj2b' => {
        'model'    => 'hp-laserjet-p3015',
        'location' => 'Building B, 2nd floor, kitchen'
    }
};

my $models = {
    'TA5007ci' => {
        'filters' => [ 'kyofilter_pre_E', 'kyofilter_E' ]
    },
    'TA4505ci' => {
        'filters' => ['kyofilter_B']
    }
};

## END OF DATA ##

sub get_description {
    my ($printer_name) = @_;
    return "$printer_name (FI MUNI)";
}

sub prompt_username {
    print "Enter username: ";
    chomp( my $username = <STDIN> );
    return $username;
}

sub prompt_password {
    print "Enter password: ";
    system("stty -echo");
    chomp( my $password1 = <STDIN> );
    system('stty echo');
    print "\nRepeat password: ";
    system('stty -echo');
    chomp( my $password2 = <STDIN> );
    system("stty echo");
    print "\n";

    if ( $password1 ne $password2 ) {
        say "Error: Passwords do not match!";
        exit 1;
    }
    return $password1;
}

sub get_url {
    my ($printer_name) = @_;
    my $user           = prompt_username();
    my $password       = prompt_password();

    return "smb://NTFI\\${user}:${password}\@print.fi.muni.cz/$printer_name";
}

sub hp_laserjet_600 {
    my ($printer_name) = @_;

    my $url = get_url($printer_name);

    my $command = qq(lpadmin \\
    -p "${printer_name}.fi.muni" \\
    -D "${printer_name} (FI MUNI)" \\
    -L "$printers->{$printer_name}->{'location'}" \\
    -E \\
    -v "${url}" \\
    -P "ppds/${printer_name}.ppd" \\
    -o media-default=iso_a4_210x297mm \\
    -o sides-default=two-sided-long-edge \\
    -o auth-info-required=username,password \\
           -o HPOption_Duplexer=True);    # REVIEW nevím jestli tohle je ok

    say $command;

    system($command);

    return;
}

sub TA_4505ci {
    my ($printer_name) = @_;
    my $url = get_url($printer_name);

# Add cups printer
# sudo lpadmin                              CLI CUPS administration
# -p "${printers[$printer]}"                Set printer name
# -D "${descriptions[$printer]}"            Set printer description
# -L "${locations[$printer]}"               Set printer location
# -E                                        Enables the destination and accepts jobs (cupsaccept+cupsenable)
# -v smb://print.fi.muni.cz/$printer        Set printer URI
# -m UTAX_TA/TA4505ci.ppd                   Set PPD file
# -o media-default=iso_a4_210x297mm         Set default paper format
# -o sides-default=two-sided-long-edge      Set two-sided as default
# -o auth-info-required=username,password   Enable password authentication
# -o Option19=One                           Cassettes 3, 4 installed
# -o Option21=True                          Punch unit installed
# -o Option17=DF730                         1000-page finisher installed

    my $command = qq(lpadmin \\
    -p "${printer_name}.fi.muni" \\
    -D "${printer_name} (FI MUNI)" \\
    -L "$printers->{$printer_name}->{'location'}" \\
    -E \\
    -v "${url}" \\
    -P "ppds/${printer_name}.ppd" \\
    -o media-default=iso_a4_210x297mm \\
    -o sides-default=two-sided-long-edge \\
    -o auth-info-required=username,password \\
    -o Option19=One \\
    -o Option21=True \\
    -o Option17=DF730);

    say $command;

    system($command);

    return;
}

sub generic_printer {
    my ($printer_name) = @_;
    my $url = get_url($printer_name);

    my $command = qq(lpadmin \\
    -p "${printer_name}.fi.muni" \\
    -D "${printer_name} (FI MUNI)" \\
    -L "$printers->{$printer_name}->{'location'}" \\
    -E \\
    -v "${url}" \\
    -P "ppds/${printer_name}.ppd" \\
    -o media-default=iso_a4_210x297mm \\
    -o sides-default=two-sided-long-edge \\
    -o auth-info-required=username,password);

    say $command;

    system($command);

    return;
}

sub copy_filter {
    ( my $filter ) = @_;

    # my $filter = "kyofilter_B";
    my $destination = "/usr/libexec/cups/filter/";
    $destination = "first/second/";

    if ( !-d $destination ) {
        my $dirs = eval { mkpath($destination) };
        die "Failed to create $destination $@\n" unless $dirs;
    }

    copy( "filters" . $filter, $destination )
      or die "Failed to copy $filter: $!\n";
    say "[OK] Copied $filter.";

    return;
}

sub print_printers() {
    say "Available printers:";
    printf "%-14s | %s\n", "Printer name", "Location";
    say "-" x 50;
    for ( sort keys %$printers ) {
        printf "%-14s | %s\n", $_, $printers->{$_}->{location};
    }
    return;
}

sub usage() {
    say "Script to install FI printers on linux. ";
    say "Requires local CUPS server running and SAMBA client installed.";
    say "usage: $0 <printer-name>";
    say "Must be run as root.";
    say
"Triumph-Adler 50007ci needs Python 2.7 as a dependency and will install 2 python modules automatically.";
    print "\n\n";
    print_printers();

    exit 1;
}

# NOTE SEEMS FIXED with $? == 0
sub check_python {
    my $regex =
      /^Python 2\.7*/;    #FIXME Use of unitialized value $_ in pattern match
    my $output = qx/python -V 2>&1/;

    if ( $? == 0 && $output =~ $regex ) {
        say "[OK] Python 2.7 is present.";
        return "python ";
    }
    else {
        # TODO FIXME ADD python2
        say "[ERROR] Python 2.7 is not present";

        # TRY python2 command
        my $s_output = qx/python2 -V 2>&1/;
        if ( $? == 0 && $s_output =~ $regex ) {
            say "ASI OK, TESTING NEEDED";    # TODO OTESTOVAT
            return "python2 ";
        }
        else {
            die "Python 2.7 Not Found and is needed for TA5007ci\n";
        }
    }
}

sub python_package {
    ( my $package_name, my $python ) = @_;

    say "[INFO] Installing $package_name";
    my $status = chdir "$package_name";
    if ( $status == 0 ) {
        say "[ERROR] folder $package_name is not present";
    }
    my $output = system("${python} setup.py install");
    if ( $? != 0 ) {
        croak "[ERROR] $package_name exited with different exit code than 0!";
    }
    $status = chdir '..';
    if ( $status == 0 ) {
        croak "[FATAL] Could not return to the working directory";
    }
    return;
}

sub pre_TA5007ci {
    my $python = check_python;
    python_package( "PyPDF2-1.26.0", $python );
    python_package( "reportlab",     $python );
    return;
}

#######################
# START OF THE SCRIPT #
#######################

# TODO restructure this mess
# TODO put this as static data and not yml

if ( @ARGV == 0 || $ARGV[0] eq "-h" || $ARGV[0] eq "--help" ) {
    usage;
}

if ( @ARGV != 1 ) {
    usage;
}

my ($printer_name) = @ARGV;

# Check for smbclient
my $output = `which smbclient >/dev/null 2>/dev/null`;
if ( $? != 0 ) {
    say "Samba client seems not to be installed. (smbclinet)";
    exit 1;
}

if ( not( exists( $printers->{$printer_name} ) ) ) {
    say "Printer $printer_name is not supported.";
    print_printers();
    exit 1;
}

# Check if we have Root
die "Must be run with root privileges\n" if $> != 0;

say $printers->{$printer_name}->{'model'};
my $model = $printers->{$printer_name}->{'model'};

if ( $model eq "TA5007ci" ) {
    pre_TA5007ci();
}

if ( $model eq "TA4505ci" ) {
    TA_4505ci("$printer_name");
}
elsif ( $model eq "hp-laserjet-600" ) {
    hp_laserjet_600 $printer_name;
}
else {
    generic_printer("$printer_name");
}

# NOTE there was a problem before //  THIS DOESNT WORK?
foreach ( $models->{$model}->{'filters'} ) {
    foreach (@$_) {
        say $_;
    }
}

say "DONE!";

# hp_laserjet_600($printer_name);
