<commit_before>package com.droidtools.rubiksolver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

/**
 * ColorDecoder is NOT thread safe. Working on it.
 */
public class ColorDecoder implements Parcelable {
	//private List<HColor> colors;
	//private List<Bitmap> images;
	private Map<Byte, Parcelable[]> ids;
	byte firstNewCol;
	byte nextId;
	private List<Byte> idArray;
	String cacheDir;
	
	/*static {
		System.loadLibrary("colordecoder");
    }*/
	
	public ColorDecoder(String cache) {
		//colors = new ArrayList<HColor>();
		//images = new ArrayList<Bitmap>();
		ids = new HashMap<Byte, Parcelable[]>();
		idArray = new ArrayList<Byte>();
		//firstNewCol = 0;
		nextId = 0;
		cacheDir = cache;
	}
	
	public List<Byte> getIdArray() {
		return idArray;
	}
	
	private void free() {
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			Log.d("DECODER", "(free) Recycling bitmap " + entry.getKey());
			((Bitmap)entry.getValue()[1]).recycle();
		}
	}
	
	private static int sobel(Bitmap image, int x, int y) {
		int r, g, b, color, horizSobel, vertSobel;
		int[][] sob = new int[3][3];
		for (int i = -1; i <= 1; i++) {
			for (int j = -1; j <= 1; j++) {
				color = image.getPixel(x + i, y + j);
				r = (color >> 16) & 0xFF;
				g = (color >> 8) & 0xFF;
				b = color & 0xFF;
				sob[i + 1][j + 1] = (int) (r * 299.0 / 1000 + g * 587.0 / 1000 + b * 114.0 / 1000);
			}
		}
		horizSobel = -(sob[1 - 1][1 - 1]) + (sob[1 + 1][1 - 1])
				- (sob[1 - 1][1]) - (sob[1 - 1][1]) + (sob[1 + 1][1])
				+ (sob[1 + 1][1]) - (sob[1 - 1][1 + 1]) + (sob[1 + 1][1 + 1]);
		vertSobel = -(sob[1 - 1][1 - 1]) - (sob[1][1 - 1]) - sob[1][1 - 1]
				- (sob[1 + 1][1 - 1]) + (sob[1 - 1][1 + 1]) + (sob[1][1 + 1])
				+ (sob[1][1 + 1]) + (sob[1 + 1][1 + 1]);
		return Math.min(255, Math.max(0, (horizSobel + vertSobel) / 2));
	}
	
	//protected static native int[][] nativeSobelData(Bitmap bitmap);
//	
//	protected static int[][] sobelData(Bitmap image) {
//		int r,g,b,color,horizSobel,vertSobel;
//		int imWidth = image.getWidth();
//		int imHeight = image.getHeight();
//		//Log.d("DAT", String.format("Width - %d Height %d", imWidth, imHeight));
//		int[][] out = new int[imWidth][imHeight];  
//		int[][] sob = new int[3][3];
//		for (int x=1; x<imWidth-1; x++) {
//			for (int y=1; y<imHeight-1; y++) {
//				for (int i=-1; i<=1; i++) {
//					for (int j=-1; j<=1; j++) {
//						color = image.getPixel(x+i,y+j);
//						r = (color >> 16) & 0xFF;
//						g = (color >> 8) & 0xFF;
//						b = color & 0xFF;
//						sob[i+1][j+1] = (int) (r * 299.0/1000 + g * 587.0/1000 + b * 114.0/1000);
//					}
//				}
//				horizSobel = -(sob[1-1][1-1]) + 
//			      (sob[1+1][1-1]) - 
//			      (sob[1-1][1]) - (sob[1-1][1]) +
//			      (sob[1+1][1]) + (sob[1+1][1]) -
//			      (sob[1-1][1+1]) + 
//			      (sob[1+1][1+1]);
//	            vertSobel =  -(sob[1-1][1-1]) - 
//	            (sob[1][1-1]) - sob[1][1-1] - 
//	            (sob[1+1][1-1]) +
//	            (sob[1-1][1+1]) + 
//	            (sob[1][1+1]) + (sob[1][1+1]) + 
//	            (sob[1+1][1+1]);
//	           out[x][y] = Math.min(255, Math.max(0, (horizSobel+vertSobel)/2));
//			}
//		}
//		return out;
//	}
	
	private HColor avg(List<HColor> L) {
		double h,l,s;
		int r,g,b;
		h=l=s=0;
		r=g=b=0;
		for (HColor color : L) {
			h += color.h;
			r += color.r;
			g += color.g;
			b += color.b;
			l += color.l;
			s += color.s;
		}
		int sz = L.size();
		if (sz == 0) return new HColor(0.0,0.0,0.0,0,0,0);
		return new HColor(h/sz, l/sz, s/sz, r/sz, g/sz, b/sz);
	}
	
	public HColor getColor(byte key) {
		return (HColor)ids.get(key)[0];
	}
	
	public Bitmap getBitmap(byte key) {
		Log.d("DECODER", "Trying to access key "+key);
		Log.d("DECODER", "ids size = "+ids.size());
		return (Bitmap)ids.get(key)[1];
	}
	
	public void removeColor(byte key) {
		//colors.remove(position);
		//images.remove(position);
		Log.d("DECODER", "Removing key "+key);
		HColor v = (HColor) ids.get(key)[0];
		try {
			File outPath = new File(cacheDir, v.toString());
			if (outPath.exists()) {
				outPath.delete();
			}
		} catch (Exception e)
		{
		}
		ids.remove(key);
		idArray = new ArrayList<Byte>(ids.keySet());
		Collections.sort(idArray);
	}
	
	public int colorSize() {
		return ids.size();
	}
	
