/*
 * Javascript Wolfenstein 3D Wall Object
 * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com
 */

Canvas3D.Wall = function() {

	this._oPosition = new Canvas3D.Vec3(0,0,0);
	this._iDirection = 0;

	this._oDrawOffset = new Canvas3D.Vec3(0,0,0);
	this._oClipOffset = new Canvas3D.Vec3(0,0,0);

	this._updatePoints();

	this._bDirty = true;

	this._bShaded = true;

	this._bVisible = true;

	this._oTexture = null;
};

Canvas3D.Wall.prototype.setTexture = function(oTexture) 
{
	this._oTexture = oTexture;
}

Canvas3D.Wall.prototype.setShading = function(bEnable) 
{
	this._bShaded = bEnable;
}

Canvas3D.Wall.prototype.setDirection = function(iDir) 
{
	this._iDirection = iDir;
	this._updatePoints();
}
Canvas3D.Wall.prototype.getDirection = function() 
{
	return this._iDirection;
}


Canvas3D.Wall.prototype.draw = function(oCtx, iOffsetX, iOffsetY) 
{
	if (!this._oTexture.getCanvas()) return;
	this._bDirty = false;

	if (!this._bVisible) return false;

	var oScene = this._oScene;

	var iSceneWidth = oScene.getWidth();
	var iSceneHeight = oScene.getHeight();

	var oCam = oScene.getActiveCamera();

	var oPos = this._oPosition;
	var iDir = this._iDirection;

	var bDebug = false;

	var oDrawOffset = this._oDrawOffset;

	var oBL = this._oBottomLeft.clone().addVector(oDrawOffset);
	var oTL = this._oTopLeft.clone().addVector(oDrawOffset);
	var oBR = this._oBottomRight.clone().addVector(oDrawOffset);
	var oTR = this._oTopRight.clone().addVector(oDrawOffset);

	var oTransBottomLeft = oCam.transformPoint(oBL);
	if (oTransBottomLeft.z <= -oCam.getFocal()) {
		return false;
	}

	var oTransBottomRight = oCam.transformPoint(oBR);
	if (oTransBottomRight.z <= -oCam.getFocal()) {
		return false;
	}

	var oTransTopLeft = oCam.transformPoint(oTL);
	var oTransTopRight = oCam.transformPoint(oTR);

	var oPoint2DBottomLeft = oCam.project(oTransBottomLeft, iSceneWidth, iSceneHeight);

	if (oPoint2DBottomLeft.x + iOffsetX > oScene.getWidth()) {
		return false;
	}

	var oPoint2DBottomRight = oCam.project(oTransBottomRight, iSceneWidth, iSceneHeight);

	if (oPoint2DBottomRight.x < oPoint2DBottomLeft.x) {
		return false;
	}


	if (oPoint2DBottomRight.x + iOffsetX < 0) {
		return false;
	}


	var oPoint2DTopLeft = oCam.project(oTransTopLeft, iSceneWidth, iSceneHeight);
	var oPoint2DTopRight = oCam.project(oTransTopRight, iSceneWidth, iSceneHeight);

	var fHeightLeft = oPoint2DBottomLeft.y - oPoint2DTopLeft.y;
	var fHeightRight = oPoint2DBottomRight.y - oPoint2DTopRight.y;

	if (fHeightLeft <= 0) {
		return false;
	}
	if (fHeightRight <= 0) {
		return false;
	}

	var fWidth = Math.abs(oPoint2DBottomLeft.x - oPoint2DBottomRight.x);

	var fMaxHeight = Math.max(fHeightLeft, fHeightRight);
	var fMinHeight = Math.min(fHeightLeft, fHeightRight);

	// var fAngle = atan2(v2.y,v2.x) - atan2(v1.y,v1.x)

	var fAngle = Math.atan2(oTransBottomLeft.x , oTransBottomLeft.z) / Math.PI * 180;

	var oDrawCanvas = this._oDrawCanvas;

	var oTexture = this._oDrawCanvas;

	var oTextureCanvas = this._oTexture.getCanvas();

	var fSlope = fHeightRight / fHeightLeft;

	var iTextureIdx = -1;

	if (fSlope == 1) {
		iTextureIdx = 0;
	}
	if (fSlope < 1) {
		var fRatio = fHeightLeft / 64;
		var iTexSlope = Math.round((fHeightRight / fRatio) / 2);
		var iTextureIdx = 32 - iTexSlope;
	}
	if (fSlope > 1) {
		var fRatio = fHeightRight / 64;
		var iTexSlope = Math.round((fHeightLeft / fRatio) / 2);
		var iTextureIdx = 32 - iTexSlope + 32;
	}


	var iMaxY = Math.max(oPoint2DBottomLeft.y, oPoint2DBottomRight.y);

	var iX = oPoint2DBottomLeft.x + iOffsetX;
	var iY = iMaxY - fMaxHeight + iOffsetY;

	oCtx.save();

	var oClipBL = oCam.project(oCam.transformPoint(this._oBottomLeft));
	var oClipTL = oCam.project(oCam.transformPoint(this._oTopLeft));
	var oClipBR = oCam.project(oCam.transformPoint(this._oBottomRight));
	var oClipTR = oCam.project(oCam.transformPoint(this._oTopRight));

	oCtx.beginPath();
	oCtx.moveTo(oClipBL.x + iOffsetX, oClipBL.y + iOffsetY);
	oCtx.lineTo(oClipTL.x + iOffsetX, oClipTL.y + iOffsetY);
	oCtx.lineTo(oClipTR.x + iOffsetX, oClipTR.y + iOffsetY);
	oCtx.lineTo(oClipBR.x + iOffsetX, oClipBR.y + iOffsetY);
	oCtx.closePath();
	oCtx.clip();


	var oClipOffset = this._oClipOffset;
	if (oClipOffset.x != 0 || oClipOffset.y != 0 || oClipOffset.z != 0) {
		var oOffClipBL = oCam.project(oCam.transformPoint(this._oBottomLeft.clone().addVector(oClipOffset)));
		var oOffClipTL = oCam.project(oCam.transformPoint(this._oTopLeft.clone().addVector(oClipOffset)));
		var oOffClipBR = oCam.project(oCam.transformPoint(this._oBottomRight.clone().addVector(oClipOffset)));
		var oOffClipTR = oCam.project(oCam.transformPoint(this._oTopRight.clone().addVector(oClipOffset)));
	
		oCtx.beginPath();
		oCtx.moveTo(oOffClipBL.x + iOffsetX, oOffClipBL.y + iOffsetY);
		oCtx.lineTo(oOffClipTL.x + iOffsetX, oOffClipTL.y + iOffsetY);
		oCtx.lineTo(oOffClipTR.x + iOffsetX, oOffClipTR.y + iOffsetY);
		oCtx.lineTo(oOffClipBR.x + iOffsetX, oOffClipBR.y + iOffsetY);
		oCtx.closePath();
		oCtx.clip();
	}


	var oTexture = this._oTexture;

	if (iTextureIdx > -1) {
		if (bLowRes) {
			// low quality
			var iLOD = 0;
			if (fMaxHeight < 128)
				iLOD = 1;
			if (fMaxHeight < 64)
				iLOD = 2;
			if (fMaxHeight < 32)
				iLOD = 2;
		} else {
			// high quality
			iLOD = 0
			if (fMaxHeight < 64)
				iLOD = 1;
			if (fMaxHeight < 48)
				iLOD = 2;
			if (fMaxHeight < 24)
				iLOD = 2;
		}

		oTexture.draw(
			oCtx, 
			iTextureIdx,
			iLOD,
			iX - 1,
			iY - 1,
			fWidth + 2, 		// increase this "expanding" based on angle/slope/scale/(whatever works) to fill gaps between segments
			fMaxHeight + 2
		);
	}


	if (bWallShading && this._bShaded && (iDir == 0 || iDir == 2)) {
		oCtx.beginPath();
		oCtx.moveTo(oClipBL.x + iOffsetX, oClipBL.y + iOffsetY);
		oCtx.lineTo(oClipTL.x + iOffsetX, oClipTL.y + iOffsetY);
		oCtx.lineTo(oClipTR.x + iOffsetX, oClipTR.y + iOffsetY);
		oCtx.lineTo(oClipBR.x + iOffsetX, oClipBR.y + iOffsetY);
		oCtx.closePath();
		oCtx.fillStyle = "rgba(0,0,0,0.3)";
		oCtx.fill();
	}

	oCtx.restore();

	/*
	var oSortPos = oCam.project(oCam.transformPoint(this.getSortPosition()));
	oCtx.beginPath();
	oCtx.moveTo(oSortPos.x + iOffsetX, oSortPos.y + iOffsetY);
	oCtx.arc(oSortPos.x + iOffsetX, oSortPos.y + iOffsetY, 2, 0, 360, false);
	oCtx.fillStyle = "yellow";
	oCtx.fill();
	*/

	/*
	var aPoints = [oPoint2DBottomLeft, oPoint2DTopLeft, oPoint2DBottomRight, oPoint2DTopRight];
	for (var i=0;i<4;i++) {
		var oPoint = aPoints[i];
		oCtx.beginPath();
		oCtx.moveTo(oPoint.x + iOffsetX, oPoint.y + iOffsetY);
		oCtx.arc(oPoint.x + iOffsetX, oPoint.y + iOffsetY, 2, 0, 360, false);
		oCtx.fillStyle = "red";
		oCtx.fill();
	}
	*/

	return true;

}

