using System;
using System.Collections.Generic;
using System.Linq;
namespace Ariadne.Vellum
{
///
/// Remembers the key and type of each field and local an arc class listed, in the order it listed them, and the
/// same for each call it listed the locals of.
///
public class ArcPartList : IArcPartLister
{
public readonly List Keys = new List();
public readonly List Types = new List();
public readonly List IsLocal = new List();
///
/// Holds the name of each call the arc class listed locals for.
///
public readonly List ScopeNames = new List();
///
/// Holds what each of listed, in the same order. A call that repeats one above it
/// holds that one's list, so the lists can form a cycle.
///
public readonly List Scopes = new List();
///
/// Holds the name of each call that runs a frame whose type arguments only a save says.
///
public readonly List PolymorphicNames = new List();
///
/// Holds the open generic frame class of each of , in the same order.
///
public readonly List PolymorphicDefinitions = new List();
private readonly ArcPartList parent;
private readonly Type[] frames;
public ArcPartList()
{
}
private ArcPartList(ArcPartList parent, Type[] frames)
{
this.parent = parent;
this.frames = frames;
}
public int Count
{
get
{
return Keys.Count;
}
}
public void Field(string key)
{
Keys.Add(key);
Types.Add(typeof(T));
IsLocal.Add(false);
}
public void Local(string key)
{
Keys.Add(key);
Types.Add(typeof(T));
IsLocal.Add(true);
}
public void Polymorphic(string name, Type frameDefinition)
{
PolymorphicNames.Add(name);
PolymorphicDefinitions.Add(frameDefinition);
}
///
/// Returns the list for the call , which is the same one each time it's named, or null
/// if a call above this one runs already.
///
public IArcPartLister Scope(string name, params Type[] frames)
{
int index = ScopeNames.IndexOf(name);
if (index >= 0)
{
// A repeat of a call above has nothing more to list.
return Scopes[index].parent == this ? Scopes[index] : null;
}
for (ArcPartList above = this; above != null && frames.Length > 0; above = above.parent)
{
if (above.frames != null && above.frames.SequenceEqual(frames))
{
ScopeNames.Add(name);
Scopes.Add(above);
return null;
}
}
var returnMe = new ArcPartList(this, frames);
ScopeNames.Add(name);
Scopes.Add(returnMe);
return returnMe;
}
}
}