From 7e6ccedfc8dfc1aa103184edfa4acd74433d1b60 Mon Sep 17 00:00:00 2001
From: Vojtech Moravec <vojtech.moravec.st@vsb.cz>
Date: Tue, 21 Jan 2020 17:11:19 +0100
Subject: [PATCH] Use special exception types for compression and
 decompression.

---
 .../compression/IImageCompressor.java         |  6 +-
 .../compression/IImageDecompressor.java       |  4 +-
 .../ImageCompressionException.java            | 24 +++++++
 .../compression/ImageCompressor.java          |  6 +-
 .../ImageDecompressionException.java          | 24 +++++++
 .../compression/ImageDecompressor.java        |  9 +--
 .../compression/SQImageCompressor.java        | 47 +++++++++----
 .../compression/SQImageDecompressor.java      | 46 +++++++++----
 .../compression/VQImageCompressor.java        | 48 ++++++++-----
 .../compression/VQImageDecompressor.java      | 67 ++++++++++++-------
 .../java/azgracompress/io/InBitStream.java    |  7 +-
 .../quantization/vector/LBGResult.java        |  3 +
 .../vector/LBGVectorQuantizer.java            |  7 +-
 13 files changed, 212 insertions(+), 86 deletions(-)
 create mode 100644 src/main/java/azgracompress/compression/ImageCompressionException.java
 create mode 100644 src/main/java/azgracompress/compression/ImageDecompressionException.java

diff --git a/src/main/java/azgracompress/compression/IImageCompressor.java b/src/main/java/azgracompress/compression/IImageCompressor.java
index 7752a28..d0165c9 100644
--- a/src/main/java/azgracompress/compression/IImageCompressor.java
+++ b/src/main/java/azgracompress/compression/IImageCompressor.java
@@ -4,12 +4,10 @@ import java.io.DataOutputStream;
 
 public interface IImageCompressor {
 
-    // TODO(Moravec): Replace default Exception with better Exception type.
-
     /**
      * Compress the image planes.
      * @param compressStream Compressed data stream.
-     * @throws Exception when compression fails.
+     * @throws ImageCompressionException when compression fails.
      */
-    void compress(DataOutputStream compressStream) throws Exception;
+    void compress(DataOutputStream compressStream) throws ImageCompressionException;
 }
diff --git a/src/main/java/azgracompress/compression/IImageDecompressor.java b/src/main/java/azgracompress/compression/IImageDecompressor.java
index a9516bd..e21bc41 100644
--- a/src/main/java/azgracompress/compression/IImageDecompressor.java
+++ b/src/main/java/azgracompress/compression/IImageDecompressor.java
@@ -20,10 +20,10 @@ public interface IImageDecompressor {
      * @param compressedStream Input stream of compressed data.
      * @param decompressStream Output stream for decompressed data.
      * @param header           QCMPFile information.
-     * @throws Exception when decompression fails.
+     * @throws ImageDecompressionException when decompression fails.
      */
     void decompress(DataInputStream compressedStream,
                     DataOutputStream decompressStream,
-                    final QCMPFileHeader header) throws Exception;
+                    final QCMPFileHeader header) throws ImageDecompressionException;
 
 }
diff --git a/src/main/java/azgracompress/compression/ImageCompressionException.java b/src/main/java/azgracompress/compression/ImageCompressionException.java
new file mode 100644
index 0000000..7fe5e34
--- /dev/null
+++ b/src/main/java/azgracompress/compression/ImageCompressionException.java
@@ -0,0 +1,24 @@
+package azgracompress.compression;
+
+public class ImageCompressionException extends Exception {
+    private final Exception innerException;
+
+    public ImageCompressionException(final String message, final Exception innerException) {
+        super(message);
+        this.innerException = innerException;
+    }
+
+    public ImageCompressionException(final String message) {
+        super(message);
+        this.innerException = null;
+    }
+
+    @Override
+    public String getMessage() {
+        String msg = super.getMessage();
+        if (msg != null && innerException != null) {
+            msg += "\nInner exception:\n" + innerException.getMessage();
+        }
+        return msg;
+    }
+}
diff --git a/src/main/java/azgracompress/compression/ImageCompressor.java b/src/main/java/azgracompress/compression/ImageCompressor.java
index 80f35e2..866c41d 100644
--- a/src/main/java/azgracompress/compression/ImageCompressor.java
+++ b/src/main/java/azgracompress/compression/ImageCompressor.java
@@ -62,10 +62,12 @@ public class ImageCompressor extends CompressorDecompressorBase {
                 reportCompressionRatio(header, compressStream.size());
             }
 