//	public Set<Map.Entry<Byte, Parcelable[]>> entrySet() {
//		return ids.entrySet();
//	}
	
	public boolean hasId(byte id) {
		return ids.containsKey(id);
	}
	
	public Set<Byte> getIds() {
		return new HashSet<Byte>(ids.keySet());
	}
	
	private void deleteImages() 
	{
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			HColor v = (HColor) entry.getValue()[0];
			try {
				File outPath = new File(cacheDir, v.toString());
				if (outPath.exists()) {
					outPath.delete();
				}
			} catch (Exception e)
			{
			}
		}
		
	}
	
	public byte[] colorArray() {
		byte[] ret = new byte[5*ids.size()];
		int i = 0;
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			ret[i] = entry.getKey();
			i++;
			System.arraycopy(((HColor)entry.getValue()[0]).asByteArray(), 0, ret, i, ((HColor)entry.getValue()[0]).asByteArray().length);
			i += ((HColor)entry.getValue()[0]).asByteArray().length;
		}
		return ret;
	}
	
	public void clear() {
		//colors.clear();
		//images.clear();
		Log.d("DECODER", "(Clear) Clearing ids");
		free();
		deleteImages();
		ids.clear();
		idArray = new ArrayList<Byte>(ids.keySet());
	}
	
	public byte[] decode(Bitmap im) {
		firstNewCol = (byte) (nextId+1);
		long s = System.currentTimeMillis();
		/*int[][] sobelDat;
		if (android.os.Build.VERSION.SDK_INT >= 8 ) {
			sobelDat = nativeSobelData(im); 
		} 
		else {
			sobelDat = sobelData(im); 
		}*/
		long e = System.currentTimeMillis();
		long sobelTime = e-s;
		byte[] ret = new byte[]{-1,-1,-1,-1,-1,-1,-1,-1,-1};//new ArrayList<Byte>();
		s = System.currentTimeMillis();
		int retCount = 0;
		ArrayList<HColor> subCubes = new ArrayList<HColor>();
		//ArrayList<HColor> hues = new ArrayList<HColor>();<commit_msg>Beginnings of making ColorDecoder thread safe. This does not solve many of the problems because EntitySet is still public.<commit_after>package com.droidtools.rubiksolver;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

/**
 * ColorDecoder is NOT thread safe. Working on it.
 */
public class ColorDecoder implements Parcelable {
	//private List<HColor> colors;
	//private List<Bitmap> images;
	private ConcurrentMap<Byte, Parcelable[]> ids;
	byte firstNewCol;
	byte nextId;
	private List<Byte> idArray;
	String cacheDir;
	
	/*static {
		System.loadLibrary("colordecoder");
    }*/
	
	public ColorDecoder(String cache) {
		//colors = new ArrayList<HColor>();
		//images = new ArrayList<Bitmap>();
		ids = new ConcurrentHashMap<Byte, Parcelable[]>();
		idArray = new ArrayList<Byte>();
		//firstNewCol = 0;
		nextId = 0;
		cacheDir = cache;
	}
	
	public List<Byte> getIdArray() {
		return idArray;
	}
	
	private void free() {
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			Log.d("DECODER", "(free) Recycling bitmap " + entry.getKey());
			((Bitmap)entry.getValue()[1]).recycle();
		}
	}
	
	private static int sobel(Bitmap image, int x, int y) {
		int r, g, b, color, horizSobel, vertSobel;
		int[][] sob = new int[3][3];
		for (int i = -1; i <= 1; i++) {
			for (int j = -1; j <= 1; j++) {
				color = image.getPixel(x + i, y + j);
				r = (color >> 16) & 0xFF;
				g = (color >> 8) & 0xFF;
				b = color & 0xFF;
				sob[i + 1][j + 1] = (int) (r * 299.0 / 1000 + g * 587.0 / 1000 + b * 114.0 / 1000);
			}
		}
		horizSobel = -(sob[1 - 1][1 - 1]) + (sob[1 + 1][1 - 1])
				- (sob[1 - 1][1]) - (sob[1 - 1][1]) + (sob[1 + 1][1])
				+ (sob[1 + 1][1]) - (sob[1 - 1][1 + 1]) + (sob[1 + 1][1 + 1]);
		vertSobel = -(sob[1 - 1][1 - 1]) - (sob[1][1 - 1]) - sob[1][1 - 1]
				- (sob[1 + 1][1 - 1]) + (sob[1 - 1][1 + 1]) + (sob[1][1 + 1])
				+ (sob[1][1 + 1]) + (sob[1 + 1][1 + 1]);
		return Math.min(255, Math.max(0, (horizSobel + vertSobel) / 2));
	}
	
	//protected static native int[][] nativeSobelData(Bitmap bitmap);
//	
//	protected static int[][] sobelData(Bitmap image) {
//		int r,g,b,color,horizSobel,vertSobel;
//		int imWidth = image.getWidth();
//		int imHeight = image.getHeight();
//		//Log.d("DAT", String.format("Width - %d Height %d", imWidth, imHeight));
//		int[][] out = new int[imWidth][imHeight];  
//		int[][] sob = new int[3][3];
//		for (int x=1; x<imWidth-1; x++) {
//			for (int y=1; y<imHeight-1; y++) {
//				for (int i=-1; i<=1; i++) {
//					for (int j=-1; j<=1; j++) {
//						color = image.getPixel(x+i,y+j);
//						r = (color >> 16) & 0xFF;
//						g = (color >> 8) & 0xFF;
//						b = color & 0xFF;
//						sob[i+1][j+1] = (int) (r * 299.0/1000 + g * 587.0/1000 + b * 114.0/1000);
//					}
//				}
//				horizSobel = -(sob[1-1][1-1]) + 
//			      (sob[1+1][1-1]) - 
//			      (sob[1-1][1]) - (sob[1-1][1]) +
//			      (sob[1+1][1]) + (sob[1+1][1]) -
//			      (sob[1-1][1+1]) + 
//			      (sob[1+1][1+1]);
//	            vertSobel =  -(sob[1-1][1-1]) - 
//	            (sob[1][1-1]) - sob[1][1-1] - 
//	            (sob[1+1][1-1]) +
//	            (sob[1-1][1+1]) + 
//	            (sob[1][1+1]) + (sob[1][1+1]) + 
//	            (sob[1+1][1+1]);
//	           out[x][y] = Math.min(255, Math.max(0, (horizSobel+vertSobel)/2));
//			}
//		}
//		return out;
//	}
	
	private HColor avg(List<HColor> L) {
		double h,l,s;
		int r,g,b;
		h=l=s=0;
		r=g=b=0;
		for (HColor color : L) {
			h += color.h;
			r += color.r;
			g += color.g;
			b += color.b;
			l += color.l;
			s += color.s;
		}
		int sz = L.size();
		if (sz == 0) return new HColor(0.0,0.0,0.0,0,0,0);
		return new HColor(h/sz, l/sz, s/sz, r/sz, g/sz, b/sz);
	}
	
	public HColor getColor(byte key) {
		return (HColor)ids.get(key)[0];
	}
	
	public Bitmap getBitmap(byte key) {
		Log.d("DECODER", "Trying to access key " + key);
		Log.d("DECODER", "ids size = " + ids.size());
		return (Bitmap)ids.get(key)[1];
	}
	
	public void removeColor(byte key) {
		//colors.remove(position);
		//images.remove(position);
		Log.d("DECODER", "Removing key "+key);
		Parcelable[] color = ids.get(key);
		HColor v = (HColor) color[0];
		//try {
			File outPath = new File(cacheDir, v.toString());
			if (outPath.exists()) {
				if (!outPath.delete()) {
					Log.e("DECODER", "Failed to delete file: " + outPath.getAbsolutePath());
				}
			}
		// } catch (Exception e) {}
		if (!ids.remove(key, color)) {
			throw new ConcurrentModificationException(
					"Value at Key " + key + " was modified while trying to be removed.");
		}
		idArray = new ArrayList<Byte>(ids.keySet());
		Collections.sort(idArray);
	}
	
	public int colorSize() {
		return ids.size();
	}
	
//	public Set<Map.Entry<Byte, Parcelable[]>> entrySet() {
//		return ids.entrySet();
//	}
	
	public boolean hasId(byte id) {
		return ids.containsKey(id);
	}
	
	public Set<Byte> getIds() {
		return new HashSet<Byte>(ids.keySet());
	}
	
	private void deleteImages() 
	{
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			HColor v = (HColor) entry.getValue()[0];
			// try {
				File outPath = new File(cacheDir, v.toString());
				if (outPath.exists()) {
					if (!outPath.delete()) {
						Log.e("DECODER", "Failed to delete file: " + outPath.getAbsolutePath());
					}
				}
			//} catch (Exception e)
			//{
			//}
		}
	}
	
	public byte[] colorArray() {
		byte[] ret = new byte[5*ids.size()];
		int i = 0;
		for (Map.Entry<Byte, Parcelable[]> entry : ids.entrySet()) {
			if (i >= ret.length) {
				throw new ConcurrentModificationException("Keys were added to ids while trying to create the colorArray");
			}
			ret[i] = entry.getKey();
			i++;
			System.arraycopy(((HColor)entry.getValue()[0]).asByteArray(), 0, ret, i, ((HColor)entry.getValue()[0]).asByteArray().length);
			i += ((HColor)entry.getValue()[0]).asByteArray().length;
		}
		if (i < ret.length) {
			throw new ConcurrentModificationException("Keys were removed from ids while trying to create the colorArray");
		}
		return ret;
	}
	
	public void clear() {
		//colors.clear();
		//images.clear();
		Log.d("DECODER", "(Clear) Clearing ids");
		free();
		deleteImages();
		ids.clear();
		idArray = new ArrayList<Byte>(ids.keySet());
	}
	
	public byte[] decode(Bitmap im) {
		firstNewCol = (byte) (nextId+1);
		long s = System.currentTimeMillis();
		/*int[][] sobelDat;
		if (android.os.Build.VERSION.SDK_INT >= 8 ) {
			sobelDat = nativeSobelData(im); 
		} 
		else {
			sobelDat = sobelData(im); 
		}*/
		long e = System.currentTimeMillis();
		long sobelTime = e-s;
		byte[] ret = new byte[]{-1,-1,-1,-1,-1,-1,-1,-1,-1};//new ArrayList<Byte>();
		s = System.currentTimeMillis();
		int retCount = 0;
		ArrayList<HColor> subCubes = new ArrayList<HColor>();
		//ArrayList<HColor> hues = new ArrayList<HColor>();
{'fraction_non_alphanumeric': 0.21154970760233918, 'fraction_numerical': 0.03494152046783626, 'mean_word_length': 2.876735619155568, 'pattern_counts': {'":': 0, '<': 64, '<?xml version=': 0, '>': 70, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2973073', 'n_tokens_mistral': 6211, 'n_tokens_neox': 5488, 'n_words': 1186}