#! /bin/sh
#!perl -w # --*- Perl -*--
eval 'exec perl -x $0 ${1+"$@"}'
    if 0;
#------------------------------------------------------------------------------
#$Author: Yaroslav_Rozdobudko $
#$Revision: 10533 $
#$URL: svn+ssh://www.crystallography.net/home/coder/svn-repositories/cod-tools/tags/v3.11.0/scripts/cif2qg $
#$Date: 2025-03-04 10:46:30 +0200 (Tue, 04 Mar 2025) $
#------------------------------------------------------------------------------
#*
#* Parse CIF file and print out the quotient graph.
#*
#* USAGE:
#*    $0 [options] input.cif [input2.cif ...]
#**

use strict;
use warnings;

use COD::CIF::Parser qw( parse_cif );
use COD::CIF::Tags::CanonicalNames qw( canonicalize_all_names );
use COD::UserMessage qw( error );
use COD::SOptions qw( getOptions );
use COD::SUsage qw( usage options );
use COD::ToolsVersion qw( get_version_string );

use Graph::Easy;

sub extract_atom_symbol {
    my ($atom_label) = @_;
    if ($atom_label =~ /^([A-Za-z]+)/) {
        return $1;
    }
    return $atom_label;
}

my $use_parser = 'c';
my $output_format = 'dot';

@ARGV = getOptions(

#* OPTIONS:
#*
#*   --use-c-parser
#*                     Use Perl & C parser for CIF parsing. Default.
#*   --use-perl-parser
#*                     Use Perl parser for CIF parsing.
#*   --dot-output
#*                     Output as graphviz graph in dot format. Default.
#*   --ascii-output
#*                     Output as ascii.
#*   --txt-output
#*                     Output as txt.
#*   --svg-output
#*                     Output as svg.
#*   --boxart-output
#*                     Output as boxart.
#*   --html-output
#*                     Output as html.
#*   --cgd-output
#*                     Output as cgd format, needed by Systre.
#*   --help, --usage
#*                     Output a short usage message (this message) and exit.
#*   --version
#*                     Output version information and exit.
#**

    '--use-perl-parser' => sub { $use_parser = 'perl' },
    '--use-c-parser'    => sub { $use_parser = 'c' },
    '--dot-output'      => sub { $output_format = 'dot' },
    '--ascii-output'    => sub { $output_format = 'ascii' },
    '--txt-output'      => sub { $output_format = 'txt' },
    '--svg-output'      => sub { $output_format = 'svg' },
    '--boxart-output'   => sub { $output_format = 'boxart' },
    '--html-output'     => sub { $output_format = 'html' },
    '--cgd-output'      => sub { $output_format = 'cgd' },
    '--help,--usage'    => sub { usage(); exit },
    '--version'         => sub { print get_version_string(), "\n"; exit },
);

@ARGV = ( '-' ) unless @ARGV;

binmode STDOUT, ':encoding(UTF-8)';
binmode STDERR, ':encoding(UTF-8)';

