JD2022-TU1/main/tools/services/JD.LocalizationExport.Service/Implementation/IntermediaryFile/IntermediaryFileManager.cs

183 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using JD.LocalizationExport.Service.Implementation.IntermediaryFile.Serialization;
using JD.LocalizationExport.Service.Model;
using Newtonsoft.Json;
namespace JD.LocalizationExport.Service.Implementation.IntermediaryFile
{
internal class IntermediaryFileManager : IIntermediaryFileManager
{
private const int IntermediaryFileVersion = 1;
private readonly string _intermediaryFilePath;
internal IntermediaryFileManager(string intermediaryFilePath)
{
_intermediaryFilePath = intermediaryFilePath;
}
#region IIntermediaryFileManager implementation
// For several exports and for the intermediary file, we need to export all languages already exported, so all languages present in the intermediary file
// That's why all these languages are returned even though they haven't necessarily been selected
public async Task<Tuple<Line[], Language[]>> LoadFileAndMergeAsync(IEnumerable<Line> linesToExport, IEnumerable<Language> languagesToExport, IEnumerable<Language> allLanguages)
{
if (linesToExport == null)
throw new ArgumentNullException(nameof(linesToExport));
if (languagesToExport == null)
throw new ArgumentNullException(nameof(languagesToExport));
if (allLanguages == null)
throw new ArgumentNullException(nameof(allLanguages));
Line[] linesToExportArray = linesToExport.ToArray();
Language[] languagesToExportArray = languagesToExport.ToArray();
Language[] allLanguagesArray = allLanguages.ToArray();
// Check allLanguages is a superset of languagesToExport
if (languagesToExportArray.Except(allLanguagesArray).Any())
{
throw new ArgumentException($"The list of all languages doesn't contain the list of languages to export");
}
string intermediaryFileContent;
using (StreamReader reader = File.OpenText(_intermediaryFilePath))
{
intermediaryFileContent = await reader.ReadToEndAsync();
}
Serialization.IntermediaryFile previousExport = JsonConvert.DeserializeObject<Serialization.IntermediaryFile>(intermediaryFileContent);
string[] languagesToExportNames = languagesToExportArray.Select(l => l.OasisName).ToArray();
string[] languageNames = languagesToExportNames.Union(previousExport.Languages).ToArray();
int[] languageIndexes = languageNames.Select(l => Array.IndexOf(previousExport.Languages, l)).ToArray();
string[] languagesToLoadFromFile = languageNames.Except(languagesToExportNames).ToArray();
int[] languagesToLoadFromFileIndexes = languagesToLoadFromFile.Select(l => Array.IndexOf(previousExport.Languages, l)).ToArray();
List<Line> newLinesToExport = new List<Line>();
// Exporting the lines from Oasis using the saved data from intermediary file if necessary (for missing languages)
foreach (Line line in linesToExportArray)
{
Dictionary<string, string> newTranslations = new Dictionary<string, string>(line.Translations);
string lineId = line.LineId.ToString();
bool lineExistsInIntermediaryFile = previousExport.LinesById.TryGetValue(lineId, out SerializedLine intermediaryFileLine);
foreach (int i in languagesToLoadFromFileIndexes)
{
if (lineExistsInIntermediaryFile)
{
newTranslations[previousExport.Languages[i]] = intermediaryFileLine.Translations[i];
}
else
{
newTranslations[previousExport.Languages[i]] = string.Empty;
}
}
newLinesToExport.Add(new Line(line.LineId, line.MasterText, newTranslations, line.IsLineForPhone)); // TODO: Use correct MasterText if this language is not exported
}
// Loading data from intermediary file for the lines not exported from Oasis
string[] lineToExportIds = linesToExportArray.Select(l => l.LineId.ToString()).ToArray();
Dictionary<string, SerializedLine> missingLines = previousExport.LinesById.Where(pair => !lineToExportIds.Contains(pair.Key)).ToDictionary(pair => pair.Key, pair => pair.Value);
foreach (KeyValuePair<string, SerializedLine> pair in missingLines)
{
int lineId = int.Parse(pair.Key);
SerializedLine line = pair.Value;
Dictionary<string, string> newTranslations = new Dictionary<string, string>();
foreach (int i in languageIndexes)
{
newTranslations[previousExport.Languages[i]] = line.Translations[i];
}
newLinesToExport.Add(new Line(lineId, line.MasterText, newTranslations, (bool)line.IsUsedInMCA));
}
// Getting the missing language info from allLanguages using the name in the intermediary file
// Need to do all this LINQ query since we return a Language array, not just a string array
// (in which case returning the names of the languages in the intermediary file would have sufficed)
languagesToExportArray = languagesToExportArray.Union(allLanguagesArray.Where(l => languagesToLoadFromFile.Contains(l.OasisName))).ToArray();
return new Tuple<Line[], Language[]>(newLinesToExport.ToArray(), languagesToExportArray);
}
public async Task SaveFileAsync(IEnumerable<Line> linesToExport, IEnumerable<Language> languagesToExport)
{
Serialization.IntermediaryFile save = new Serialization.IntermediaryFile
{
Version = IntermediaryFileVersion.ToString(),
Languages = languagesToExport.Select(l => l.OasisName).OrderBy(l => l).ToArray()
};
save.LinesById = linesToExport.OrderBy(l => l.LineId).ToDictionary(l => l.LineId.ToString(),
l => new SerializedLine()
{
MasterText = l.MasterText,
IsUsedInMCA = l.IsLineForPhone,
Translations = l.Translations.OrderBy(pair => Array.IndexOf(save.Languages, pair.Key))
.Where(pair => save.Languages.Contains(pair.Key))
.Select(pair => pair.Value)
.ToArray()
});
// TODO: Check if better with BackgroundWorker, cheap async here with JsonConvert
//BackgroundWorker worker = new BackgroundWorker();
//string s = null;
//worker.DoWork += new DoWorkEventHandler((sender, e) =>
//{
// s = JsonConvert.SerializeObject(save, Formatting.Indented);
//});
//worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(async (sender, e) =>
//{
// string updatedFileContent = s;
// //string updatedFileContent = JsonConvert.SerializeObject(save, Formatting.Indented);
// using (StreamWriter outputFile = new StreamWriter(_intermediaryFilePath))
// {
// await outputFile.WriteAsync(updatedFileContent);
// }
//});
//worker.RunWorkerAsync();
//await Task.CompletedTask;
try
{
string updatedFileContent = await Task.Run(() => JsonConvert.SerializeObject(save, Formatting.Indented));
string tempOutputFile = _intermediaryFilePath + ".tmp";
string backupIntermediaryFile = _intermediaryFilePath + ".backup";
using (StreamWriter outputFileWriter = new StreamWriter(tempOutputFile))
{
await outputFileWriter.WriteAsync(updatedFileContent);
}
if (File.Exists(_intermediaryFilePath))
{
File.Replace(tempOutputFile, _intermediaryFilePath, backupIntermediaryFile);
}
else
{
File.Move(tempOutputFile, _intermediaryFilePath);
}
}
catch (Exception e)
{
await Task.FromException(e);
}
}
#endregion
}
}