using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEditor.Localization;
using UnityEditorInternal;
using UnityEngine.Localization.Tables;
using System.Text.RegularExpressions;

namespace PixelCrushers.DialogueSystem.LocalizationPackageSupport
{

    /// <summary>
    /// Custom editor window to populate Localization Package string table with
    /// actor names and dialogue entry text. At runtime, DialogueSystemLocalizationPackageBridge
    /// will read localized values from string table.
    /// </summary>
    public class DialogueToLocalizationTableWindow : EditorWindow
    {

        [MenuItem("Tools/Pixel Crushers/Dialogue System/Third Party/Localization/Dialogue To Localization Table", false, 3)]
        public static void Init()
        {
            var window = EditorWindow.GetWindow(typeof(DialogueToLocalizationTableWindow), false, "DS To Loc") as DialogueToLocalizationTableWindow;
            window.minSize = new Vector2(300, 280);
        }

        private const string PrefsKey = "DialogueSystem.DSToLTPrefs";

        [Serializable]
        public class Prefs
        {
            public List<string> databaseGuids = new List<string>();
            public List<string> textTableGuids = new List<string>();
            public string localizationSettingsGuid;
            public string stringTableCollectionGuid;
            public string defaultLocaleGuid;
            public string guidFieldTitle = "Guid";
            public bool prependNamesToKey = false;
            public bool localizedFieldsToStringTable = false;
        }

        private Prefs prefs;
        private LocalizationSettings localizationSettings;
        private StringTableCollection stringTableCollection;
        private Locale defaultLocale;
        private List<DialogueDatabase> databases = new List<DialogueDatabase>();
        private List<TextTable> textTables = new List<TextTable>();
        private ReorderableList databasesList;
        private ReorderableList textTablesList;
        private Vector2 scrollPosition = Vector2.zero;

        private void OnEnable()
        {
            if (EditorPrefs.HasKey(PrefsKey))
            {
                prefs = JsonUtility.FromJson<Prefs>(EditorPrefs.GetString(PrefsKey));
            }
            if (prefs == null) prefs = new Prefs();

            databases.Clear();
            foreach (var databaseGuid in prefs.databaseGuids)
            {
                if (!string.IsNullOrEmpty(databaseGuid))
                {
                    var database = AssetDatabase.LoadAssetAtPath<DialogueDatabase>(AssetDatabase.GUIDToAssetPath(databaseGuid));
                    if (database != null)
                    {
                        databases.Add(database);
                    }
                }
            }
            textTables.Clear();
            foreach (var textTableGuid in prefs.textTableGuids)
            {
                if (!string.IsNullOrEmpty(textTableGuid))
                {
                    var textTable = AssetDatabase.LoadAssetAtPath<TextTable>(AssetDatabase.GUIDToAssetPath(textTableGuid));
                    if (textTable != null)
                    {
                        textTables.Add(textTable);
                    }
                }
            }
            localizationSettings = AssetDatabase.LoadAssetAtPath<LocalizationSettings>(AssetDatabase.GUIDToAssetPath(prefs.localizationSettingsGuid));
            stringTableCollection = AssetDatabase.LoadAssetAtPath<StringTableCollection>(AssetDatabase.GUIDToAssetPath(prefs.stringTableCollectionGuid));
            defaultLocale = AssetDatabase.LoadAssetAtPath<Locale>(AssetDatabase.GUIDToAssetPath(prefs.defaultLocaleGuid));
        }

        private void OnDisable()
        {
            prefs.databaseGuids.Clear();
            foreach (var database in databases)
            {
                prefs.databaseGuids.Add((database != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(database)) : string.Empty);
            }
            prefs.textTableGuids.Clear();
            foreach (var textTable in textTables)
            {
                prefs.textTableGuids.Add((textTable != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(textTable)) : string.Empty);
            }
            prefs.localizationSettingsGuid = (localizationSettings != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(localizationSettings)) : string.Empty;
            prefs.stringTableCollectionGuid = (stringTableCollection != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(stringTableCollection)) : string.Empty;
            prefs.defaultLocaleGuid = (defaultLocale != null) ? AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(defaultLocale)) : string.Empty;
            EditorPrefs.SetString(PrefsKey, JsonUtility.ToJson(prefs));
        }

