package gen2wave.rp70biodemo.passport;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;

import org.jnbis.internal.WsqDecoder;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import ucar.jpeg.jj2000.j2k.decoder.Decoder;
import ucar.jpeg.jj2000.j2k.util.ParameterList;

//import org.jnbis.WSQDecoder;

public class PUtils {

    public static final int INFO=0xA;
    public static final int DEBUG=0xB;
    public static final int ERROR=0xC;
//    public static WSQDecoder decoder=new WSQDecoder();

    public static String
    JPEG_MIME_TYPE = "image/jpeg",
    JPEG2000_MIME_TYPE = "image/jp2",
    JPEG2000_ALT_MIME_TYPE = "image/jpeg2000",
    WSQ_MIME_TYPE = "image/x-wsq";

    public static String bytesToHex(byte[] bytes) {
        final char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] getMD5Hash(byte[] bytes) throws NoSuchAlgorithmException{
        MessageDigest md=MessageDigest.getInstance("MD5");
        return md.digest(bytes);
    }

    public static byte[] getSHA1Hash(byte[] bytes) throws NoSuchAlgorithmException{
        MessageDigest md=MessageDigest.getInstance("SHA-1");
        return md.digest(bytes);
    }

    /* IMAGE DECODIFICATION METHODS */
//    public  static Bitmap read(InputStream inputStream, int imageLength, String mimeType) throws IOException {
//        /* DEBUG */
//        synchronized(inputStream) {
//            DataInputStream dataIn = new DataInputStream(inputStream);
//            byte[] bytes = new byte[imageLength];
//            dataIn.readFully(bytes);
//            inputStream = new ByteArrayInputStream(bytes);
//        }
//        /* END DEBUG */
//
//        if (JPEG2000_MIME_TYPE.equalsIgnoreCase(mimeType) || JPEG2000_ALT_MIME_TYPE.equalsIgnoreCase(mimeType)) {
//            org.jmrtd.jj2000.Bitmap bitmap = org.jmrtd.jj2000.JJ2000Decoder.decode(inputStream);
//            return toAndroidBitmap(bitmap);
//        } else if (WSQ_MIME_TYPE.equalsIgnoreCase(mimeType)) {
//            org.jnbis.Bitmap bitmap = WSQDecoder.decode(inputStream);
//            return toAndroidBitmap(bitmap);
//        } else {
//            return BitmapFactory.decodeStream(inputStream);
//        }
//    }

    /* ONLY PRIVATE METHODS BELOW */

//    private static Bitmap toAndroidBitmap(org.jmrtd.jj2000.Bitmap bitmap) {
//        int[] intData = bitmap.getPixels();
//        return Bitmap.createBitmap(intData, 0, bitmap.getWidth(), bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
//
//    }
//
//    private static Bitmap toAndroidBitmap(org.jnbis.Bitmap bitmap) {
//        byte[] byteData = bitmap.getPixels();
//        int[] intData = new int[byteData.length];
//        for (int j = 0; j < byteData.length; j++) {
//            intData[j] = 0xFF000000 | ((byteData[j] & 0xFF) << 16) | ((byteData[j] & 0xFF) << 8) | (byteData[j] & 0xFF);
//        }
//        return Bitmap.createBitmap(intData, 0, bitmap.getWidth(), bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
//    }

    static class BoundedInputStream extends FilterInputStream {

        private final long bound;
        private long position;

        protected BoundedInputStream(InputStream inputStream, long bound) {
            super(inputStream);
            this.position = 0;
            this.bound = bound;
        }

        @Override
        public int read() throws IOException {
            if (position >= bound) { return -1; }
            try {
                return super.read();
            } finally {
                position++;
            }
        }
    }

    public static Bitmap decodeImage(Context context, String mimeType, InputStream inputStream, byte[] dataArray) throws IOException {

        if (mimeType.equalsIgnoreCase("image/jp2") || mimeType.equalsIgnoreCase("image/jpeg2000")) {

            // Save jp2 file

            OutputStream output = new FileOutputStream(new File(context.getCacheDir(), "temp.jp2"));
            byte[] buffer = new byte[1024];
            int read;
            while ((read = inputStream.read(buffer)) != -1) {
                output.write(buffer, 0, read);
            }
            output.close();

            // Decode jp2 file

            String pinfo[][] = Decoder.getAllParameters();
            ParameterList parameters, defaults;

            defaults = new ParameterList();
            for (int i = pinfo.length - 1; i >= 0; i--) {
                if(pinfo[i][3] != null) {
                    defaults.put(pinfo[i][0], pinfo[i][3]);
                }
            }

            parameters = new ParameterList(defaults);

            parameters.setProperty("rate", "3");
            parameters.setProperty("o", context.getCacheDir().toString() + "/temp.ppm");
            parameters.setProperty("debug", "on");

            parameters.setProperty("i", context.getCacheDir().toString() + "/temp.jp2");

            Decoder decoder = new Decoder(parameters);
            decoder.run();

            // Read ppm file

            BufferedInputStream reader = new BufferedInputStream(
                    new FileInputStream(new File(context.getCacheDir().toString() + "/temp.ppm")));
            if (reader.read() != 'P' || reader.read() != '6') return null;

            reader.read();
            String widths = "" , heights = "";
            char temp;
            while ((temp = (char) reader.read()) != ' ') widths += temp;
            while ((temp = (char) reader.read()) >= '0' && temp <= '9') heights += temp;
            if (reader.read() != '2' || reader.read() != '5' || reader.read() != '5') return null;
            reader.read();

            int width = Integer.valueOf(widths);
            int height = Integer.valueOf(heights);
            int[] colors = new int[width * height];

            byte [] pixel = new byte[3];
            int len, cnt = 0, total = 0;
            int[] rgb = new int[3];
            while ((len = reader.read(pixel)) > 0) {
                for (int i = 0; i < len; i ++) {
                    rgb[cnt] = pixel[i]>=0?pixel[i]:(pixel[i] + 255);
                    if ((++cnt) == 3) {
                        cnt = 0;
                        colors[total++] = Color.rgb(rgb[0], rgb[1], rgb[2]);
                    }
                }
            }

            return Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);

        } else if (mimeType.equalsIgnoreCase("image/x-wsq")) {

            WsqDecoder wsqDecoder = new WsqDecoder();
            org.jnbis.api.model.Bitmap bitmap = wsqDecoder.decode(dataArray);
            byte[] byteData = bitmap.getPixels();
            int[] intData = new int[byteData.length];
            for (int j = 0; j < byteData.length; j++) {
                intData[j] = 0xFF000000 | ((byteData[j] & 0xFF) << 16) | ((byteData[j] & 0xFF) << 8) | (byteData[j] & 0xFF);
            }
            return Bitmap.createBitmap(intData, 0, bitmap.getWidth(), bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

        } else {

            return BitmapFactory.decodeStream(inputStream);

        }

    }
}
