using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


using System.IO;
using System.Numerics;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations;

using Model.Entities.Base;
using Model.Entities.Files.FS_Entities;
using Model.Entities.Users;

namespace Model.Entities.Files
{
    public enum Enum_FileSize
    {
        _byte = 1,
        Kbyte = 1024,
        MByte = 1024 * 1024,
        GByte = 1024 * 1024 * 1024
    }


    public enum Enum_BaseDirectoryEntity
    {
        RootDirectory,
        Directory,

        File,     
        UploadFile
    }

    public class FS_Item : BaseEntity
    {

        #region DB_Data

        [Index]
        [Required]
        public Enum_BaseDirectoryEntity Type { private set; get; }

        /// <summary>
        /// Наименование объекта (без пути)
        /// </summary>
        /// 
        [Required]
        public string Name { private set; get; }


        [ForeignKey("User")]
        public int? UserID { set; get; }        
        public virtual User User { private set; get; }


        /// <summary>
        /// Коренная папка для данного элемента
        /// </summary>
        [ForeignKey("Root")]
        public int? Root_ID { private set; get; }
        public virtual SRootDirectory Root { private set; get; }


        /// <summary>
        /// Родителькася папка
        /// </summary>
        //[Index]
        [ForeignKey("Parent")]
        public int? Parent_ID { private set; get; }
        //[InverseProperty("")]
        public virtual SDirectory Parent { set; get; }
        
        /// <summary>
        /// Содержимое папки
        /// </summary>
        /// 
        [InverseProperty("Parent")]
        protected virtual List<FS_Item> _Items { set; get; }

        #endregion


        #region GetProperty

        [NotMapped]
        public virtual IReadOnlyList<FS_Item> Items => _Items ?? new List<FS_Item>();

        [NotMapped]
        public virtual BigInteger Size => (Items.Count != 0)
            ? Items.Select(e1 => e1.Size).Aggregate((CurSum, elem) => CurSum + elem)
            : 0;
        public double GetSize(Enum_FileSize sizetype, int RoundTo = 3)
        {
            return Math.Round(((double)Size / (int)sizetype), RoundTo);
        }


        public virtual bool IsDirectory => false;
        public virtual bool IsFile => false;


        [NotMapped]
        public bool IsRoot => !Parent_ID.HasValue;

        public bool Contains(FS_Item elem)
        {
            return elem.Items.Contains(elem);
        }

        //public bool ContainsName(SDirectory parent, string Name)
        //{
        //    return parent.Items.FirstOrDefault(e => e.Name == Name) != null;
        //}
        public bool ContainsName(FS_Item elem)
        {
            return Items.FirstOrDefault(e => e.Name == elem.Name) != null;
        }


        [NotMapped]
        public IEnumerable<SFile> Files { get { return Items.Where(e => e.Type == Enum_BaseDirectoryEntity.File).Cast<SFile>(); } }
        [NotMapped]
        public IEnumerable<SDirectory> Directories => Items.Where(e => e.Type == Enum_BaseDirectoryEntity.Directory).Cast<SDirectory>();
        [NotMapped]
        public IEnumerable<SFileUpload> UploadFiles => Items.Where(e => e.Type == Enum_BaseDirectoryEntity.UploadFile).Cast<SFileUpload>();


        [NotMapped]
        public virtual string PhysicalPath => Path.Combine(Parent.PhysicalPath, Name);
        [NotMapped]
        public virtual string LogicPath => Path.Combine(Parent.LogicPath, Name);

        #endregion


        [Obsolete]
        public FS_Item() { }
        protected FS_Item(Enum_BaseDirectoryEntity type, SDirectory parent, string Name, User user)
        {
            this.Type = type;
            this.Parent = parent;
            this.User = user;
            if (Parent != null)
            {
                Root_ID = (parent.IsRoot) ? parent.ID : parent.Root_ID;
            }

            this.Name = Name;
        }


        public override string ToString()
        {
            return Name;
        }
    }
}