        private void OnGUI()
        {
            try
            {
                scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
                if (databasesList == null)
                {
                    databasesList = new ReorderableList(databases, typeof(DialogueDatabase), true, true, true, true);
                    databasesList.drawHeaderCallback += OnDrawDatabasesListHeader;
                    databasesList.drawElementCallback += OnDrawDatabasesListElement;
                    databasesList.onAddCallback += OnAddDatabase;
                }
                databasesList.DoLayoutList();
                if (textTablesList == null)
                {
                    textTablesList = new ReorderableList(textTables, typeof(TextTable), true, true, true, true);
                    textTablesList.drawHeaderCallback += OnDrawTextTablesListHeader;
                    textTablesList.drawElementCallback += OnDrawTextTablesListElement;
                    textTablesList.onAddCallback += OnAddTextTable;
                }
                textTablesList.DoLayoutList();
                prefs.guidFieldTitle = EditorGUILayout.TextField(new GUIContent("Unique Field Title", "Field title to use/create in dialogue database to uniquely and persistently identify each Key in string table."), prefs.guidFieldTitle);
                prefs.prependNamesToKey = EditorGUILayout.Toggle(new GUIContent("Prepend Names", "Prepend names to localization key GUID."), prefs.prependNamesToKey);
                prefs.localizedFieldsToStringTable = EditorGUILayout.Toggle(new GUIContent("Export Localized Fields", "Export localized fields in dialogue database to string table."), prefs.localizedFieldsToStringTable);
                localizationSettings = EditorGUILayout.ObjectField("Localization Settings", localizationSettings, typeof(LocalizationSettings), false) as LocalizationSettings;
                stringTableCollection = EditorGUILayout.ObjectField("String Table", stringTableCollection, typeof(StringTableCollection), false) as StringTableCollection;
                defaultLocale = EditorGUILayout.ObjectField("Default Locale", defaultLocale, typeof(Locale), false) as Locale;
                EditorGUI.BeginDisabledGroup(!HasAnyDatabases() || stringTableCollection == null || defaultLocale == null || string.IsNullOrEmpty(prefs.guidFieldTitle));
                if (GUILayout.Button("Dialogue System To String Table"))
                {
                    CopyDialogueSystemToStringTable();
                }
                if (GUILayout.Button("String Table To Dialogue System"))
                {
                    CopyStringTableToDialogueSystem();
                }
                //--- Note: This is not accessible yet because stringTable.RemoveEntry()
                //--- appears to clear content but not actually delete entire entry.
                //if (GUILayout.Button(new GUIContent("Delete GUID Keys From String Table", "Delete all keys containing GUIDs from String Table.")))
                //{
                //    if (EditorUtility.DisplayDialog("Delete GUID Keys", "This will delete all keys from the Localization Package string table that appear to have GUIDs. This is usually only Dialogue System keys, but be careful in case other keys use GUIDs. Continue?", "OK", "Cancel"))
                //    {
                //        DeleteGuidKeysFromStringTable();
                //    }
                //}
                EditorGUI.EndDisabledGroup();
            }
            finally
            {
                EditorGUILayout.EndScrollView();
            }
        }

        private bool HasAnyDatabases()
        {
            return databases.Find(x => x != null) != null;
        }

        private void OnDrawDatabasesListHeader(Rect rect)
        {
            EditorGUI.LabelField(rect, "Databases");
        }

