var pInv = player.getInventory();
var undo = new Array(new Array());
var undoCheck = new Array();
var undoLimit = 50;
chat.print("Sculpt Tool v1.5 Initialized!");
effect.replaceTexture("/gui/inventory.png", "sculptInv.png");
effect.replaceTexture("/gui/heartPiece.png", "sculptHeart.png");

function lerp(a,b,lrp,ID) {
	if (!(lrp >= 0 && lrp <= 1)) {lrp = 0;}
	if (ID == 2) {return a-(1-lrp)*(a-b);}
	return a-lrp*(a-b);
}

function metaCheck(ID) {
	if ((ID >= 31 && ID <= 35) || (ID >= 205 && ID <= 230)) {return true;}
	return false;
}

function undoStart(undoMethod) {
	var tl = undoCheck.length;
	
	if(tl > 0) {
		for (x = 0; x < undo[tl-1][0].length; x++) {
			if (undo[tl-1][0][x] != null) {
			for (y = 0; y < undo[tl-1][0][x].length; y++) {
				if (undo[tl-1][0][x][y] != null) {
				for (z = 0; z < undo[tl-1][0][x][y].length; z++) {
					if ((undo[tl-1][0][x][y][z] == null) 
					|| (undoMethod && (undoCheck[tl-1][x][y][z][0] !=
					world.getBlockID(x+undo[tl-1][1],y+undo[tl-1][2],z+undo[tl-1][3])
					|| (metaCheck(undoCheck[tl-1][x][y][z][0]) && undoCheck[tl-1][x][y][z][1] !=
					world.getMetadata(x+undo[tl-1][1],y+undo[tl-1][2],z+undo[tl-1][3])))))
					{ continue; }
					
					world.setBlockIDAndMetadata(x+undo[tl-1][1],y+undo[tl-1][2],z+undo[tl-1][3],
					undo[tl-1][0][x][y][z][0],undo[tl-1][0][x][y][z][1]);
				}
				}
			}
			}
		}
		
		undo.pop();
		undo.pop();
		undo.push(new Array());
		undoCheck.pop();
	} else {
		chat.print("No more undos left.");
	}
	
}

function vecSqrDist(x1,y1,z1,x2,y2,z2) {
	var cX = x2 - x1;
	var cY = y2 - y1;
	var cZ = z2 - z1;
	return (cX*cX)+(cY*cY)+(cZ*cZ);
}

function checkBlock(dist,lVec,lPos,lItem,lMeta) {
	var x = Math.floor(lVec.x * dist + lPos.x);
	var y = Math.floor(lVec.y * dist + lPos.y);
	var z = Math.floor(lVec.z * dist + lPos.z);
	var tMC = metaCheck(lItem); 
	
	if ((tMC && lItem == world.getBlockID(x,y,z) && lMeta == world.getMetadata(x,y,z))
	|| (!tMC && lItem == world.getBlockID(x,y,z))) { return true; }
	return false;
}

function sculptStart(cenX,cenY,cenZ) {
	var bType = 1;
	try { bType = pInv.getItemInSlot(33).getQuantity(); } catch(e) {}
	
	var offX = 0;
	var offY = 0;
	var offZ = 0;
	try { offX = pInv.getItemInSlot(15).getQuantity(); } catch(e) {}
	try { offY = pInv.getItemInSlot(16).getQuantity(); } catch(e) {}
	try { offZ = pInv.getItemInSlot(17).getQuantity(); } catch(e) {}
	
	if(offX != 0) { if (pInv.getItemInSlot(15).getItemID() == 2) { offX *= -1; }}
	if(offY != 0) { if (pInv.getItemInSlot(16).getItemID() == 2) { offY *= -1; }}
	if(offZ != 0) { if (pInv.getItemInSlot(17).getItemID() == 2) { offZ *= -1; }}
	
	world.setBlockID(cenX,cenY,cenZ,0);
	
	var block = 0;
	var blockMeta = 0;
	var offItem = pInv.getOffhandItem();
	if (offItem != null) {
		if (offItem.getItemID() < 255) {
			block = offItem.getItemID();
			if (metaCheck(block)) { blockMeta = offItem.getDamage(); }
			else if (block == 121) { blockMeta = 15; }
		} else if (offItem.getItemID() != 558) {
			chat.print("ERROR: Offhand not set to block or eraser!");
			return;
		}
	} else {
		chat.print("ERROR: Offhand not set to block or eraser!");
		return;
	}
	
	var ignoreAir = false;
	var ignoreBlock = false;
	var selectBlock = false;
	var selectBlockID = 0;
	var selectBlockMeta = 0;
	var sBMC = false;
	var shiftMode = false;
	var airCheck = pInv.getItemInSlot(14);
	if (airCheck != null) {
		switch (airCheck.getQuantity()) {
			case 1:
				ignoreAir = true;
				break;
			case 2:
				ignoreBlock = true;
				break;
			case 3:
				selectBlock = true;
				selectBlockID = airCheck.getItemID();
				sBMC = metaCheck(selectBlockID);
				if (sBMC) 
				{ selectBlockMeta = airCheck.getDamage(); }
				break;
			case 4:
				shiftMode = true;
				break;
			case 5:
				shiftMode = true;
				ignoreAir = true;
				break;
		}
	}
	
	var noiseCount = 0;
	try { noiseCount = pInv.getItemInSlot(23).getQuantity(); } catch(e) {}
	
	var taper = 1;
	var taperID = 0;
	if (pInv.getItemInSlot(32) != null) {
		taper = 1 - (pInv.getItemInSlot(32).getQuantity() / 64.0);
		taperID = pInv.getItemInSlot(32).getItemID();
	}
	
	switch(bType) {
		case 2:
			sculptCyl(cenX,cenY,cenZ,offX,offY,offZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC,
			taper,taperID);
			break;
		case 3:
			sculptSphere(cenX,cenY,cenZ,offX,offY,offZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC);
			break;
		default:
			sculptRect(cenX,cenY,cenZ,offX,offY,offZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC);
	}
}

