using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace MatFileHandler
{
///
/// Implementation of Matlab's "opaque objects" via links to subsystem data.
///
internal class OpaqueLink : Opaque, IMatObject
{
///
/// Initializes a new instance of the class.
///
/// Name of the object.
/// Description of object's class.
/// Name of the object's class.
/// Dimensions of the object.
/// Raw data containing links to object's storage.
/// Links to object's storage.
/// Index of object's class.
/// Reference to global subsystem data.
public OpaqueLink(
string name,
string typeDescription,
string className,
int[] dimensions,
DataElement data,
int[] indexToObjectId,
int classIndex,
SubsystemData subsystemData)
: base(name, typeDescription, className, dimensions, data, subsystemData)
{
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
ClassIndex = classIndex;
}
///
/// Gets index of this object's class in subsystem data class list.
///
public int ClassIndex { get; }
///
public IReadOnlyDictionary[] Data
{
get
{
var result = new IReadOnlyDictionary[Count];
for (var i = 0; i < Count; i++)
{
result[i] = FieldNamesArray.ToDictionary(
name => name,
name => this[name, i]);
}
return result;
}
}
///
public IEnumerable FieldNames => FieldNamesArray;
///
/// Gets links to the fields stored in subsystem data.
///
public int[] IndexToObjectId { get; }
///
/// Gets name of this object's class.
///
public override string ClassName => SubsystemData.ClassInformation[ClassIndex].Name;
private string[] FieldNamesArray => SubsystemData.ClassInformation[ClassIndex].FieldNames.ToArray();
///
public IArray this[string field, params int[] list]
{
get => TryGetValue(field, out var result, list) ? result! : throw new ArgumentOutOfRangeException(nameof(list));
set => throw new NotImplementedException();
}
///
public IReadOnlyDictionary this[params int[] list]
{
get => ExtractObject(Dimensions.DimFlatten(list));
set => throw new NotImplementedException();
}
private OpaqueObjectArrayElement ExtractObject(int i)
{
return new OpaqueObjectArrayElement(this, i);
}
private bool TryGetValue(string field, out IArray? output, params int[] list)
{
var index = Dimensions.DimFlatten(list);
var maybeFieldIndex = SubsystemData.ClassInformation[ClassIndex].FindField(field);
if (maybeFieldIndex is not int fieldIndex)
{
output = default;
return false;
}
if (index >= IndexToObjectId.Length)
{
output = default;
return false;
}
var objectId = IndexToObjectId[index];
var objectInfo = SubsystemData.ObjectInformation[objectId];
var fieldId = objectInfo.FieldLinks[fieldIndex];
output = SubsystemData.Data[fieldId];
return true;
}
///
/// Provides access to a single object in object array.
///
internal class OpaqueObjectArrayElement : IReadOnlyDictionary
{
private readonly int index;
private readonly OpaqueLink parent;
///
/// Initializes a new instance of the class.
///
/// Parent object array.
/// Index of the object in the array.
public OpaqueObjectArrayElement(OpaqueLink parent, int index)
{
this.parent = parent ?? throw new ArgumentNullException(nameof(parent));
this.index = index;
}
///
public int Count => parent.FieldNamesArray.Length;
///
public IEnumerable Keys => parent.FieldNames;
///
public IEnumerable Values => parent.FieldNames.Select(fieldName => parent[fieldName, index]);
///
public IArray this[string key] => parent[key, index];
///
public bool ContainsKey(string key)
{
return parent.FieldNames.Contains(key);
}
///
public IEnumerator> GetEnumerator()
{
foreach (var field in parent.FieldNamesArray)
{
yield return new KeyValuePair(field, parent[field, index]);
}
}
#pragma warning disable CS8767
///
public bool TryGetValue(string key, out IArray? value)
#pragma warning restore CS8767
{
return parent.TryGetValue(key, out value, index);
}
///
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
}