        private void OnDrawDatabasesListElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            if (!(0 <= index && index < databases.Count)) return;
            databases[index] = EditorGUI.ObjectField(rect, databases[index], typeof(DialogueDatabase), true) as DialogueDatabase;
        }

        private void OnAddDatabase(ReorderableList list)
        {
            databases.Add(null);
        }

        private void OnDrawTextTablesListHeader(Rect rect)
        {
            EditorGUI.LabelField(rect, "Text Tables");
        }

        private void OnDrawTextTablesListElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            if (!(0 <= index && index < textTables.Count)) return;
            textTables[index] = EditorGUI.ObjectField(rect, textTables[index], typeof(TextTable), true) as TextTable;
        }

        private void OnAddTextTable(ReorderableList list)
        {
            textTables.Add(null);
        }

        private void SaveStringTables()
        {
            EditorUtility.SetDirty(stringTableCollection);
            for (int i = 0; i < stringTableCollection.StringTables.Count; i++)
            {
                EditorUtility.SetDirty(stringTableCollection.StringTables[i]);
            }
            foreach (var database in databases) // Also save databases to save new GUIDs
            {
                EditorUtility.SetDirty(database);
            }
            AssetDatabase.SaveAssets();
        }

        private void CopyDialogueSystemToStringTable()
        {
            CopyDialogueDatabasesToStringTable();
            CopyTextTablesToStringTable();
            SaveStringTables();
        }

        private void CopyStringTableToDialogueSystem()
        {
            CopyStringTableToDialogueDatabases();
            CopyStringTableToTextTables();
        }

        private void CopyDialogueDatabasesToStringTable()
        {
            try
            {
                Undo.RecordObjects(new UnityEngine.Object[] { stringTableCollection.SharedData, stringTableCollection }, "Modified table");

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                var hasRecordedDatabaseUndo = false;
                float total = 0;
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    total += database.actors.Count + database.conversations.Count;
                    var quests = database.items.FindAll(x => !x.IsItem);
                    total += quests.Count;
                }
                int progress = 0;

                // Actor display names:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var actor in database.actors)
                    {
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", actor.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        if (IsActorSyncedFromOtherDatabase(actor, database)) continue;

                        // Get actor guid:
                        var field = Field.Lookup(actor.fields, prefs.guidFieldTitle);
                        if (field == null)
                        {
                            if (!hasRecordedDatabaseUndo)
                            {
                                hasRecordedDatabaseUndo = true;
                                Undo.RecordObject(database, "Modify database");
                            }
                            field = new Field(prefs.guidFieldTitle, GetKeyName(actor.Name, Guid.NewGuid().ToString()), FieldType.Text);
                            actor.fields.Add(field);
                        }
                        else if (string.IsNullOrEmpty(field.value))
                        {
                            field.value = GetKeyName(actor.Name, Guid.NewGuid().ToString());
                        }

                        var actorDisplayName = actor.FieldExists("Display Name") ? actor.LookupValue("Display Name") : actor.Name;
                        table.AddEntry(field.value, actorDisplayName);
                    }
                }

                // Quests:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var quest in database.items)
                    {
                        if (quest.IsItem) continue;
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", quest.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        if (IsQuestSyncedFromOtherDatabase(quest, database)) continue;

                        // Get quest guid:
                        var field = Field.Lookup(quest.fields, prefs.guidFieldTitle);
                        if (field == null)
                        {
                            if (!hasRecordedDatabaseUndo)
                            {
                                hasRecordedDatabaseUndo = true;
                                Undo.RecordObject(database, "Modify database");
                            }
                            field = new Field(prefs.guidFieldTitle, GetKeyName(quest.Name, Guid.NewGuid().ToString()), FieldType.Text);
                            quest.fields.Add(field);
                        }
                        else if (string.IsNullOrEmpty(field.value))
                        {
                            field.value = GetKeyName(quest.Name, Guid.NewGuid().ToString());
                        }

                        var questDisplayName = quest.FieldExists("Display Name") ? quest.LookupValue("Display Name") : quest.Name;
                        table.AddEntry(field.value, questDisplayName);

                        var description = quest.LookupValue("Description");
                        table.AddEntry(field.value + "_Description", description);
                        var successDescription = quest.LookupValue("Success Description");
                        if (!string.IsNullOrEmpty(successDescription)) table.AddEntry(field.value + "_SuccessDescription", successDescription);
                        var failureDescription = quest.LookupValue("Failure Description");
                        if (!string.IsNullOrEmpty(failureDescription)) table.AddEntry(field.value + "_FailureDescription", failureDescription);

                        var entryCount = quest.LookupInt("Entry Count");
                        for (int i = 1; i <= entryCount; i++)
                        {
                            table.AddEntry(field.value + "_Entry_" + i, quest.LookupValue("Entry " + i));
                        }
                    }
                }

                // Conversations:
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    foreach (var conversation in database.conversations)
                    {
                        progress++;
                        if (EditorUtility.DisplayCancelableProgressBar("Dialogue To String Table", conversation.Title, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        foreach (var entry in conversation.dialogueEntries)
                        {

                            if (string.IsNullOrEmpty(entry.DialogueText) &&
                                string.IsNullOrEmpty(entry.MenuText))
                            {
                                continue;
                            }

                            // Get dialogue entry guid:
                            var field = Field.Lookup(entry.fields, prefs.guidFieldTitle);
                            if (field == null)
                            {
                                if (!hasRecordedDatabaseUndo)
                                {
                                    hasRecordedDatabaseUndo = true;
                                    Undo.RecordObject(database, "Modify database");
                                }
                                field = new Field(prefs.guidFieldTitle, GetKeyName(conversation.Title, Guid.NewGuid().ToString()), FieldType.Text);
                                entry.fields.Add(field);
                            }
                            else if (string.IsNullOrEmpty(field.value))
                            {
                                field.value = GetKeyName(conversation.Title, Guid.NewGuid().ToString());
                            }

                            // Add localized entries:
                            if (!string.IsNullOrEmpty(entry.DialogueText))
                            {
                                table.AddEntry(field.value, entry.DialogueText);
                                if (prefs.localizedFieldsToStringTable)
                                {
                                    foreach (var stringTable in stringTableCollection.StringTables)
                                    {
                                        var localizedField = Field.Lookup(entry.fields, stringTable.LocaleIdentifier.Code);
                                        if (localizedField == null) continue;
                                        string localizedText = localizedField.value;
                                        if (string.IsNullOrEmpty(localizedText)) continue;
                                        stringTable.AddEntry(field.value, localizedText);
                                    }
                                }
                            }
                            if (!string.IsNullOrEmpty(entry.MenuText))
                            {
                                table.AddEntry(field.value + "_MenuText", entry.MenuText);
                                if (prefs.localizedFieldsToStringTable)
                                {
                                    foreach (var stringTable in stringTableCollection.StringTables)
                                    {
                                        var localizedField = Field.Lookup(entry.fields, "Menu Text " + stringTable.LocaleIdentifier.Code);
                                        if (localizedField == null) continue;
                                        string localizedText = localizedField.value;
                                        if (string.IsNullOrEmpty(localizedText)) continue;
                                        stringTable.AddEntry(field.value, localizedText);
                                    }
                                }
                            }
                        }
                    }
                }

                Debug.Log("Populated Localization Package string table " + stringTableCollection.name + " with dialogue database fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private string GetKeyName(string name, string guid)
        {
            return prefs.prependNamesToKey ? $"{name}_{guid}" : guid;
        }

        private bool IsActorSyncedFromOtherDatabase(Actor actor, DialogueDatabase database)
        {
            if (actor == null || database == null) return false;
            if (!database.syncInfo.syncActors) return false;
            var sourceDatabase = database.syncInfo.syncActorsDatabase;
            return sourceDatabase.actors.Find(x => x.id == actor.id) != null;
        }

        private bool IsQuestSyncedFromOtherDatabase(Item quest, DialogueDatabase database)
        {
            if (quest == null || database == null) return false;
            if (!database.syncInfo.syncItems) return false;
            var sourceDatabase = database.syncInfo.syncItemsDatabase;
            return sourceDatabase.items.Find(x => x.id == quest.id) != null;
        }

        private void CopyStringTableToDialogueDatabases()
        {
            try
            {
                float total = databases.Count;
                int progress = 0;
                foreach (var database in databases)
                {
                    if (database == null) continue;
                    Undo.RecordObject(database, "Localization to Database");
                    progress++;

                    // Actor display names:
                    foreach (var actor in database.actors)
                    {
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", actor.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get actor guid:
                        var field = Field.Lookup(actor.fields, prefs.guidFieldTitle);
                        if (field == null || string.IsNullOrEmpty(field.value)) continue;
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            var stringTableEntry = stringTable.GetEntry(field.value);
                            if (stringTableEntry == null) continue;
                            var displayNameFieldTitle = "Display Name";
                            if (stringTable.LocaleIdentifier != defaultLocale.Identifier)
                            {
                                displayNameFieldTitle += $" {stringTable.LocaleIdentifier.Code}";
                            }
                            Field.SetValue(actor.fields, displayNameFieldTitle, stringTableEntry.LocalizedValue, FieldType.Localization);
                        }
                    }

                    // Quests:
                    foreach (var quest in database.items)
                    {
                        if (quest.IsItem) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", quest.Name, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        // Get quest guid:
                        var field = Field.Lookup(quest.fields, prefs.guidFieldTitle);
                        if (field == null || string.IsNullOrEmpty(field.value)) continue;
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            CopyStringTableEntryToField(stringTable, field.value, quest.fields, "Display Name");
                            CopyStringTableEntryToField(stringTable, field.value + "_Description", quest.fields, "Description");
                            CopyStringTableEntryToField(stringTable, field.value + "_SuccessDescription", quest.fields, "Success Description");
                            CopyStringTableEntryToField(stringTable, field.value + "_FailureDescription", quest.fields, "Failure Description");
                            var entryCount = quest.LookupInt("Entry Count");
                            for (int i = 1; i <= entryCount; i++)
                            {
                                CopyStringTableEntryToField(stringTable, field.value + "_Entry_" + i, quest.fields, "Entry " + i);
                            }
                        }
                    }

                    // Conversations:
                    if (database == null) continue;
                    foreach (var conversation in database.conversations)
                    {
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Dialogue", conversation.Title, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }

                        foreach (var entry in conversation.dialogueEntries)
                        {
                            // Get dialogue entry guid:
                            var field = Field.Lookup(entry.fields, prefs.guidFieldTitle);
                            if (field == null || string.IsNullOrEmpty(field.value)) continue;
                            // Add localized entries:
                            foreach (var stringTable in stringTableCollection.StringTables)
                            {
                                if (stringTable == null) continue;
                                var stringTableEntry = stringTable.GetEntry(field.value);
                                if (stringTableEntry != null)
                                {
                                    if (stringTable.LocaleIdentifier == defaultLocale.Identifier)
                                    {
                                        Field.SetValue(entry.fields, "Dialogue Text", stringTableEntry.LocalizedValue);
                                    }
                                    else
                                    {
                                        Field.SetValue(entry.fields, stringTable.LocaleIdentifier.Code, stringTableEntry.LocalizedValue, FieldType.Localization);
                                    }
                                }
                                stringTableEntry = stringTable.GetEntry(field.value + "_MenuText");
                                if (stringTableEntry != null)
                                {
                                    if (stringTable.LocaleIdentifier == defaultLocale.Identifier)
                                    {
                                        Field.SetValue(entry.fields, "Menu Text", stringTableEntry.LocalizedValue);
                                    }
                                    else
                                    {
                                        Field.SetValue(entry.fields, "Menu Text " + stringTable.LocaleIdentifier.Code, stringTableEntry.LocalizedValue, FieldType.Localization);
                                    }
                                }
                            }
                        }
                    }
                    EditorUtility.SetDirty(database);
                }
                Debug.Log("Copied Localization Package string table " + stringTableCollection.name + " values back to dialogue database.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private void CopyStringTableEntryToField(UnityEngine.Localization.Tables.StringTable stringTable, string entryKey, List<Field> fields, string fieldTitle)
        {
            var stringTableEntry = stringTable.GetEntry(entryKey);
            if (stringTableEntry == null) return;
            if (stringTable.LocaleIdentifier != defaultLocale.Identifier)
            {
                fieldTitle += $" {stringTable.LocaleIdentifier.Code}";
            }
            Field.SetValue(fields, fieldTitle, stringTableEntry.LocalizedValue, FieldType.Localization);
        }

        private void CopyTextTablesToStringTable()
        {
            try
            {

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                float total = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    total += textTable.fields.Count;
                }

                int progress = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    foreach (var field in textTable.fields.Values)
                    {
                        progress++;
                        if (string.IsNullOrEmpty(field.fieldName) || field.texts == null || field.texts.Count == 0) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("Text Table To String Table", field.fieldName, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }
                        table.AddEntry(field.fieldName, field.texts[0]);
                    }
                }

                Debug.Log("Populated Localization Package string table " + stringTableCollection.name + " with text table fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private void CopyStringTableToTextTables()
        {
            try
            {

                var table = stringTableCollection.StringTables.First(x => x.LocaleIdentifier == defaultLocale.Identifier);
                if (table == null)
                {
                    Debug.LogError("Can't find string table for locale " + defaultLocale.Identifier.Code);
                    return;
                }

                float total = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;
                    total += textTable.fields.Count;
                }

                int progress = 0;
                foreach (var textTable in textTables)
                {
                    if (textTable == null) continue;

                    var languageCodeToTextTableID = new Dictionary<string, int>();
                    foreach (var kvp in textTable.languages)
                    {
                        languageCodeToTextTableID[kvp.Key] = kvp.Value;
                        if (kvp.Key == "Default" && defaultLocale != null)
                        {
                            languageCodeToTextTableID[defaultLocale.Identifier.Code] = kvp.Value;
                        }
                    }
                    foreach (var field in textTable.fields.Values)
                    {
                        progress++;
                        if (string.IsNullOrEmpty(field.fieldName) || field.texts == null || field.texts.Count == 0) continue;
                        if (EditorUtility.DisplayCancelableProgressBar("String Table To Text Table", field.fieldName, progress / total))
                        {
                            Debug.Log("Cancelled.");
                            return;
                        }
                        foreach (var stringTable in stringTableCollection.StringTables)
                        {
                            var stringTableEntry = stringTable.GetEntry(field.fieldName);
                            if (stringTableEntry == null) continue;
                            int languageID;
                            if (languageCodeToTextTableID.TryGetValue(stringTable.LocaleIdentifier.Code, out languageID))
                            {
                                textTable.SetFieldTextForLanguage(field.fieldName, languageID, stringTableEntry.LocalizedValue);
                            }
                        }
                    }
                    EditorUtility.SetDirty(textTable);
                }

                Debug.Log("Copied Localization Package string table " + stringTableCollection.name + " back to text table fields.", stringTableCollection);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }
        }

        // Note: This is not accessible yet because stringTable.RemoveEntry()
        // appears to clear content but not actually delete entire entry.
        private void DeleteGuidKeysFromStringTable()
        {
            foreach (var stringTable in stringTableCollection.StringTables)
            {
                // Identify entries to delete:
                var entriesToDelete = new List<StringTableEntry>();
                foreach (var entry in stringTable.Values)
                {
                    if (DoesEndWithGuid(entry.Key))
                    {
                        entriesToDelete.Add(entry);
                    }
                }

                foreach (var entry in entriesToDelete)
                {
                    if (entry == null || string.IsNullOrEmpty(entry.Key)) continue;
                    stringTable.RemoveEntry(entry.KeyId);
                }
            }
        }

        private static Regex GuidRegex = new Regex(".*[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9]-[a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9][a-z0-9]$");

        private bool DoesEndWithGuid(string s)
        {
            if (string.IsNullOrEmpty(s)) return false;
            return GuidRegex.IsMatch(s);
        }

    }
}