function sculptRect(cenX,cenY,cenZ,oX,oY,oZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC) {
	var bX = 1;
	var bY = 1;
	var bZ = 1;
	try { bX = pInv.getItemInSlot(24).getQuantity(); } catch(e) {}
	try { bY = pInv.getItemInSlot(25).getQuantity(); } catch(e) {}
	try { bZ = pInv.getItemInSlot(26).getQuantity(); } catch(e) {}
	
	var minX = cenX - Math.floor(bX*0.5);
	var minY = cenY - Math.floor(bY*0.5);
	var minZ = cenZ - Math.floor(bZ*0.5);
	
	var shift = 0;
	var tl = undoCheck.length;
	
	undo[tl][1] = minX + oX;
	undo[tl][2] = minY + oY;
	undo[tl][3] = minZ + oZ;
	undo[tl][0] = new Array(new Array(new Array()));
	undoCheck[tl] = new Array(new Array(new Array()));
	
	for (x = minX; x < minX + bX; x++) {
		undo[tl][0][x - minX] = new Array();
		undoCheck[tl][x - minX] = new Array();
		for (y = minY; y < minY + bY; y++) {
			if (y+oY < 0 || y+oY > 127) {continue;}
			if (undo[tl][0][x - minX][y - minY] == null) {
				undo[tl][0][x - minX][y - minY] = new Array();
				undoCheck[tl][x - minX][y - minY] = new Array();
			}
			for (z = minZ; z < minZ + bZ; z++) {
				if ((ignoreAir && world.getBlockID(x+oX,y+oY,z+oZ) == 0)
				|| (ignoreBlock && world.getBlockID(x+oX,y+oY,z+oZ) != 0)
				|| (selectBlock && (
				(sBMC && (world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID
				|| world.getMetadata(x+oX,y+oY,z+oZ) != selectBlockMeta))
				|| (!sBMC && world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID)))
				|| (Math.random() < noiseCount/64.0))
				{ continue; }

				if (shiftMode) { shift = 0;
					for (j = y; world.getBlockID(x+oX,j+oY,z+oZ) != 0; j++) { shift++; }
				}
				if (undo[tl][0][x - minX][y + shift - minY] == null) {
						undo[tl][0][x - minX][y + shift - minY] = new Array();
						undoCheck[tl][x - minX][y + shift - minY] = new Array();
				}
				
				undo[tl][0][x - minX][y + shift - minY]
				[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
				world.getMetadata(x+oX,y+oY+shift,z+oZ)];
				world.setBlockIDAndMetadata(x+oX,y+oY+shift,z+oZ,block,blockMeta);
				undoCheck[tl][x - minX][y + shift - minY]
				[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
				world.getMetadata(x+oX,y+oY+shift,z+oZ)];
			}
		}
	}
	
	undo.push(new Array());
	if (undoCheck.length >= undoLimit) {
		undo.shift();
		undoCheck.shift();
	}
	
}