my %jmol_colors = (
    'H'  => '#FFFFFF',
    'He' => '#D9FFFF',
    'Li' => '#CC80FF',
    'Be' => '#C2FF00',
    'B'  => '#FFB5B5',
    'C'  => '#909090',
    'N'  => '#3050F8',
    'O'  => '#FF0D0D',
    'F'  => '#90E050',
    'Ne' => '#B3E3F5',
    'Na' => '#AB5CF2',
    'Mg' => '#8AFF00',
    'Al' => '#BFA6A6',
    'Si' => '#F0C8A0',
    'P'  => '#FF8000',
    'S'  => '#FFFF30',
    'Cl' => '#1FF01F',
    'Ar' => '#80D1E3',
    'K'  => '#8F40D4',
    'Ca' => '#3DFF00',
    'Sc' => '#E6E6E6',
    'Ti' => '#BFC2C7',
    'V'  => '#A6A6AB',
    'Cr' => '#8A99C7',
    'Mn' => '#9C7AC7',
    'Fe' => '#E06633',
    'Co' => '#F090A0',
    'Ni' => '#50D050',
    'Cu' => '#C88033',
    'Zn' => '#7D80B0',
    'Ga' => '#C28F8F',
    'Ge' => '#668F8F',
    'As' => '#BD80E3',
    'Se' => '#FFA100',
    'Br' => '#A62929',
    'Kr' => '#5CB8D1',
    'Rb' => '#702EB0',
    'Sr' => '#00FF00',
    'Y'  => '#94FFFF',
    'Zr' => '#94E0E0',
    'Nb' => '#73C2C9',
    'Mo' => '#54B5B5',
    'Tc' => '#3B9E9E',
    'Ru' => '#248F8F',
    'Rh' => '#0A7D8C',
    'Pd' => '#006985',
    'Ag' => '#C0C0C0',
    'Cd' => '#FFD98F',
    'In' => '#A67573',
    'Sn' => '#668080',
    'Sb' => '#9E63B5',
    'Te' => '#D47A00',
    'I'  => '#940094',
    'Xe' => '#429EB0',
    'Cs' => '#57178F',
    'Ba' => '#00C900',
    'La' => '#70D4FF',
    'Ce' => '#FFFFC7',
    'Pr' => '#D9FFC7',
    'Nd' => '#C7FFC7',
    'Pm' => '#A3FFC7',
    'Sm' => '#8FFFC7',
    'Eu' => '#61FFC7',
    'Gd' => '#45FFC7',
    'Tb' => '#30FFC7',
    'Dy' => '#1FFFC7',
    'Ho' => '#00FF9C',
    'Er' => '#00E675',
    'Tm' => '#00D452',
    'Yb' => '#00BF38',
    'Lu' => '#00AB24',
    'Hf' => '#4DC2FF',
    'Ta' => '#4DA6FF',
    'W'  => '#2194D6',
    'Re' => '#267DAB',
    'Os' => '#266696',
    'Ir' => '#175487',
    'Pt' => '#D0D0E0',
    'Au' => '#FFD123',
    'Hg' => '#B8B8D0',
    'Tl' => '#A6544D',
    'Pb' => '#575961',
    'Bi' => '#9E4FB5',
    'Po' => '#AB5C00',
    'At' => '#754F45',
    'Rn' => '#428296',
    'Fr' => '#420066',
    'Ra' => '#007D00',
    'Ac' => '#70ABFA',
    'Th' => '#00BAFF',
    'Pa' => '#00A1FF',
    'U'  => '#008FFF',
    'Np' => '#0080FF',
    'Pu' => '#006BFF',
    'Am' => '#545CF2',
    'Cm' => '#785CE3',
    'Bk' => '#8A4FE3',
    'Cf' => '#A136D4',
    'Es' => '#B31FD4',
    'Fm' => '#B31FBA',
    'Md' => '#B30DA6',
    'No' => '#BD0D87',
    'Lr' => '#C70066',
    'Rf' => '#CC0059',
    'Db' => '#D1004F',
    'Sg' => '#D90045',
    'Bh' => '#E00038',
    'Hs' => '#E6002E',
    'Mt' => '#EB0026'
);

