using System;
using System.Collections.Generic;
using System.Linq;
namespace StardewModdingAPI.Framework.ModData
{
/// Handles access to SMAPI's internal mod metadata list.
internal class ModDatabase
{
/*********
** Properties
*********/
/// The underlying mod data records indexed by default display name.
private readonly IDictionary Records;
/// Get an update URL for an update key (if valid).
private readonly Func GetUpdateUrl;
/*********
** Public methods
*********/
/// Construct an empty instance.
public ModDatabase()
: this(new Dictionary(), key => null) { }
/// Construct an instance.
/// The underlying mod data records indexed by default display name.
/// Get an update URL for an update key (if valid).
public ModDatabase(IDictionary records, Func getUpdateUrl)
{
this.Records = records;
this.GetUpdateUrl = getUpdateUrl;
}
/// Get a parsed representation of the which match a given manifest.
/// The manifest to match.
public ParsedModDataRecord GetParsed(IManifest manifest)
{
// get raw record
if (!this.TryGetRaw(manifest?.UniqueID, out string displayName, out ModDataRecord record))
return null;
// parse fields
ParsedModDataRecord parsed = new ParsedModDataRecord { DisplayName = displayName, DataRecord = record };
foreach (ModDataField field in record.GetFields().Where(field => field.IsMatch(manifest)))
{
switch (field.Key)
{
// update key
case ModDataFieldKey.UpdateKey:
parsed.UpdateKey = field.Value;
break;
// alternative URL
case ModDataFieldKey.AlternativeUrl:
parsed.AlternativeUrl = field.Value;
break;
// status
case ModDataFieldKey.Status:
parsed.Status = (ModStatus)Enum.Parse(typeof(ModStatus), field.Value, ignoreCase: true);
parsed.StatusUpperVersion = field.UpperVersion;
break;
// status reason phrase
case ModDataFieldKey.StatusReasonPhrase:
parsed.StatusReasonPhrase = field.Value;
break;
}
}
return parsed;
}
/// Get the display name for a given mod ID (if available).
/// The unique mod ID.
public string GetDisplayNameFor(string id)
{
return this.TryGetRaw(id, out string displayName, out ModDataRecord _)
? displayName
: null;
}
/// Get the mod page URL for a mod (if available).
/// The unique mod ID.
public string GetModPageUrlFor(string id)
{
// get raw record
if (!this.TryGetRaw(id, out string _, out ModDataRecord record))
return null;
// get update key
ModDataField updateKeyField = record.GetFields().FirstOrDefault(p => p.Key == ModDataFieldKey.UpdateKey);
if (updateKeyField == null)
return null;
// get update URL
return this.GetUpdateUrl(updateKeyField.Value);
}
/*********
** Private models
*********/
/// Get a raw data record.
/// The mod ID to match.
/// The mod's default display name.
/// The raw mod record.
private bool TryGetRaw(string id, out string displayName, out ModDataRecord record)
{
if (!string.IsNullOrWhiteSpace(id))
{
foreach (var entry in this.Records)
{
displayName = entry.Key;
record = entry.Value;
// try main ID
if (record.ID != null && record.ID.Equals(id, StringComparison.InvariantCultureIgnoreCase))
return true;
// try former IDs
if (record.FormerIDs != null)
{
foreach (string part in record.FormerIDs.Split('|'))
{
if (part.Trim().Equals(id, StringComparison.InvariantCultureIgnoreCase))
return true;
}
}
}
}
displayName = null;
record = null;
return false;
}
}
}