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; }


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


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


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


        // Родителькася папка
        //[Index]
        [ForeignKey("Parent")]
        public int? Parent_ID { private set; get; }
        //[InverseProperty("")]
        public virtual SDirectory Parent { set; get; }


        // Содержимое папки
        [InverseProperty("Parent")]
        protected virtual List<FS_Item> _Items { set; get; }

        #endregion


        #region GetProperty

        //Это папка (перегружается потомками)
        public virtual bool IsDirectory => false;
        //Это файл (перегружается потомками)
        public virtual bool IsFile => false;

        //Это коренная папка
        [NotMapped]
        public bool IsRoot => !Parent_ID.HasValue;

        //Содержимое папки
        [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 decimal GetSize(Enum_FileSize sizetype, int RoundTo = 3)
        {
            return Math.Round(((decimal)Size / (int)sizetype), RoundTo);
        }

        //Расширение файла
        public virtual string FileExtension => throw new NotImplementedException();


        //Папка содержит указанный элемент
        public bool Contains(FS_Item elem)
        {
            return elem.Items.Contains(elem);
        }
        //Папка содерэит указанное имя
        public bool ContainsName(string Name)
        {
            return Items.FirstOrDefault(e => e.Name == Name) != null;
        }
        //Папка содерэит указанное имя
        public bool ContainsName(FS_Item elem)
        {
            return Items.FirstOrDefault(e => e.Name == elem.Name) != null;
        }

        //Файлы входящие в папкуs
        [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);


        // Виртуальный путь fsitems (в виде коллекции)(рекурсивный)
        [NotMapped]
        public virtual List<FS_Item> LogicPath2
        {
            get
            {
                var path = Parent.LogicPath2;
                path.Add(this);
                return path;
            }
        }     


        #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;
        }
    }
}
