public AmazonDriveSeekableStream(AmazonDrive Drive, FileMetadata_Info downitem) : base()
        {
            this.Drive = Drive;
            targetItem = downitem;
            FileSize   = targetItem.OrignalLength ?? 0;

            if (FileSize <= 0)
            {
                return;
            }

            slots = new SlotMaster(Drive, downitem, cts.Token);

            _Position = 0;

            if (downitem.contentProperties?.size > ConfigAPI.FilenameChangeTrickSize && !Regex.IsMatch(downitem.name, "^[\x20-\x7e]*$"))
            {
                OrgFilename = downitem.name;
                Config.Log.LogOut("AmazonDriveSeekableStream : <BIG FILE> temporary filename change");
                Config.Log.LogOut("AmazonDriveSeekableStream : orgnal name : " + OrgFilename);
                Drive.renameItem(downitem.id, ConfigAPI.temporaryFilename + downitem.id).Wait();
            }

            lastslot  = ((downitem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize;
            lockslot1 = AmazonDriveStreamConfig.lockslotfirstnum;
            lockslot2 = lastslot - AmazonDriveStreamConfig.lockslotlastnum;
            if (lockslot2 < lockslot1)
            {
                lockslot2 = lockslot1;
            }
            slots.CreateTask(0);
            slots.CreateTask(lockslot2);
            slots.CreateTask(lockslot1);
            slots.CreateTask(lockslot1 + AmazonDriveStreamConfig.preforwardnum);
        }
 public SlotTask(AmazonDrive Drive, FileMetadata_Info targetItem, CancellationToken ct = default(CancellationToken))
 {
     cts             = CancellationTokenSource.CreateLinkedTokenSource(ct, Internal_cts.Token);
     this.Drive      = Drive;
     this.targetItem = targetItem;
     lastslot        = ((targetItem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize;
 }
        public SlotMaster(AmazonDrive Drive, FileMetadata_Info downitem, CancellationToken ct = default(CancellationToken))
        {
            cts        = CancellationTokenSource.CreateLinkedTokenSource(cts_internal.Token, ct);
            this.Drive = Drive;
            targetItem = downitem;
            lastslot   = ((downitem.OrignalLength ?? 0) - 1) / AmazonDriveStreamConfig.slotsize;
            lockslot1  = AmazonDriveStreamConfig.lockslotfirstnum;
            lockslot2  = lastslot - AmazonDriveStreamConfig.lockslotlastnum;
            if (lockslot2 < lockslot1)
            {
                lockslot2 = lockslot1;
            }
            int extraslot = 0;

            Task.Run(() =>
            {
                foreach (var newitem in SlotBuffer.GetConsumingEnumerable(cts.Token))
                {
                    try
                    {
                        slot.GetOrAdd(newitem.Key, newitem.Value);

                        while (slot.Count > AmazonDriveStreamConfig.slotbacklog + extraslot)
                        {
                            Task.Delay(100, cts.Token).Wait(cts.Token);
                        }
                        if (cts.Token.IsCancellationRequested)
                        {
                            return;
                        }
                    }
                    catch { }
                }
            }, cts.Token);
            Task.Run(() =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    try
                    {
                        const int slotnumc = AmazonDriveStreamConfig.slotbacklog;
                        // slotが多すぎるのでいらないものから消す
                        if (slot.Count > slotnumc)
                        {
                            var pos = slot
                                      .OrderByDescending(x => x.Value.Age)
                                      .OrderBy(x => x.Value.ReadAge)
                                      .First().Key;

                            var s = StartLock;
                            if (s != null)
                            {
                                pos = s.Value;
                            }

                            //Config.Log.LogOut(string.Format("AmazonDriveStream : Removing slots current pos {0}", pos));

                            var deleteitem = slot
                                             .Where(x => !(x.Key >= StartLock && x.Key <= EndLock))
                                             .Where(x => x.Key > lockslot1 && x.Key < lockslot2);

                            deleteitem = deleteitem
                                         .Where(x => x.Key <pos - AmazonDriveStreamConfig.slotkeepold || x.Key> pos + AmazonDriveStreamConfig.slotbacklog * 2)
                                         .OrderByDescending(x => x.Value.ReadAge)
                                         .Take(slot.Count - slotnumc).ToArray();
                            foreach (var item in deleteitem)
                            {
                                MemoryStreamSlot o;
                                if (slot.TryRemove(item.Key, out o))
                                {
                                    //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove slot {0} pos {1:#,0} len {2:#,0}", item.Key, o.Offset, o.Length));
                                    if (!(item.Key >= StartLock && item.Key <= EndLock))
                                    {
                                        o.Dispose();
                                    }
                                    else
                                    {
                                        slot.GetOrAdd(item.Key, o);
                                    }
                                }
                            }
                            extraslot = slot.Count - slotnumc;
                        }
                        // 終了したタスクを除去する
                        if (Tasks.Any(x => x.Done))
                        {
                            var deleteitem = Tasks.Where(x => x.Done).ToArray();
                            foreach (var item in deleteitem)
                            {
                                SlotTask o;
                                if (Tasks.TryTake(out o))
                                {
                                    //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove end Task slot {0}", o.ReadingSlotno));
                                    o.Dispose();
                                }
                            }
                        }
                        // 走りすぎているスレットを消す
                        if (accesslog.Count() > 0)
                        {
                            var min_point = accesslog.OrderByDescending(x => x.Value).Take(1).Min(x => x.Key);
                            var max_point = min_point + AmazonDriveStreamConfig.slotbacklog;
                            min_point     = Math.Max(min_point - AmazonDriveStreamConfig.slotnearby * 2, 0);
                            max_point     = Math.Min(max_point + AmazonDriveStreamConfig.slotnearby * 2, lastslot);
                            //Config.Log.LogOut(string.Format("AmazonDriveStream : min_point {0}", min_point));
                            //Config.Log.LogOut(string.Format("AmazonDriveStream : max_point {0}", max_point));
                            if (min_point < lockslot2 && Tasks.Any(x => x.ReadingSlotno < min_point && x.ReadingSlotno > lockslot1))
                            {
                                var deleteitem = Tasks.Where(x => x.ReadingSlotno <min_point && x.ReadingSlotno> lockslot1).ToList();
                                SlotTask o;
                                while (deleteitem.Count > 0 && Tasks.TryTake(out o))
                                {
                                    if (deleteitem.Contains(o))
                                    {
                                        //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove1 Task slot {0} too far({1})", o.ReadingSlotno, min_point));
                                        deleteitem.Remove(o);
                                        o.Dispose();
                                    }
                                    else
                                    {
                                        Tasks.Add(o);
                                    }
                                }
                            }
                            if (Tasks.Count == 1)
                            {
                                Tasks.First().leadThread = true;
                            }
                            else
                            {
                                foreach (var item in Tasks)
                                {
                                    item.leadThread = false;
                                }
                            }
                            if (max_point > lockslot1 && Tasks.Any(x => x.ReadingSlotno > max_point && x.ReadingSlotno < lockslot2))
                            {
                                var deleteitem = Tasks.Where(x => x.ReadingSlotno > max_point && x.ReadingSlotno < lockslot2).ToList();
                                SlotTask o;
                                while (deleteitem.Count > 0 && Tasks.TryTake(out o))
                                {
                                    if (deleteitem.Contains(o))
                                    {
                                        if (o.leadThread)
                                        {
                                            //Config.Log.LogOut(string.Format("AmazonDriveStream : LeadThread Task slot {0} too far({1})", o.ReadingSlotno, min_point));
                                            deleteitem.Remove(o);
                                            Tasks.Add(o);
                                        }
                                        else
                                        {
                                            //Config.Log.LogOut(string.Format("AmazonDriveStream : Remove2 Task slot {0} too far({1})", o.ReadingSlotno, min_point));
                                            deleteitem.Remove(o);
                                            o.Dispose();
                                        }
                                    }
                                    else
                                    {
                                        Tasks.Add(o);
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    //Config.Log.LogOut(string.Format("AmazonDriveStream : Tasks {0} slots {1}", Tasks.Count, slot.Count));
                    //Config.Log.LogOut(string.Format("AmazonDriveStream : slot {0}", string.Join(",",Tasks.Select(x=>x.ReadingSlotno.ToString()))));
                    Task.Delay(500, cts.Token).Wait(cts.Token);
                }
            }, cts.Token);
        }