#!/usr/bin/perl

use strict;
use warnings;

# VERSION

use ChemOnomatopist;
use File::Basename qw( basename );
use Getopt::Long::Descriptive;
use List::Util qw( sum );

=head1 NAME

chemonomatopist - derive IUPAC systematic names for chemical structures

=head1 SYNOPSYS

chemonomatopist [args] [files]

=head1 DESCRIPTION

ChemOnomatopist analyses chemical graphs to determine IUPAC names according to the "Nomenclature of Organic Chemistry. IUPAC Recommendations and Preferred Names 2013", also known as the Blue Book.

=cut

my $basename = basename $0;
my( $opt, $usage ) = describe_options( <<"END" . 'OPTIONS',
USAGE
    $basename [<args>] [<files>]

DESCRIPTION
    $basename derives IUPAC systematic names for chemical structures

END
    [ 'check', 'treat the input as list of SMILES and IUPAC names and check whether given and generated names match' ],
    [ 'opsin', 'along \'check\', attempt parsing own-generated IUPAC names with OPSIN (requires SmilesScripts::OPSIN Perl module)' ],
    [ 'isomorphism', 'along \'check\' and \'opsin\', perform isomorphism checks for nonmatching chemical names (requires SmilesScripts::Isomorphism Perl module)' ],
    [],
    [ 'cautious', 'avoid experimental features, refuse processing only partially supported compounds' ],
    [ 'debug', 'turn on the debug mode' ],
    [],
    [ 'help', 'print usage message and exit', { shortcircuit => 1 } ],
    [ 'version', 'print version and exit', { shortcircuit => 1 } ],
);

if( $opt->help ) {
    print $usage->text;
    exit;
}

if( $opt->version ) {
    print $ChemOnomatopist::VERSION, "\n";
    exit;
}

my $opsin;
if( $opt->opsin || $opt->isomorphism ) {
    require  SmilesScripts::OPSIN;
    $opsin = SmilesScripts::OPSIN->new;
}

$ChemOnomatopist::CAUTIOUS = 1 if $opt->cautious;
$ChemOnomatopist::DEBUG = 1    if $opt->debug;

my %counts = ( OK => 0, FAIL => 0, ERROR => 0 );

local $\ = "\n";
while (<>) {
    chomp;
    my( $id, $given_name, $SMILES );
    if( $opt->check ) {
        ( $id, $given_name, $SMILES ) = split "\t", $_;
    } else {
        $SMILES = $_;
    }

    my $derived_name;
    eval {
        $derived_name = ChemOnomatopist::get_name( $SMILES );
    };
    $@ =~ s/\n$// if $@;

    if( $opt->check ) {
        if( $@ ) {
            print $id, "\t", 'ERROR', "\t", $@;
            $counts{ERROR}++;
        } elsif( $given_name eq $derived_name ) {
            print $id, "\t", 'OK', "\t", $derived_name;
            $counts{OK}++;
        } elsif( $opt->isomorphism ) {
            require SmilesScripts::Isomorphism;
            my $SMILES_derived = $opsin->IUPAC_to_SMILES( "$derived_name" );
            if( !defined $SMILES_derived ) {
                print $id, "\t", 'MISPARSE', "\t", $derived_name;
                $counts{MISPARSE}++;
                next;
            }
            my  $reason = SmilesScripts::Isomorphism::smi_compare( $SMILES, $SMILES_derived );
            if( $reason eq 'isomorphic' ) {
                print $id, "\t", 'ALT', "\t", $given_name, "\t", $derived_name;
                $counts{ALT}++;
            } else {
                print $id, "\t", 'FAIL', "\t", $given_name, "\t", $derived_name;
                $counts{FAIL}++;
            }
        } elsif( $opt->opsin && !defined $opsin->IUPAC_to_SMILES( "$derived_name" ) ) {
            print $id, "\t", 'MISPARSE', "\t", $derived_name;
            $counts{MISPARSE}++;
        } else {
            print $id, "\t", 'FAIL', "\t", $given_name, "\t", $derived_name;
            $counts{FAIL}++;
        }
    } else {
        if( $@ ) {
            print STDERR $SMILES, "\t", $@;
        } else {
            print $SMILES, "\t", $derived_name;
        }
    }
}

if( $opt->check ) {
    print '';
    for (reverse sort keys %counts) {
        print "$_:\t", $counts{$_};
    }
    print "TOTAL:\t", sum values %counts;
}
