using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Model.Entities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Entities
{
    /// 
    /// Class Video
    /// 
    public class Video : BaseItem, IHasMediaStreams
    {
        public bool IsMultiPart { get; set; }
        public List AdditionalPartIds { get; set; }
        public Video()
        {
            MediaStreams = new List();
            PlayableStreamFileNames = new List();
            AdditionalPartIds = new List();
        }
        public VideoFormat VideoFormat
        {
            get
            {
                if (!Video3DFormat.HasValue)
                {
                    return VideoFormat.Standard;
                }
                return VideoFormat.Digital3D;
            }
        }
        /// 
        /// Gets or sets the type of the video.
        /// 
        /// The type of the video.
        public VideoType VideoType { get; set; }
        /// 
        /// Gets or sets the type of the iso.
        /// 
        /// The type of the iso.
        public IsoType? IsoType { get; set; }
        /// 
        /// Gets or sets the video3 D format.
        /// 
        /// The video3 D format.
        public Video3DFormat? Video3DFormat { get; set; }
        /// 
        /// Gets or sets the media streams.
        /// 
        /// The media streams.
        public List MediaStreams { get; set; }
        /// 
        /// If the video is a folder-rip, this will hold the file list for the largest playlist
        /// 
        public List PlayableStreamFileNames { get; set; }
        /// 
        /// Gets the playable stream files.
        /// 
        /// List{System.String}.
        public List GetPlayableStreamFiles()
        {
            return GetPlayableStreamFiles(Path);
        }
        /// 
        /// Gets the playable stream files.
        /// 
        /// The root path.
        /// List{System.String}.
        public List GetPlayableStreamFiles(string rootPath)
        {
            if (PlayableStreamFileNames == null)
            {
                return null;
            }
            var allFiles = Directory.EnumerateFiles(rootPath, "*", SearchOption.AllDirectories).ToList();
            return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase)))
                .Where(f => !string.IsNullOrEmpty(f))
                .ToList();
        }
        /// 
        /// The default video stream for this video.  Use this to determine media info for this item.
        /// 
        /// The default video stream.
        [IgnoreDataMember]
        public MediaStream DefaultVideoStream
        {
            get { return MediaStreams != null ? MediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video) : null; }
        }
        /// 
        /// Gets a value indicating whether [is3 D].
        /// 
        /// true if [is3 D]; otherwise, false.
        [IgnoreDataMember]
        public bool Is3D
        {
            get { return Video3DFormat.HasValue; }
        }
        /// 
        /// Gets the type of the media.
        /// 
        /// The type of the media.
        public override string MediaType
        {
            get
            {
                return Model.Entities.MediaType.Video;
            }
        }
        /// 
        /// 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].
        /// The reset resolve args.
        /// true if a provider reports we changed
        public override async Task RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)
        {
            // Kick off a task to refresh the main item
            var result = await base.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders, resetResolveArgs).ConfigureAwait(false);
            var additionalPartsChanged = false;
            // Must have a parent to have additional parts
            // In other words, it must be part of the Parent/Child tree
            // The additional parts won't have additional parts themselves
            if (IsMultiPart && LocationType == LocationType.FileSystem && Parent != null)
            {
                try
                {
                    additionalPartsChanged = await RefreshAdditionalParts(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false);
                }
                catch (IOException ex)
                {
                    Logger.ErrorException("Error loading additional parts for {0}.", ex, Name);
                }
            }
            return additionalPartsChanged || result;
        }
        /// 
        /// Refreshes the additional parts.
        /// 
        /// The cancellation token.
        /// if set to true [force save].
        /// if set to true [force refresh].
        /// if set to true [allow slow providers].
        /// Task{System.Boolean}.
        private async Task RefreshAdditionalParts(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true)
        {
            var newItems = LoadAdditionalParts().ToList();
            var newItemIds = newItems.Select(i => i.Id).ToList();
            var itemsChanged = !AdditionalPartIds.SequenceEqual(newItemIds);
            var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders));
            var results = await Task.WhenAll(tasks).ConfigureAwait(false);
            AdditionalPartIds = newItemIds;
            return itemsChanged || results.Contains(true);
        }
        /// 
        /// Loads the additional parts.
        /// 
        /// IEnumerable{Video}.
        private IEnumerable