/Source/ContentRenderingApi/Data/AbstractData.cs
C# | 596 lines | 389 code | 100 blank | 107 comment | 67 complexity | 87c229be697af55735ee98c637c41ce7 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Text;
- using Com.ContentRendering.Api.DataEngine;
- using ContentRenderingApi.Configuration;
- using ContentRenderingApi.Extender;
- using ContentRenderingApi.Skeleton;
- using ContentRenderingApi.Path;
- using ContentRenderingApi.Data.Comparer;
- using System.Linq;
-
- namespace ContentRenderingApi.Data
- {
- /// <summary/>
- internal abstract class AbstractData
- {
- private ReflectionCache _reflectionCache;
- private TransformationConfiguration _transformationConfiguration;
- private bool _isCaching;
- private AbstractData _parent;
- private Dictionary<string, List<AbstractData>> _cachedChildData;
- private string _cachedValue;
-
- /// <summary/>
- internal AbstractData(
- ReflectionCache reflectionCache,
- TransformationConfiguration transformationConfiguration,
- bool isCaching,
- AbstractData parent)
- {
- this._reflectionCache = reflectionCache;
- this._transformationConfiguration = transformationConfiguration;
- this._isCaching = isCaching;
- this._parent = parent;
- this._cachedChildData = new Dictionary<string, List<AbstractData>>();
- }
-
- /// <summary/>
- internal ReflectionCache ReflectionCache
- {
- get { return this._reflectionCache; }
- }
-
- /// <summary/>
- protected abstract void ResolveChildData(List<object> values, string name);
-
- /// <summary/>
- internal IEnumerator<AbstractData> FetchChildData(string name)
- {
- // if the cached value if set and caching is supported .. return it
- if (this._isCaching && this._cachedChildData.ContainsKey(name))
- {
- return this._cachedChildData[name].GetEnumerator();
- }
-
- List<object> values = new List<object>();
-
- NodeExtender nodeExtender = new NodeExtender(this);
-
- bool preOverride = false;
-
- // check for matching functions
- foreach (PreOverrideSkeleton preOverrideSkeleton in this._transformationConfiguration.PreOverrideSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesChildPathMatch(name, preOverrideSkeleton.Path))
- {
- continue;
- }
-
- // data was overridden
- preOverride = true;
-
- // invoke the function
- object[] outputsResults = preOverrideSkeleton.Invoke(nodeExtender);
-
- // move each element to the new list
- if (outputsResults != null)
- {
- foreach (object outputsResult in outputsResults)
- {
- values.Add(outputsResult);
- }
- }
- }
-
- // get child values only if data was not overridden
- if (!preOverride)
- {
- this.ResolveChildData(
- values,
- name);
- }
-
- // check for matching functions
- foreach (PostOverrideSkeleton postOverrideSkeleton in this._transformationConfiguration.PostOverrideSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesChildPathMatch(name, postOverrideSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- postOverrideSkeleton.Invoke(nodeExtender, values);
- }
-
- // check for matching functions
- foreach (ConditionalFunctionSkeleton conditionalFunctionSkeleton in this._transformationConfiguration.ConditionalFunctionSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesChildPathMatch(name, conditionalFunctionSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- bool conditionalResult = conditionalFunctionSkeleton.Invoke(nodeExtender);
-
- // move each element to the new list
- if (conditionalResult)
- {
- values.Add(string.Empty);
- }
- }
-
- // check for matching functions
- foreach (FormattedOutputFunctionSkeleton outputFunctionSkeleton in this._transformationConfiguration.FormattedOutputFunctionSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesChildPathMatch(name, outputFunctionSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- string outputResult = outputFunctionSkeleton.Invoke(nodeExtender);
-
- // move each element to the new list
- if (outputResult != null)
- {
- values.Add(ValueReflection.Translate(outputResult));
- }
- }
-
- // check for matching functions
- foreach (FormattedOutputsFunctionSkeleton outputsFunctionSkeleton in this._transformationConfiguration.FormattedOutputsFunctionSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesChildPathMatch(name, outputsFunctionSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- string[] outputsResults = outputsFunctionSkeleton.Invoke(nodeExtender);
-
- // move each element to the new list
- if (outputsResults != null)
- {
- foreach (string outputsResult in outputsResults)
- {
- values.Add(ValueReflection.Translate(outputsResult));
- }
- }
- }
-
- // check for matching functions
- foreach (ObserverFunctionSkeleton observerFunctionSkeleton in this._transformationConfiguration.ObserverFunctionSkeletons)
- {
- // does the name match ... if not move on
- if (!this.DoesChildPathMatch(name, observerFunctionSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- observerFunctionSkeleton.Invoke(nodeExtender);
- }
-
- // check for matching functions
- foreach (WildcardOverrideSkeleton wildcardOverrideSkeleton in this._transformationConfiguration.WildcardOverrideSkeletons)
- {
- // does the path match ... if not move on
- if (!this.DoesSelfPathMatch(wildcardOverrideSkeleton.Path))
- {
- continue;
- }
-
- // invoke the function
- wildcardOverrideSkeleton.Invoke(nodeExtender, name, values);
- }
-
- List<AbstractData> datas = new List<AbstractData>();
-
- foreach (object value in values)
- {
- datas.Add(new ChildData(
- this._reflectionCache,
- this._transformationConfiguration,
- this._isCaching,
- this,
- name,
- value,
- values.Count));
- }
-
- List<SortComparer> sortComparers = new List<SortComparer>();
-
- // check for matching functions
- foreach (SortSkeleton sortSkeleton in this._transformationConfiguration.SortSkeletons)
- {
- // fetch the parents ...is this a match
- if (!this.DoesChildPathMatch(name, sortSkeleton.Path))
- {
- continue;
- }
-
- // add the sort object
- sortComparers.Add(new SortComparer(sortSkeleton));
- }
-
- // perform the sort if any names were found
- if (sortComparers.Count != 0)
- {
- datas.Sort(AbstractData.ChainSortComparer(sortComparers));
- }
-
- List<SelfSortComparer> selfSortComparers = new List<SelfSortComparer>();
-
- // check for matching functions
- foreach (SelfSortSkeleton selfSortSkeleton in this._transformationConfiguration.SelfSortSkeletons)
- {
- // fetch the parents ...is this a match
- if (!this.DoesChildPathMatch(name, selfSortSkeleton.Path))
- {
- continue;
- }
-
- // add the sort object
- selfSortComparers.Add(new SelfSortComparer(selfSortSkeleton));
- }
-
- // perform the sort if any names were found
- if (selfSortComparers.Count != 0)
- {
- datas.Sort(AbstractData.ChainSelfSortComparer(selfSortComparers));
- }
-
- List<ChildSortComparer> childSortComparers = new List<ChildSortComparer>();
-
- // check for matching functions
- foreach (ChildSortSkeleton childSortSkeleton in this._transformationConfiguration.ChildSortSkeletons)
- {
- // fetch the parents ...is this a m atch
- if (!this.DoesChildPathMatch(name, childSortSkeleton.Path))
- {
- continue;
- }
-
- // add the sort object
- childSortComparers.Add(new ChildSortComparer(childSortSkeleton));
- }
-
- // perform the sort if any names were found
- if (childSortComparers.Count != 0)
- {
- datas.Sort(AbstractData.ChainChildSortComparer(childSortComparers));
- }
-
- // reset the positions after sorting ... read this comment the next time you
- // want to merge the position assignment with the constructor arguments
- for (int index =0; index < datas.Count; index++)
- {
- datas[index].AssignPosition(index + 1);
- }
-
- // if caching is supported ... then record it
- if (this._isCaching)
- {
- this._cachedChildData[name] = datas;
- }
-
- return datas.GetEnumerator();
- }
-
- /// <summary/>
- internal IEnumerator<AbstractData> FetchRawChildData(string name)
- {
- List<object> values = new List<object>();
-
- // get the base class to resolve the data data
- this.ResolveChildData(
- values,
- name);
-
- List<AbstractData> datas = new List<AbstractData>();
-
- foreach (object value in values)
- {
- datas.Add(new ChildData(
- this._reflectionCache,
- this._transformationConfiguration,
- this._isCaching,
- this,
- name,
- value,
- values.Count));
- }
-
- // there is usually sorting ... but not here ... thats why assign position is used
- for (int index = 0; index < values.Count; index++)
- {
- datas[index].AssignPosition(index + 1);
- }
-
- return datas.GetEnumerator();
- }
-
- /// <summary/>
- private static ChildSortComparer ChainChildSortComparer(List<ChildSortComparer> childSortComparers)
- {
- // asssoaited the compar objects
- for (int index = 0; index < childSortComparers.Count - 1; index++)
- {
- childSortComparers[index].Successor = childSortComparers[index + 1];
- }
-
- // return the first in the chain
- return childSortComparers[0];
- }
-
- /// <summary/>
- private static SelfSortComparer ChainSelfSortComparer(List<SelfSortComparer> selfSortComparers)
- {
- // assosiate the compare objects
- for (int index = 0; index < selfSortComparers.Count - 1; index++)
- {
- selfSortComparers[index].Successor = selfSortComparers[index + 1];
- }
-
- // return the first in the chain
- return selfSortComparers[0];
- }
-
- /// <summary/>
- private static SortComparer ChainSortComparer(List<SortComparer> sortComparers)
- {
- // assosiate the compare objects
- for (int index = 0; index < sortComparers.Count - 1; index++)
- {
- sortComparers[index].Successor = sortComparers[index + 1];
- }
-
- // return the first in the chain
- return sortComparers[0];
- }
-
- /// <summary/>
- private bool DoesChildPathMatch(
- string childName,
- AbstractPath path)
- {
- // only compare the current name if the path is not absolute
- if (!path.IsFull())
- {
- return (path.PartialName == childName);
- }
-
- IEnumerable<string> reversedNames = path.FullNames.Reverse();
-
- using (IEnumerator<string> enumerator = reversedNames.GetEnumerator())
- {
- // there needs to be at least one record
- if (!enumerator.MoveNext())
- {
- return false;
- }
-
- // compare the first items
- if (childName != enumerator.Current)
- {
- return false;
- }
-
- AbstractData data = this;
-
- // keep looking until the data without a parent is found ... thats the root
- while (data._parent != null)
- {
- // there needs to be at least one record
- if (!enumerator.MoveNext())
- {
- return false;
- }
-
- // compare the first items
- if (data.Name != enumerator.Current)
- {
- return false;
- }
-
- // fetch the parent data of the current data
- data = data._parent;
- }
-
- // fail if there are more records
- if (enumerator.MoveNext())
- {
- return false;
- }
- }
-
- return true;
- }
-
- /// <summary/>
- private bool DoesSelfPathMatch(AbstractPath path)
- {
- // only compare the current name if the path is not absolute
- if (!path.IsFull())
- {
- return (path.PartialName == this.Name);
- }
-
- IEnumerable<string> reversedNames = path.FullNames.Reverse();
-
- using (IEnumerator<string> enumerator = reversedNames.GetEnumerator())
- {
- AbstractData data = this;
-
- // keep looking until the data without a parent is found ... thats the root
- while (data._parent != null)
- {
- // there needs to be at least one record
- if (!enumerator.MoveNext())
- {
- return false;
- }
-
- // compare the first items
- if (data.Name != enumerator.Current)
- {
- return false;
- }
-
- // fetch the parent data of the current data
- data = data._parent;
- }
-
- // fail if there are more records
- if (enumerator.MoveNext())
- {
- return false;
- }
- }
-
- return true;
- }
-
- /// <summary/>
- internal IEnumerator<AbstractData> FetchRootData(string name)
- {
- // fetch the parent node
- AbstractData data = this;
-
- // keep looking until the data without a parent is found ... thats the root
- while (data._parent != null)
- {
- // fetch the parent data of the current data
- data = data._parent;
- }
-
- // ask the data for its children
- return data.FetchChildData(name);
- }
-
- /// <summary/>
- internal IEnumerator<AbstractData> FetchParentData(int level)
- {
- // fetch the parent node (that is level 0)
- AbstractData data = this;
-
- // move back through the parents until the correct one is found
- for (int index = 0; index < level; index++)
- {
- // if the data isn't found then exit the loop
- if (data == null)
- {
- break;
- }
-
- // fetch the parent data of the current data
- data = data._parent;
- }
-
- List<AbstractData> datas = new List<AbstractData>();
-
- // if the data is non-existent then return nothing
- if (data != null)
- {
- datas.Add(data);
- }
-
- // ask the data for its children
- return datas.GetEnumerator();
- }
-
- /// <summary/>
- internal string Value
- {
- get
- {
- // if the cached value if set and caching is supported .. return it
- if (this._isCaching && this._cachedValue != null)
- {
- return this._cachedValue;
- }
-
- // fetch the raw value
- string value = this.FetchValue();
-
- // if caching is supported ... then record it
- if (this._isCaching)
- {
- this._cachedValue = value;
- }
-
- // use the default formatter
- return value;
- }
- }
-
- /// <summary/>
- private string FetchValue()
- {
- // fetch the raw value
- object rawValue = this.RawValue;
-
- // if the value is null then exit
- if (rawValue == null)
- {
- return null;
- }
-
- // use the name formatters first
- foreach (LocalFormatterSkeleton localFormatterSkeleton in this._transformationConfiguration.LocalFormatterSkeletons)
- {
- // fetch the parents ...is this a match
- if (!this.DoesSelfPathMatch(localFormatterSkeleton.Path))
- {
- continue;
- }
-
- // does the type match
- if (localFormatterSkeleton.Type.IsInstanceOfType(rawValue))
- {
- return localFormatterSkeleton.Invoke(rawValue);
- }
- }
-
- // use the generic formatter second
- foreach (GlobalFormatterSkeleton globalFormatterSkeleton in this._transformationConfiguration.GlobalFormatterSkeletons)
- {
- // does the type match
- if (globalFormatterSkeleton.Type.IsInstanceOfType(rawValue))
- {
- return globalFormatterSkeleton.Invoke(rawValue);
- }
- }
-
- return ValueReflection.Translate(rawValue);
- }
-
- /// <summary/>
- protected abstract string Name { get; }
-
- /// <summary/>
- internal abstract object RawValue { get; }
-
- /// <summary/>
- internal abstract int Length { get; }
-
- /// <summary/>
- internal abstract int Position { get; }
-
- /// <summary/>
- internal AbstractData Parent
- {
- get { return this._parent; }
- }
-
- /// <summary/>
- protected abstract void AssignPosition(int position);
- }
- }