for my $filename (@ARGV) {

    my $options = { 'parser' => $use_parser, 'no_print' => 1 };
    my ( $data, $err_count, $messages ) = parse_cif( $filename, $options );

    if( $err_count > 0 ) {
        print STDERR $_ foreach ( @{$messages} );
        error( {
            'program'  => $0,
            'filename' => $filename,
            'message'  =>
                "$err_count error(s) encountered while parsing the file"
        } );
        next;
    }

    canonicalize_all_names( $data, $options );

    foreach( @{$data} ) {
        next unless exists $_->{values}{'_topol_net.id'};

        my $graph = Graph::Easy->new();
        $graph->strict( undef );
        $graph->{gid} = $_->{name};
        my @topol_atom_labels = @{ $_->{values}{'_topol_atom.atom_label'} };
        my @topol_atom_node_ids = @{ $_->{values}{'_topol_atom.node_id'} };
        my @topol_atom_symbols = @{ $_->{values}{'_topol_atom.element_symbol'} };
        my %node_id_label;
        my %node_id_symbol;

        for my $i ( 0..$#topol_atom_labels ) {
            my $atom_label = $topol_atom_labels[$i];
            my $atom_node_id = $topol_atom_node_ids[$i];
            my $atom_symbol = $topol_atom_symbols[$i];
            $node_id_label{$atom_node_id} = $atom_label;
            $node_id_symbol{$atom_symbol} = $atom_symbol;

            my $color = $jmol_colors{$atom_symbol} || '#000000';
            my $node = $graph->add_node( $atom_label );

            $node->set_attribute( 'shape', 'circle' );
            $node->set_attribute( 'style', 'filled' );
            $node->set_attribute( 'fillcolor', $color );
            $node->set_attribute( 'fixedsize', 'true' );
        }

        my $topol_link_node_id_1 =
                                $_->{values}{'_topol_link.node_id_1'};
        my $topol_link_node_id_2 =
                                $_->{values}{'_topol_link.node_id_2'};
        my $topol_link_translation_x =
                                $_->{values}{'_topol_link.translation_2_x'};
        my $topol_link_translation_y =
                                $_->{values}{'_topol_link.translation_2_y'};
        my $topol_link_translation_z =
                                $_->{values}{'_topol_link.translation_2_z'};

        for my $i ( 0..$#$topol_link_node_id_1 ) {
            my $node_id_1 = $topol_link_node_id_1->[$i];
            my $node_id_2 = $topol_link_node_id_2->[$i];
            my $translation_x = $topol_link_translation_x->[$i];
            my $translation_y = $topol_link_translation_y->[$i];
            my $translation_z = $topol_link_translation_z->[$i];

            if ( $translation_x == 0 &&
                 $translation_y == 0 &&
                 $translation_z == 0) {
                my $edge = $graph->add_edge(
                                $node_id_label{$node_id_1},
                                $node_id_label{$node_id_2}
                            );
                $edge->set_attribute('arrowstyle', 'none');
            } else {
                $graph->add_edge(
                            $node_id_label{$node_id_1},
                            $node_id_label{$node_id_2},
                            "$translation_x,$translation_y,$translation_z"
                        );
            }
        }
        if ( $output_format eq 'dot' ) {
            print $graph->as_graphviz();
        } elsif ( $output_format eq 'ascii' ) {
            print $graph->as_ascii();
        } elsif ( $output_format eq 'txt' ) {
            print $graph->as_txt();
        } elsif ( $output_format eq 'svg' ) {
            print $graph->as_svg();
        } elsif ( $output_format eq 'boxart' ) {
            print $graph->as_boxart();
        } elsif ( $output_format eq 'html' ) {
            print $graph->as_html();
        } elsif ( $output_format eq 'cgd' ) {
            my $id = $_->{name};
            my @cgd_lines = ('PERIODIC_GRAPH', "ID $id", 'EDGES');
            for my $i (0..$#$topol_link_node_id_1) {
                my $x = $topol_link_translation_x->[$i];
                my $y = $topol_link_translation_y->[$i];
                my $z = $topol_link_translation_z->[$i];

                push @cgd_lines,
                     '  ' .
                     $topol_link_node_id_1->[$i] . ' ' .
                     $topol_link_node_id_2->[$i] . ' ' .
                     "$x $y $z";
            }
            push @cgd_lines, "END\n";
            my $cgd_file = join "\n", @cgd_lines;

            print $cgd_file;
        } else {
            warn "WARNING, unsupported output format\n";
        }
    }
}
