PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/ContentRenderingApi/Data/AbstractData.cs

#
C# | 596 lines | 389 code | 100 blank | 107 comment | 67 complexity | 87c229be697af55735ee98c637c41ce7 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Com.ContentRendering.Api.DataEngine;
  5. using ContentRenderingApi.Configuration;
  6. using ContentRenderingApi.Extender;
  7. using ContentRenderingApi.Skeleton;
  8. using ContentRenderingApi.Path;
  9. using ContentRenderingApi.Data.Comparer;
  10. using System.Linq;
  11. namespace ContentRenderingApi.Data
  12. {
  13. /// <summary/>
  14. internal abstract class AbstractData
  15. {
  16. private ReflectionCache _reflectionCache;
  17. private TransformationConfiguration _transformationConfiguration;
  18. private bool _isCaching;
  19. private AbstractData _parent;
  20. private Dictionary<string, List<AbstractData>> _cachedChildData;
  21. private string _cachedValue;
  22. /// <summary/>
  23. internal AbstractData(
  24. ReflectionCache reflectionCache,
  25. TransformationConfiguration transformationConfiguration,
  26. bool isCaching,
  27. AbstractData parent)
  28. {
  29. this._reflectionCache = reflectionCache;
  30. this._transformationConfiguration = transformationConfiguration;
  31. this._isCaching = isCaching;
  32. this._parent = parent;
  33. this._cachedChildData = new Dictionary<string, List<AbstractData>>();
  34. }
  35. /// <summary/>
  36. internal ReflectionCache ReflectionCache
  37. {
  38. get { return this._reflectionCache; }
  39. }
  40. /// <summary/>
  41. protected abstract void ResolveChildData(List<object> values, string name);
  42. /// <summary/>
  43. internal IEnumerator<AbstractData> FetchChildData(string name)
  44. {
  45. // if the cached value if set and caching is supported .. return it
  46. if (this._isCaching && this._cachedChildData.ContainsKey(name))
  47. {
  48. return this._cachedChildData[name].GetEnumerator();
  49. }
  50. List<object> values = new List<object>();
  51. NodeExtender nodeExtender = new NodeExtender(this);
  52. bool preOverride = false;
  53. // check for matching functions
  54. foreach (PreOverrideSkeleton preOverrideSkeleton in this._transformationConfiguration.PreOverrideSkeletons)
  55. {
  56. // does the path match ... if not move on
  57. if (!this.DoesChildPathMatch(name, preOverrideSkeleton.Path))
  58. {
  59. continue;
  60. }
  61. // data was overridden
  62. preOverride = true;
  63. // invoke the function
  64. object[] outputsResults = preOverrideSkeleton.Invoke(nodeExtender);
  65. // move each element to the new list
  66. if (outputsResults != null)
  67. {
  68. foreach (object outputsResult in outputsResults)
  69. {
  70. values.Add(outputsResult);
  71. }
  72. }
  73. }
  74. // get child values only if data was not overridden
  75. if (!preOverride)
  76. {
  77. this.ResolveChildData(
  78. values,
  79. name);
  80. }
  81. // check for matching functions
  82. foreach (PostOverrideSkeleton postOverrideSkeleton in this._transformationConfiguration.PostOverrideSkeletons)
  83. {
  84. // does the path match ... if not move on
  85. if (!this.DoesChildPathMatch(name, postOverrideSkeleton.Path))
  86. {
  87. continue;
  88. }
  89. // invoke the function
  90. postOverrideSkeleton.Invoke(nodeExtender, values);
  91. }
  92. // check for matching functions
  93. foreach (ConditionalFunctionSkeleton conditionalFunctionSkeleton in this._transformationConfiguration.ConditionalFunctionSkeletons)
  94. {
  95. // does the path match ... if not move on
  96. if (!this.DoesChildPathMatch(name, conditionalFunctionSkeleton.Path))
  97. {
  98. continue;
  99. }
  100. // invoke the function
  101. bool conditionalResult = conditionalFunctionSkeleton.Invoke(nodeExtender);
  102. // move each element to the new list
  103. if (conditionalResult)
  104. {
  105. values.Add(string.Empty);
  106. }
  107. }
  108. // check for matching functions
  109. foreach (FormattedOutputFunctionSkeleton outputFunctionSkeleton in this._transformationConfiguration.FormattedOutputFunctionSkeletons)
  110. {
  111. // does the path match ... if not move on
  112. if (!this.DoesChildPathMatch(name, outputFunctionSkeleton.Path))
  113. {
  114. continue;
  115. }
  116. // invoke the function
  117. string outputResult = outputFunctionSkeleton.Invoke(nodeExtender);
  118. // move each element to the new list
  119. if (outputResult != null)
  120. {
  121. values.Add(ValueReflection.Translate(outputResult));
  122. }
  123. }
  124. // check for matching functions
  125. foreach (FormattedOutputsFunctionSkeleton outputsFunctionSkeleton in this._transformationConfiguration.FormattedOutputsFunctionSkeletons)
  126. {
  127. // does the path match ... if not move on
  128. if (!this.DoesChildPathMatch(name, outputsFunctionSkeleton.Path))
  129. {
  130. continue;
  131. }
  132. // invoke the function
  133. string[] outputsResults = outputsFunctionSkeleton.Invoke(nodeExtender);
  134. // move each element to the new list
  135. if (outputsResults != null)
  136. {
  137. foreach (string outputsResult in outputsResults)
  138. {
  139. values.Add(ValueReflection.Translate(outputsResult));
  140. }
  141. }
  142. }
  143. // check for matching functions
  144. foreach (ObserverFunctionSkeleton observerFunctionSkeleton in this._transformationConfiguration.ObserverFunctionSkeletons)
  145. {
  146. // does the name match ... if not move on
  147. if (!this.DoesChildPathMatch(name, observerFunctionSkeleton.Path))
  148. {
  149. continue;
  150. }
  151. // invoke the function
  152. observerFunctionSkeleton.Invoke(nodeExtender);
  153. }
  154. // check for matching functions
  155. foreach (WildcardOverrideSkeleton wildcardOverrideSkeleton in this._transformationConfiguration.WildcardOverrideSkeletons)
  156. {
  157. // does the path match ... if not move on
  158. if (!this.DoesSelfPathMatch(wildcardOverrideSkeleton.Path))
  159. {
  160. continue;
  161. }
  162. // invoke the function
  163. wildcardOverrideSkeleton.Invoke(nodeExtender, name, values);
  164. }
  165. List<AbstractData> datas = new List<AbstractData>();
  166. foreach (object value in values)
  167. {
  168. datas.Add(new ChildData(
  169. this._reflectionCache,
  170. this._transformationConfiguration,
  171. this._isCaching,
  172. this,
  173. name,
  174. value,
  175. values.Count));
  176. }
  177. List<SortComparer> sortComparers = new List<SortComparer>();
  178. // check for matching functions
  179. foreach (SortSkeleton sortSkeleton in this._transformationConfiguration.SortSkeletons)
  180. {
  181. // fetch the parents ...is this a match
  182. if (!this.DoesChildPathMatch(name, sortSkeleton.Path))
  183. {
  184. continue;
  185. }
  186. // add the sort object
  187. sortComparers.Add(new SortComparer(sortSkeleton));
  188. }
  189. // perform the sort if any names were found
  190. if (sortComparers.Count != 0)
  191. {
  192. datas.Sort(AbstractData.ChainSortComparer(sortComparers));
  193. }
  194. List<SelfSortComparer> selfSortComparers = new List<SelfSortComparer>();
  195. // check for matching functions
  196. foreach (SelfSortSkeleton selfSortSkeleton in this._transformationConfiguration.SelfSortSkeletons)
  197. {
  198. // fetch the parents ...is this a match
  199. if (!this.DoesChildPathMatch(name, selfSortSkeleton.Path))
  200. {
  201. continue;
  202. }
  203. // add the sort object
  204. selfSortComparers.Add(new SelfSortComparer(selfSortSkeleton));
  205. }
  206. // perform the sort if any names were found
  207. if (selfSortComparers.Count != 0)
  208. {
  209. datas.Sort(AbstractData.ChainSelfSortComparer(selfSortComparers));
  210. }
  211. List<ChildSortComparer> childSortComparers = new List<ChildSortComparer>();
  212. // check for matching functions
  213. foreach (ChildSortSkeleton childSortSkeleton in this._transformationConfiguration.ChildSortSkeletons)
  214. {
  215. // fetch the parents ...is this a m atch
  216. if (!this.DoesChildPathMatch(name, childSortSkeleton.Path))
  217. {
  218. continue;
  219. }
  220. // add the sort object
  221. childSortComparers.Add(new ChildSortComparer(childSortSkeleton));
  222. }
  223. // perform the sort if any names were found
  224. if (childSortComparers.Count != 0)
  225. {
  226. datas.Sort(AbstractData.ChainChildSortComparer(childSortComparers));
  227. }
  228. // reset the positions after sorting ... read this comment the next time you
  229. // want to merge the position assignment with the constructor arguments
  230. for (int index =0; index < datas.Count; index++)
  231. {
  232. datas[index].AssignPosition(index + 1);
  233. }
  234. // if caching is supported ... then record it
  235. if (this._isCaching)
  236. {
  237. this._cachedChildData[name] = datas;
  238. }
  239. return datas.GetEnumerator();
  240. }
  241. /// <summary/>
  242. internal IEnumerator<AbstractData> FetchRawChildData(string name)
  243. {
  244. List<object> values = new List<object>();
  245. // get the base class to resolve the data data
  246. this.ResolveChildData(
  247. values,
  248. name);
  249. List<AbstractData> datas = new List<AbstractData>();
  250. foreach (object value in values)
  251. {
  252. datas.Add(new ChildData(
  253. this._reflectionCache,
  254. this._transformationConfiguration,
  255. this._isCaching,
  256. this,
  257. name,
  258. value,
  259. values.Count));
  260. }
  261. // there is usually sorting ... but not here ... thats why assign position is used
  262. for (int index = 0; index < values.Count; index++)
  263. {
  264. datas[index].AssignPosition(index + 1);
  265. }
  266. return datas.GetEnumerator();
  267. }
  268. /// <summary/>
  269. private static ChildSortComparer ChainChildSortComparer(List<ChildSortComparer> childSortComparers)
  270. {
  271. // asssoaited the compar objects
  272. for (int index = 0; index < childSortComparers.Count - 1; index++)
  273. {
  274. childSortComparers[index].Successor = childSortComparers[index + 1];
  275. }
  276. // return the first in the chain
  277. return childSortComparers[0];
  278. }
  279. /// <summary/>
  280. private static SelfSortComparer ChainSelfSortComparer(List<SelfSortComparer> selfSortComparers)
  281. {
  282. // assosiate the compare objects
  283. for (int index = 0; index < selfSortComparers.Count - 1; index++)
  284. {
  285. selfSortComparers[index].Successor = selfSortComparers[index + 1];
  286. }
  287. // return the first in the chain
  288. return selfSortComparers[0];
  289. }
  290. /// <summary/>
  291. private static SortComparer ChainSortComparer(List<SortComparer> sortComparers)
  292. {
  293. // assosiate the compare objects
  294. for (int index = 0; index < sortComparers.Count - 1; index++)
  295. {
  296. sortComparers[index].Successor = sortComparers[index + 1];
  297. }
  298. // return the first in the chain
  299. return sortComparers[0];
  300. }
  301. /// <summary/>
  302. private bool DoesChildPathMatch(
  303. string childName,
  304. AbstractPath path)
  305. {
  306. // only compare the current name if the path is not absolute
  307. if (!path.IsFull())
  308. {
  309. return (path.PartialName == childName);
  310. }
  311. IEnumerable<string> reversedNames = path.FullNames.Reverse();
  312. using (IEnumerator<string> enumerator = reversedNames.GetEnumerator())
  313. {
  314. // there needs to be at least one record
  315. if (!enumerator.MoveNext())
  316. {
  317. return false;
  318. }
  319. // compare the first items
  320. if (childName != enumerator.Current)
  321. {
  322. return false;
  323. }
  324. AbstractData data = this;
  325. // keep looking until the data without a parent is found ... thats the root
  326. while (data._parent != null)
  327. {
  328. // there needs to be at least one record
  329. if (!enumerator.MoveNext())
  330. {
  331. return false;
  332. }
  333. // compare the first items
  334. if (data.Name != enumerator.Current)
  335. {
  336. return false;
  337. }
  338. // fetch the parent data of the current data
  339. data = data._parent;
  340. }
  341. // fail if there are more records
  342. if (enumerator.MoveNext())
  343. {
  344. return false;
  345. }
  346. }
  347. return true;
  348. }
  349. /// <summary/>
  350. private bool DoesSelfPathMatch(AbstractPath path)
  351. {
  352. // only compare the current name if the path is not absolute
  353. if (!path.IsFull())
  354. {
  355. return (path.PartialName == this.Name);
  356. }
  357. IEnumerable<string> reversedNames = path.FullNames.Reverse();
  358. using (IEnumerator<string> enumerator = reversedNames.GetEnumerator())
  359. {
  360. AbstractData data = this;
  361. // keep looking until the data without a parent is found ... thats the root
  362. while (data._parent != null)
  363. {
  364. // there needs to be at least one record
  365. if (!enumerator.MoveNext())
  366. {
  367. return false;
  368. }
  369. // compare the first items
  370. if (data.Name != enumerator.Current)
  371. {
  372. return false;
  373. }
  374. // fetch the parent data of the current data
  375. data = data._parent;
  376. }
  377. // fail if there are more records
  378. if (enumerator.MoveNext())
  379. {
  380. return false;
  381. }
  382. }
  383. return true;
  384. }
  385. /// <summary/>
  386. internal IEnumerator<AbstractData> FetchRootData(string name)
  387. {
  388. // fetch the parent node
  389. AbstractData data = this;
  390. // keep looking until the data without a parent is found ... thats the root
  391. while (data._parent != null)
  392. {
  393. // fetch the parent data of the current data
  394. data = data._parent;
  395. }
  396. // ask the data for its children
  397. return data.FetchChildData(name);
  398. }
  399. /// <summary/>
  400. internal IEnumerator<AbstractData> FetchParentData(int level)
  401. {
  402. // fetch the parent node (that is level 0)
  403. AbstractData data = this;
  404. // move back through the parents until the correct one is found
  405. for (int index = 0; index < level; index++)
  406. {
  407. // if the data isn't found then exit the loop
  408. if (data == null)
  409. {
  410. break;
  411. }
  412. // fetch the parent data of the current data
  413. data = data._parent;
  414. }
  415. List<AbstractData> datas = new List<AbstractData>();
  416. // if the data is non-existent then return nothing
  417. if (data != null)
  418. {
  419. datas.Add(data);
  420. }
  421. // ask the data for its children
  422. return datas.GetEnumerator();
  423. }
  424. /// <summary/>
  425. internal string Value
  426. {
  427. get
  428. {
  429. // if the cached value if set and caching is supported .. return it
  430. if (this._isCaching && this._cachedValue != null)
  431. {
  432. return this._cachedValue;
  433. }
  434. // fetch the raw value
  435. string value = this.FetchValue();
  436. // if caching is supported ... then record it
  437. if (this._isCaching)
  438. {
  439. this._cachedValue = value;
  440. }
  441. // use the default formatter
  442. return value;
  443. }
  444. }
  445. /// <summary/>
  446. private string FetchValue()
  447. {
  448. // fetch the raw value
  449. object rawValue = this.RawValue;
  450. // if the value is null then exit
  451. if (rawValue == null)
  452. {
  453. return null;
  454. }
  455. // use the name formatters first
  456. foreach (LocalFormatterSkeleton localFormatterSkeleton in this._transformationConfiguration.LocalFormatterSkeletons)
  457. {
  458. // fetch the parents ...is this a match
  459. if (!this.DoesSelfPathMatch(localFormatterSkeleton.Path))
  460. {
  461. continue;
  462. }
  463. // does the type match
  464. if (localFormatterSkeleton.Type.IsInstanceOfType(rawValue))
  465. {
  466. return localFormatterSkeleton.Invoke(rawValue);
  467. }
  468. }
  469. // use the generic formatter second
  470. foreach (GlobalFormatterSkeleton globalFormatterSkeleton in this._transformationConfiguration.GlobalFormatterSkeletons)
  471. {
  472. // does the type match
  473. if (globalFormatterSkeleton.Type.IsInstanceOfType(rawValue))
  474. {
  475. return globalFormatterSkeleton.Invoke(rawValue);
  476. }
  477. }
  478. return ValueReflection.Translate(rawValue);
  479. }
  480. /// <summary/>
  481. protected abstract string Name { get; }
  482. /// <summary/>
  483. internal abstract object RawValue { get; }
  484. /// <summary/>
  485. internal abstract int Length { get; }
  486. /// <summary/>
  487. internal abstract int Position { get; }
  488. /// <summary/>
  489. internal AbstractData Parent
  490. {
  491. get { return this._parent; }
  492. }
  493. /// <summary/>
  494. protected abstract void AssignPosition(int position);
  495. }
  496. }