Canvas3D.Wall.prototype.setScene = function(oScene)
{
	if (this._oScene != oScene) {
		this._oScene = oScene;
	}
}

Canvas3D.Wall.prototype.setLighting = function(bEnable)
{
	this._bShading = bEnable;
}


Canvas3D.Wall.prototype.setPosition = function(oVec)
{
	if (oVec.x != this._oPosition.x || oVec.y != this._oPosition.y || oVec.z != this._oPosition.z) {
		this._oPosition = oVec;
		this._bDirty = true;
	}
	this._updatePoints();

}

Canvas3D.Wall.prototype.setDrawOffset = function(oVec)
{
	this._oDrawOffset = oVec;
	this._bDirty = true;
}
Canvas3D.Wall.prototype.getDrawOffset = function()
{
	return this._oDrawOffset;
}

Canvas3D.Wall.prototype._updatePoints = function() 
{
	var oPos = this._oPosition;
	var iDir = this._iDirection;

	this._oBottomLeft = new Canvas3D.Vec3(
		oPos.x, oPos.y, oPos.z
	);
	this._oBottomRight = new Canvas3D.Vec3(
		oPos.x + (iDir == 1 ? 64 : 0) + (iDir == 3 ? -64 : 0), 
		oPos.y, 
		oPos.z + (iDir == 0 ? 64 : 0) + (iDir == 2 ? -64 : 0)
	);
	this._oTopLeft = new Canvas3D.Vec3(
		oPos.x, 
		oPos.y + 64, 
		oPos.z
	);
	this._oTopRight = new Canvas3D.Vec3(
		oPos.x + (iDir == 1 ? 64 : 0) + (iDir == 3 ? -64 : 0), 
		oPos.y + 64, 
		oPos.z + (iDir == 0 ? 64 : 0) + (iDir == 2 ? -64 : 0)
	);

	this._oSortCenter = new Canvas3D.Vec3(
		(this._oBottomLeft.x + this._oBottomRight.x) / 2,
		0,
		(this._oBottomLeft.z + this._oBottomRight.z) / 2
	);

}


Canvas3D.Wall.prototype.getPosition = function()
{
	return this._oPosition;
}

Canvas3D.Wall.prototype.getSortPosition = function()
{
	return this._oSortCenter;
}

Canvas3D.Wall.prototype.setSortPosition = function(oVec)
{
	this._oSortCenter = oVec;
}


Canvas3D.Wall.prototype.getClipOffset = function()
{
	return this._oClipOffset;
}

Canvas3D.Wall.prototype.setClipOffset = function(oVec)
{
	this._oClipOffset = oVec;
}

Canvas3D.Wall.prototype.getDirty = function()
{
	return this._bDirty;
}


Canvas3D.Wall.prototype.hide = function()
{
	this._bVisible = false;
	this._bDirty = true;
}

Canvas3D.Wall.prototype.show = function()
{
	this._bVisible = true;
	this._bDirty = true;
}

Canvas3D.Wall.prototype.getForcedZ = function()
{
	return -1;
}

Canvas3D.Wall.prototype.isVisible = function()
{
	return this._bVisible;
}


