private async Task Uncompress(GdItem item, int folderNumber)
        {
            var newPath = Path.Combine(sdPath, FormatFolderNumber(folderNumber));

            if (!await Helper.DirectoryExistsAsync(newPath))
            {
                await Helper.CreateDirectoryAsync(newPath);
            }

            await Task.Run(() => Helper.DependencyManager.ExtractArchive(Path.Combine(item.FullFolderPath, item.ImageFile), newPath));

            item.FullFolderPath = newPath;
            item.Work           = WorkMode.None;
            item.SdNumber       = folderNumber;

            item.FileFormat = FileFormat.Uncompressed;

            var gdi = await ImageHelper.CreateGdItemAsync(newPath);

            //item.ImageFiles[0] = gdi.ImageFile;
            item.ImageFiles.Clear();
            item.ImageFiles.AddRange(gdi.ImageFiles);
            item.Length = gdi.Length;
            item.Ip     = gdi.Ip;
        }
        private async Task <GdItem> LazyLoadItemFromCard(int sdNumber, string folderPath)
        {
            var files = await Helper.GetFilesAsync(folderPath);

            var itemName = string.Empty;
            var nameFile = files.FirstOrDefault(x => Path.GetFileName(x).Equals(Constants.NameTextFile, StringComparison.OrdinalIgnoreCase));

            if (nameFile != null)
            {
                itemName = await Helper.ReadAllTextAsync(nameFile);
            }

            if (string.IsNullOrWhiteSpace(nameFile))
            {
                return(null);
            }

            string itemImageFile = null;

            //is uncompressed?
            foreach (var file in files)
            {
                if (supportedImageFormats.Any(x => x.Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase)))
                {
                    itemImageFile = file;
                    break;
                }
            }

            if (itemImageFile == null)
            {
                throw new Exception("No valid image found on folder");
            }

            var item = new GdItem
            {
                Guid           = Guid.NewGuid().ToString(),
                FullFolderPath = folderPath,
                FileFormat     = FileFormat.Uncompressed,
                SdNumber       = sdNumber,
                Name           = itemName,
                Length         = ByteSizeLib.ByteSize.FromBytes(new DirectoryInfo(folderPath).GetFiles().Sum(x => x.Length)),
            };

            item.ImageFiles.Add(Path.GetFileName(itemImageFile));

            return(item);
        }
        public async Task LoadItemsFromCard()
        {
            ItemList.Clear();

            var toAdd    = new List <Tuple <int, string> >();
            var rootDirs = await Helper.GetDirectoriesAsync(sdPath);

            foreach (var item in rootDirs)//.OrderBy(x => x))
            {
                if (int.TryParse(Path.GetFileName(item), out int number))
                {
                    toAdd.Add(new Tuple <int, string>(number, item));
                }
            }

            var invalid = new List <string>();

            foreach (var item in toAdd.OrderBy(x => x.Item1))
            {
                try
                {
                    GdItem itemToAdd = null;

                    if (EnableLazyLoading)//load item without reading ip.bin. only read name.txt+serial.txt. will be null if no name.txt or empty
                    {
                        try
                        {
                            itemToAdd = await LazyLoadItemFromCard(item.Item1, item.Item2);
                        }
                        catch { }
                    }

                    if (itemToAdd == null)
                    {
                        itemToAdd = await ImageHelper.CreateGdItemAsync(item.Item2);
                    }

                    ItemList.Add(itemToAdd);
                }
                catch (Exception ex) { invalid.Add($"{item.Item2} {ex.Message}"); }
            }

            if (invalid.Any())
            {
                throw new Exception(string.Join(Environment.NewLine, invalid));
            }
        }
        public bool SearchInItem(GdItem item, string text)
        {
            if (item.Name?.IndexOf(text, 0, StringComparison.InvariantCultureIgnoreCase) != -1)
            {
                return(true);
            }
            else if (item.Ip != null)
            {
                if (item.Ip.Name?.IndexOf(text, 0, StringComparison.InvariantCultureIgnoreCase) != -1)
                {
                    return(true);
                }
                //if (item.Ip.ProductNumber?.IndexOf(text, 0, StringComparison.InvariantCultureIgnoreCase) != -1)
                //    return true;
            }

            return(false);
        }
        public async Task LoadIP(GdItem item)
        {
            //await Task.Delay(2000);

            string filePath = string.Empty;

            try
            {
                filePath = Path.Combine(item.FullFolderPath, item.ImageFile);

                var i = await ImageHelper.CreateGdItemAsync(filePath);

                item.Ip = i.Ip;
                item.CanApplyGDIShrink = i.CanApplyGDIShrink;
                item.ImageFiles.Clear();
                item.ImageFiles.AddRange(i.ImageFiles);
            }
            catch (Exception)
            {
                throw new Exception("Error loading file " + filePath);
            }
        }
        private async Task MoveOrCopyFolder(GdItem item, bool shrink, int folderNumber)
        {
            var newPath = Path.Combine(sdPath, FormatFolderNumber(folderNumber));

            if (item.Work == WorkMode.Move)
            {
                await Helper.MoveDirectoryAsync(Path.Combine(sdPath, item.Guid), newPath);
            }
            else if (item.Work == WorkMode.New)
            {
                if (shrink)
                {
                    using (var p = CreateProcess(gdishrinkPath))
                        if (!await RunShrinkProcess(p, Path.Combine(item.FullFolderPath, item.ImageFile), newPath))
                        {
                            throw new Exception("Error during GDIShrink");
                        }
                }
                else
                {
                    //if (item.ImageFile.EndsWith(".gdi", StringComparison.InvariantCultureIgnoreCase))
                    //{
                    //    await Helper.CopyDirectoryAsync(item.FullFolderPath, newPath);
                    //}
                    //else
                    //{
                    //    if (!Directory.Exists(item.FullFolderPath))
                    //        throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " + item.FullFolderPath);

                    //    // If the destination directory exist, delete it.
                    //    if (Directory.Exists(newPath))
                    //        await Helper.DeleteDirectoryAsync(newPath);
                    //    //then create a new one
                    //    await Helper.CreateDirectoryAsync(newPath);

                    //    //todo async!
                    //    await Task.Run(() => File.Copy(Path.Combine(item.FullFolderPath, Path.GetFileName(item.ImageFile)), Path.Combine(newPath, Path.GetFileName(item.ImageFile))));
                    //}

                    // If the destination directory exist, delete it.
                    if (Directory.Exists(newPath))
                    {
                        await Helper.DeleteDirectoryAsync(newPath);
                    }
                    //then create a new one
                    await Helper.CreateDirectoryAsync(newPath);

                    foreach (var f in item.ImageFiles)
                    {
                        //todo async!
                        await Task.Run(() => File.Copy(Path.Combine(item.FullFolderPath, f), Path.Combine(newPath, f)));
                    }
                }
            }

            item.FullFolderPath = newPath;
            item.SdNumber       = folderNumber;

            if (item.Work == WorkMode.New && shrink)
            {
                //get the new filenames
                var gdi = await ImageHelper.CreateGdItemAsync(newPath);

                item.ImageFiles.Clear();
                item.ImageFiles.AddRange(gdi.ImageFiles);
                UpdateItemLength(item);
            }
            item.Work = WorkMode.None;
        }
 //todo implement
 internal static void UpdateItemLength(GdItem item)
 {
     item.Length = ByteSizeLib.ByteSize.FromBytes(item.ImageFiles.Sum(x => new FileInfo(Path.Combine(item.FullFolderPath, x)).Length));
 }
        internal static async Task <GdItem> CreateGdItem2Async(string filePath)
        {
            string folderPath = Path.GetDirectoryName(filePath);

            var item = new GdItem
            {
                Guid           = Guid.NewGuid().ToString(),
                FullFolderPath = folderPath,
                FileFormat     = FileFormat.Uncompressed
            };

            IpBin ip = null;

            var    ext           = Path.GetExtension(filePath).ToLower();
            string itemImageFile = null;

            item.ImageFiles.Add(Path.GetFileName(filePath));

            if (ext == ".gdi")
            {
                itemImageFile = filePath;

                var gdi = await GetGdiFileListAsync(filePath);

                foreach (var datafile in gdi.Where(x => !x.EndsWith(".raw", StringComparison.InvariantCultureIgnoreCase)).Skip(1))
                {
                    ip = await Task.Run(() => GetIpData(Path.Combine(item.FullFolderPath, datafile)));

                    if (ip != null)
                    {
                        break;
                    }
                }

                var gdifiles = gdi.Distinct().ToArray();
                item.ImageFiles.AddRange(gdifiles);
            }
            else
            {
                var    imageNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
                string dataFile;
                if (ext == ".ccd")
                {
                    var img = Path.ChangeExtension(filePath, ".img");
                    if (!File.Exists(img))
                    {
                        throw new Exception("Missing file: " + img);
                    }
                    item.ImageFiles.Add(Path.GetFileName(img));

                    var sub = Path.ChangeExtension(filePath, ".sub");
                    if (File.Exists(sub))
                    {
                        item.ImageFiles.Add(Path.GetFileName(sub));
                    }

                    dataFile = img;
                }
                else if (ext == ".mds")
                {
                    var mdf = Path.ChangeExtension(filePath, ".mdf");
                    if (!File.Exists(mdf))
                    {
                        throw new Exception("Missing file: " + mdf);
                    }
                    item.ImageFiles.Add(Path.GetFileName(mdf));

                    dataFile = mdf;
                }
                else //cdi
                {
                    dataFile = filePath;
                }

                ip = await Task.Run(() => GetIpData(dataFile));
            }


            if (ip == null)
            {
                throw new Exception("Cant't read data from file");
            }


            item.Ip   = ip;
            item.Name = ip.Name;

            var itemNamePath = Path.Combine(item.FullFolderPath, Constants.NameTextFile);

            if (await Helper.FileExistsAsync(itemNamePath))
            {
                item.Name = await Helper.ReadAllTextAsync(itemNamePath);
            }

            var itemSerialPath = Path.Combine(item.FullFolderPath, Constants.SerialTextFile);

            if (await Helper.FileExistsAsync(itemSerialPath))
            {
                item.Ip.ProductNumber = await Helper.ReadAllTextAsync(itemSerialPath);
            }

            item.Name             = item.Name.Trim();
            item.Ip.ProductNumber = item.Ip.ProductNumber.Trim();

            if (item.FullFolderPath.StartsWith(Manager.sdPath, StringComparison.InvariantCultureIgnoreCase) && int.TryParse(new DirectoryInfo(item.FullFolderPath).Name, out int number))
            {
                item.SdNumber = number;
            }

            Manager.UpdateItemLength(item);

            return(item);
        }
        public static async Task <GdItem> CreateGdItemAsync(string fileOrFolderPath)
        {
            string folderPath;

            string[] files;

            FileAttributes attr = await Helper.GetAttributesAsync(fileOrFolderPath);//path is a file or folder?

            if (attr.HasFlag(FileAttributes.Directory))
            {
                folderPath = fileOrFolderPath;
                files      = await Helper.GetFilesAsync(folderPath);
            }
            else
            {
                folderPath = Path.GetDirectoryName(fileOrFolderPath);
                files      = new string[] { fileOrFolderPath };
            }

            var item = new GdItem
            {
                Guid           = Guid.NewGuid().ToString(),
                FullFolderPath = folderPath,
                FileFormat     = FileFormat.Uncompressed
            };

            IpBin  ip            = null;
            string itemImageFile = null;

            //is uncompressed?
            foreach (var file in files)
            {
                var fileExt = Path.GetExtension(file).ToLower();
                if (Manager.supportedImageFormats.Any(x => x == fileExt))
                {
                    itemImageFile = file;
                    break;
                }
            }

            //is compressed?
            if (itemImageFile == null && files.Any(Helper.CompressedFileExpression))
            {
                string compressedFile = files.First(Helper.CompressedFileExpression);

                var filesInsideArchive = await Task.Run(() => Helper.DependencyManager.GetArchiveFiles(compressedFile));

                foreach (var file in filesInsideArchive.Keys)
                {
                    var fileExt = Path.GetExtension(file).ToLower();
                    if (Manager.supportedImageFormats.Any(x => x == fileExt))
                    {
                        itemImageFile = file;
                        break;
                    }
                }

                item.CanApplyGDIShrink = filesInsideArchive.Keys.Any(x => Path.GetExtension(x).Equals(".gdi", StringComparison.InvariantCultureIgnoreCase));

                if (!string.IsNullOrEmpty(itemImageFile))
                {
                    item.ImageFiles.Add(Path.GetFileName(compressedFile));

                    var itemName = Path.GetFileNameWithoutExtension(compressedFile);
                    var m        = RegularExpressions.TosecnNameRegexp.Match(itemName);
                    if (m.Success)
                    {
                        itemName = itemName.Substring(0, m.Index);
                    }

                    ip = new IpBin
                    {
                        Name = itemName,
                        Disc = "?/?"
                    };

                    item.Length     = ByteSizeLib.ByteSize.FromBytes(filesInsideArchive.Sum(x => x.Value));
                    item.FileFormat = FileFormat.SevenZip;
                }
            }

            if (itemImageFile == null)
            {
                throw new Exception("Cant't read data from file");
            }

            if (item.FileFormat == FileFormat.Uncompressed)
            {
                var     filtersList = new FiltersList();
                IFilter inputFilter = null;
                try
                {
                    inputFilter = await Task.Run(() => filtersList.GetFilter(itemImageFile));

                    //todo check inputFilter null Cannot open specified file.

                    IOpticalMediaImage opticalImage;

                    switch (Path.GetExtension(itemImageFile).ToLower())
                    {
                    case ".gdi":
                        opticalImage = new Aaru.DiscImages.Gdi();
                        break;

                    case ".cdi":
                        opticalImage = new Aaru.DiscImages.DiscJuggler();
                        break;

                    case ".mds":
                        opticalImage = new Aaru.DiscImages.Alcohol120();
                        break;

                    case ".ccd":
                        opticalImage = new Aaru.DiscImages.CloneCd();
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    //if(!opticalImage.Identify(inputFilter))
                    //    throw new NotSupportedException();

                    //todo check imageFormat null Image format not identified.

                    try
                    {
                        bool useAaru;
                        try
                        {
                            useAaru = await Task.Run(() => opticalImage.Open(inputFilter));
                        }
                        catch (Exception)
                        {
                            useAaru = false;
                            opticalImage?.Close();
                        }


                        if (useAaru) //try to load file using Aaru
                        {
                            try
                            {
                                Partition partition;

                                if (Path.GetExtension(itemImageFile).Equals(".gdi", StringComparison.InvariantCultureIgnoreCase))//first track not audio and skip one
                                {
                                    partition = opticalImage.Partitions.Where(x => x.Type != "Audio").Skip(1).First();
                                    ip        = await GetIpData(opticalImage, partition);
                                }
                                else//try to find from last
                                {
                                    for (int i = opticalImage.Partitions.Count - 1; i >= 0; i--)
                                    {
                                        partition = opticalImage.Partitions[i];
                                        ip        = await GetIpData(opticalImage, partition);

                                        if (ip != null)
                                        {
                                            break;
                                        }
                                    }
                                }

                                //Aaru fails to read the ip.bin from some cdis in CdMode2Formless.
                                if (ip == null)
                                {
                                    throw new Exception();
                                }

                                //var imageFiles = new List<string> { Path.GetFileName(item.ImageFile) };
                                item.ImageFiles.Add(Path.GetFileName(itemImageFile));
                                foreach (var track in opticalImage.Tracks)
                                {
                                    if (!string.IsNullOrEmpty(track.TrackFile) && !item.ImageFiles.Any(x => x.Equals(track.TrackFile, StringComparison.InvariantCultureIgnoreCase)))
                                    {
                                        item.ImageFiles.Add(track.TrackFile);
                                    }
                                    if (!string.IsNullOrEmpty(track.TrackSubchannelFile) && !item.ImageFiles.Any(x => x.Equals(track.TrackSubchannelFile, StringComparison.InvariantCultureIgnoreCase)))
                                    {
                                        item.ImageFiles.Add(track.TrackSubchannelFile);
                                    }
                                }

                                item.CanApplyGDIShrink = Path.GetExtension(itemImageFile).Equals(".gdi", StringComparison.InvariantCultureIgnoreCase);

                                Manager.UpdateItemLength(item);
                            }
                            catch
                            {
                                useAaru = false;
                            }
                            finally
                            {
                                opticalImage?.Close();
                            }
                        }


                        if (!useAaru) //if cant open using Aaru, try to parse file manually
                        {
                            if (inputFilter != null && inputFilter.IsOpened())
                            {
                                inputFilter.Close();
                            }

                            var temp = await CreateGdItem2Async(itemImageFile);

                            if (temp == null || temp.Ip == null)
                            {
                                throw new Exception("Unable to open image format");
                            }

                            ip   = temp.Ip;
                            item = temp;
                        }
                    }
                    finally
                    {
                        opticalImage?.Close();
                    }
                }
                //catch (Exception ex)
                //{

                //    throw;
                //}
                finally
                {
                    if (inputFilter != null && inputFilter.IsOpened())
                    {
                        inputFilter.Close();
                    }
                }
            }

            if (ip == null)
            {
                throw new Exception("Cant't read data from file");
            }


            item.Ip   = ip;
            item.Name = ip.Name;

            var itemNamePath = Path.Combine(item.FullFolderPath, Constants.NameTextFile);

            if (await Helper.FileExistsAsync(itemNamePath))
            {
                item.Name = await Helper.ReadAllTextAsync(itemNamePath);
            }

            var itemSerialPath = Path.Combine(item.FullFolderPath, Constants.SerialTextFile);

            if (await Helper.FileExistsAsync(itemSerialPath))
            {
                item.Ip.ProductNumber = await Helper.ReadAllTextAsync(itemSerialPath);
            }

            item.Name             = item.Name.Trim();
            item.Ip.ProductNumber = item.Ip.ProductNumber.Trim();

            if (item.FullFolderPath.StartsWith(Manager.sdPath, StringComparison.InvariantCultureIgnoreCase) && int.TryParse(Path.GetFileName(Path.GetDirectoryName(itemImageFile)), out int number))
            {
                item.SdNumber = number;
            }

            //item.ImageFile = Path.GetFileName(item.ImageFile);

            return(item);
        }