function sculptCyl(cenX,cenY,cenZ,oX,oY,oZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC,
			taper,taperID) {
	var bR = 1;
	var bH = 1;
	var bT = 1;
	try { bR = pInv.getItemInSlot(24).getQuantity(); } catch(e) {}
	try { bH = pInv.getItemInSlot(25).getQuantity(); } catch(e) {}
	try { bT = pInv.getItemInSlot(26).getQuantity(); } catch(e) {}
	var bR2 = bR + .75;
	
	var minX = cenX
	var minY = cenY
	var minZ = cenZ
	
	var shift = 0;
	var tl = undoCheck.length;
	undo[tl][0] = new Array(new Array(new Array()));
	undoCheck[tl] = new Array(new Array(new Array()));
	
	switch (bT) {
		case 2:
			minX -= bR;
			minY -= Math.floor(bH * 0.5);
			minZ -= bR;
			
			undo[tl][1] = minX + oX;
			undo[tl][2] = minY + oY;
			undo[tl][3] = minZ + oZ;
			
			for (x = minX; x <= cenX + bR; x++) {
				undo[tl][0][x - minX] = new Array();
				undoCheck[tl][x - minX] = new Array();
				for (y = minY; y < minY + bH; y++) {
					if (y+oY < 0 || y+oY > 127) {continue;}
					if (undo[tl][0][x - minX][y - minY] == null) {
						undo[tl][0][x - minX][y - minY] = new Array();
						undoCheck[tl][x - minX][y - minY] = new Array();
					}
					for (z = minZ; z <= cenZ + bR; z++) {
						if ((ignoreAir && world.getBlockID(x+oX,y+oY,z+oZ) == 0)
						|| (vecSqrDist(cenX,y,cenZ,x,y,z) > 
						lerp(bR2*bR2,bR2*bR2*taper*taper,(y-minY)/(bH-1),taperID))
						|| (ignoreBlock && world.getBlockID(x+oX,y+oY,z+oZ) != 0)
						|| (selectBlock && (
						(sBMC && (world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID
						|| world.getMetadata(x+oX,y+oY,z+oZ) != selectBlockMeta))
						|| (!sBMC && world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID)))
						|| (Math.random() < noiseCount/64.0))
						{ continue; }

						if (shiftMode) { shift = 0;
							for (j = y; world.getBlockID(x+oX,j+oY,z+oZ) != 0; j++) { shift++; }
						}
						if (undo[tl][0][x - minX][y + shift - minY] == null) {
								undo[tl][0][x - minX][y + shift - minY] = new Array();
								undoCheck[tl][x - minX][y + shift - minY] = new Array();
						}
					
						undo[tl][0][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
						world.setBlockIDAndMetadata(x+oX,y+oY+shift,z+oZ,block,blockMeta);
						undoCheck[tl][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
					}
				}
			}
			break;
		case 3:
			minX -= bR;
			minY -= bR;
			minZ -= Math.floor(bH * 0.5);
			
			undo[tl][1] = minX + oX;
			undo[tl][2] = minY + oY;
			undo[tl][3] = minZ + oZ;
			
			for (x = minX; x <= cenX + bR; x++) {
				undo[tl][0][x - minX] = new Array();
				undoCheck[tl][x - minX] = new Array();
				for (y = minY; y <= cenY + bR; y++) {
					if (y+oY < 0 || y+oY > 127) {continue;}
					if (undo[tl][0][x - minX][y - minY] == null) {
						undo[tl][0][x - minX][y - minY] = new Array();
						undoCheck[tl][x - minX][y - minY] = new Array();
					}
					for (z = minZ; z < minZ + bH; z++) {
						if ((ignoreAir && world.getBlockID(x+oX,y+oY,z+oZ) == 0)
						|| (vecSqrDist(cenX,y,cenZ,x,y,z) >= 
						lerp(bR2*bR2,bR2*bR2*taper*taper,(z-minZ)/(bH-1),taperID))
						|| (ignoreBlock && world.getBlockID(x+oX,y+oY,z+oZ) != 0)
						|| (selectBlock && (
						(sBMC && (world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID
						|| world.getMetadata(x+oX,y+oY,z+oZ) != selectBlockMeta))
						|| (!sBMC && world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID)))
						|| (Math.random() < noiseCount/64.0))
						{ continue; }
						
						if (shiftMode) { shift = 0;
							for (j = y; world.getBlockID(x+oX,j+oY,z+oZ) != 0; j++) { shift++; }
						}
						if (undo[tl][0][x - minX][y + shift - minY] == null) {
								undo[tl][0][x - minX][y + shift - minY] = new Array();
								undoCheck[tl][x - minX][y + shift - minY] = new Array();
						}
					
						undo[tl][0][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
						world.setBlockIDAndMetadata(x+oX,y+oY+shift,z+oZ,block,blockMeta);
						undoCheck[tl][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
					}
				}
			}
			break;
		default:
			minX -= Math.floor(bH * 0.5);
			minY -= bR;
			minZ -= bR;
			
			undo[tl][1] = minX + oX;
			undo[tl][2] = minY + oY;
			undo[tl][3] = minZ + oZ;
			
			for (x = minX; x < minX + bH; x++) {
				undo[tl][0][x - minX] = new Array();
				undoCheck[tl][x - minX] = new Array();
				for (y = minY; y <= cenY + bR; y++) {
					if (y+oY < 0 || y+oY > 127) {continue;}
					if (undo[tl][0][x - minX][y - minY] == null) {
						undo[tl][0][x - minX][y - minY] = new Array();
						undoCheck[tl][x - minX][y - minY] = new Array();
					}
					for (z = minZ; z <= cenZ + bR; z++) {
						if ((ignoreAir && world.getBlockID(x+oX,y+oY,z+oZ) == 0)
						|| (vecSqrDist(cenX,y,cenZ,x,y,z) >= 
						lerp(bR2*bR2,bR2*bR2*taper*taper,(x-minX)/(bH-1),taperID))
						|| (ignoreBlock && world.getBlockID(x+oX,y+oY,z+oZ) != 0)
						|| (selectBlock && (
						(sBMC && (world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID
						|| world.getMetadata(x+oX,y+oY,z+oZ) != selectBlockMeta))
						|| (!sBMC && world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID)))
						|| (Math.random() < noiseCount/64.0)) 
						{ continue; }
						
						if (shiftMode) { shift = 0;
							for (j = y; world.getBlockID(x+oX,j+oY,z+oZ) != 0; j++) { shift++; }
						}
						if (undo[tl][0][x - minX][y + shift - minY] == null) {
								undo[tl][0][x - minX][y + shift - minY] = new Array();
								undoCheck[tl][x - minX][y + shift - minY] = new Array();
						}
					
						undo[tl][0][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
						world.setBlockIDAndMetadata(x+oX,y+oY+shift,z+oZ,block,blockMeta);
						undoCheck[tl][x - minX][y + shift - minY]
						[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
						world.getMetadata(x+oX,y+oY+shift,z+oZ)];
					}
				}
			}
	}
	
	undo.push(new Array());
	if (undoCheck.length >= undoLimit) {
		undo.shift();
		undoCheck.shift();
	}
		
}

function sculptSphere(cenX,cenY,cenZ,oX,oY,oZ,block,
			ignoreAir,ignoreBlock,selectBlock,selectBlockID,
			noiseCount,shiftMode,blockMeta,selectBlockMeta,sBMC) {
	var bR = 1;
	try { bR = pInv.getItemInSlot(24).getQuantity(); } catch(e) {}
	var bR2 = bR + .75;
	
	var minX = cenX - bR;
	var minY = cenY - bR;
	var minZ = cenZ - bR;
	
	var shift = 0;
	var tl = undoCheck.length;
	
	undo[tl][1] = minX + oX;
	undo[tl][2] = minY + oY;
	undo[tl][3] = minZ + oZ;
	undo[tl][0] = new Array(new Array(new Array()));
	undoCheck[tl] = new Array(new Array(new Array()));
	
	for (x = minX; x <= cenX + bR; x++) {
		undo[tl][0][x - minX] = new Array();
		undoCheck[tl][x - minX] = new Array();
		for (y = minY; y <= cenY + bR; y++) {
			if (y+oY < 0 || y+oY > 127) {continue;}
			if (undo[tl][0][x - minX][y - minY] == null) {
				undo[tl][0][x - minX][y - minY] = new Array();
				undoCheck[tl][x - minX][y - minY] = new Array();
			}
			for (z = minZ; z <= cenZ + bR; z++) {
				if ((ignoreAir && world.getBlockID(x+oX,y+oY,z+oZ) == 0)
				|| (vecSqrDist(cenX,cenY,cenZ,x,y,z) > bR2*bR2)
				|| (ignoreBlock && world.getBlockID(x+oX,y+oY,z+oZ) != 0)
				|| (selectBlock && (
				(sBMC && (world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID
				|| world.getMetadata(x+oX,y+oY,z+oZ) != selectBlockMeta))
				|| (!sBMC && world.getBlockID(x+oX,y+oY,z+oZ) != selectBlockID)))
				|| (Math.random() < noiseCount/64.0)) 
				{ continue; }
				
				if (shiftMode) { shift = 0;
					for (j = y; world.getBlockID(x+oX,j+oY,z+oZ) != 0; j++) { shift++; }
				}
				if (undo[tl][0][x - minX][y + shift - minY] == null) {
						undo[tl][0][x - minX][y + shift - minY] = new Array();
						undoCheck[tl][x - minX][y + shift - minY] = new Array();
				}
				
				undo[tl][0][x - minX][y + shift - minY]
				[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
				world.getMetadata(x+oX,y+oY+shift,z+oZ)];
				world.setBlockIDAndMetadata(x+oX,y+oY+shift,z+oZ,block,blockMeta);
				undoCheck[tl][x - minX][y + shift - minY]
				[z - minZ] = [world.getBlockID(x+oX,y+oY+shift,z+oZ),
				world.getMetadata(x+oX,y+oY+shift,z+oZ)];		
			}
		}
	}
	
	undo.push(new Array());
	if (undoCheck.length >= undoLimit) {
		undo.shift();
		undoCheck.shift();
	}
}