//
// NostaleDataParser.cs
//
// Copyright (c) František Boháček. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Extensions.Options;
using NosSmooth.Data.Abstractions;
using NosSmooth.Data.Abstractions.Language;
using NosSmooth.Data.NOSFiles.Files;
using NosSmooth.Data.NOSFiles.Options;
using NosSmooth.Data.NOSFiles.Parsers;
using NosSmooth.Data.NOSFiles.Readers;
using Remora.Results;
namespace NosSmooth.Data.NOSFiles;
/// <summary>
/// Parser of NosTale .NOS files.
/// </summary>
public class NostaleDataParser
{
private readonly FileReader _fileReader;
private readonly NostaleDataOptions _options;
private readonly LanguageServiceOptions _languageOptions;
private NostaleData? _parsed;
/// <summary>
/// Initializes a new instance of the <see cref="NostaleDataParser"/> class.
/// </summary>
/// <param name="fileReader">The file reader.</param>
/// <param name="options">The options.</param>
/// <param name="languageOptions">The language options.</param>
public NostaleDataParser
(
FileReader fileReader,
IOptions<NostaleDataOptions> options,
IOptions<LanguageServiceOptions> languageOptions
)
{
_fileReader = fileReader;
_options = options.Value;
_languageOptions = languageOptions.Value;
}
/// <summary>
/// Extract NosTale files from archives.
/// </summary>
/// <param name="path">The path to the nostale data files.</param>
/// <param name="languages">The languages to include.</param>
/// <returns>The nostale files.</returns>
public Result<NostaleFiles> GetFiles(string? path = null, params Language[] languages)
{
string datFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.InfosFileName);
string mapGridsFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.MapGridsFileName);
string languageFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.LanguageFileName);
var datFile = _fileReader.ReadFileSystemFile<FileArchive>(datFilesPath);
if (!datFile.IsSuccess)
{
return Result<NostaleFiles>.FromError(datFile);
}
var mapGridsFile = _fileReader.ReadFileSystemFile<FileArchive>(mapGridsFilesPath);
if (!mapGridsFile.IsSuccess)
{
return Result<NostaleFiles>.FromError(mapGridsFile);
}
var languageFiles = new Dictionary<Language, FileArchive>();
foreach (var language in languages.Concat(_options.SupportedLanguages).Distinct())
{
var langString = language.ToString().ToUpper();
var langPath = languageFilesPath.Replace("%lang%", langString);
var languageFile = _fileReader.ReadFileSystemFile<FileArchive>(langPath);
if (!languageFile.IsSuccess)
{
return Result<NostaleFiles>.FromError(languageFile);
}
languageFiles.Add(language, languageFile.Entity.Content);
}
return new NostaleFiles(languageFiles, datFile.Entity.Content, mapGridsFile.Entity.Content);
}
/// <summary>
/// Parse the nostale files.
/// </summary>
/// <param name="path">The path to the files.</param>
/// <param name="languages">The languages to parse.</param>
/// <returns>Parsed data or an error.</returns>
public Result<NostaleData> ParseFiles(string? path = null, params Language[] languages)
{
try
{
if (_parsed is not null)
{
return _parsed;
}
var filesResult = GetFiles(path, languages);
if (!filesResult.IsSuccess)
{
return Result<NostaleData>.FromError(filesResult);
}
var files = filesResult.Entity;
var skillParser = new SkillParser();
var skillsResult = skillParser.Parse(files);
if (!skillsResult.IsSuccess)
{
return Result<NostaleData>.FromError(skillsResult);
}
var mapParser = new MapParser();
var mapsResult = mapParser.Parse(files);
if (!mapsResult.IsSuccess)
{
return Result<NostaleData>.FromError(mapsResult);
}
var itemParser = new ItemParser();
var itemsResult = itemParser.Parse(files);
if (!itemsResult.IsSuccess)
{
return Result<NostaleData>.FromError(itemsResult);
}
var monsterParser = new MonsterParser();
var monstersResult = monsterParser.Parse(files);
if (!monstersResult.IsSuccess)
{
return Result<NostaleData>.FromError(monstersResult);
}
var langParser = new LangParser();
var translations
= new Dictionary<Language, IReadOnlyDictionary<TranslationRoot, IReadOnlyDictionary<string, string>>>();
foreach (var language in files.LanguageFiles.Keys)
{
var languageParseResult = langParser.Parse(files, language);
if (!languageParseResult.IsSuccess)
{
return Result<NostaleData>.FromError(languageParseResult);
}
translations.Add(language, languageParseResult.Entity);
}
return _parsed = new NostaleData
(
translations,
itemsResult.Entity,
monstersResult.Entity,
skillsResult.Entity,
mapsResult.Entity
);
}
catch (Exception e)
{
return e;
}
}
/// <summary>
/// Create a language service from parsed files.
/// </summary>
/// <returns>A language service or an error.</returns>
public Result<ILanguageService> CreateLanguageService()
{
var parsed = ParseFiles();
if (!parsed.IsSuccess)
{
return Result<ILanguageService>.FromError(parsed);
}
return new LanguageService(parsed.Entity.Translations, _languageOptions);
}
/// <summary>
/// Create an info service from parsed files.
/// </summary>
/// <returns>An info service or an error.</returns>
public Result<IInfoService> CreateInfoService()
{
var parsed = ParseFiles();
if (!parsed.IsSuccess)
{
return Result<IInfoService>.FromError(parsed);
}
return new InfoService(parsed.Entity);
}
}