using Apewer;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Apewer.Internals
{

    internal class StreamHelper
    {

        public static void Dispose(Stream stream, bool flush = false, bool close = true)
        {
            if (stream != null)
            {
                try { if (flush) stream.Flush(); } catch { }
                try { if (close) stream.Close(); } catch { }
                try { stream.Dispose(); } catch { }
            }
        }

        public static bool ResetPosition(Stream stream)
        {
            if (stream == null) return false;
            try
            {
                stream.Position = 0;
                if (stream.CanSeek) stream.Seek(0, SeekOrigin.Begin);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static long Read(Stream source, Stream destination, int argBuffer = Constant.DefaultBufferCapacity, Action<long> progress = null)
        {
            if (source == null) return 0;
            if (destination == null) return 0;
            if (!source.CanRead) return 0;
            if (!destination.CanWrite) return 0;
            if (argBuffer < 1) return 0;

            long result = 0;
            var failed = false;
            var callback = progress != null;
            var count = 0;
            while (true)
            {
                count = 0;
                var buffer = new byte[argBuffer];
                try { count = source.Read(buffer, 0, buffer.Length); } catch { failed = true; }
                if (failed) break;
                if (callback) progress(result);
                if (count == 0) break;
                try { destination.Write(buffer, 0, count); } catch { failed = true; }
                if (failed) break;
                result += count;
            }
            return result;
        }

        public static byte[] Read(Stream argSource, int argBuffer = Constant.DefaultBufferCapacity, Action<long> argCallback = null)
        {
            var memory = new MemoryStream();
            Read(argSource, memory, argBuffer, argCallback);
            var result = memory.ToArray();
            Dispose(memory);
            return result;
        }

        public static long Read(IEnumerable<Stream> argSource, Stream argDestination, bool argDispose = false, int argBuffer = Constant.DefaultBufferCapacity, Action<long> argCallback = null)
        {
            var result = 0L;
            if (argSource != null)
            {
                foreach (var source in argSource)
                {
                    var count = Read(source, argDestination, argBuffer, argCallback);
                    if (argDispose) Dispose(source);
                    result += count;
                }
            }
            return result;
        }

    }

}