using Renci.SshNet.Security;
using System.IO;
using System;
namespace Renci.SshNet.Compression
{
    /// 
    /// Represents base class for compression algorithm implementation
    /// 
    public abstract class Compressor : Algorithm, IDisposable
    {
        private readonly ZlibStream _compressor;
        private readonly ZlibStream _decompressor;
        private MemoryStream _compressorStream;
        private MemoryStream _decompressorStream;
        /// 
        /// Gets or sets a value indicating whether compression is active.
        /// 
        /// 
        ///   true if compression is active; otherwise, false.
        /// 
        protected bool IsActive { get; set; }
        /// 
        /// Gets the session.
        /// 
        protected Session Session { get; private set; }
        /// 
        /// Initializes a new instance of the  class.
        /// 
        protected Compressor()
        {
            _compressorStream = new MemoryStream();
            _decompressorStream = new MemoryStream();
            _compressor = new ZlibStream(_compressorStream, CompressionMode.Compress);
            _decompressor = new ZlibStream(_decompressorStream, CompressionMode.Decompress);
        }
        /// 
        /// Initializes the algorithm
        /// 
        /// The session.
        public virtual void Init(Session session)
        {
            Session = session;
        }
        /// 
        /// Compresses the specified data.
        /// 
        /// Data to compress.
        /// Compressed data
        public virtual byte[] Compress(byte[] data)
        {
            return Compress(data, 0, data.Length);
        }
        /// 
        /// Compresses the specified data.
        /// 
        /// Data to compress.
        /// The zero-based byte offset in  at which to begin reading the data to compress. 
        /// The number of bytes to be compressed. 
        /// 
        /// The compressed data.
        /// 
        public virtual byte[] Compress(byte[] data, int offset, int length)
        {
            if (!IsActive)
            {
                if (offset == 0 && length == data.Length)
                    return data;
                var buffer = new byte[length];
                Buffer.BlockCopy(data, offset, buffer, 0, length);
                return buffer;
            }
            _compressorStream.SetLength(0);
            _compressor.Write(data, offset, length);
            return _compressorStream.ToArray();
        }
        /// 
        /// Decompresses the specified data.
        /// 
        /// Compressed data.
        /// 
        /// The decompressed data.
        /// 
        public virtual byte[] Decompress(byte[] data)
        {
            return Decompress(data, 0, data.Length);
        }
        /// 
        /// Decompresses the specified data.
        /// 
        /// Compressed data.
        /// The zero-based byte offset in  at which to begin reading the data to decompress. 
        /// The number of bytes to be read from the compressed data. 
        /// 
        /// The decompressed data.
        /// 
        public virtual byte[] Decompress(byte[] data, int offset, int length)
        {
            if (!IsActive)
            {
                if (offset == 0 && length == data.Length)
                    return data;
                var buffer = new byte[length];
                Buffer.BlockCopy(data, offset, buffer, 0, length);
                return buffer;
            }
            _decompressorStream.SetLength(0);
            _decompressor.Write(data, offset, length);
            return _decompressorStream.ToArray();
        }
        #region IDisposable Members
        private bool _isDisposed;
        /// 
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
        /// 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        /// 
        /// Releases unmanaged and - optionally - managed resources
        /// 
        /// true to release both managed and unmanaged resources; false to release only unmanaged ResourceMessages.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!_isDisposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged ResourceMessages.
                if (disposing)
                {
                    // Dispose managed ResourceMessages.
                    if (_compressorStream != null)
                    {
                        _compressorStream.Dispose();
                        _compressorStream = null;
                    }
                    if (_decompressorStream != null)
                    {
                        _decompressorStream.Dispose();
                        _decompressorStream = null;
                    }
                }
                // Note disposing has been done.
                _isDisposed = true;
            }
        }
        /// 
        /// Releases unmanaged resources and performs other cleanup operations before the
        ///  is reclaimed by garbage collection.
        /// 
        ~Compressor()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
        #endregion
    }
}