using MediaBrowser.Common.Extensions;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
{
///
/// Class IndexFolder
///
public class IndexFolder : Folder
{
///
/// Initializes a new instance of the class.
///
/// The parent.
/// The shadow.
/// The children.
/// Name of the index.
/// if set to true [group contents].
public IndexFolder(Folder parent, BaseItem shadow, IEnumerable children, string indexName, bool groupContents = true)
{
ChildSource = children;
ShadowItem = shadow;
GroupContents = groupContents;
if (shadow == null)
{
Name = ForcedSortName = "";
}
else
{
SetShadowValues();
}
Id = (parent.Id.ToString() + Name).GetMBId(typeof(IndexFolder));
IndexName = indexName;
Parent = parent;
}
///
/// Resets the parent.
///
/// The parent.
public void ResetParent(Folder parent)
{
Parent = parent;
Id = (parent.Id.ToString() + Name).GetMBId(typeof(IndexFolder));
}
///
/// Override this to true if class should be grouped under a container in indicies
/// The container class should be defined via IndexContainer
///
/// true if [group in index]; otherwise, false.
[IgnoreDataMember]
public override bool GroupInIndex
{
get
{
return ShadowItem != null && ShadowItem.GroupInIndex;
}
}
public override LocationType LocationType
{
get
{
return LocationType.Virtual;
}
}
///
/// Override this to return the folder that should be used to construct a container
/// for this item in an index. GroupInIndex should be true as well.
///
/// The index container.
[IgnoreDataMember]
public override Folder IndexContainer
{
get { return ShadowItem != null ? ShadowItem.IndexContainer : new IndexFolder(this, null, null, "", false); }
}
///
/// Gets or sets a value indicating whether [group contents].
///
/// true if [group contents]; otherwise, false.
protected bool GroupContents { get; set; }
///
/// Gets or sets the child source.
///
/// The child source.
protected IEnumerable ChildSource { get; set; }
///
/// Gets or sets our children.
///
/// Our children.
protected ConcurrentBag OurChildren { get; set; }
///
/// Gets the name of the index.
///
/// The name of the index.
public string IndexName { get; private set; }
///
/// Override to return the children defined to us when we were created
///
/// The actual children.
protected override ConcurrentBag LoadChildren()
{
var originalChildSource = ChildSource.ToList();
var kids = originalChildSource;
if (GroupContents)
{
// Recursively group up the chain
var group = true;
var isSubsequentLoop = false;
while (group)
{
kids = isSubsequentLoop || kids.Any(i => i.GroupInIndex)
? GroupedSource(kids).ToList()
: originalChildSource;
group = kids.Any(i => i.GroupInIndex);
isSubsequentLoop = true;
}
}
// Now - since we built the index grouping from the bottom up - we now need to properly set Parents from the top down
SetParents(this, kids.OfType());
return new ConcurrentBag(kids);
}
///
/// Sets the parents.
///
/// The parent.
/// The kids.
private void SetParents(Folder parent, IEnumerable kids)
{
foreach (var child in kids)
{
child.ResetParent(parent);
child.SetParents(child, child.Children.OfType());
}
}
///
/// Groupeds the source.
///
/// The source.
/// IEnumerable{BaseItem}.
protected IEnumerable GroupedSource(IEnumerable source)
{
return source.GroupBy(i => i.IndexContainer).Select(container => new IndexFolder(this, container.Key, container, null, false));
}
///
/// The item we are shadowing as a folder (Genre, Actor, etc.)
/// We inherit the images and other meta from this item
///
/// The shadow item.
protected BaseItem ShadowItem { get; set; }
///
/// Sets the shadow values.
///
protected void SetShadowValues()
{
if (ShadowItem != null)
{
Name = ShadowItem.Name;
ForcedSortName = ShadowItem.SortName;
Genres = ShadowItem.Genres;
Studios = ShadowItem.Studios;
OfficialRating = ShadowItem.OfficialRating;
BackdropImagePaths = ShadowItem.BackdropImagePaths;
Images = ShadowItem.Images;
Overview = ShadowItem.Overview;
DisplayMediaType = ShadowItem.GetType().Name;
}
}
///
/// Overrides the base implementation to refresh metadata for local trailers
///
/// The cancellation token.
/// if set to true [is new item].
/// if set to true [force].
/// if set to true [allow slow providers].
/// if set to true [reset resolve args].
/// Task{System.Boolean}.
public override async Task RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
{
if (ShadowItem != null)
{
var changed = await ShadowItem.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
SetShadowValues();
return changed;
}
return false;
}
}
}