package com.swiftcleaner.chovey.model.tool;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ThumbnailUtils;

import com.swiftcleaner.chovey.model.bean.SimilarBean;

import java.io.File;

class ImageHelpers {
    private Bitmap loadBitmapFromFile(String path) {
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
            return null;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        if (options.outHeight == -1 || options.outWidth == -1) {
            return null;
        }
        int inSampleSize = (int) (0.5f + options.outHeight / (float) bitmap.getHeight()) >= (int) (0.5f + options.outWidth / (float) bitmap.getWidth())?
                (int) (0.5f + options.outHeight / (float) bitmap.getHeight()) : (int) (0.5f + options.outWidth / (float) bitmap.getWidth());
        inSampleSize++;
        options.inSampleSize = inSampleSize >= 1? inSampleSize : 1;
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(path, options);
    }

    SimilarBean createImage(String path) {
        try {
            int width = 8;
            int height = 8;
            Bitmap source = loadBitmapFromFile(path);
            Bitmap thumb = ThumbnailUtils.extractThumbnail(source, width, height);
            int[] pixels = new int[width * height];
            for (int i = 0; i < width; i++) {
                for (int j = 0; j < height; j++) {
                    pixels[i * height + j] = rgbToGray(thumb.getPixel(i, j));
                }
            }

            int avgPixel = average(pixels);
            int[] comps = new int[width * height];
            for (int i = 0; i < comps.length; i++) {
                if (pixels[i] >= avgPixel) {
                    comps[i] = 1;
                } else {
                    comps[i] = 0;
                }
            }

            StringBuffer hashCode = new StringBuffer();
            for (int i = 0; i < comps.length; i += 4) {
                int result = comps[i] * (int) Math.pow(2, 3) + comps[i + 1] * (int) Math.pow(2, 2) +
                        comps[i + 2] * (int) Math.pow(2, 1) + comps[i + 3];
                hashCode.append(binaryToHex(result));
            }
            recycleBitmap(thumb);
            recycleBitmap(source);
            return new SimilarBean(path, hashCode.toString(), avgPixel, new File(path).length(), false);
        } catch (Exception e) {
            return null;
        }
    }

    private int rgbToGray(int pixels) {
        int red = (pixels >> 16) & 0xff;
        int green = (pixels >> 8) & 0xff;
        int blue = pixels & 0xff;
        return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
    }

    private int average(int[] pixels) {
        int sum = 0;
        for (int pixel : pixels) {
            sum += pixel;
        }
        return sum / pixels.length;
    }

    private void recycleBitmap(Bitmap thumb) {
        if (thumb!= null &&!thumb.isRecycled()) {
            thumb.recycle();
        }
    }

    boolean similarCondition(SimilarBean first, SimilarBean second) {
        return hammingDistance(first.getHashCode(), second.getHashCode()) <= 6 &&
                (first.getAvgPixel() / (float) second.getAvgPixel()) >= 0.8 && (first.getAvgPixel() / (float) second.getAvgPixel()) <= 1.0;
    }

    private int hammingDistance(String sourceHashCode, String hashCode) {
        int difference = 0;
        for (int i = 0; i < sourceHashCode.length(); i++) {
            if (sourceHashCode.charAt(i)!= hashCode.charAt(i)) {
                difference++;
            }
        }
        return difference;
    }

    private char binaryToHex(int binary) {
        switch (binary) {
            case 0:
                return '0';
            case 1:
                return '1';
            case 2:
                return '2';
            case 3:
                return '3';
            case 4:
                return '4';
            case 5:
                return '5';
            case 6:
                return '6';
            case 7:
                return '7';
            case 8:
                return '8';
            case 9:
                return '9';
            case 10:
                return 'a';
            case 11:
                return 'b';
            case 12:
                return 'c';
            case 13:
                return 'd';
            case 14:
                return 'e';
            case 15:
                return 'f';
            default:
                return ' ';
        }
    }
}