#!/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;

# use File::Chmod qw(chmod);

# 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'],
        'options' => [ 'Option19=One', 'Option21=True', 'Option17=DF730' ]
    },
    'hp-laserjet-600' => {
        'options' => ['HPOption_Duplexer=True'],
    }
};

## END OF DATA ##

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

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

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

    if ( $password1 ne $password2 ) {
        die "[ERROR] Passwords do not match!";
    }
    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 install_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);

    foreach ( $models->{ $printers->{$printer_name}->{'model'} }->{'options'} )
    {
        $command = $command . ' -o $_ ';
    }

    system($command);

    return;
}

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

    my $destination = "/usr/lib/cups/filter/";

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

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

    chmod( 755, $destination . $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 ";
    say "and will install 2 python modules automatically.";
    print "\n\n";
    print_printers();

    exit 1;
}

sub check_python {
    my $regex  = qr/^Python 2\.7*/;
    my $output = qx/python -V 2>&1/;

    if ( $? == 0 && $output =~ $regex ) {
        say "[OK] Python 2.7 is present.";
        return "python ";
    }

    # 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 "[OK] Python 2.7 is present as python2";    # TODO OTESTOVAT
        return "python2 ";
    }

    die "[ERROR] 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 ) {
        die "[ERROR] folder $package_name is not present";
    }
    my $output = system("${python} setup.py install");
    if ( $? != 0 ) {
        die "[ERROR] $package_name exited with different exit code than 0!";
    }
    $status = chdir '..';
    if ( $status == 0 ) {
        die "[ERROR] 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 #
#######################

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 ) {
    die "[ERROR] Samba client seems not to be installed. (smbclinet)";
}

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

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

my $model = $printers->{$printer_name}->{'model'};
say "[INFO] Selected model is $model";

#TA5007ci requires python2 reportlab and PyPDF2
if ( $model eq "TA5007ci" ) {
    pre_TA5007ci();
}

# NOTE This could be written better but idk how
foreach ( $models->{$model}->{'filters'} ) {
    foreach (@$_) {
        copy_filter($_);
    }
}

install_printer("$printer_name");

say "[INFO] Installation is completed";
say "You may alter the printer settings in cups interface.";    # NOTE usefull?

# hp_laserjet_600($printer_name);
