<commit_before>﻿using ARKBreedingStats.Library;
using ARKBreedingStats.species;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace ARKBreedingStats.uiControls
{
    public static class NamePatterns
    {
        /// <summary>
        /// Generates a creature name with a given pattern
        /// </summary>
        public static string generateCreatureName(Creature creature, List<Creature> females, List<Creature> males)
        {
            //try
            //{
            // collect creatures of the same species
            List<Creature> sameSpecies = (females ?? new List<Creature>()).Concat(males ?? new List<Creature>()).ToList();
            List<string> creatureNames = sameSpecies.Select(x => x.name).ToList();

            Dictionary<string, string> tokenDictionary = CreateTokenDictionary(creature, sameSpecies);
            string resolvedPattern = ResolveConditions(creature, Properties.Settings.Default.sequentialUniqueNamePattern);
            string name = AssemblePatternedName(tokenDictionary, resolvedPattern);

            if (name.Contains("{n}"))
            {
                // find the sequence token, and if not, return because the configurated pattern string is invalid without it
                int index = name.IndexOf("{n}", StringComparison.OrdinalIgnoreCase);
                string patternStart = name.Substring(0, index);
                string patternEnd = name.Substring(index + 3);

                // loop until we find a unique name in the sequence which is not taken

                int n = 1;
                do
                {
                    name = string.Concat(patternStart, (n < 10 ? "0" : "") + n, patternEnd);
                    n++;
                } while (creatureNames.Contains(name, StringComparer.OrdinalIgnoreCase));
            }

            if (creatureNames.Contains(name, StringComparer.OrdinalIgnoreCase))
            {
                MessageBox.Show("WARNING: The generated name for the creature already exists in the database.");
            }
            else if (name.Length > 24)
            {
                MessageBox.Show("WARNING: The generated name is longer than 24 characters, ingame-preview:" + name.Substring(0, 24));
            }

            return name;
            //}
            //catch
            //{
            //    MessageBox.Show("There was an error while generating the creature name.");
            //}
            //return "";
        }

        /// <summary>
        /// If a pattern contains conditional expressions, resolve them.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="sequentialUniqueNamePattern"></param>
        /// <returns></returns>
        private static string ResolveConditions(Creature creature, string pattern)
        {
            // a conditional expression looks like {{#if:conditional-keyword|result if true|result if false}}, e.g. {{#if:IsTopHP|{HP}H}}

            Regex r = new Regex(@"\{\{#if: *(istop\w+) *\| *([^\|]+?)(?: *\| *(.+?))? *\}\}", RegexOptions.IgnoreCase);
            return r.Replace(pattern, (m) => ResolveCondition(creature, m));
        }

        private static string ResolveCondition(Creature c, Match m)
        {
            // Group1 contains the condition
            // Group2 contains the result if true
            // Group3 (optional) contains the result if false
            if (m.Groups[1].Value.Substring(0, 5).ToLower() == "istop")
            {
                int si = StatIndexFromAbbreviation(m.Groups[1].Value.Substring(5, 2));
                if (si == -1) return string.Empty;
                return m.Groups[c.topBreedingStats[si] ? 2 : 3].Value;
            }
            return string.Empty;

        }

        private static int StatIndexFromAbbreviation(string statAb)
        {
            switch (statAb)
            {
                case "hp": return (int)StatNames.Health;
                case "st": return (int)StatNames.Stamina;
                case "ox": return (int)StatNames.Oxygen;
                case "fo": return (int)StatNames.Food;
                case "we": return (int)StatNames.Weight;
                case "dm": return (int)StatNames.MeleeDamageMultiplier;
                case "sp": return (int)StatNames.SpeedMultiplier;
                case "to": return (int)StatNames.Torpidity;
                case "wa": return (int)StatNames.Water;<commit_msg>another casing fix.<commit_after>﻿using ARKBreedingStats.Library;
using ARKBreedingStats.species;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace ARKBreedingStats.uiControls
{
    public static class NamePatterns
    {
        /// <summary>
        /// Generates a creature name with a given pattern
        /// </summary>
        public static string generateCreatureName(Creature creature, List<Creature> females, List<Creature> males)
        {
            //try
            //{
            // collect creatures of the same species
            List<Creature> sameSpecies = (females ?? new List<Creature>()).Concat(males ?? new List<Creature>()).ToList();
            List<string> creatureNames = sameSpecies.Select(x => x.name).ToList();

            Dictionary<string, string> tokenDictionary = CreateTokenDictionary(creature, sameSpecies);
            string resolvedPattern = ResolveConditions(creature, Properties.Settings.Default.sequentialUniqueNamePattern);
            string name = AssemblePatternedName(tokenDictionary, resolvedPattern);

            if (name.Contains("{n}"))
            {
                // find the sequence token, and if not, return because the configurated pattern string is invalid without it
                int index = name.IndexOf("{n}", StringComparison.OrdinalIgnoreCase);
                string patternStart = name.Substring(0, index);
                string patternEnd = name.Substring(index + 3);

                // loop until we find a unique name in the sequence which is not taken

                int n = 1;
                do
                {
                    name = string.Concat(patternStart, (n < 10 ? "0" : "") + n, patternEnd);
                    n++;
                } while (creatureNames.Contains(name, StringComparer.OrdinalIgnoreCase));
            }

            if (creatureNames.Contains(name, StringComparer.OrdinalIgnoreCase))
            {
                MessageBox.Show("WARNING: The generated name for the creature already exists in the database.");
            }
            else if (name.Length > 24)
            {
                MessageBox.Show("WARNING: The generated name is longer than 24 characters, ingame-preview:" + name.Substring(0, 24));
            }

            return name;
            //}
            //catch
            //{
            //    MessageBox.Show("There was an error while generating the creature name.");
            //}
            //return "";
        }

        /// <summary>
        /// If a pattern contains conditional expressions, resolve them.
        /// </summary>
        /// <param name="creature"></param>
        /// <param name="sequentialUniqueNamePattern"></param>
        /// <returns></returns>
        private static string ResolveConditions(Creature creature, string pattern)
        {
            // a conditional expression looks like {{#if:conditional-keyword|result if true|result if false}}, e.g. {{#if:IsTopHP|{HP}H}}

            Regex r = new Regex(@"\{\{#if: *(istop\w+) *\| *([^\|]+?)(?: *\| *(.+?))? *\}\}", RegexOptions.IgnoreCase);
            return r.Replace(pattern, (m) => ResolveCondition(creature, m));
        }

        private static string ResolveCondition(Creature c, Match m)
        {
            // Group1 contains the condition
            // Group2 contains the result if true
            // Group3 (optional) contains the result if false
            string conditional = m.Groups[1].Value.ToLower();
            if (conditional.Substring(0, 5) == "istop")
            {
                int si = StatIndexFromAbbreviation(conditional.Substring(5, 2));
                if (si == -1) return string.Empty;
                return m.Groups[c.topBreedingStats[si] ? 2 : 3].Value;
            }
            return string.Empty;

        }

        private static int StatIndexFromAbbreviation(string statAb)
        {
            switch (statAb)
            {
                case "hp": return (int)StatNames.Health;
                case "st": return (int)StatNames.Stamina;
                case "ox": return (int)StatNames.Oxygen;
                case "fo": return (int)StatNames.Food;
                case "we": return (int)StatNames.Weight;
                case "dm": return (int)StatNames.MeleeDamageMultiplier;
                case "sp": return (int)StatNames.SpeedMultiplier;
                case "to": return (int)StatNames.Torpidity;
                case "wa": return (int)StatNames.Water;
{'fraction_non_alphanumeric': 0.1145418326693227, 'fraction_numerical': 0.005422753430721558, 'mean_word_length': 1.9227037516170764, 'pattern_counts': {'":': 18, '<': 39, '<?xml version=': 0, '>': 43, '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': '813374', 'n_tokens_mistral': 2421, 'n_tokens_neox': 2280, 'n_words': 614}