using DicomObjects;
using DicomObjects.Enums;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;

namespace MyHTJ2KCodec
{
    public class MyHTJ2KEncoder : DicomObjects.Codecs.ICompressor
    {
        int DicomObjects.Codecs.ICompressor.MaximumBits => 32;

        bool DicomObjects.Codecs.ICompressor.NeedsPlanarConfigTransform => false;

        [DllImport("OpenJPHWrapper.dll")]
        public static extern IntPtr Create();
        [DllImport("OpenJPHWrapper.dll")]
        public static extern IntPtr Compress(IntPtr a, byte[] inputData, IntPtr dataSize, string photometricInterpretation,
            IntPtr width, IntPtr height, IntPtr bitDepth, IntPtr isSigned, IntPtr planarConfig, string transferSyntax, IntPtr quality, out IntPtr compressedSize);

        public void Compress(DicomObjects.Codecs.CompressionArguments args)
        {
            IntPtr wrapper = Create();
            int srcLengthInBytes = 0;
            if (args.SourceArray is byte[]) srcLengthInBytes = args.SourceArray.Length;
            else if (args.SourceArray is ushort[]) srcLengthInBytes = args.SourceArray.Length * 2;
            else if (args.SourceArray is uint[]) srcLengthInBytes = args.SourceArray.Length * 4;

            var srcBytes = new byte[srcLengthInBytes];
            Buffer.BlockCopy(args.SourceArray, 0, srcBytes, 0, srcLengthInBytes);
            IntPtr dataSize = (IntPtr)srcLengthInBytes;
            IntPtr width = (IntPtr)Convert.ToInt16(args.Image[Keyword.Columns].Value);
            IntPtr height = (IntPtr)Convert.ToInt16(args.Image[Keyword.Rows].Value);
            short qualityValue = args.Quality != null ? Convert.ToInt16(args.Quality) : (short)10;
            IntPtr quality = (IntPtr)qualityValue;

            IntPtr outputDataPtr = Compress(wrapper, srcBytes, dataSize, args.PhotometricInterpretation, width, height, (IntPtr)args.BitsAllocated, (IntPtr)(args.isSigned ? 1 : 0), (IntPtr)args.Planarconfig, args.OutputTransferSyntax, quality, out IntPtr compressedSizePtr);
            int compressedSize = compressedSizePtr.ToInt32();
            byte[] compressedData = new byte[compressedSize];
            Marshal.Copy(outputDataPtr, compressedData, 0, compressedSize);
            using (MemoryStream ms = new MemoryStream(compressedData))
            {
                ms.CopyTo(args.DestinationStream);
            }
        }

        public void PrepareFunction(DicomObjects.Codecs.ModificationArguments ModificationArguments)
        {
            // Make any changes to the DicomDataSet which are required for compatibility with the 
            // compressed data, e.g.the BitDepth / Photometric Interpretation may need altering
        }

        public object LockObject()
        {
            return this;
        }

        public object Quality(string TransferSyntax, Dictionary<string, object> qmap, DicomDataSet dataset)
        {
            if (qmap != null && qmap.TryGetValue(TransferSyntax, out object value))
            {
                return value;
            }

            return null;
        }
    }
}

