<commit_before>﻿namespace Nine.Storage
{
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public struct ProgressInBytes
    {
        public readonly int Bytes;
        public readonly int TotalBytes;

        public float Percentage => TotalBytes > 0 ? (float)Bytes / TotalBytes : 0;

        public ProgressInBytes(int bytes, int totalBytes)
        {
            this.Bytes = bytes;
            this.TotalBytes = totalBytes;
        }
    }

    public enum BlobProgressState
    {
        None,
        Running,
        Succeeded,
        Failed,
    }

    public struct BlobProgress
    {
        public readonly string Uri;
        public readonly BlobProgressState State;
        public readonly ProgressInBytes Progress;

        public BlobProgress(string uri, BlobProgressState state, ProgressInBytes progress)
        {
            this.Uri = uri;
            this.State = state;
            this.Progress = progress;
        }
    }

    public interface IBlobStorage
    {
        Task<bool> Exists(string key);

        Task<string> GetUri(string key);

        Task<Stream> Get(string key, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));

        Task<string> Put(string key, Stream stream, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));
    }

    /// <summary>
    /// Represents a basic content addressable storage.
    /// </summary>
    public interface IContentAddressableStorage : IBlobStorage
    {
        Task<string> Put(Stream stream, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    public static class BlobStorageExtensions
    {
        public static async Task<string> Download(this IBlobStorage blob, string key, CancellationToken cancellationToken = default(CancellationToken))
        {
            await blob.Get(key, null, cancellationToken).ConfigureAwait(false);
            return await blob.GetUri(key).ConfigureAwait(false);
        }

        public static async Task Download(this IBlobStorage blob, string key, Action<BlobProgress> progress, CancellationToken cancellationToken = default(CancellationToken))
        {
            progress(new BlobProgress(null, BlobProgressState.Running, default(ProgressInBytes)));

            if (string.IsNullOrEmpty(key))
            {
                progress(new BlobProgress(null, BlobProgressState.Failed, default(ProgressInBytes)));
                return;
            }

            try
            {
                var sizeInBytes = 0;
                var progressReporter = new Progress<ProgressInBytes>(p => progress(new BlobProgress(null, BlobProgressState.Running, p)));
                using (var stream = await blob.Get(key, progressReporter, cancellationToken).ConfigureAwait(false))
                {
                    try<commit_msg>Return immediate if key is null on Blob.Download<commit_after>﻿namespace Nine.Storage
{
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    public struct ProgressInBytes
    {
        public readonly int Bytes;
        public readonly int TotalBytes;

        public float Percentage => TotalBytes > 0 ? (float)Bytes / TotalBytes : 0;

        public ProgressInBytes(int bytes, int totalBytes)
        {
            this.Bytes = bytes;
            this.TotalBytes = totalBytes;
        }
    }

    public enum BlobProgressState
    {
        None,
        Running,
        Succeeded,
        Failed,
    }

    public struct BlobProgress
    {
        public readonly string Uri;
        public readonly BlobProgressState State;
        public readonly ProgressInBytes Progress;

        public BlobProgress(string uri, BlobProgressState state, ProgressInBytes progress)
        {
            this.Uri = uri;
            this.State = state;
            this.Progress = progress;
        }
    }

    public interface IBlobStorage
    {
        Task<bool> Exists(string key);

        Task<string> GetUri(string key);

        Task<Stream> Get(string key, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));

        Task<string> Put(string key, Stream stream, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));
    }

    /// <summary>
    /// Represents a basic content addressable storage.
    /// </summary>
    public interface IContentAddressableStorage : IBlobStorage
    {
        Task<string> Put(Stream stream, IProgress<ProgressInBytes> progress = null, CancellationToken cancellationToken = default(CancellationToken));
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    public static class BlobStorageExtensions
    {
        public static async Task<string> Download(this IBlobStorage blob, string key, CancellationToken cancellationToken = default(CancellationToken))
        {
            await blob.Get(key, null, cancellationToken).ConfigureAwait(false);
            return await blob.GetUri(key).ConfigureAwait(false);
        }

        public static async Task Download(this IBlobStorage blob, string key, Action<BlobProgress> progress, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (string.IsNullOrEmpty(key)) return;

            progress(new BlobProgress(null, BlobProgressState.Running, default(ProgressInBytes)));
            
            try
            {
                var sizeInBytes = 0;
                var progressReporter = new Progress<ProgressInBytes>(p => progress(new BlobProgress(null, BlobProgressState.Running, p)));
                using (var stream = await blob.Get(key, progressReporter, cancellationToken).ConfigureAwait(false))
                {
                    try
{'fraction_non_alphanumeric': 0.07682141087064266, 'fraction_numerical': 0.0009912440112340988, 'mean_word_length': 2.5444964871194378, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6060355', 'n_tokens_mistral': 1504, 'n_tokens_neox': 1494, 'n_words': 390}