using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace SharpGLTF.SchemaReflection
{
///
/// Base class for all schema Types
///
///
/// Derived classes:
/// -
/// -
/// -
/// -
/// -
/// -
/// -
/// -
///
public abstract partial class SchemaType
{
#region constructor
protected SchemaType(Context ctx) { _Owner = ctx; }
#endregion
#region data
///
/// context where this type is stored
///
private readonly Context _Owner;
///
/// identifier used for serialization and deserialization
///
public abstract string PersistentName { get; }
#endregion
#region properties
public String Description { get; set; }
public Context Owner => _Owner;
#endregion
}
///
/// Represents a type.
///
[System.Diagnostics.DebuggerDisplay("StringType {PersistentName}")]
public sealed class StringType : SchemaType
{
#region constructor
internal StringType(Context ctx) : base(ctx) { }
#endregion
#region properties
public override string PersistentName => typeof(String).Name;
#endregion
}
///
/// Represents an undefined type.
///
///
/// undefined objects are serialized/deserialized as
///
[System.Diagnostics.DebuggerDisplay("ObjectType {PersistentName}")]
public sealed class ObjectType : SchemaType
{
#region constructor
internal ObjectType(Context ctx) : base(ctx) { }
#endregion
#region properties
public override string PersistentName => typeof(System.Text.Json.Nodes.JsonNode).FullName;
#endregion
}
///
/// Represents a "by value" type , , , etc
///
///
/// This type can optionally be set as nullable.
///
[System.Diagnostics.DebuggerDisplay("BlittableType {PersistentName}")]
public sealed class BlittableType : SchemaType
{
#region constructor
internal BlittableType(Context ctx, TypeInfo t, bool isNullable) : base(ctx)
{
if (t == typeof(String).GetTypeInfo()) isNullable = false;
_Type = t;
_IsNullable = isNullable;
}
#endregion
#region data
// https://en.wikipedia.org/wiki/Blittable_types
private readonly TypeInfo _Type;
private readonly Boolean _IsNullable;
#endregion
#region properties
public TypeInfo DataType => _Type;
public bool IsNullable => _IsNullable;
public override string PersistentName => _IsNullable ? $"{_Type.Name}?" : _Type.Name;
#endregion
}
[System.Diagnostics.DebuggerDisplay("EnumType {PersistentName}")]
public sealed class EnumType : SchemaType
{
#region constructor
internal EnumType(Context ctx, string name, bool isNullable) : base(ctx)
{
_PersistentName = name;
_IsNullable = isNullable;
}
#endregion
#region data
private readonly String _PersistentName;
private readonly Boolean _IsNullable;
private bool _UseIntegers;
private readonly Dictionary _Values = new Dictionary();
#endregion
#region properties
public bool IsNullable => _IsNullable;
public override string PersistentName => _PersistentName;
public bool UseIntegers { get => _UseIntegers; set => _UseIntegers = value; }
public SchemaType ItemType => UseIntegers ? (SchemaType)Owner.UseBlittable(typeof(int).GetTypeInfo()) : Owner.UseString();
public IEnumerable> Values => _Values;
#endregion
#region API
public void SetValue(string key, int val) { _Values[key] = val; }
#endregion
}
[System.Diagnostics.DebuggerDisplay("ArrayType {PersistentName}")]
public sealed class ArrayType : SchemaType
{
#region constructor
internal ArrayType(Context ctx, SchemaType element) : base(ctx)
{
_ItemType = element;
}
#endregion
#region data
private readonly SchemaType _ItemType;
public SchemaType ItemType => _ItemType;
#endregion
#region properties
public override string PersistentName => $"{_ItemType.PersistentName}[]";
#endregion
}
[System.Diagnostics.DebuggerDisplay("DictionaryType {PersistentName}")]
public sealed class DictionaryType : SchemaType
{
#region lifecycle
internal DictionaryType(Context ctx, SchemaType key,SchemaType val) : base(ctx)
{
_KeyType = key;
_ValueType = val;
}
#endregion
#region data
private readonly SchemaType _KeyType;
private readonly SchemaType _ValueType;
#endregion
#region properties
public SchemaType KeyType => _KeyType;
public SchemaType ValueType => _ValueType;
public override string PersistentName => $"<{_KeyType.PersistentName},{_ValueType.PersistentName}>[]";
#endregion
}
///
/// Represents a field property within a
///
[System.Diagnostics.DebuggerDisplay("FieldInfo {_FieldType} {FieldType.PersistentName} {PersistentName}")]
public sealed class FieldInfo
{
#region lifecycle
internal FieldInfo(ClassType owner, string name)
{
_Owner = owner;
_PersistentName = name;
}
#endregion
#region data
private readonly ClassType _Owner;
private readonly String _PersistentName;
private SchemaType _FieldType;
private Object _ExclusiveMinimumValue;
private Object _InclusiveMinimumValue;
private Object _DefaultValue;
private Object _InclusiveMaximumValue;
private Object _ExclusiveMaximumValue;
private int _MinItems;
private int _MaxItems;
#endregion
#region properties
public ClassType DeclaringClass => _Owner;
public String Description { get; set; }
public String PersistentName => _PersistentName;
public SchemaType FieldType { get => _FieldType; set => _FieldType = value; }
public Object ExclusiveMinimumValue { get => _ExclusiveMinimumValue; set => _ExclusiveMinimumValue = value; }
public Object InclusiveMinimumValue { get => _InclusiveMinimumValue; set => _InclusiveMinimumValue = value; }
public Object DefaultValue { get => _DefaultValue; set => _DefaultValue = value; }
public Object InclusiveMaximumValue { get => _InclusiveMaximumValue; set => _InclusiveMaximumValue = value; }
public Object ExclusiveMaximumValue { get => _ExclusiveMaximumValue; set => _ExclusiveMaximumValue = value; }
public int MinItems { get => _MinItems; set => _MinItems = value; }
public int MaxItems { get => _MaxItems; set => _MaxItems = value; }
#endregion
#region fluent api
public FieldInfo SetDataType(SchemaType type) { _FieldType = type; return this; }
public FieldInfo SetDataType(Type type, bool isNullable)
{
if (type == typeof(string)) { _FieldType = DeclaringClass.Owner.UseString(); return this; }
_FieldType = DeclaringClass.Owner.UseBlittable(type.GetTypeInfo(), isNullable);
return this;
}
public FieldInfo RemoveDefaultValue() { _DefaultValue = null; return this; }
public FieldInfo SetDefaultValue(string defval) { _DefaultValue = defval; return this; }
public FieldInfo SetLimits(Decimal? min, Decimal? max) { _InclusiveMinimumValue = min; _InclusiveMaximumValue = max; return this; }
public FieldInfo SetItemsRange(int min, int max = int.MaxValue) { _MinItems = min; _MaxItems = max; return this; }
#endregion
#region comparer helper
private sealed class _Comparer : IEqualityComparer , IComparer
{
public int Compare(FieldInfo x, FieldInfo y)
{
var xx = _Adjust(x._PersistentName);
var yy = _Adjust(y._PersistentName);
return string.CompareOrdinal(xx, yy);
}
private static string _Adjust(string name)
{
if (name.StartsWith("asset")) return "____" + name;
if (name.StartsWith("extensions")) return "___" + name;
return name;
}
public bool Equals(FieldInfo x, FieldInfo y) { return Compare(x,y) == 0; }
public int GetHashCode(FieldInfo obj) { return obj._PersistentName.GetHashCode(StringComparison.Ordinal); }
}
private static readonly _Comparer _DefaultComparer = new _Comparer();
public static IEqualityComparer EqualityComparer => _DefaultComparer;
public static IComparer Comparer => _DefaultComparer;
#endregion
}
[System.Diagnostics.DebuggerDisplay("ClassType {PersistentName} : {BaseClass.PersistentName}")]
public sealed class ClassType : SchemaType
{
#region constructor
internal ClassType(Context ctx, string name) : base(ctx)
{
_PersistentName = name;
}
#endregion
#region data
private readonly String _PersistentName;
private readonly SortedSet _Fields = new SortedSet(FieldInfo.Comparer);
private ClassType _BaseClass;
public override string PersistentName => _PersistentName;
public ClassType BaseClass { get => _BaseClass; set => _BaseClass = value; }
public IEnumerable Fields => _Fields;
///
/// True to prevent to codegen emitter to emit this class
///
public bool IgnoredByEmitter { get; set; }
#endregion
#region API
public FieldInfo GetField(string name)
{
return _Fields.First(item => item.PersistentName == name);
}
public FieldInfo UseField(string name)
{
var f = new FieldInfo(this, name);
_Fields.Add(f);
return GetField(name);
}
#endregion
}
///
/// not used
///
public sealed class ReferenceType : SchemaType
{
#region constructor
internal ReferenceType(Context ctx, SchemaType refType) : base(ctx)
{
_ReferencedType = refType;
}
#endregion
#region data
// In code it has the representation List();
// In serialization, it has the representation List();
private readonly SchemaType _ReferencedType;
#pragma warning disable CA1065 // Do not raise exceptions in unexpected locations
public override string PersistentName => throw new NotImplementedException();
#pragma warning restore CA1065 // Do not raise exceptions in unexpected locations
#endregion
}
}