<commit_before>﻿/*
 * Copyright (C) 2018  <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 * All we ask is that proper credit is given for our work, which includes
 * - but is not limited to - adding the above copyright notice to the beginning
 * of your source code files, and to any copyright notice that you may distribute
 * with programs based on this work.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT Any WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

using NCDK.Aromaticities;
using NCDK.Geometries;
using NCDK.Graphs.InChI;
using NCDK.Isomorphisms;
using NCDK.Isomorphisms.Matchers;
using NCDK.Layout;
using NCDK.Renderers;
using NCDK.Renderers.Colors;
using NCDK.Smiles;
using NCDK.Tools.Manipulator;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using WPF = System.Windows;

namespace NCDK.MolViewer
{
    partial class AppearanceViewModel 
        : BindableBase
    {
        private static readonly IChemObjectBuilder builder = CDK.Builder;
        private static StructureDiagramGenerator sdg = new StructureDiagramGenerator();
        private static SmilesParser parser = new SmilesParser(builder);
        private static SmilesGenerator smilesGenerator = new SmilesGenerator(SmiFlavors.Default);

        private string _Smiles = null;
        private IChemObject _ChemObject = null;
        private ColoringStyle _Coloring = ColoringStyle.COW;
        private DelegateCommand _CleanStructureCommand;
        private DelegateCommand _PasteAsInChICommand;
        private DelegateCommand _SanitizeCommand;

        public string Smiles
        {
            get { return _Smiles; }

            set
            {
                if (this._Smiles != value)
                {
                    var text = value;
                    if (string.IsNullOrWhiteSpace(text))
                        return;

                    IChemObject o;

                    if (IsReactionSmilees(text))
                    {
                        IReaction rxn = null;
                        try
                        {
                            rxn = parser.ParseReactionSmiles(text);
                        }
                        catch (Exception)
                        {
                            // ignore
                        }

                        o = rxn;
                    }
                    else
                    {
                        IAtomContainer mol = null;
                        try
                        {
                            mol = parser.ParseSmiles(text);
                        }
                        catch (Exception)
                        {
                            // ignore
                        }

                        o = mol;
                    }

                    if (o != null)
                    {
                        _ChemObject = o;
                        this.RaisePropertyChanged(nameof(ChemObject));
                    }

                    this.SetProperty(ref this._Smiles, text);
                }
            }
        }

        public IChemObject ChemObject
        {
            get => _ChemObject;
            set
            {
                switch (value)
                {
                    case IAtomContainer mol:
                        if (!GeometryUtil.Has2DCoordinates(mol))
                        {
                            mol = (IAtomContainer)mol.Clone();
                            sdg.GenerateCoordinates(mol);
                            value = mol;
                        }
                        break;
                    case IReaction rxn:
                        if (!GeometryUtil.Has2DCoordinates(rxn))
                        {
                            rxn = (IReaction)rxn.Clone();
                            sdg.GenerateCoordinates(rxn);
                            value = rxn;
                        }
                        break;
                    default:
                        break;<commit_msg>Add perceive dative bonds for MolViewer.<commit_after>﻿/*
 * Copyright (C) 2018  <NAME> <<EMAIL>>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 * All we ask is that proper credit is given for our work, which includes
 * - but is not limited to - adding the above copyright notice to the beginning
 * of your source code files, and to any copyright notice that you may distribute
 * with programs based on this work.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT Any WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

using NCDK.Aromaticities;
using NCDK.Geometries;
using NCDK.Graphs.InChI;
using NCDK.Isomorphisms;
using NCDK.Isomorphisms.Matchers;
using NCDK.Layout;
using NCDK.Renderers;
using NCDK.Renderers.Colors;
using NCDK.Smiles;
using NCDK.Tools;
using NCDK.Tools.Manipulator;
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using WPF = System.Windows;

namespace NCDK.MolViewer
{
    partial class AppearanceViewModel 
        : BindableBase
    {
        private static readonly IChemObjectBuilder builder = CDK.Builder;
        private static StructureDiagramGenerator sdg = new StructureDiagramGenerator();
        private static SmilesParser parser = new SmilesParser(builder);
        private static SmilesGenerator smilesGenerator = new SmilesGenerator(SmiFlavors.Default);

        private string _Smiles = null;
        private IChemObject _ChemObject = null;
        private ColoringStyle _Coloring = ColoringStyle.COW;
        private DelegateCommand _CleanStructureCommand;
        private DelegateCommand _PasteAsInChICommand;
        private DelegateCommand _SanitizeCommand;

        public string Smiles
        {
            get { return _Smiles; }

            set
            {
                if (this._Smiles != value)
                {
                    var text = value;
                    if (string.IsNullOrWhiteSpace(text))
                        return;

                    IChemObject o;

                    if (IsReactionSmilees(text))
                    {
                        IReaction rxn = null;
                        try
                        {
                            rxn = parser.ParseReactionSmiles(text);
                            PerceiveDativeBonds(rxn);
                        }
                        catch (Exception)
                        {
                            // ignore
                        }

                        o = rxn;
                    }
                    else
                    {
                        IAtomContainer mol = null;
                        try
                        {
                            mol = parser.ParseSmiles(text);
                            PerceiveDativeBonds(mol);
                        }
                        catch (Exception)
                        {
                            // ignore
                        }

                        o = mol;
                    }

                    if (o != null)
                    {
                        _ChemObject = o;
                        this.RaisePropertyChanged(nameof(ChemObject));
                    }

                    this.SetProperty(ref this._Smiles, text);
                }
            }
        }

        private static int CalcValence(IAtom atom)
        {
            int v = atom.ImplicitHydrogenCount ?? 0;
            foreach (var bond in atom.Bonds)
            {
                var order = bond.Order;
                if (!order.IsUnset())
                    v += order.Numeric();
            }
            return v;
        }


        private static bool IsDativeDonor(IAtom a)
        {
            switch (a.AtomicNumber)
            {
                case 7:
                case 15:
                    return a.FormalCharge == 0 && CalcValence(a) == 4;
                case 8:
                    return a.FormalCharge == 0 && CalcValence(a) == 3;
                default:
                    return false;
            }
        }

        private static bool IsDativeAcceptor(IAtom a)
        {
            if (PeriodicTable.IsMetal(a.AtomicNumber))
                return true;
            switch (a.AtomicNumber)
            {
                case 5:
                    return a.FormalCharge == 0 && CalcValence(a) == 4;
                case 8:
                    return a.FormalCharge == 0 && CalcValence(a) == 1;
                default:
                    return false;
            }
        }

        private static bool IsChargedDativeDonor(IAtom a)
        {
            switch (a.AtomicNumber)
            {
                case 7:
                case 15:
                    return a.FormalCharge == +1 && CalcValence(a) == 4;
                case 8:
                    return a.FormalCharge == +1 && CalcValence(a) == 3;
                default:
                    return false;
            }
        }

        private static bool IsChargedDativeAcceptor(IAtom a)
        {
            if (a.FormalCharge != -1)
                return false;
            if (PeriodicTable.IsMetal(a.AtomicNumber))
                return true;
            switch (a.AtomicNumber)
            {
                case 5:
                    return CalcValence(a) == 4;
                case 8:
                    return CalcValence(a) == 1;
                default:
                    return false;
            }
        }

        private static void PerceiveDativeBonds(IAtomContainer mol)
        {
            foreach (var bond in mol.Bonds)
            {
                var beg = bond.Begin;
                var end = bond.End;
                if (IsDativeDonor(end) && IsDativeAcceptor(beg))
                {
                    bond.Display = BondDisplay.ArrowBegin;
                }
                else if (IsDativeDonor(beg) && IsDativeAcceptor(end))
                {
                    bond.Display = BondDisplay.ArrowEnd;
                    //bond.setOrder(IBond.Order.UNSET);
                }
                else if (IsChargedDativeDonor(end) && IsChargedDativeAcceptor(beg))
                {
                    bond.Display = BondDisplay.ArrowBegin;
                    //bond.setOrder(IBond.Order.UNSET);
                }
                else if (IsChargedDativeDonor(beg) && IsChargedDativeAcceptor(end))
                {
                    bond.Display = BondDisplay.ArrowEnd;
                    //bond.setOrder(IBond.Order.UNSET);
                }
            }
            foreach (var bond in mol.Bonds)
            {
                var beg = bond.Begin;
                var end = bond.End;
                if (bond.Display == BondDisplay.ArrowBegin
                 || bond.Display == BondDisplay.ArrowEnd)
                {
                    beg.FormalCharge = 0;
                    end.FormalCharge = 0;
                }
            }
        }

        private static void PerceiveDativeBonds(IReaction reaction)
        {
            foreach (var mol in ReactionManipulator.GetAllMolecules(reaction))
            {
                PerceiveDativeBonds(mol);
            }
        }

        public IChemObject ChemObject
        {
            get => _ChemObject;
            set
            {
                switch (value)
                {
                    case IAtomContainer mol:
                        if (!GeometryUtil.Has2DCoordinates(mol))
                        {
                            mol = (IAtomContainer)mol.Clone();
                            sdg.GenerateCoordinates(mol);
                            value = mol;
                        }
                        break;
                    case IReaction rxn:
                        if (!GeometryUtil.Has2DCoordinates(rxn))
                        {
                            rxn = (IReaction)rxn.Clone();
                            sdg.GenerateCoordinates(rxn);
                            value = rxn;
                        }
                        break;
                    default:
                        break;
{'fraction_non_alphanumeric': 0.06544912411479686, 'fraction_numerical': 0.0050689526649273205, 'mean_word_length': 1.1684176499111039, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2208232', 'n_tokens_mistral': 3433, 'n_tokens_neox': 3160, 'n_words': 899}