ficdown/Ficdown.Parser/Engine/SceneLinker.cs

127 lines
5.2 KiB
C#
Raw Normal View History

2014-06-30 11:59:56 -05:00
namespace Ficdown.Parser.Engine
{
2014-06-30 23:55:16 -05:00
using System;
2014-06-30 11:59:56 -05:00
using System.Collections.Generic;
2014-06-30 23:55:16 -05:00
using System.Collections.Specialized;
2014-06-30 16:57:14 -05:00
using System.Linq;
2014-06-30 11:59:56 -05:00
using System.Text.RegularExpressions;
using Model.Story;
2014-06-30 16:57:14 -05:00
using Model.Story.Extensions;
2014-06-30 11:59:56 -05:00
public class SceneLinker : ISceneLinker
{
2014-06-30 16:57:14 -05:00
2014-06-30 11:59:56 -05:00
public void ExpandScenes(Story story)
{
2014-06-30 16:57:14 -05:00
VerifySanity(story);
2014-06-30 11:59:56 -05:00
var newScenes = new Dictionary<string, IList<Scene>>();
foreach(var key in story.Scenes.Keys)
{
newScenes.Add(key, new List<Scene>());
foreach (var scene in story.Scenes[key])
{
var anchors = RegexLib.Anchors.Matches(scene.Description);
2014-06-30 16:57:14 -05:00
// get a list of all unique condition combinations from the anchors
var uniques = new List<IList<string>>();
2014-06-30 11:59:56 -05:00
foreach (Match anchor in anchors)
{
string target;
IList<string> conditions, toggles;
Utilities.ParseHref(anchor.Groups["href"].Value, out target, out conditions, out toggles);
2014-06-30 16:57:14 -05:00
if (conditions != null)
{
// union with the conditions required to reach this scene, if any
if (scene.Conditions != null)
{
conditions = conditions.Union(scene.Conditions).ToList();
if (conditions.Count == scene.Conditions.Count)
continue; //WARN this anchor will never resolve false
}
AddUnique(uniques, conditions);
}
}
// resolve the current scene
2014-06-30 23:55:16 -05:00
var original = scene.Clone();
2014-06-30 16:57:14 -05:00
newScenes[key].Add(ResolveScene(scene, anchors));
// resolve the uniques
foreach (var unique in uniques)
{
2014-06-30 23:55:16 -05:00
var uscene = original.Clone();
2014-06-30 16:57:14 -05:00
uscene.Conditions = unique;
newScenes[key].Add(ResolveScene(uscene, anchors));
2014-06-30 11:59:56 -05:00
}
}
}
2014-06-30 16:57:14 -05:00
story.Scenes = newScenes;
}
private void AddUnique(IList<IList<string>> uniques, IList<string> conditions)
{
// ignore this combo if there's a contradiction
if (conditions.Where(c => !c.StartsWith("!"))
.Any(c => conditions.Contains(string.Format("!{0}", c))))
return; // WARN this anchor will never resolve true
// make sure this is actually unique
if (uniques.Any(u => u.Intersect(conditions).Count() == conditions.Count)) return;
uniques.Add(conditions);
// we need to treat this unioned with all other existing uniques as another potential unique
var existing = new List<IList<string>>(uniques);
foreach (var old in existing)
{
AddUnique(uniques, old.Union(conditions).ToList());
}
}
private Scene ResolveScene(Scene scene, MatchCollection anchors)
{
foreach (Match anchor in anchors)
{
2014-06-30 23:55:16 -05:00
string target;
IList<string> conditions, toggles;
Utilities.ParseHref(anchor.Groups["href"].Value, out target, out conditions, out toggles);
if (conditions != null)
{
var satisfied = scene.Conditions != null && conditions.All(c => scene.Conditions.Contains(c));
2014-06-30 23:55:16 -05:00
var text = anchor.Groups["text"].Value;
var alts = RegexLib.ConditionalText.Match(text);
if (!alts.Success)
throw new FormatException(string.Format("Bad conditional anchor: {0}",
anchor.Groups["anchor"].Value));
var replace =
RegexLib.EscapeChar.Replace(satisfied ? alts.Groups["true"].Value : alts.Groups["false"].Value,
string.Empty);
// if there's no target or toggles, or the replace text is an empty string, replace the whole anchor
if (string.IsNullOrEmpty(replace) || (target == null && toggles == null))
2014-06-30 23:55:16 -05:00
{
scene.Description = scene.Description.Replace(anchor.Groups["anchor"].Value, replace);
}
// if there's a target or toggles, replace the text and remove the conditions on the anchor
else
{
var parsedHref = RegexLib.Href.Match(anchor.Groups["href"].Value);
2014-06-30 23:55:16 -05:00
scene.Description = scene.Description.Replace(anchor.Groups["anchor"].Value,
string.Format("[{0}]({1}{2})", replace, parsedHref.Groups["target"].Value,
parsedHref.Groups["toggles"].Value));
2014-06-30 23:55:16 -05:00
}
}
2014-06-30 16:57:14 -05:00
}
return scene;
}
private void VerifySanity(Story story)
{
2014-06-30 11:59:56 -05:00
}
}
}