csharp/Adoxio/xRM-Portals-Community-Edition/Framework/Adxstudio.Xrm/Web/Mvc/Liquid/EnumerableFilters.cs

Liquid
EnumerableFilters.cs
/*
  Copyright (c) Microsoft Corporation. All rights reserved.
  Licensed under the MIT License. See License.txt in the project root for license information.
*/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DotLiquid;
using Adxstudio.Xrm.Resources;

namespace Adxstudio.Xrm.Web.Mvc.Liquid
{
	public static clast EnumerableFilters
	{
		public static object All(object input)
		{
			var blogPostsDrop = input as BlogPostsDrop;

			if (blogPostsDrop != null)
			{
				return BlogFunctions.All(blogPostsDrop);
			}

			var forumThreadsDrop = input as ForumThreadsDrop;

			if (forumThreadsDrop != null)
			{
				return ForumFunctions.All(forumThreadsDrop);
			}

			var forumPostsDrop = input as ForumPostsDrop;

			if (forumPostsDrop != null)
			{
				return ForumFunctions.All(forumPostsDrop);
			}

			var enumerable = input as IEnumerable;

			if (enumerable != null)
			{
				return enumerable;
			}

			return input;
		}

		public static IEnumerable Batch(IEnumerable input, int batchSize)
		{
			return input.Cast().Batch(batchSize);
		}

		public static IEnumerable Concat(IEnumerable first, object second)
		{
			var firstEnumerable = first == null ? Enumerable.Empty() : first.Cast();
			var secondEnumerable = second as IEnumerable;

			return secondEnumerable == null
				? firstEnumerable.Concat(new[] { second })
				: firstEnumerable.Concat(secondEnumerable.Cast());
		}

		public static IEnumerable Except(IEnumerable input, string key, object value)
		{
			return input.Cast().Where(e => !KeyEquals(e, key, value));
		}

		public static IEnumerable GroupBy(IEnumerable input, string key)
		{
			return input.Cast().GroupBy(e => Get(e, key)).Select(group => new Hash
			{
				{ "key", @group.Key },
				{ "items", @group.AsEnumerable() }
			});
		}

		public static object Orderby(object input, string key, string direction = "asc")
		{
			return OrderBy(input, key, direction);
		}

		public static object OrderBy(object input, string key, string direction = "asc")
		{
			var blogPostsDrop = input as BlogPostsDrop;

			if (blogPostsDrop != null)
			{
				return BlogFunctions.OrderBy(blogPostsDrop, key, direction);
			}

			var forumThreadsDrop = input as ForumThreadsDrop;

			if (forumThreadsDrop != null)
			{
				return ForumFunctions.OrderBy(forumThreadsDrop, key, direction);
			}

			var enumerable = input as IEnumerable;

			if (enumerable != null)
			{
				return string.Equals(direction, "desc", StringComparison.InvariantCultureIgnoreCase)
					|| string.Equals(direction, "descending", StringComparison.InvariantCultureIgnoreCase)
					? enumerable.Cast().OrderByDescending(e => Get(e, key))
					: enumerable.Cast().OrderBy(e => Get(e, key));
			}

			return input;
		}

		public static object TopLevel(object input, int pageSize)
		{
			var categoriesDrop = input as CategoriesDrop;

			if (categoriesDrop != null)
			{
				return CategoryFunctions.TopLevel(categoriesDrop, pageSize);
			}

			return input;
		}

		public static object CategoryNumber(object input, string categoryNumber)
		{
			var categoriesDrop = input as CategoriesDrop;

			if (categoriesDrop != null)
			{
				return CategoryFunctions.CategoryNumber(categoriesDrop, categoryNumber);
			}

			return input;
		}

		public static object Related(object input, string categoryIdString, int pageSize)
		{
			var categoriesDrop = input as CategoriesDrop;
			Guid categoryId;
			
			if (categoriesDrop != null && Guid.TryParse(categoryIdString, out categoryId))
			{
				return CategoryFunctions.Related(categoriesDrop, categoryId, pageSize);
			}

			return input;
		}


		public static object Top(object input, int pageSize, string lang)
		{
			var articlesDrop = input as KnowledgeArticlesDrop;

			if (articlesDrop != null)
			{
				return KnowledgeArticleFunctions.Top(articlesDrop, pageSize, lang);
			}

			return input;
		}

		public static object Recent(object input, int pageSize, string lang)
		{
			var articlesDrop = input as KnowledgeArticlesDrop;

			if (articlesDrop != null)
			{
				return KnowledgeArticleFunctions.Recent(articlesDrop, pageSize, lang);
			}

			var categoriesDrop = input as CategoriesDrop;

			if (categoriesDrop != null)
			{
				return CategoryFunctions.Recent(categoriesDrop, pageSize);
			}

			return input;
		}

		public static object Popular(object input, int pageSize, string lang)
		{
			var articlesDrop = input as KnowledgeArticlesDrop;

			if (articlesDrop != null)
			{
				return KnowledgeArticleFunctions.Popular(articlesDrop, pageSize, lang);
			}

			return input;
		}

		public static object Paginate(object input, int index, int count)
		{
			var blogPostsDrop = input as BlogPostsDrop;

			if (blogPostsDrop != null)
			{
				return BlogFunctions.Paginate(blogPostsDrop, index, count);
			}

			var forumThreadsDrop = input as ForumThreadsDrop;

			if (forumThreadsDrop != null)
			{
				return ForumFunctions.Paginate(forumThreadsDrop, index, count);
			}

			var forumPostsDrop = input as ForumPostsDrop;

			if (forumPostsDrop != null)
			{
				return ForumFunctions.Paginate(forumPostsDrop, index, count);
			}

			var enumerable = input as IEnumerable;

			if (enumerable != null)
			{
				return enumerable.Cast().Skip(index).Take(count);
			}

			return input;
		}

		public static object Random(Context context, IEnumerable input)
		{
			IPortalLiquidContext portalLiquidContext;

			var random = context.TryGetPortalLiquidContext(out portalLiquidContext)
				? portalLiquidContext.Random
				: new Random();

			var items = input.Cast().ToArray();

			return items.ElementAt(random.Next(items.Length));
		}

		public static IEnumerable Select(IEnumerable input, string key)
		{
			return input.Cast().Select(e => Get(e, key));
		}

		public static IEnumerable Shuffle(Context context, IEnumerable input)
		{
			IPortalLiquidContext portalLiquidContext;

			var random = context.TryGetPortalLiquidContext(out portalLiquidContext)
				? portalLiquidContext.Random
				: new Random();

			return input.Cast().ShuffleIterator(random);
		}

		private static IEnumerable ShuffleIterator(this IEnumerable source, Random random)
		{
			var buffer = source.ToList();

			for (var i = 0; i < buffer.Count; i++)
			{
				var j = random.Next(i, buffer.Count);

				yield return buffer[j];

				buffer[j] = buffer[i];
			}
		}

		public static object Skip(object input, int count)
		{
			var blogPostsDrop = input as BlogPostsDrop;

			if (blogPostsDrop != null)
			{
				return BlogFunctions.FromIndex(blogPostsDrop, count);
			}

			var forumThreadsDrop = input as ForumThreadsDrop;

			if (forumThreadsDrop != null)
			{
				return ForumFunctions.FromIndex(forumThreadsDrop, count);
			}

			var forumPostsDrop = input as ForumPostsDrop;

			if (forumPostsDrop != null)
			{
				return ForumFunctions.FromIndex(forumPostsDrop, count);
			}

			var enumerable = input as IEnumerable;

			if (enumerable != null)
			{
				return enumerable.Cast().Skip(count);
			}

			return input;
		}

		public static object Take(object input, int count)
		{
			var blogPostsDrop = input as BlogPostsDrop;

			if (blogPostsDrop != null)
			{
				return BlogFunctions.Take(blogPostsDrop, count);
			}

			var forumThreadsDrop = input as ForumThreadsDrop;

			if (forumThreadsDrop != null)
			{
				return ForumFunctions.Take(forumThreadsDrop, count);
			}

			var forumPostsDrop = input as ForumPostsDrop;

			if (forumPostsDrop != null)
			{
				return ForumFunctions.Take(forumPostsDrop, count);
			}

			var enumerable = input as IEnumerable;

			if (enumerable != null)
			{
				return enumerable.Cast().Take(count);
			}

			return input;
		}

		public static IEnumerable Thenby(IOrderedEnumerable input, string key, string direction = "asc")
		{
			return ThenBy(input, key, direction);
		}

		public static IEnumerable ThenBy(IOrderedEnumerable input, string key, string direction = "asc")
		{
			return string.Equals(direction, "desc", StringComparison.InvariantCultureIgnoreCase)
				|| string.Equals(direction, "descending", StringComparison.InvariantCultureIgnoreCase)
				? input.ThenByDescending(e => Get(e, key))
				: input.ThenBy(e => Get(e, key));
		}

		public static IEnumerable Where(IEnumerable input, string key, object value)
		{
			return input.Cast().Where(e => KeyEquals(e, key, value));
		}

		private static object Get(object input, string key)
		{
			if (input == null || key == null)
			{
				return null;
			}

			var hash = input as Hash;

			if (hash != null)
			{
				return hash[key];
			}

			var dictionary = input as IDictionary;

			if (dictionary != null)
			{
				object value;

				return dictionary.TryGetValue(key, out value) ? value : null;
			}

			var drop = input as Drop;

			if (drop != null)
			{
				var dotIndex = key.IndexOf(".", StringComparison.InvariantCultureIgnoreCase);

				if (dotIndex > 0 && dotIndex < (key.Length - 1))
				{
					return Get(drop.InvokeDrop(key.Substring(0, dotIndex)), key.Substring(dotIndex + 1));
				}

				return drop.InvokeDrop(key);
			}

			var liquidizable = input as ILiquidizable;

			if (liquidizable != null)
			{
				return Get(liquidizable.ToLiquid(), key);
			}

			return null;
		}

		private static bool KeyEquals(object @object, string key, object value)
		{
			var propertyValue = Get(@object, key);

			return propertyValue == null ? value == null : propertyValue.Equals(value);
		}
	}
}