#!/usr/bin/perl

use strict;
use warnings;

use Chemistry::OpenSMILES qw( is_chiral mirror );
use File::Basename qw( basename );
use Getopt::Long::Descriptive;
use List::Util qw( none );
use SmilesScripts::Isomorphism;

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

DESCRIPTION
    $basename reads in files with SMILES descriptors and outputs whether
    they qualify as racemates or not.

END
    [ 'check-isomorphism',
      'perform an extra isomorphism check on molecular entities detected ' .
      'as isomorphic by comparing their canonical representations' ],
    [],
    [ 'help', 'print usage message and exit', { shortcircuit => 1 } ],
);

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

my $pair_moieties_options = { check_isomorphism => $opt->check_isomorphism };

while( <> ) {
    chomp;

    my $additional_position = '';
    if( s/\t([^\t]*)$// ) {
        $additional_position = ' ' . $1;
    }

    local $SIG{__WARN__} = sub {
        print STDERR "$basename: $ARGV($.)$additional_position: $_[0]"
    };

    my @moieties;
    eval {
        @moieties = @{ SmilesScripts::Isomorphism::parse_smiles( $_ ) };
    };
    print STDERR "$basename: $ARGV($.) $additional_position: $@" if $@;

    my $total = scalar @moieties;
    my $n_achiral     = 0;
    my $n_self_mirror = 0;
    my $n_enantiomers = 0;
    my $n_enantiopure = 0;

    @moieties = grep { is_chiral( $_ ) } @moieties;
    $n_achiral = $total - @moieties;

    eval {
        for my $moiety (@moieties) {
            my @A;
            my @B;

            # Check for self-chiral moieties
            @A = SmilesScripts::Isomorphism::copy_moiety( $moiety );
            @B = SmilesScripts::Isomorphism::copy_moiety( $moiety );
            mirror $B[0];
            SmilesScripts::Isomorphism::pair_moieties( \@A, \@B, $pair_moieties_options );
            if( !@A && !@B ) {
                $n_self_mirror++;
                next;
            }

            @A = @moieties;
            @B = SmilesScripts::Isomorphism::copy_moiety( $moiety );
            mirror $B[0];
            SmilesScripts::Isomorphism::pair_moieties( \@A, \@B, $pair_moieties_options );
            if( @B ) { # Mirrored moiety is not found among declared moieties
                $n_enantiopure++;
            } else {
                $n_enantiomers++;
            }
        }
    };
    print STDERR "$basename: $ARGV($.) $additional_position: $@" if $@;

    my @results;
    push @results, "achiral ($n_achiral)"         if $n_achiral;
    push @results, "self-mirror ($n_self_mirror)" if $n_self_mirror;
    push @results, "enantiomer ($n_enantiomers)"  if $n_enantiomers;
    push @results, "enantiopure ($n_enantiopure)" if $n_enantiopure;
    print join( ' ', sort @results ), "\n";
}
