//
// © Copyright Henrik Ravn 2004
//
// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace DotZLib
{
    #region Internal types
    /// 
    /// Defines constants for the various flush types used with zlib
    /// 
    internal enum FlushTypes
    {
        None,  Partial,  Sync,  Full,  Finish,  Block
    }
    #region ZStream structure
    // internal mapping of the zlib zstream structure for marshalling
    [StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)]
    internal struct ZStream
    {
        public IntPtr next_in;
        public uint avail_in;
        public uint total_in;
        public IntPtr next_out;
        public uint avail_out;
        public uint total_out;
        [MarshalAs(UnmanagedType.LPStr)]
        string msg;
        uint state;
        uint zalloc;
        uint zfree;
        uint opaque;
        int data_type;
        public uint adler;
        uint reserved;
    }
    #endregion
    #endregion
    #region Public enums
    /// 
    /// Defines constants for the available compression levels in zlib
    /// 
    public enum CompressLevel : int
    {
        /// 
        /// The default compression level with a reasonable compromise between compression and speed
        /// 
        Default = -1,
        /// 
        /// No compression at all. The data are passed straight through.
        /// 
        None = 0,
        /// 
        /// The maximum compression rate available.
        /// 
        Best = 9,
        /// 
        /// The fastest available compression level.
        /// 
        Fastest = 1
    }
    #endregion
    #region Exception classes
    /// 
    /// The exception that is thrown when an error occurs on the zlib dll
    /// 
    public class ZLibException : ApplicationException
    {
        /// 
        /// Initializes a new instance of the  class with a specified
        /// error message and error code
        /// 
        /// The zlib error code that caused the exception
        /// A message that (hopefully) describes the error
        public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg))
        {
        }
        /// 
        /// Initializes a new instance of the  class with a specified
        /// error code
        /// 
        /// The zlib error code that caused the exception
        public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode))
        {
        }
    }
    #endregion
    #region Interfaces
    /// 
    /// Declares methods and properties that enables a running checksum to be calculated
    /// 
    public interface ChecksumGenerator
    {
        /// 
        /// Gets the current value of the checksum
        /// 
        uint Value { get; }
        /// 
        /// Clears the current checksum to 0
        /// 
        void Reset();
        /// 
        /// Updates the current checksum with an array of bytes
        /// 
        /// The data to update the checksum with
        void Update(byte[] data);
        /// 
        /// Updates the current checksum with part of an array of bytes
        /// 
        /// The data to update the checksum with
        /// Where in data to start updating
        /// The number of bytes from data to use
        /// The sum of offset and count is larger than the length of data
        /// data is a null reference
        /// Offset or count is negative.
        void Update(byte[] data, int offset, int count);
        /// 
        /// Updates the current checksum with the data from a string
        /// 
        /// The string to update the checksum with
        /// The characters in the string are converted by the UTF-8 encoding
        void Update(string data);
        /// 
        /// Updates the current checksum with the data from a string, using a specific encoding
        /// 
        /// The string to update the checksum with
        /// The encoding to use
        void Update(string data, Encoding encoding);
    }
    /// 
    /// Represents the method that will be called from a codec when new data
    /// are available.
    /// 
    /// The byte array containing the processed data
    /// The index of the first processed byte in data
    /// The number of processed bytes available
    /// On return from this method, the data may be overwritten, so grab it while you can.
    /// You cannot assume that startIndex will be zero.
    /// 
    public delegate void DataAvailableHandler(byte[] data, int startIndex, int count);
    /// 
    /// Declares methods and events for implementing compressors/decompressors
    /// 
    public interface Codec
    {
        /// 
        /// Occurs when more processed data are available.
        /// 
        event DataAvailableHandler DataAvailable;
        /// 
        /// Adds more data to the codec to be processed.
        /// 
        /// Byte array containing the data to be added to the codec
        /// Adding data may, or may not, raise the DataAvailable event
        void Add(byte[] data);
        /// 
        /// Adds more data to the codec to be processed.
        /// 
        /// Byte array containing the data to be added to the codec
        /// The index of the first byte to add from data
        /// The number of bytes to add
        /// Adding data may, or may not, raise the DataAvailable event
        void Add(byte[] data, int offset, int count);
        /// 
        /// Finishes up any pending data that needs to be processed and handled.
        /// 
        void Finish();
        /// 
        /// Gets the checksum of the data that has been added so far
        /// 
        uint Checksum { get; }
    }
    #endregion
    #region Classes
    /// 
    /// Encapsulates general information about the ZLib library
    /// 
    public class Info
    {
        #region DLL imports
        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
        private static extern uint zlibCompileFlags();
        [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
        private static extern string zlibVersion();
        #endregion
        #region Private stuff
        private uint _flags;
        // helper function that unpacks a bitsize mask
        private static int bitSize(uint bits)
        {
            switch (bits)
            {
                case 0: return 16;
                case 1: return 32;
                case 2: return 64;
            }
            return -1;
        }
        #endregion
        /// 
        /// Constructs an instance of the Info class.
        /// 
        public Info()
        {
            _flags = zlibCompileFlags();
        }
        /// 
        /// True if the library is compiled with debug info
        /// 
        public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } }
        /// 
        /// True if the library is compiled with assembly optimizations
        /// 
        public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } }
        /// 
        /// Gets the size of the unsigned int that was compiled into Zlib
        /// 
        public int SizeOfUInt { get { return bitSize(_flags & 3); } }
        /// 
        /// Gets the size of the unsigned long that was compiled into Zlib
        /// 
        public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } }
        /// 
        /// Gets the size of the pointers that were compiled into Zlib
        /// 
        public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } }
        /// 
        /// Gets the size of the z_off_t type that was compiled into Zlib
        /// 
        public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } }
        /// 
        /// Gets the version of ZLib as a string, e.g. "1.2.1"
        /// 
        public static string Version { get { return zlibVersion(); } }
    }
    #endregion
}