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

namespace MaddoShared
{
    public class FileHelperOptions
    {
        public bool SeparateFiles { get; set; }
        public NumerazioneType NumerationType { get; set; }
        public int CounterSize { get; set; }
        public string Suffix { get; set; }
        public int FilesPerFolder { get; set; }
    }
    public enum NumerazioneType
    {
        Progressiva,
        Files
    }
    public class FileHelperSharp
    {

        public List<FileData> GetFilesRecursive(DirectoryInfo root, DirectoryInfo destRoot, string filter, FileHelperOptions options)
        {
            ConcurrentDictionary<FileInfo, DirectoryInfo> dirSourceDest = new ConcurrentDictionary<FileInfo, DirectoryInfo>();
            List<FileInfo> result = new List<FileInfo>();

            // Dim stack As New Stack(Of DirectoryInfo)
            Stack<KeyValuePair<DirectoryInfo, DirectoryInfo>> stack = new Stack<KeyValuePair<DirectoryInfo, DirectoryInfo>>();



            KeyValuePair<DirectoryInfo, DirectoryInfo> pair = new KeyValuePair<DirectoryInfo, DirectoryInfo>();


            // stack.Push(root)
            stack.Push(new KeyValuePair<DirectoryInfo, DirectoryInfo>(root, destRoot));

            while ((stack.Count > 0))
            {
                KeyValuePair<DirectoryInfo, DirectoryInfo> curDirKV = stack.Pop();
                // curDirKP = stack.Pop()
                DirectoryInfo dir = curDirKV.Key;
                DirectoryInfo dDir = curDirKV.Value;
                try
                {
                    // result.AddRange(dir.GetFiles(filter, SearchOption.TopDirectoryOnly))
                    // dividere file qui
                    if (options.FilesPerFolder > 0 & options.SeparateFiles)
                        AppendDictionaryConcurrent(dirSourceDest, DividiFilesInDirConcurrent(dir, dDir, options, filter));
                    else
                        AppendDictionaryConcurrent(dirSourceDest, DividiFilesInDirConcurrent(dir, dDir, options, filter));

                    foreach (DirectoryInfo subDirectory in dir.GetDirectories())
                        stack.Push(new KeyValuePair<DirectoryInfo, DirectoryInfo>(subDirectory, new DirectoryInfo(Path.Combine(dDir.FullName, subDirectory.Name))));
                }
                catch (Exception ex)
                {
                    // TODO ERROR
                }
            }

            List<FileData> resultData = new List<FileData>();
            resultData.AddRange(from p in dirSourceDest
                                select new FileData(p.Key, p.Value));
            return resultData;
        }

        public ConcurrentDictionary<FileInfo, DirectoryInfo> AppendDictionaryConcurrent(ConcurrentDictionary<FileInfo, DirectoryInfo> dictA, ConcurrentDictionary<FileInfo, DirectoryInfo> dictB)
        {
            foreach (KeyValuePair<FileInfo, DirectoryInfo> pair in dictB)
                dictA.TryAdd(pair.Key, pair.Value);
            return dictA;
        }


        private ConcurrentDictionary<FileInfo, DirectoryInfo> DividiFilesInDirConcurrent(DirectoryInfo dir, DirectoryInfo dirDest, FileHelperOptions options, string filter)
        {
            //int filesCount = dir.GetFiles(Filter).Length;
            int contaFilePerDir = 0;
            int contaDirPerDir = 0;
            string tempText;// = string.Empty;
            ConcurrentDictionary<FileInfo, DirectoryInfo> foldersDict = new ConcurrentDictionary<FileInfo, DirectoryInfo>();

            DirectoryInfo destDir;
            destDir = new DirectoryInfo(Path.Combine(dirDest.FullName));
            foreach (FileInfo file in dir.GetFiles(filter))
            {
                contaFilePerDir += 1;

                if (contaFilePerDir == (contaDirPerDir * options.FilesPerFolder) + 1)
                {
                    contaDirPerDir += 1;

                    tempText = options.NumerationType == NumerazioneType.Progressiva ? contaDirPerDir.ToString() : (contaDirPerDir * options.FilesPerFolder).ToString();
                    int i;
                    for (i = 1; i <= (options.CounterSize - tempText.Length); i++)
                        tempText = "0" + tempText;
                    destDir = new DirectoryInfo(Path.Combine(dirDest.FullName, options.Suffix + tempText));
                }

                if (!destDir.Exists)
                    destDir.Create();

                foldersDict.TryAdd(file, destDir);
            }

            return foldersDict;
        }

    }
}