-        } catch (Exception ex) {
+        } catch (ImageCompressionException ex) {
             System.err.println(ex.getMessage());
             return false;
-
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
         }
         return true;
     }
diff --git a/src/main/java/azgracompress/compression/ImageDecompressionException.java b/src/main/java/azgracompress/compression/ImageDecompressionException.java
new file mode 100644
index 0000000..5ed88cc
--- /dev/null
+++ b/src/main/java/azgracompress/compression/ImageDecompressionException.java
@@ -0,0 +1,24 @@
+package azgracompress.compression;
+
+public class ImageDecompressionException extends Exception {
+    private final Exception innerException;
+
+    public ImageDecompressionException(final String message, final Exception innerException) {
+        super(message);
+        this.innerException = innerException;
+    }
+
+    public ImageDecompressionException(final String message) {
+        super(message);
+        this.innerException = null;
+    }
+
+    @Override
+    public String getMessage() {
+        String msg = super.getMessage();
+        if (msg != null && innerException != null) {
+            msg += "\nInner exception:\n" + innerException.getMessage();
+        }
+        return msg;
+    }
+}
diff --git a/src/main/java/azgracompress/compression/ImageDecompressor.java b/src/main/java/azgracompress/compression/ImageDecompressor.java
index 30993f7..badbbfa 100644
--- a/src/main/java/azgracompress/compression/ImageDecompressor.java
+++ b/src/main/java/azgracompress/compression/ImageDecompressor.java
@@ -62,8 +62,7 @@ public class ImageDecompressor extends CompressorDecompressorBase {
         try (FileInputStream fileInputStream = new FileInputStream(options.getInputFile());
              DataInputStream dataInputStream = new DataInputStream(fileInputStream)) {
             header = readQCMPFileHeader(dataInputStream);
-        }
-        catch (IOException ioEx){
+        } catch (IOException ioEx) {
             ioEx.printStackTrace();
             return "";
         }
@@ -154,9 +153,11 @@ public class ImageDecompressor extends CompressorDecompressorBase {
 
             try (FileOutputStream fos = new FileOutputStream(options.getOutputFile(), false);
                  DataOutputStream decompressStream = new DataOutputStream(fos)) {
+
                 imageDecompressor.decompress(dataInputStream, decompressStream, header);
-            } catch (Exception ex) {
-                ex.printStackTrace();
+
+            } catch (ImageDecompressionException ex) {
+                System.err.println(ex.getMessage());
                 return false;
             }
 
diff --git a/src/main/java/azgracompress/compression/SQImageCompressor.java b/src/main/java/azgracompress/compression/SQImageCompressor.java
index 2181a7a..314dbfd 100644
--- a/src/main/java/azgracompress/compression/SQImageCompressor.java
+++ b/src/main/java/azgracompress/compression/SQImageCompressor.java
@@ -35,13 +35,17 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
      *
      * @param quantizer      Quantizer used for compression of the image.
      * @param compressStream Compressed data stream.
-     * @throws IOException when writing to the stream fails.
+     * @throws ImageCompressionException when writing to the stream fails.
      */
     private void writeCodebookToOutputStream(final ScalarQuantizer quantizer,
-                                             DataOutputStream compressStream) throws IOException {
+                                             DataOutputStream compressStream) throws ImageCompressionException {
         final int[] centroids = quantizer.getCentroids();
-        for (final int quantizationValue : centroids) {
-            compressStream.writeShort(quantizationValue);
+        try {
+            for (final int quantizationValue : centroids) {
+                compressStream.writeShort(quantizationValue);
+            }
+        } catch (IOException ioEx) {
+            throw new ImageCompressionException("Unable to write codebook to compress stream.", ioEx);
         }
         if (options.isVerbose()) {
             Log("Wrote quantization values to compressed stream.");
@@ -52,21 +56,29 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
      * Compress the image file specified by parsed CLI options using scalar quantization.
      *
      * @param compressStream Stream to which compressed data will be written.
-     * @throws Exception When compress process fails.
+     * @throws ImageCompressionException When compress process fails.
      */
-    public void compress(DataOutputStream compressStream) throws Exception {
+    public void compress(DataOutputStream compressStream) throws ImageCompressionException {
         ScalarQuantizer quantizer = null;
         Stopwatch stopwatch = new Stopwatch();
         if (options.hasReferencePlaneIndex()) {
             stopwatch.restart();
-            final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
-                                                                   options.getImageDimension(),
-                                                                   options.getReferencePlaneIndex());
+            ImageU16 referencePlane = null;
+            try {
+                referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
+                                                        options.getImageDimension(),
+                                                        options.getReferencePlaneIndex());
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to load reference plane data.", ex);
+            }
+
 
             Log(String.format("Training scalar quantizer from reference plane %d.", options.getReferencePlaneIndex()));
             quantizer = trainScalarQuantizerFromData(referencePlane.getData());
             stopwatch.stop();
+
             writeCodebookToOutputStream(quantizer, compressStream);
+
             Log("Reference codebook created in: " + stopwatch.getElapsedTimeString());
         }
 
@@ -74,9 +86,16 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
         for (final int planeIndex : planeIndices) {
             stopwatch.restart();
             Log(String.format("Loading plane %d.", planeIndex));
-            final ImageU16 plane = RawDataIO.loadImageU16(options.getInputFile(),
-                                                          options.getImageDimension(),
-                                                          planeIndex);
+
+            ImageU16 plane = null;
+
+            try {
+                plane = RawDataIO.loadImageU16(options.getInputFile(),
+                                               options.getImageDimension(),
+                                               planeIndex);
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to load plane data.", ex);
+            }
 
             if (!options.hasReferencePlaneIndex()) {
                 Log(String.format("Training scalar quantizer from plane %d.", planeIndex));
@@ -91,8 +110,8 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
 
             try (OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048)) {
                 outBitStream.write(indices);
-            } catch (IOException ioEx) {
-                ioEx.printStackTrace();
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to write indices to OutBitStream.", ex);
             }
             stopwatch.stop();
             Log("Plane time: " + stopwatch.getElapsedTimeString());
diff --git a/src/main/java/azgracompress/compression/SQImageDecompressor.java b/src/main/java/azgracompress/compression/SQImageDecompressor.java
index 0c6cbea..0eb6dbc 100644
--- a/src/main/java/azgracompress/compression/SQImageDecompressor.java
+++ b/src/main/java/azgracompress/compression/SQImageDecompressor.java
@@ -15,10 +15,15 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
         super(options);
     }
 
-    private int[] readScalarQuantizationValues(DataInputStream compressedStream, final int n) throws IOException {
+    private int[] readScalarQuantizationValues(DataInputStream compressedStream,
+                                               final int n) throws ImageDecompressionException {
         int[] quantizationValues = new int[n];
-        for (int i = 0; i < n; i++) {
-            quantizationValues[i] = compressedStream.readUnsignedShort();
+        try {
+            for (int i = 0; i < n; i++) {
+                quantizationValues[i] = compressedStream.readUnsignedShort();
+            }
+        } catch (IOException ioEx) {
+            throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx);
         }
         return quantizationValues;
     }
@@ -44,7 +49,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
     @Override
     public void decompress(DataInputStream compressedStream,
                            DataOutputStream decompressStream,
-                           QCMPFileHeader header) throws Exception {
+                           QCMPFileHeader header) throws ImageDecompressionException {
         final int codebookSize = (int) Math.pow(2, header.getBitsPerPixel());
         final int planeCountForDecompression = header.getImageSizeZ();
 
@@ -68,18 +73,31 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
             assert (quantizationValues != null);
 
             Log(String.format("Decompressing plane %d...", planeIndex));
-            InBitStream inBitStream = new InBitStream(compressedStream, header.getBitsPerPixel(), planeIndicesDataSize);
-            inBitStream.readToBuffer();
-            inBitStream.setAllowReadFromUnderlyingStream(false);
-            final int[] indices = inBitStream.readNValues(planePixelCount);
-
-            int[] decompressedValues = new int[planePixelCount];
-            for (int i = 0; i < planePixelCount; i++) {
-                decompressedValues[i] = quantizationValues[indices[i]];
+            byte[] decompressedPlaneData = null;
+            try (InBitStream inBitStream = new InBitStream(compressedStream,
+                                                           header.getBitsPerPixel(),
+                                                           planeIndicesDataSize)) {
+                inBitStream.readToBuffer();
+                inBitStream.setAllowReadFromUnderlyingStream(false);
+                final int[] indices = inBitStream.readNValues(planePixelCount);
+
+                int[] decompressedValues = new int[planePixelCount];
+                for (int i = 0; i < planePixelCount; i++) {
+                    decompressedValues[i] = quantizationValues[indices[i]];
+                }
+                decompressedPlaneData =
+                        TypeConverter.unsignedShortArrayToByteArray(decompressedValues, false);
+
+
+            } catch (Exception ex) {
+                throw new ImageDecompressionException("Unable to read indices from InBitStream.", ex);
+            }
+            try {
+                decompressStream.write(decompressedPlaneData);
+            } catch (IOException e) {
+                throw new ImageDecompressionException("Unable to write decompressed data to decompress stream.", e);
             }
-            final byte[] decompressedPlaneData = TypeConverter.unsignedShortArrayToByteArray(decompressedValues, false);
 
-            decompressStream.write(decompressedPlaneData);
             stopwatch.stop();
             Log(String.format("Decompressed plane %d in %s.", planeIndex, stopwatch.getElapsedTimeString()));
         }
diff --git a/src/main/java/azgracompress/compression/VQImageCompressor.java b/src/main/java/azgracompress/compression/VQImageCompressor.java
index 312cb18..cffc856 100644
--- a/src/main/java/azgracompress/compression/VQImageCompressor.java
+++ b/src/main/java/azgracompress/compression/VQImageCompressor.java
@@ -56,16 +56,20 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
      *
      * @param quantizer      Quantizer with the codebook.
      * @param compressStream Stream with compressed data.
-     * @throws IOException When unable to write quantizer.
+     * @throws ImageCompressionException When unable to write quantizer.
      */
     private void writeQuantizerToCompressStream(final VectorQuantizer quantizer,
-                                                DataOutputStream compressStream) throws IOException {
+                                                DataOutputStream compressStream) throws ImageCompressionException {
         final CodebookEntry[] codebook = quantizer.getCodebook();
-        for (final CodebookEntry entry : codebook) {
-            final int[] entryVector = entry.getVector();
-            for (final int vecVal : entryVector) {
-                compressStream.writeShort(vecVal);
+        try {
+            for (final CodebookEntry entry : codebook) {
+                final int[] entryVector = entry.getVector();
+                for (final int vecVal : entryVector) {
+                    compressStream.writeShort(vecVal);
+                }
             }
+        } catch (IOException ioEx) {
+            throw new ImageCompressionException("Unable to write codebook to compress stream.", ioEx);
         }
         if (options.isVerbose()) {
             Log("Wrote quantization vectors to compressed stream.");
@@ -76,16 +80,22 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
      * Compress the image file specified by parsed CLI options using vector quantization.
      *
      * @param compressStream Stream to which compressed data will be written.
-     * @throws Exception When compress process fails.
+     * @throws ImageCompressionException When compress process fails.
      */
-    public void compress(DataOutputStream compressStream) throws Exception {
+    public void compress(DataOutputStream compressStream) throws ImageCompressionException {
         VectorQuantizer quantizer = null;
         Stopwatch stopwatch = new Stopwatch();
         if (options.hasReferencePlaneIndex()) {
             stopwatch.restart();
-            final ImageU16 referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
-                                                                   options.getImageDimension(),
-                                                                   options.getReferencePlaneIndex());
+
+            ImageU16 referencePlane = null;
+            try {
+                referencePlane = RawDataIO.loadImageU16(options.getInputFile(),
+                                                        options.getImageDimension(),
+                                                        options.getReferencePlaneIndex());
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to load reference plane data.", ex);
+            }
 
             Log(String.format("Training vector quantizer from reference plane %d.", options.getReferencePlaneIndex()));
             final int[][] refPlaneVectors = getPlaneVectors(referencePlane);
@@ -101,9 +111,15 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
         for (final int planeIndex : planeIndices) {
             stopwatch.restart();
             Log(String.format("Loading plane %d.", planeIndex));
-            final ImageU16 plane = RawDataIO.loadImageU16(options.getInputFile(),
-                                                          options.getImageDimension(),
-                                                          planeIndex);
+
+            ImageU16 plane = null;
+            try {
+                plane = RawDataIO.loadImageU16(options.getInputFile(),
+                                               options.getImageDimension(),
+                                               planeIndex);
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to load plane data.", ex);
+            }
 
             final int[][] planeVectors = getPlaneVectors(plane);
 
@@ -121,8 +137,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
 
             try (OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerPixel(), 2048)) {
                 outBitStream.write(indices);
-            } catch (IOException ioEx) {
-                ioEx.printStackTrace();
+            } catch (Exception ex) {
+                throw new ImageCompressionException("Unable to write indices to OutBitStream.", ex);
             }
             stopwatch.stop();
             Log("Plane time: " + stopwatch.getElapsedTimeString());
diff --git a/src/main/java/azgracompress/compression/VQImageDecompressor.java b/src/main/java/azgracompress/compression/VQImageDecompressor.java
index 2e27c31..1f77f77 100644
--- a/src/main/java/azgracompress/compression/VQImageDecompressor.java
+++ b/src/main/java/azgracompress/compression/VQImageDecompressor.java
@@ -30,13 +30,17 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
 
     private int[][] readCodebookVectors(DataInputStream compressedStream,
                                         final int codebookSize,
-                                        final int vectorSize) throws IOException {
+                                        final int vectorSize) throws ImageDecompressionException {
 
         int[][] codebook = new int[codebookSize][vectorSize];
-        for (int codebookIndex = 0; codebookIndex < codebookSize; codebookIndex++) {
-            for (int vecIndex = 0; vecIndex < vectorSize; vecIndex++) {
-                codebook[codebookIndex][vecIndex] = compressedStream.readUnsignedShort();
+        try {
+            for (int codebookIndex = 0; codebookIndex < codebookSize; codebookIndex++) {
+                for (int vecIndex = 0; vecIndex < vectorSize; vecIndex++) {
+                    codebook[codebookIndex][vecIndex] = compressedStream.readUnsignedShort();
+                }
             }
+        } catch (IOException ioEx) {
+            throw new ImageDecompressionException("Unable to read quantization values from compressed stream.", ioEx);
         }
         return codebook;
     }
@@ -87,7 +91,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
     @Override
     public void decompress(DataInputStream compressedStream,
                            DataOutputStream decompressStream,
-                           QCMPFileHeader header) throws Exception {
+                           QCMPFileHeader header) throws ImageDecompressionException {
         final int codebookSize = (int) Math.pow(2, header.getBitsPerPixel());
         assert (header.getVectorSizeZ() == 1);
         final int vectorSize = header.getVectorSizeX() * header.getVectorSizeY() * header.getVectorSizeZ();
@@ -114,28 +118,43 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
             assert (quantizationVectors != null);
 
             Log(String.format("Decompressing plane %d...", planeIndex));
-            InBitStream inBitStream = new InBitStream(compressedStream, header.getBitsPerPixel(), (int) planeDataSize);
-            inBitStream.readToBuffer();
-            inBitStream.setAllowReadFromUnderlyingStream(false);
-            final int[] indices = inBitStream.readNValues((int) planeVectorCount);
-
-            int[][] decompressedVectors = new int[(int) planeVectorCount][vectorSize];
-            for (int vecIndex = 0; vecIndex < planeVectorCount; vecIndex++) {
-                System.arraycopy(quantizationVectors[indices[vecIndex]],
-                                 0,
-                                 decompressedVectors[vecIndex],
-                                 0,
-                                 vectorSize);
+
+            byte[] decompressedPlaneData = null;
+
+            try (InBitStream inBitStream = new InBitStream(compressedStream,
+                                                           header.getBitsPerPixel(),
+                                                           (int) planeDataSize)) {
+                inBitStream.readToBuffer();
+                inBitStream.setAllowReadFromUnderlyingStream(false);
+                final int[] indices = inBitStream.readNValues((int) planeVectorCount);
+
+                int[][] decompressedVectors = new int[(int) planeVectorCount][vectorSize];
+                for (int vecIndex = 0; vecIndex < planeVectorCount; vecIndex++) {
+
+                    System.arraycopy(quantizationVectors[indices[vecIndex]],
+                                     0,
+                                     decompressedVectors[vecIndex],
+                                     0,
+                                     vectorSize);
+                }
+
+
+                final ImageU16 decompressedPlane = reconstructImageFromQuantizedVectors(decompressedVectors,
+                                                                                        qVector,
+                                                                                        header.getImageDims());
+                decompressedPlaneData =
+                        TypeConverter.unsignedShortArrayToByteArray(decompressedPlane.getData(), false);
+            } catch (Exception ex) {
+                throw new ImageDecompressionException("Unable to read indices from InBitStream.", ex);
             }
 
 
-            final ImageU16 decompressedPlane = reconstructImageFromQuantizedVectors(decompressedVectors,
-                                                                                    qVector,
-                                                                                    header.getImageDims());
-            final byte[] decompressedPlaneData = TypeConverter.unsignedShortArrayToByteArray(
-                    decompressedPlane.getData(),
-                    false);
-            decompressStream.write(decompressedPlaneData);
+            try {
+                decompressStream.write(decompressedPlaneData);
+            } catch (IOException e) {
+                throw new ImageDecompressionException("Unable to write decompressed data to decompress stream.", e);
+            }
+
             stopwatch.stop();
             Log(String.format("Decompressed plane %d in %s.", planeIndex, stopwatch.getElapsedTimeString()));
         }
diff --git a/src/main/java/azgracompress/io/InBitStream.java b/src/main/java/azgracompress/io/InBitStream.java
index a104d85..c64c120 100644
--- a/src/main/java/azgracompress/io/InBitStream.java
+++ b/src/main/java/azgracompress/io/InBitStream.java
@@ -3,7 +3,7 @@ package azgracompress.io;
 import java.io.IOException;
 import java.io.InputStream;
 
-public class InBitStream {
+public class InBitStream implements AutoCloseable {
 
     private InputStream inputStream;
     private byte[] buffer;
@@ -90,4 +90,9 @@ public class InBitStream {
     }
 
 
+    @Override
+    public void close() throws Exception {
+        bitBufferSize = 0;
+        bytesAvailable = 0;
+    }
 }
diff --git a/src/main/java/azgracompress/quantization/vector/LBGResult.java b/src/main/java/azgracompress/quantization/vector/LBGResult.java
index 57c290b..6b75114 100644
--- a/src/main/java/azgracompress/quantization/vector/LBGResult.java
+++ b/src/main/java/azgracompress/quantization/vector/LBGResult.java
@@ -1,6 +1,9 @@
 package azgracompress.quantization.vector;
 
+import azgracompress.quantization.QTrainIteration;
+
 public class LBGResult {
+
     private final CodebookEntry[] codebook;
     private final double averageMse;
     private final double psnr;
diff --git a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
index d4391c2..13d0099 100644
--- a/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
+++ b/src/main/java/azgracompress/quantization/vector/LBGVectorQuantizer.java
@@ -28,7 +28,6 @@ public class LBGVectorQuantizer {
         return findOptimalCodebook(true);
     }
 
-    // TODO(Moravec): Maybe return QTrainIteration somehow?
     public LBGResult findOptimalCodebook(boolean verbose) {
         ArrayList<LearningCodebookEntry> codebook = initializeCodebook(verbose);
         if (verbose) {
@@ -118,8 +117,6 @@ public class LBGVectorQuantizer {
             // Create perturbation vector.
 
 
-            // TODO(Moravec):   Make sure that when we are splitting entry we don't end up creating two same entries.
-            //                  The problem happens when we try to split Vector full of zeroes.
             // Split each entry in codebook with fixed perturbation vector.
             for (final LearningCodebookEntry entryToSplit : codebook) {
                 double[] prtV;
@@ -142,8 +139,8 @@ public class LBGVectorQuantizer {
                     newCodebook.add(entryToSplit);
 
                     ArrayList<Integer> rndEntryValues = new ArrayList<>(prtV.length);
-                    for (int j = 0; j < prtV.length; j++) {
-                        final int value = (int) Math.floor(prtV[j]);
+                    for (final double v : prtV) {
+                        final int value = (int) Math.floor(v);
                         assert (value >= 0) : "value is too low!";
                         assert (value <= U16.Max) : "value is too big!";
                         rndEntryValues.add(value);
-- 
GitLab