summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework/ModData/ModDatabase.cs
blob: 62f37d9bbfc4eb5a2cd68fd8cdb0ef944871eca1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using System.Collections.Generic;
using System.Linq;

namespace StardewModdingAPI.Framework.ModData
{
    /// <summary>Handles access to SMAPI's internal mod metadata list.</summary>
    internal class ModDatabase
    {
        /*********
        ** Properties
        *********/
        /// <summary>The underlying mod data records indexed by default display name.</summary>
        private readonly IDictionary<string, ModDataRecord> Records;

        /// <summary>Get an update URL for an update key (if valid).</summary>
        private readonly Func<string, string> GetUpdateUrl;


        /*********
        ** Public methods
        *********/
        /// <summary>Construct an empty instance.</summary>
        public ModDatabase()
        : this(new Dictionary<string, ModDataRecord>(), key => null) { }

        /// <summary>Construct an instance.</summary>
        /// <param name="records">The underlying mod data records indexed by default display name.</param>
        /// <param name="getUpdateUrl">Get an update URL for an update key (if valid).</param>
        public ModDatabase(IDictionary<string, ModDataRecord> records, Func<string, string> getUpdateUrl)
        {
            this.Records = records;
            this.GetUpdateUrl = getUpdateUrl;
        }

        /// <summary>Get a parsed representation of the <see cref="ModDataRecord.Fields"/> which match a given manifest.</summary>
        /// <param name="manifest">The manifest to match.</param>
        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;
        }

        /// <summary>Get the display name for a given mod ID (if available).</summary>
        /// <param name="id">The unique mod ID.</param>
        public string GetDisplayNameFor(string id)
        {
            return this.TryGetRaw(id, out string displayName, out ModDataRecord _)
                ? displayName
                : null;
        }

        /// <summary>Get the mod page URL for a mod (if available).</summary>
        /// <param name="id">The unique mod ID.</param>
        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
        *********/
        /// <summary>Get a raw data record.</summary>
        /// <param name="id">The mod ID to match.</param>
        /// <param name="displayName">The mod's default display name.</param>
        /// <param name="record">The raw mod record.</param>
        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;
        }
    }
}