package org.kne.codec.kif;

import org.kne.membandboost.MembandBoost;

public class Predictor {
	public static int[] predict(int[] data, int w, int h,int vx,int vy) {
		int[] result=MembandBoost.allocateUninitializedIntArray(data.length);
		if(vy==0) {
			horizontalPredict0(data, result, w, h, vx, vy);
		}else {
			verticalPredict0(data, result, w, h, vx, vy);
		}
		return result;
	}
	public static int[] inverse(int[] data, int w, int h,int vx,int vy) {
		int[] result=MembandBoost.allocateUninitializedIntArray( data.length);
		if(vy==0) {
			horizontalInverse0(data, result, w, h, vx, vy);
		}else {
			verticalInverse0(data, result, w, h, vx, vy);
		}
		return result;
	}
	public static void predictInPlace(int[] data, int w, int h,int vx,int vy) {
		if(vy==0) {
			horizontalPredict0(data, data, w, h, vx, vy);
		}else {
			verticalPredict0(data, data, w, h, vx, vy);
		}
	}
	public static void inverseInPlace(int[] data, int w, int h,int vx,int vy) {
		if(vy==0) {
			horizontalInverse0(data, data, w, h, vx, vy);
		}else {
			verticalInverse0(data, data, w, h, vx, vy);
		}
	}
	

	private static void horizontalPredict0(int[] datain,int[] datadout, int w, int h,int vx,int vy) {
		 for (int y = 0; y < h; y++) {
		        // 从右往左！因为左边是原始值，右边要用左边的原始值
		        for (int x = w - 1; x >= 0; x--) {
		            int idx = y * w + x;
		            int px=x+vx;
		            int py=y+vy;
		            int pred=0;
		            if(px>=0&&px<w&&py>=0&&py<h) {
		            	pred=datain[py*w+px];
		            }
		            	datadout[idx] = pixelSub(datain[idx] , pred);
		        }
		    }
	}
	
	
	
	
	private static void horizontalInverse0(int[] datain,int[] datadout, int w, int h,int vx,int vy) {
		 for (int y = 0; y < h; y++) {
		        for (int x = 0; x < w; x++) {
		            int idx = y * w + x;
		            int px=x+vx;
		            int py=y+vy;
		            int pred=0;
		            if(px>=0&&px<w&&py>=0&&py<h) {
		            	pred=datadout[py*w+px];
		            }
		                // 还原：当前 = 左邻居 + 残差
		            	datadout[idx] =pixelAdd( pred , datain[idx]);
		            
		        }
		    }
	}
	
	
	
	private static void verticalPredict0(int[] datain,int[] datadout, int w, int h,int vx,int vy) {
	    for (int y = h - 1; y >= 0; y--) {
	        for (int x = 0; x < w; x++) {
	        	  int idx = y * w + x;
		            int px=x+vx;
		            int py=y+vy;
		            int pred=0;
		            if(px>=0&&px<w&&py>=0&&py<h) {
		            	pred=datain[py*w+px];
		            }
		            	datadout[idx] = pixelSub(datain[idx] , pred);
	        }
	    }
	}

	
	private static void verticalInverse0(int[] datain,int[] datadout, int w, int h,int vx,int vy) {
	    for (int y = 0; y < h; y++) {
	        for (int x = 0; x < w; x++) {
	            int idx = y * w + x;
	            int px=x+vx;
	            int py=y+vy;
	            int pred=0;
	            if(px>=0&&px<w&&py>=0&&py<h) {
	            	pred=datadout[py*w+px];
	            }
	            	datadout[idx] =pixelAdd( pred , datain[idx]);
	            
	        }
	    }
	}
	/**
	 * 像素安全加法：将两个 RGBA 像素相加，每个通道独立计算，结果裁剪到 0~255
	 * 用于预测逆运算：还原 = 预测值 + 残差
	 */
	public static int pixelAdd(int a, int b) {
	    int ar = (a >> 16) & 0xFF;
	    int ag = (a >> 8) & 0xFF;
	    int ab = a & 0xFF;
	    int aa = (a >> 24) & 0xFF;
	    
	    int br = (b >> 16) & 0xFF;
	    int bg = (b >> 8) & 0xFF;
	    int bb = b & 0xFF;
	    int ba = (b >> 24) & 0xFF;
	    
	    int r = ar + br;
	    int g = ag + bg;
	    int bv = ab + bb;
	    int av = aa + ba;  // Alpha 通道也要处理！
	    
	    // 用 &0xFF 替代 min/max，保留低 8 位（自动溢出，等同于裁剪）
	    return ((av & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (bv & 0xFF);
	}

	/**
	 * 像素安全减法：计算 a - b，每个通道独立计算，结果裁剪到 0~255
	 * 用于预测编码：残差 = 当前像素 - 预测值
	 */
	public static int pixelSub(int a, int b) {
	    int ar = (a >> 16) & 0xFF;
	    int ag = (a >> 8) & 0xFF;
	    int ab = a & 0xFF;
	    int aa = (a >> 24) & 0xFF;
	    
	    int br = (b >> 16) & 0xFF;
	    int bg = (b >> 8) & 0xFF;
	    int bb = b & 0xFF;
	    int ba = (b >> 24) & 0xFF;
	    
	    int r = ar - br;
	    int g = ag - bg;
	    int bv = ab - bb;
	    int av = aa - ba;  // Alpha 通道也要处理！
	    
	    // 用 &0xFF 替代 min/max，保留低 8 位（自动溢出，等同于裁剪）
	    return ((av & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (bv & 0xFF);
	}
    
}
