/////////////////////////////////////////////
// Class Draggable (implements Observable) //
/////////////////////////////////////////////

/************************************
 listenerObj must implement methods:	
 onDragStop(DraggableEventObj event)
 onDrag(DraggableEventObj event)
************************************/

DraggableMode= {HORIZONTAL : 1,VERTICAL : 2,HORIZONTAL_VERTICAL : 3};

function Draggable(dragObj,dragHandleObj,boundingObj,dragMode) {
	this.dragObj=dragObj;
	if (dragHandleObj==null) {
		this.dragHandle=this.dragObj;
	} else {
		this.dragHandle=dragHandleObj;
	}
	this.mode=dragMode;
	this.boundingObj = boundingObj;			
	this.boundingBox = this.getBoundingBox();
	
	this.mousePosXOnHandle=null;
	this.mousePosYOnHandle=null;
	
	this.mouseDownHandler=null;
	this.mouseUpHandler=null;
	this.mouseMoveHandler=null;
	this.touchOn=((navigator.userAgent).search(/(iPhone|iPod|iPad|Android)/)==-1)? false : true; 
};

Draggable.prototype = implementsInterface(Observable);

Draggable.prototype.set=function() {
	var obj=this;
	
	function dragStart(e) {
		obj.notifyListeners("onDragStart",obj.getDraggableEventObj());
		obj.boundingBox = obj.getBoundingBox();
		obj.mousePosXOnHandle=MousePositionOnPage.getX(e)-DHTMLApi.Position.getXPosOnPage(obj.dragObj);
		obj.mousePosYOnHandle=MousePositionOnPage.getY(e)-DHTMLApi.Position.getYPosOnPage(obj.dragObj);
		if (obj.touchOn===false) {
			obj.mouseMoveHandler=DOMEvent.addDomListener(document, "mousemove" , drag);
			obj.mouseUpHandler=DOMEvent.addDomListener(document, "mouseup" , dragEnd);
		} else {
			obj.mouseMoveHandler=DOMEvent.addDomListener(document, "touchmove" , drag);
			obj.mouseUpHandler=DOMEvent.addDomListener(document, "touchend" , dragEnd);
		}
		DOMEvent.preventDefault(e);
	}
	
	function dragEnd(e) {
		DOMEvent.removeListener(obj.mouseMoveHandler);
		DOMEvent.removeListener(obj.mouseUpHandler);
		obj.notifyListeners("onDragStop",obj.getDraggableEventObj());
	}
	
	function drag(e) {
		var dragObjPosX,dragObjPosY;
		DOMEvent.preventDefault(e);
		dragObjPosX=obj.calculatePosX(MousePositionOnPage.getX(e));
		dragObjPosY=obj.calculatePosY(MousePositionOnPage.getY(e));
		if (obj.mode!=DraggableMode.VERTICAL) {
			if (obj.boundingBox.tlX<=dragObjPosX && dragObjPosX<=obj.boundingBox.brX) {
				DHTMLApi.Position.setXPos(obj.dragObj, dragObjPosX-obj.boundingBox.tlX, obj.boundingObj);
			} else if (obj.boundingBox.tlX>dragObjPosX) {
				DHTMLApi.Position.setXPos(obj.dragObj, 0, obj.boundingObj);
			} else {
				DHTMLApi.Position.setXPos(obj.dragObj, obj.boundingBox.brX-obj.boundingBox.tlX, obj.boundingObj);
			}
		}		
		if (obj.mode!=DraggableMode.HORIZONTAL) {
			if (obj.boundingBox.tlY<=dragObjPosY && dragObjPosY<=obj.boundingBox.brY) {
				DHTMLApi.Position.setYPos(obj.dragObj, dragObjPosY-obj.boundingBox.tlY, obj.boundingObj);
			} else if (obj.boundingBox.tlY>dragObjPosY) {
				DHTMLApi.Position.setYPos(obj.dragObj, 0, obj.boundingObj);
			} else {
				DHTMLApi.Position.setYPos(obj.dragObj, obj.boundingBox.brY-obj.boundingBox.tlY, obj.boundingObj);
			}
		}
		obj.notifyListeners("onDrag",obj.getDraggableEventObj());
	}
	
	if (obj.touchOn===false) {
		this.mouseDownHandler=DOMEvent.addDomListener(this.dragHandle, "mousedown" , dragStart);
	} else {
		this.mouseDownHandler=DOMEvent.addDomListener(this.dragHandle, "touchstart" , dragStart);
	}
};

Draggable.prototype.unset=function() {
	DOMEvent.removeListener(this.mouseDownHandler);
	DOMEvent.removeListener(this.mouseMoveHandler);
	DOMEvent.removeListener(this.mouseUpHandler);	
};

Draggable.prototype.getXBounds=function() {
	return (this.boundingBox.brX-this.boundingBox.tlX);
}

Draggable.prototype.getYBounds=function() {
	return (this.boundingBox.brY-this.boundingBox.tlY);
}

Draggable.prototype.setDragObjXPos=function(xPos) {
	DHTMLApi.Position.setXPos(this.dragObj, xPos, this.boundingObj);
}

Draggable.prototype.setDragObjYPos=function(yPos) {
	DHTMLApi.Position.setYPos(this.dragObj, yPos, this.boundingObj);
}

Draggable.prototype.getDragObjXPos=function() {
	return  DHTMLApi.Position.getXPosOnPage(this.dragObj)-DHTMLApi.Position.getXPosOnPage(this.boundingObj);
}

Draggable.prototype.getDragObjYPos=function() {
	return  DHTMLApi.Position.getYPosOnPage(this.dragObj)-DHTMLApi.Position.getYPosOnPage(this.boundingObj);
}

Draggable.prototype.refreshAfterResize=function() {
	this.boundingBox = this.getBoundingBox();
}

// private

Draggable.prototype.calculatePosX=function (mousePosX) {
	return mousePosX-this.mousePosXOnHandle;
};

Draggable.prototype.calculatePosY=function (mousePosY) {
	return mousePosY-this.mousePosYOnHandle;
};

Draggable.prototype.getBoundingBox= function () {
	return {
		tlX: DHTMLApi.Position.getXPosOnPage(this.boundingObj), 
		tlY: DHTMLApi.Position.getYPosOnPage(this.boundingObj),
		brX: DHTMLApi.Position.getXPosOnPage(this.boundingObj)+DHTMLApi.Size.getElementWidth(this.boundingObj)-DHTMLApi.Size.getElementWidth(this.dragObj),
		brY: DHTMLApi.Position.getYPosOnPage(this.boundingObj)+DHTMLApi.Size.getElementHeight(this.boundingObj)-DHTMLApi.Size.getElementHeight(this.dragObj)};
}

Draggable.prototype.getDraggableEventObj=function() {
	return new DraggableEventObj(DHTMLApi.Position.getXPosInElement(this.dragObj,this.boundingObj), DHTMLApi.Position.getYPosInElement(this.dragObj,this.boundingObj), this.boundingBox.brX-this.boundingBox.tlX, this.boundingBox.brY-this.boundingBox.tlY);
}

/////////////////////////////
// Class DraggableEventObj //
/////////////////////////////

function DraggableEventObj (objPosX, objPosY, boundWidth, boundHeight) {
	this.posX=objPosX;
	this.posY=objPosY;
	this.boundWidth=boundWidth;
	this.boundHeight=boundHeight;
}

/*

projectsMatrixData=[[{image_file: string, project_name: string, image_position: int, position: {left: int, top: int, right: int, bottom: int}} or null]]
projectContainerSize={width: int, height: int}

*/

//////////////////////////
// class ProjectsMatrix //
//////////////////////////

function ProjectMatrix(projectsMatrixData,projectsTextData,projectContainerSize) {
	this.projectContainerSize=projectContainerSize;
	this.matrixData=projectsMatrixData;
	this.projectTextData=projectsTextData;
	this.preloader=new ImagePreloader();
	this.preloadedImages=[];
	this.preloadingOn=false;
	this.preloadInterval=null;
	this.matrixWidth=null;
	this.matrixHeight=null;
	this.numOfImages=null;
	this.matrixPosition=null;
	this.vectorPreloadCache=null;
	this.matrixLoopExtraWidth=Math.ceil(screen.width/this.projectContainerSize.width);
	this.matrixLoopExtraHeight=Math.ceil(screen.height/this.projectContainerSize.height);
	this.currentPositionX=0;
	this.currentPositionY=0;
	this.dragMode=false;
	this.controllerPanelNavMode=false;
	this.textData=[];
	this.preloader.addListener(this);
	this.parseProjectMatrixData();
}

ProjectMatrix.MATRIX_DRAG_MODE=1;
ProjectMatrix.SLIDER_DRAG_MODE=2;

ProjectMatrix.prototype=implementsInterface(Observable);

ProjectMatrix.prototype.parseProjectMatrixData=function () {
	var maxWidth;
	this.matrixHeight=this.matrixData.length;
	maxWidth=0;
	for (var i=0; i<this.matrixData.length; i++) {
		if (this.matrixData[i].length>maxWidth) maxWidth=this.matrixData[i].length; 
	}
	this.matrixWidth=maxWidth;
	this.numOfImages=0;
	for (var i=0; i<this.matrixHeight; i++) {
		for (var j=0; j<this.matrixWidth; j++) {
			if (typeof this.matrixData[i][j] == "undefined") {
				this.matrixData[i][j]=null;
			} else {
				if (this.matrixData[i][j]!==null && typeof this.matrixData[i][j].image_file != "undefined") {
					this.numOfImages++;
				}
				
				if (this.matrixData[i][j]!==null && typeof this.matrixData[i][j].text_id != "undefined") {
					if (typeof this.textData[this.matrixData[i][j].text_id] == "undefined") {
						this.textData[this.matrixData[i][j].text_id]={anchorPos: {i: i, j: j}, size: {width: 1, height: 1}};
					} else {
						var textId=this.matrixData[i][j].text_id;
						var calcWidth=Math.abs(j-this.textData[textId].anchorPos.j)+1;
						var calcHeight=Math.abs(i-this.textData[textId].anchorPos.i)+1;
						if (calcWidth>this.textData[textId].size.width) this.textData[textId].size.width=calcWidth;
						if (calcHeight>this.textData[textId].size.height) this.textData[textId].size.height=calcHeight;
					}
				}
			}
		}
	}
}

ProjectMatrix.prototype.startPreload=function () {
	var obj=this;
	this.startRadialPreload();
	this.preloadInterval=window.setInterval(function () {
		if (obj.preloadingOn===false) {
			if (obj.dragMode!==false) {
				obj.startVectorPreload();
			} else {
				obj.startRadialPreload();
			}
		}
	},50);
}

ProjectMatrix.prototype.getImageFile=function (dataMatrixPosition) {
	if (typeof this.matrixData[dataMatrixPosition.i]=="undefined" || typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j]=="undefined" || this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j]===null) return false;
	return (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].image_file != "undefined") ? this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].image_file : false;
}

ProjectMatrix.prototype.getProjectName=function (dataMatrixPosition) {
	if (this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j]===null) return false;
	return (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].project_name != "undefined") ? this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].project_name : false;
}

ProjectMatrix.prototype.getDisplayPosition=function (dataMatrixPosition) {
	var position={};
	if (this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j]===null) return {top: 0, left: 0, right: 0, bottom: 0};
	if (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position== "undefined") return {top: 0, left: 0, right: 0, bottom: 0};
	if (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.left != "undefined") {
		position.left=this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.left;
	}
	if (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.top != "undefined") {
		position.top=this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.top;
	}
	if (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.right != "undefined") {
		position.right=this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.right;
	}
	if (typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.bottom != "undefined") {
		position.bottom=this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].position.bottom;
	}
	return position;
}

ProjectMatrix.prototype.getImageFileDataMatrixPosition=function (imageFile) {
	for (var i=0; i<this.matrixHeight; i++) {
		for (var j=0; j<this.matrixWidth; j++) {
			if (this.matrixData[i][j] !== null && this.matrixData[i][j].image_file == imageFile) {
				return {i: i, j: j};
			}
		}
	}
	return false;
}

ProjectMatrix.prototype.isImageFilePreloaded=function (imageFile) {
	for (var i=0; i<this.preloadedImages.length; i++) {
		if (imageFile==this.preloadedImages[i]) return true;
	}
	return false;
}


ProjectMatrix.prototype.startRadialPreload=function (dataMatrixPosition) {
	if (typeof dataMatrixPosition =="undefined") dataMatrixPosition=this.matrixPosition;
	this.preloadingOn=true;
	this.preloader.start(this.getRadialPreloadCue(dataMatrixPosition));
}

ProjectMatrix.prototype.startVectorPreload=function () {
	var preloadCue;
	if (this.vectorPreloadCache!==null) {
		preloadCue=[];
		preloadCue.push(this.vectorPreloadCache);
		this.preloadingOn=true;
		this.preloader.start(preloadCue);
	}
}

ProjectMatrix.prototype.setVectorPreloadCache=function (dataMatrixPosition) {
	var preloadFile;
	preloadFile=this.getImageFile(dataMatrixPosition); 
	if (preloadFile===false) {
		this.vectorPreloadCache=null;
		return;
	}
	if (this.isImageFilePreloaded(preloadFile)) {
		this.vectorPreloadCache=null;
		return;
	}
	this.vectorPreloadCache=preloadFile;
}

ProjectMatrix.prototype.onImageLoadStart=function (imageFile) {
	if (this.isImageFilePreloaded(imageFile)===false) {
		this.notifyListeners("onMatrixPositionLoadStart",this.getImageFileDataMatrixPosition(imageFile));
	}
}

ProjectMatrix.prototype.onImageLoad=function (imageFile) {
	if (this.isImageFilePreloaded(imageFile)===false) { 
		this.preloadedImages.push(imageFile);
		this.notifyListeners("onMatrixPositionLoad",this.getImageFileDataMatrixPosition(imageFile));
	}
	if (this.preloadedImages.length==this.numOfImages) {
		this.preloader.removeListener(this);	
		window.clearInterval(this.preloadInterval);	
		this.preloadingOn=false;
		
	}
}

ProjectMatrix.prototype.onAllImagesLoad=function () {
	this.preloadingOn=false;
}

ProjectMatrix.prototype.calculateMatrixXPosition=function (dataMatrixJ) {
	var centerPosition=((DHTMLApi.Browser.getViewportWidth()-this.projectContainerSize.width)/2.0>0) ? Math.round((DHTMLApi.Browser.getViewportWidth()-this.projectContainerSize.width)/2.0) : 0; 
	return -1*((this.matrixLoopExtraWidth+dataMatrixJ)*this.projectContainerSize.width-centerPosition);
}

ProjectMatrix.prototype.calculateMatrixYPosition=function (dataMatrixI) {
	var centerPosition=((DHTMLApi.Browser.getViewportHeight()-this.projectContainerSize.height)/2.0>0) ? Math.round((DHTMLApi.Browser.getViewportHeight()-this.projectContainerSize.height)/2.0) : 0; 
	return -1*((this.matrixLoopExtraHeight+dataMatrixI)*this.projectContainerSize.height-centerPosition);
}

ProjectMatrix.prototype.getMapToLoopMatrixCoordinates=function (dataMatrixPosition) {
	var resultArray=[];
	var duplicatedLoopMatrixIPositions=[(dataMatrixPosition.i+this.matrixLoopExtraHeight)];
	var duplicatedLoopMatrixJPositions=[(dataMatrixPosition.j+this.matrixLoopExtraWidth)];
	if ((this.matrixHeight-this.matrixLoopExtraHeight)<=dataMatrixPosition.i && dataMatrixPosition.i<=(this.matrixHeight-1)) {
		duplicatedLoopMatrixIPositions.push((dataMatrixPosition.i-this.matrixHeight+this.matrixLoopExtraHeight));
	}
	if (0<=dataMatrixPosition.i && dataMatrixPosition.i<=(this.matrixLoopExtraHeight-1)) {
		duplicatedLoopMatrixIPositions.push((this.matrixHeight+this.matrixLoopExtraHeight+dataMatrixPosition.i));
	}
	
	if ((this.matrixWidth-this.matrixLoopExtraWidth)<=dataMatrixPosition.j && dataMatrixPosition.j<=(this.matrixWidth-1)) {
		duplicatedLoopMatrixJPositions.push((dataMatrixPosition.j-this.matrixWidth+this.matrixLoopExtraWidth));
	}
	if (0<=dataMatrixPosition.j && dataMatrixPosition.j<=(this.matrixLoopExtraWidth-1)) {
		duplicatedLoopMatrixJPositions.push(this.matrixWidth+this.matrixLoopExtraWidth+dataMatrixPosition.j);
	}
	for (var i=0; i<duplicatedLoopMatrixIPositions.length; i++) {
		for (var j=0; j<duplicatedLoopMatrixJPositions.length; j++) {
			resultArray.push({i: duplicatedLoopMatrixIPositions[i], j: duplicatedLoopMatrixJPositions[j]});
		}
	}
	return resultArray;
}

ProjectMatrix.prototype.getMapToDataMatrixCoordinates=function (loopMatrixPosition) {
	var iPos, jPos;
	if (0<=loopMatrixPosition.i && loopMatrixPosition.i<this.matrixLoopExtraHeight) iPos=this.matrixHeight-this.matrixLoopExtraHeight+loopMatrixPosition.i;
	if (this.matrixLoopExtraHeight<=loopMatrixPosition.i && loopMatrixPosition.i<(this.matrixHeight+this.matrixLoopExtraHeight)) iPos=loopMatrixPosition.i-this.matrixLoopExtraHeight;
	if ((this.matrixHeight+this.matrixLoopExtraHeight)<=loopMatrixPosition.i && loopMatrixPosition.i<(this.matrixHeight+this.matrixLoopExtraHeight*2)) iPos=loopMatrixPosition.i-this.matrixHeight-this.matrixLoopExtraHeight;
	if (0<=loopMatrixPosition.j && loopMatrixPosition.j<this.matrixLoopExtraWidth) jPos=this.matrixWidth-this.matrixLoopExtraWidth+loopMatrixPosition.j;
	if (this.matrixLoopExtraWidth<=loopMatrixPosition.j && loopMatrixPosition.j<(this.matrixWidth+this.matrixLoopExtraWidth)) jPos=loopMatrixPosition.j-this.matrixLoopExtraWidth;
	if ((this.matrixWidth+this.matrixLoopExtraWidth)<=loopMatrixPosition.j && loopMatrixPosition.j<(this.matrixWidth+this.matrixLoopExtraWidth*2)) jPos=loopMatrixPosition.j-this.matrixWidth-this.matrixLoopExtraWidth;
	return {i: iPos ,j: jPos};
}

ProjectMatrix.prototype.getLoopMatrixNeighbourPosition=function (loopMatrixPosition,horizontalDistance,verticalDistance) {
	var horizontalPosition, verticalPosition;
	horizontalPosition=(loopMatrixPosition.j+horizontalDistance) % this.getLoopMatrixWidth();
	verticalPosition=(loopMatrixPosition.i+verticalDistance) % this.getLoopMatrixHeight();
	horizontalPosition=(horizontalPosition<0) ? (this.getLoopMatrixWidth()+horizontalPosition) : horizontalPosition;
	verticalPosition=(verticalPosition<0) ? (this.getLoopMatrixHeight()+verticalPosition) : verticalPosition;
	return {i: verticalPosition, j: horizontalPosition};
}

ProjectMatrix.prototype.getRadialPreloadCue=function (dataMatrixPosition) {
	var currentLoopMatrixPosition, radius, widthRadius, heightRadius;
	var positionCueArray=[];
	var fileNameCue=[];
	currentLoopMatrixPosition={};
	widthRadius=Math.ceil(this.matrixWidth/2)+2;
	heightRadius=Math.ceil(this.matrixHeight/2)+2;
	radius=Math.max(widthRadius,heightRadius);
	currentLoopMatrixPosition.i=dataMatrixPosition.i+this.matrixLoopExtraHeight;
	currentLoopMatrixPosition.j=dataMatrixPosition.j+this.matrixLoopExtraWidth;
	positionCueArray.push(currentLoopMatrixPosition);
	for (var r=1; r<=radius; r++) {
		if (r<=widthRadius) {
			for (var i=r-1; i>=-r; i--) {
				positionCueArray.push(this.getLoopMatrixNeighbourPosition(currentLoopMatrixPosition,r,i));
			}
		}
		if (r<=heightRadius) {
			for (var i=r-1; i>=-r; i--) {
				positionCueArray.push(this.getLoopMatrixNeighbourPosition(currentLoopMatrixPosition,i,-r));
			}
		}
		if (r<widthRadius || (r==widthRadius && this.matrixWidth % 2 == 1)) {
			for (var i=-r+1; i<=r; i++) {
				positionCueArray.push(this.getLoopMatrixNeighbourPosition(currentLoopMatrixPosition,-r,i));
			}
		}
		if (r<heightRadius || (r==heightRadius && this.matrixHeight % 2 == 1)) {
			for (var i=-r+1; i<=r; i++) {
				positionCueArray.push(this.getLoopMatrixNeighbourPosition(currentLoopMatrixPosition,i,r));
			}
		}
	}
	for (j=0; j<positionCueArray.length; j++) {
		fileName=this.getImageFile(this.getMapToDataMatrixCoordinates(positionCueArray[j]));
		if (fileName!==false && this.isImageFilePreloaded(fileName)===false) {
			fileNameCue.push(fileName);
		}
	}
	return fileNameCue;
}

ProjectMatrix.prototype.mapLoopMatrixPositionXToWidth=function (positionX,width) {
	var absolutePositionX;
	absolutePositionX=-positionX-this.projectContainerSize.width*(this.matrixLoopExtraWidth-1)-((3*this.projectContainerSize.width-DHTMLApi.Browser.getViewportWidth())/2);
	return Math.round(width*absolutePositionX/(this.projectContainerSize.width*(this.matrixWidth)));
}

ProjectMatrix.prototype.mapLoopMatrixPositionYToHeight=function (positionY,height) {
	var absolutePositionY;
	absolutePositionY=-positionY-this.projectContainerSize.height*(this.matrixLoopExtraHeight-1)-((3*this.projectContainerSize.height-DHTMLApi.Browser.getViewportHeight())/2);
	return Math.round(height*absolutePositionY/(this.projectContainerSize.height*(this.matrixHeight)));
}

ProjectMatrix.prototype.mapWidthToLoopMatrixPositionX=function (widthPosition,width) {
	return Math.round(-this.projectContainerSize.width*(this.matrixLoopExtraWidth-1)-(3*this.projectContainerSize.width-DHTMLApi.Browser.getViewportWidth())/2-widthPosition*this.projectContainerSize.width*(this.matrixWidth-1)/width);
}

ProjectMatrix.prototype.mapHeightToLoopMatrixPositionY=function (heightPosition,height) {
	return Math.round(-this.projectContainerSize.height*(this.matrixLoopExtraHeight-1)-(3*this.projectContainerSize.height-DHTMLApi.Browser.getViewportHeight())/2-heightPosition*this.projectContainerSize.height*(this.matrixHeight-1)/height);
}

ProjectMatrix.prototype.getLoopMatrixWidth=function () {
	return this.matrixWidth+2*this.matrixLoopExtraWidth;
}

ProjectMatrix.prototype.getLoopMatrixHeight=function () {
	return this.matrixHeight+2*this.matrixLoopExtraHeight;
}

ProjectMatrix.prototype.getDataMatrixWidth=function () {
	return this.matrixWidth;
}

ProjectMatrix.prototype.getDataMatrixHeight=function () {
	return this.matrixHeight;
}

ProjectMatrix.prototype.getContainerSize=function () {
	return this.projectContainerSize;
}

ProjectMatrix.prototype.getProjectContainerWidth=function () {
	return this.projectContainerSize.width;
}

ProjectMatrix.prototype.getProjectContainerHeight=function () {
	return this.projectContainerSize.height;
}

ProjectMatrix.prototype.getTextDataId=function (dataMatrixPosition) {
	if (this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j]===null || typeof this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].text_id == "undefined") return false;
	return this.matrixData[dataMatrixPosition.i][dataMatrixPosition.j].text_id;
}

ProjectMatrix.prototype.getTextData=function (textId) {
	return this.projectTextData[textId];
}

ProjectMatrix.prototype.getTextAnchorPosition=function (textId) {
	return this.textData[textId].anchorPos;
}

ProjectMatrix.prototype.getTextSpaceWidth=function (textId) {
	return this.textData[textId].size.width;
}

ProjectMatrix.prototype.getTextSpaceHeight=function (textId) {
	return this.textData[textId].size.height;
}

ProjectMatrix.prototype.getDragMode=function () {
	return this.dragMode;
}

ProjectMatrix.prototype.setDragMode=function (dragMode) {
	if (this.preloadingOn) {
		this.preloader.stop();
	}
	this.dragMode=dragMode;
}

ProjectMatrix.prototype.unsetDragMode=function () {
	if (this.preloadingOn) {
		this.preloader.stop();
	}
	this.dragMode=false;
}

ProjectMatrix.prototype.setControllerPanelNavMode=function () {
	if (!this.isControllerPanelNavMode()) {
		this.controllerPanelNavMode=true;
		this.notifyListeners("onControllerPanelModeOn",null);
	}
}

ProjectMatrix.prototype.unsetControllerPanelNavMode=function () {
	if (this.isControllerPanelNavMode()) {
		this.controllerPanelNavMode=false;
		this.notifyListeners("onControllerPanelModeOff",null);
	}
}

ProjectMatrix.prototype.isControllerPanelNavMode=function () {
	return this.controllerPanelNavMode;
}

ProjectMatrix.prototype.setCurrentPosition=function(dataMatrixPosition) {	
	if (this.matrixPosition===null || (dataMatrixPosition.i!=this.matrixPosition.i || dataMatrixPosition.j!=this.matrixPosition.j)) {
		this.notifyListeners("onMatrixPositionChange",{i: dataMatrixPosition.i, j: dataMatrixPosition.j});
	}
	this.matrixPosition=dataMatrixPosition;
	this.setPosition(this.calculateMatrixXPosition(dataMatrixPosition.j),this.calculateMatrixYPosition(dataMatrixPosition.i),false);
}

ProjectMatrix.prototype.moveBy=function (distanceX,distanceY) {
	this.setPosition(this.currentPositionX-distanceX,this.currentPositionY-distanceY,true);
}

ProjectMatrix.prototype.setPosition=function (positionX,positionY,calculateMatrixPosition) {
	var newMatrixPosition;
	if (positionX>-1*this.projectContainerSize.width*(this.matrixLoopExtraWidth-1)-(3*this.projectContainerSize.width-DHTMLApi.Browser.getViewportWidth())/2+2) {
		this.currentPositionX=-1*(this.projectContainerSize.width*(this.matrixWidth))+positionX;
	} else if (positionX<-1*this.projectContainerSize.width*(this.matrixLoopExtraWidth+this.matrixWidth)+(DHTMLApi.Browser.getViewportWidth()-this.projectContainerSize.width)/2) {
		this.currentPositionX=positionX+this.projectContainerSize.width*(this.matrixWidth);
	}
	else {
		this.currentPositionX=positionX;
	}
	if (positionY>-1*this.projectContainerSize.height*(this.matrixLoopExtraHeight-1)+-(3*this.projectContainerSize.height-DHTMLApi.Browser.getViewportHeight())/2+2) {
		this.currentPositionY=-1*(this.projectContainerSize.height*(this.matrixHeight))+positionY;
	} else if (positionY<-1*this.projectContainerSize.height*(this.matrixLoopExtraHeight+this.matrixHeight)+(DHTMLApi.Browser.getViewportHeight()-this.projectContainerSize.height)/2) {
		this.currentPositionY=positionY+this.projectContainerSize.height*(this.matrixHeight);
	}
	else {
		this.currentPositionY=positionY;
	}
	if (calculateMatrixPosition) {
		newMatrixPosition={};
		newMatrixPosition.j=((Math.floor((-1*this.currentPositionX+DHTMLApi.Browser.getViewportWidth()/2)/this.projectContainerSize.width)-this.matrixLoopExtraWidth)) % this.matrixWidth;
		newMatrixPosition.i=(Math.floor((-1*this.currentPositionY+DHTMLApi.Browser.getViewportHeight()/2)/this.projectContainerSize.height)-this.matrixLoopExtraHeight) % this.matrixHeight;
		if (newMatrixPosition.i!=this.matrixPosition.i || newMatrixPosition.j!=this.matrixPosition.j) {
			this.notifyListeners("onMatrixPositionChange",{i: newMatrixPosition.i, j: newMatrixPosition.j});
			this.matrixPosition.i=newMatrixPosition.i;
			this.matrixPosition.j=newMatrixPosition.j;
			if (this.dragMode!==false) {
				this.setVectorPreloadCache(this.matrixPosition);
			}
		}
	}	
	this.notifyListeners("onPositionChange",{x:this.currentPositionX, y:this.currentPositionY});
}


////////////////////////////
// class LoopMatrixViewer //
////////////////////////////

function LoopMatrixViewer(projectMatrix) {
	this.containerElement=null;
	this.matrixContainerElement=null;
	this.pictureContainers=[];
	this.projectMatrix=projectMatrix;
	this.textViewer=null; 
	this.build();
	this.addBlanks();
}

LoopMatrixViewer.prototype.build=function () {
	var container, matrixDataMap, newArray;
	var obj=this;
	this.containerElement=document.createElement("DIV");
	this.matrixContainerElement=document.createElement("DIV");
	this.containerElement.appendChild(this.matrixContainerElement);
	document.body.appendChild(this.containerElement);
	DHTMLApi.CSS.setProperties(this.containerElement,{position: "absolute", zIndex: 1, width: DHTMLApi.Browser.getViewportWidth() +"px", height: DHTMLApi.Browser.getViewportHeight()+"px", overflow: "hidden"});
	DHTMLApi.CSS.setProperties(this.matrixContainerElement,{position: "absolute", width: this.projectMatrix.getLoopMatrixWidth()*this.projectMatrix.getProjectContainerWidth()+"px", height: this.projectMatrix.getLoopMatrixHeight()*this.projectMatrix.getProjectContainerHeight()+"px", cursor: "move"});
	for (var i=0; i<this.projectMatrix.getLoopMatrixHeight(); i++) {
		newArray=[];
		this.pictureContainers.push(newArray);
		for (var j=0; j<this.projectMatrix.getLoopMatrixWidth(); j++) {
			this.pictureContainers[i][j]=document.createElement("DIV");
			this.matrixContainerElement.appendChild(this.pictureContainers[i][j]);
			DHTMLApi.CSS.setProperties(this.pictureContainers[i][j],{position: "absolute", width: this.projectMatrix.getProjectContainerWidth()+"px", height: this.projectMatrix.getProjectContainerHeight()+"px", top: (this.projectMatrix.getProjectContainerHeight()*i)+"px", left: (this.projectMatrix.getProjectContainerWidth()*j)+"px", overflow: "hidden"})
			matrixDataMap=this.projectMatrix.getMapToDataMatrixCoordinates({i: i, j: j});
		}
	}
	this.textViewer=new LoopTextViewer(this.matrixContainerElement,this.projectMatrix); 
	this.textViewer.build();	
	DOMEvent.addDomListener(window,"resize",function () {
		DHTMLApi.CSS.setProperties(obj.containerElement,{width: DHTMLApi.Browser.getViewportWidth() +"px", height: DHTMLApi.Browser.getViewportHeight()+"px"});
	});
}

LoopMatrixViewer.prototype.addBlanks=function () {
	var blankPositions;
	for (var i=0; i<this.projectMatrix.getDataMatrixHeight(); i++) {
		for (var j=0; j<this.projectMatrix.getDataMatrixWidth(); j++) {
			if (this.projectMatrix.getImageFile({i:i,j:j})===false) {
				blankPositions=this.projectMatrix.getMapToLoopMatrixCoordinates({i:i,j:j});
				for (var k=0; k<blankPositions.length; k++) {
					DHTMLApi.CSS.setProperties(this.pictureContainers[blankPositions[k].i][blankPositions[k].j],{backgroundColor: "white"});
				}
			}
		}
	}
}

LoopMatrixViewer.prototype.displayPreloader=function (dataMatrixPosition) {
	var loopMatrixPositions;
	loopMatrixPositions=this.projectMatrix.getMapToLoopMatrixCoordinates(dataMatrixPosition);
	for (var k=0; k<loopMatrixPositions.length; k++) {			
		DHTMLApi.CSS.setClass(this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j],["preload"],[]);
	}
}

LoopMatrixViewer.prototype.hidePreloader=function (dataMatrixPosition) {
	var loopMatrixPositions;
	loopMatrixPositions=this.projectMatrix.getMapToLoopMatrixCoordinates(dataMatrixPosition);
	for (var k=0; k<loopMatrixPositions.length; k++) {
		if (typeof this.pictureContainers[loopMatrixPositions[k].i]!="undefined" && typeof this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j]!="undefined") {
			DHTMLApi.CSS.setClass(this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j],[],["preload"]);
		}
	}
}

LoopMatrixViewer.prototype.addPicture=function (dataMatrixPosition) {
	var pictureElement, loopMatrixPositions, imageFile, positionCSSDictionary;
	imageFile=this.projectMatrix.getImageFile(dataMatrixPosition);
	loopMatrixPositions=this.projectMatrix.getMapToLoopMatrixCoordinates(dataMatrixPosition);
	for (var k=0; k<loopMatrixPositions.length; k++) {			
		if (typeof this.pictureContainers[loopMatrixPositions[k].i]!="undefined" && typeof this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j]!="undefined") {
			pictureElement=document.createElement("IMG");
			pictureElement.setAttribute("src",imageFile);
			this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j].appendChild(pictureElement);
			DHTMLApi.CSS.setProperties(this.pictureContainers[loopMatrixPositions[k].i][loopMatrixPositions[k].j],{backgroundColor: "white"});
			positionCSSDictionary=this.convertDisplayPositionsToCSSValues(this.projectMatrix.getDisplayPosition(dataMatrixPosition));
			positionCSSDictionary.position="absolute";
			DHTMLApi.CSS.setProperties(pictureElement,positionCSSDictionary);
		}
	}
}

LoopMatrixViewer.prototype.convertDisplayPositionsToCSSValues=function (displayPosition) {
	var cssDictionary={};
	for (var key in displayPosition) {
		cssDictionary[key]=displayPosition[key]+"px";
	}
	return cssDictionary
}

LoopMatrixViewer.prototype.getMatrixContainer=function () {
	return this.matrixContainerElement;
}

LoopMatrixViewer.prototype.onPositionChange=function (changePositionEvent) {
	DHTMLApi.CSS.setProperties(this.matrixContainerElement,{left: changePositionEvent.x+"px", top: changePositionEvent.y+"px"});
}

LoopMatrixViewer.prototype.onMatrixPositionLoadStart=function (dataMatrixPosition) {
	this.displayPreloader(dataMatrixPosition);
}

LoopMatrixViewer.prototype.onMatrixPositionLoad=function (dataMatrixPosition) {
	this.hidePreloader(dataMatrixPosition);
	this.addPicture(dataMatrixPosition);
}



//////////////////////////
// class LoopTextViewer //
//////////////////////////

function LoopTextViewer(parentContainer,projectMatrix) {
	this.displayOn=false;
	this.processedElements=[];
	this.parentContainer=parentContainer;
	this.containerElement=null;
	this.projectMatrix=projectMatrix;
	this.init();
}

LoopTextViewer.prototype.init=function () {
	for (var i=0; i<this.projectMatrix.getLoopMatrixHeight(); i++) {
		this.processedElements[i]=[];
		for (var j=0; j<this.projectMatrix.getLoopMatrixWidth(); j++) {
			this.processedElements[i][j]=false;
		}
	}
}

LoopTextViewer.prototype.toggleView=function () {
	if (this.displayOn) {
		this.hide();
		this.displayOn=false;
	} else {
		this.show();
		this.displayOn=true;
	}
}

LoopTextViewer.prototype.hide=function () {
	DHTMLApi.Visibility.hide(this.containerElement);
}

LoopTextViewer.prototype.show=function () {
	DHTMLApi.Visibility.show(this.containerElement);
}

LoopTextViewer.prototype.isProcessed=function (loopMatrixPosition) {
	return this.processedElements[loopMatrixPosition.i][loopMatrixPosition.j];
}

LoopTextViewer.prototype.markProcessed=function (anchorLoopMatrixPosition,width,height) {
	var processedI,processedJ;
	for (var i=0; i<height; i++) {
		for (var j=0; j<width; j++) {
			processedI=parseInt(anchorLoopMatrixPosition.i+i);
			processedJ=parseInt(anchorLoopMatrixPosition.j+j);
			if (processedI>=this.projectMatrix.getLoopMatrixHeight() || processedJ>=this.projectMatrix.getLoopMatrixWidth()) continue;
			this.processedElements[processedI][processedJ]=true;
		}
	}
}

LoopTextViewer.prototype.build=function () {
	var container, matrixDataMap, newArray;
	var obj=this;
	this.containerElement=document.createElement("DIV");
	this.parentContainer.appendChild(this.containerElement);
	DHTMLApi.CSS.setProperties(this.containerElement,{position: "absolute", zIndex: 2, width: this.projectMatrix.getLoopMatrixWidth()*this.projectMatrix.getProjectContainerWidth()+"px", height: this.projectMatrix.getLoopMatrixHeight()*this.projectMatrix.getProjectContainerHeight()+"px", overflow: "hidden", display: "none"});
	for (var i=0; i<this.projectMatrix.getLoopMatrixHeight(); i++) {
		for (var j=0; j<this.projectMatrix.getLoopMatrixWidth(); j++) {
			if (this.isProcessed({i: i, j: j})===false) {
				var matrixDataPosition=this.projectMatrix.getMapToDataMatrixCoordinates({i: i, j: j});
				var textId=this.projectMatrix.getTextDataId(matrixDataPosition);
				if (textId!==false) {
					this.addText({i: i, j: j},textId);
				}
			}
		}
	}
}

LoopTextViewer.prototype.addText=function (loopMatrixDataPosition,textId) {
	var textData=this.projectMatrix.getTextData(textId);
	var textAnchorPosition=this.projectMatrix.getTextAnchorPosition(textId);
	var matrixDataPosition=this.projectMatrix.getMapToDataMatrixCoordinates(loopMatrixDataPosition);
	var anchorDisplacementX=matrixDataPosition.j-textAnchorPosition.j;
	var anchorDisplacementY=matrixDataPosition.i-textAnchorPosition.i;
	var textContainer=document.createElement("DIV");
	this.containerElement.appendChild(textContainer);
	textContainer.innerHTML=textData.text;
	DHTMLApi.CSS.setClass(textContainer,["info_text_box"],[]);
	DHTMLApi.CSS.setProperties(textContainer,{position: "absolute", width: textData.parameters.width+"px", left: (loopMatrixDataPosition.j+anchorDisplacementX)*this.projectMatrix.getProjectContainerWidth()+textData.parameters.left+"px", top: (loopMatrixDataPosition.i+anchorDisplacementY)*this.projectMatrix.getProjectContainerHeight()+textData.parameters.top+"px", fontSize: textData.parameters.fontSize+"px", lineHeight: textData.parameters.lineHeight+"px"});
	if (typeof textData.parameters.textAlign!="undefined") {
		DHTMLApi.CSS.setProperties(textContainer,{textAlign: textData.parameters.textAlign});
	}
	this.markProcessed(loopMatrixDataPosition,(this.projectMatrix.getTextSpaceWidth(textId)-anchorDisplacementX),(this.projectMatrix.getTextSpaceHeight(textId)-anchorDisplacementY));
}

LoopTextViewer.prototype.convertDisplayPositionsToCSSValues=function (displayPosition) {
	var cssDictionary={};
	for (var key in displayPosition) {
		cssDictionary[key]=displayPosition[key]+"px";
	}
	return cssDictionary
}

LoopTextViewer.prototype.getMatrixContainer=function () {
	return this.matrixContainerElement;
}


////////////////////////////////
// class LoopMatrixController //
////////////////////////////////

function LoopMatrixController(projectMatrix,projectMatrixViewer) {
	this.projectMatrix=projectMatrix;
	this.projectMatrixViewer=projectMatrixViewer;
	this.mousePositionX=null;
	this.mousePositionY=null;
	this.mouseMoveHandler=null;
	this.mouseUpHandler=null;
	this.init();
}

LoopMatrixController.prototype.init=function () {
	var obj=this;
	var touchOn=((navigator.userAgent).search(/(iPhone|iPod|iPad|Android)/)==-1)? false : true; 
	if (touchOn) {
		DOMEvent.addDomListener(this.projectMatrixViewer.getMatrixContainer(), "touchstart" , function (e) {
			DOMEvent.preventDefault(e);
			obj.mousePositionX=MousePositionOnPage.getX(e);
			obj.mousePositionY=MousePositionOnPage.getY(e);
			obj.projectMatrix.setDragMode(ProjectMatrix.MATRIX_DRAG_MODE);
			obj.mouseMoveHandler=DOMEvent.addDomListener(document, "touchmove" , function (e) {
				DOMEvent.preventDefault(e);
				obj.projectMatrix.moveBy(-2*(MousePositionOnPage.getX(e)-obj.mousePositionX),-2*(MousePositionOnPage.getY(e)-obj.mousePositionY));
				obj.mousePositionX=MousePositionOnPage.getX(e);
				obj.mousePositionY=MousePositionOnPage.getY(e);
			});
			obj.mouseUpHandler=DOMEvent.addDomListener(document, "touchend" , function (e) {
				obj.projectMatrix.unsetDragMode();
				DOMEvent.removeListener(obj.mouseMoveHandler);
				DOMEvent.removeListener(obj.mouseUpHandler);
			});
		});
		
	} else {
		DOMEvent.addDomListener(this.projectMatrixViewer.getMatrixContainer(), "mousedown" , function (e) {
			if (obj.mouseMoveHandler!==null) DOMEvent.removeListener(obj.mouseMoveHandler);
			DOMEvent.preventDefault(e);
			obj.mousePositionX=MousePositionOnPage.getX(e);
			obj.mousePositionY=MousePositionOnPage.getY(e);
			obj.projectMatrix.setDragMode(ProjectMatrix.MATRIX_DRAG_MODE);
			obj.mouseMoveHandler=DOMEvent.addDomListener(document, "mousemove" , function (e) {
				DOMEvent.preventDefault(e);
				obj.projectMatrix.moveBy(-2*(MousePositionOnPage.getX(e)-obj.mousePositionX),-2*(MousePositionOnPage.getY(e)-obj.mousePositionY));
				obj.mousePositionX=MousePositionOnPage.getX(e);
				obj.mousePositionY=MousePositionOnPage.getY(e);
			});
			obj.mouseUpHandler=DOMEvent.addDomListener(document, "mouseup" , function (e) {
				obj.projectMatrix.unsetDragMode();
				DOMEvent.removeListener(obj.mouseMoveHandler);
				DOMEvent.removeListener(obj.mouseUpHandler);
			});
		});
	}
}

///////////////////////////////
// class MatrixMonitorViewer //
///////////////////////////////

function MatrixMonitorViewer(projectMatrix,maximumWidth,maximumHeight) {
	this.containerElement=null;
	this.positionSliderElement=null;
	this.projectInfoBox=null;
	this.sliderWidth=0;
	this.sliderHeight=0;
	this.containerWidth=0;
	this.containerHeight=0;
	this.projectMatrix=projectMatrix;
	this.build(maximumWidth,maximumHeight);
}

MatrixMonitorViewer.prototype.build=function (maximumWidth,maximumHeight) {
	var matrixWidth,matrixHeight,containerSize;
	var obj=this;
	matrixWidth=this.projectMatrix.getDataMatrixWidth();
	matrixHeight=this.projectMatrix.getDataMatrixHeight();
	this.sliderWidth=Math.floor(maximumWidth/matrixWidth);
	this.sliderHeight=Math.floor(maximumHeight/matrixHeight);
	this.containerWidth=this.sliderWidth*matrixWidth;
	this.containerHeight=this.sliderHeight*matrixHeight;
	this.containerElement=document.createElement("DIV");
	this.positionSliderElement=document.createElement("DIV");
	//this.projectInfoBox=document.createElement("DIV");
	this.containerElement.appendChild(this.positionSliderElement);	
	document.body.appendChild(this.containerElement);
	//document.body.appendChild(this.projectInfoBox);
	DHTMLApi.CSS.setProperties(this.containerElement,{position: "absolute", zIndex: 3, width: this.containerWidth +"px", height: this.containerHeight+"px", overflow: "hidden", backgroundColor: "white", top: "70px", right: "70px"});
	DHTMLApi.CSS.setProperties(this.positionSliderElement,{position: "absolute", width: this.sliderWidth+10+"px", height: this.sliderHeight+10+"px", backgroundColor: "black", cursor: "pointer", lineHeight: "1px"});
	//containerSize=this.projectMatrix.getContainerSize();
	//DHTMLApi.CSS.setProperties(this.projectInfoBox,{position: "absolute", zIndex: 2, width: (containerSize.width+100)+"px", display: "none", top: "250px", left: Math.round((DHTMLApi.Browser.getViewportWidth()-(containerSize.width+100))/2)+"px"});
	//DHTMLApi.CSS.setClass(this.projectInfoBox,["project_name_text_box"],[]);
	//DOMEvent.addDomListener(window,"resize",function () {DHTMLApi.CSS.setProperties(obj.projectInfoBox,{left: Math.round((DHTMLApi.Browser.getViewportWidth()-(containerSize.width+100))/2)+"px"});});
}

MatrixMonitorViewer.prototype.onPositionChange=function (event) {
	if (this.projectMatrix.getDragMode()!=ProjectMatrix.SLIDER_DRAG_MODE) {
		var posX=this.projectMatrix.mapLoopMatrixPositionXToWidth(event.x,this.containerWidth);
		var posY=this.projectMatrix.mapLoopMatrixPositionYToHeight(event.y,this.containerHeight);
		
		if (posX>(this.containerWidth-this.sliderWidth/2)) {
			posX=0;
		} 
		if (posX>(this.containerWidth-this.sliderWidth)) {
			posX=this.containerWidth-this.sliderWidth;
		}
		if (posY>(this.containerHeight-this.sliderHeight/2)) {
			posY=0;
		}
		if (posY>(this.containerHeight-this.sliderHeight)) {
			posY=this.containerHeight-this.sliderHeight;
		}
		 
		DHTMLApi.CSS.setProperties(this.positionSliderElement,{top: posY+"px", left: posX+"px"});
	}
}

MatrixMonitorViewer.prototype.getPositionSlider=function () {
	return this.positionSliderElement;
}

MatrixMonitorViewer.prototype.getContainer=function () {
	return this.containerElement;
}

MatrixMonitorViewer.prototype.getInfoBox=function () {
	return this.projectInfoBox;
}

/*
MatrixMonitorViewer.prototype.onMatrixPositionChange=function (dataMatrixPosition) {
	var displayText;
	displayText=(this.projectMatrix.getProjectName(dataMatrixPosition)===false) ? "" : this.projectMatrix.getProjectName(dataMatrixPosition);
	this.projectInfoBox.innerHTML=displayText;
}

*/


/////////////////////////////
// class ProjectNameViewer //
/////////////////////////////

function ProjectNameViewer(projectMatrix) {
	this.projectMatrix=projectMatrix;
	this.projectInfoBox=null;
	this.build();
}

ProjectNameViewer.prototype.build=function () {
	var obj=this;
	this.projectInfoBox=document.createElement("DIV");
	document.body.appendChild(this.projectInfoBox);
	var containerSize=this.projectMatrix.getContainerSize();
	DHTMLApi.CSS.setProperties(this.projectInfoBox,{position: "absolute", zIndex: 2, width: (containerSize.width)+"px", display: "none", top: "250px", left: Math.round((DHTMLApi.Browser.getViewportWidth()-(containerSize.width))/2)+"px"});
	DHTMLApi.CSS.setClass(this.projectInfoBox,["project_name_text_box"],[]);
	DOMEvent.addDomListener(window,"resize",function () {DHTMLApi.CSS.setProperties(obj.projectInfoBox,{left: Math.round((DHTMLApi.Browser.getViewportWidth()-(containerSize.width+100))/2)+"px"});});
}

ProjectNameViewer.prototype.displayName=function (dataMatrixPosition) {
	var displayText;
	displayText=(this.projectMatrix.getProjectName(dataMatrixPosition)===false) ? "" : this.projectMatrix.getProjectName(dataMatrixPosition);
	this.projectInfoBox.innerHTML=displayText;
	var textPosition=Math.round((DHTMLApi.Browser.getViewportHeight()-DHTMLApi.Size.getElementHeight(this.projectInfoBox))/2);
	if (textPosition<0) textPosition=0;
	DHTMLApi.CSS.setProperties(this.projectInfoBox,{top: textPosition+"px"});
}

ProjectNameViewer.prototype.onMatrixPositionChange=function (dataMatrixPosition) {
	this.displayName(dataMatrixPosition);
}

ProjectNameViewer.prototype.onControllerPanelModeOn=function () {
	DHTMLApi.Visibility.show(this.projectInfoBox);
}

ProjectNameViewer.prototype.onControllerPanelModeOff=function () {
	DHTMLApi.Visibility.hide(this.projectInfoBox);
}


///////////////////////////////////
// class MatrixMonitorController //
///////////////////////////////////

function MatrixMonitorController(projectMatrix,monitorViewer) {
	var obj=this;
	this.projectMatrix=projectMatrix;
	this.monitorViewer=monitorViewer;
	this.dragController=new Draggable(this.monitorViewer.getPositionSlider(),this.monitorViewer.getPositionSlider(),this.monitorViewer.getContainer(),DraggableMode.HORIZONTAL_VERTICAL);
	this.dragController.set();
	this.dragControllerEvent={};
	this.dragControllerEvent.onDragStart=function (dragEventObject) {
		obj.projectMatrix.setDragMode(ProjectMatrix.SLIDER_DRAG_MODE);
	}
	this.dragControllerEvent.onDragStop=function (dragEventObject) {
		obj.projectMatrix.unsetDragMode();
	}
	this.dragControllerEvent.onDrag=function (dragEventObject) {
		var positionX=obj.projectMatrix.mapWidthToLoopMatrixPositionX(dragEventObject.posX,dragEventObject.boundWidth);
		var positionY=obj.projectMatrix.mapHeightToLoopMatrixPositionY(dragEventObject.posY,dragEventObject.boundHeight);
		obj.projectMatrix.setPosition(positionX,positionY,true);
	}
	this.dragController.addListener(this.dragControllerEvent);
	//var infoBox=this.monitorViewer.getInfoBox();
	DOMEvent.addDomListener(this.monitorViewer.getContainer(),"mouseover",function () {
		obj.projectMatrix.setControllerPanelNavMode();
		//DHTMLApi.Visibility.show(obj.monitorViewer.getInfoBox());
	});
	DOMEvent.addDomListener(this.monitorViewer.getContainer(),"mouseout",function () {
		obj.projectMatrix.unsetControllerPanelNavMode();
		//DHTMLApi.Visibility.hide(obj.monitorViewer.getInfoBox());
	});
}

////////////////////////////
// class TextToggleButton //
////////////////////////////

function TextToggleButton(buttonElement,matrixViewer) {
	var obj=this;
	this.textOn=false;
	this.buttonElement=buttonElement;
	this.matrixViewer=matrixViewer;
	this.automaticDisplay=window.setTimeout(function () {obj.toggle(); window.clearTimeout(obj.automaticDisplay);obj.automaticDisplay=null},60*1000);
	this.init();
}

TextToggleButton.prototype.init=function () {
	var obj=this;
	DOMEvent.addDomListener(this.buttonElement,"click",function () {
		if (obj.automaticDisplay!==null) window.clearTimeout(obj.automaticDisplay);
		obj.toggle();
	});
}

TextToggleButton.prototype.toggle=function () {
	this.matrixViewer.textViewer.toggleView();
	if (this.textOn) {
		this.textOn=false;
		DHTMLApi.CSS.setClass(this.buttonElement,["text_off"],["text_on"]);
	} else {
		this.textOn=true;
		DHTMLApi.CSS.setClass(this.buttonElement,["text_on"],["text_off"]);
	}
}

TextToggleButton.prototype.onControllerPanelModeOn=function () {
	if (this.textOn) {
		this.matrixViewer.textViewer.hide();
	}
}

TextToggleButton.prototype.onControllerPanelModeOff=function () {
	if (this.textOn) {
		this.matrixViewer.textViewer.show();
	}
}


/////////////////////////////
// Static Class PopUpLayer //
/////////////////////////////

PopUpLayer= {
	
	containerZIndex: 10000,
	
	init: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.popUpDivNode=popUpDivNode;
		this.parentpopUpDivNode=popUpDivNode.parentNode;
		this.nextSiblingpopUpDivNode=popUpDivNode.nextSibling;
		this.popupContainerNode=null;
		this.backgroundNode=null;
		this.backgroundCssClass=backgroundCssClass;
		this.backgroundAlpha=backgroundAlpha;
		this.closeButtonElement=null;
		this.onCloseCallback=null;
		if (typeof closeButtonElement != "undefined") {
			this.closeButtonElement=closeButtonElement;
		}
		if (typeof onCloseCallback != "undefined") {
			this.onCloseCallback=onCloseCallback;
		}
		this.resizeHandler=null;
		this.closeHandler=null;
		this.closeButtonHandler=null;
		this.tempPopUpDivNodeStyles={position: DHTMLApi.CSS.getStyle(this.popUpDivNode, "position"), top: DHTMLApi.CSS.getStyle(this.popUpDivNode, "top"), left: DHTMLApi.CSS.getStyle(this.popUpDivNode, "left"), zIndex: DHTMLApi.CSS.getStyle(this.popUpDivNode, "z-index"), display: DHTMLApi.CSS.getStyle(this.popUpDivNode, "display")};
	},
	
	initHandlers: function () {
		var obj=this;
		this.resizeHandler=DOMEvent.addDomListener(window, "resize", function () {
			obj.centerOnPage();
		});
		this.closeHandler=DOMEvent.addDomListener(this.backgroundNode, "click", function () {
			obj.hide();
			if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
		});
		if (this.closeButtonElement!==null) {
			this.closeButtonHandler=DOMEvent.addDomListener(this.closeButtonElement, "click", function () {
				obj.hide();
				if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
			});
		}
	},
	
	removeHandlers: function () {
		DOMEvent.removeListener(this.resizeHandler);
		DOMEvent.removeListener(this.closeHandler);
		if (this.closeButtonHandler!==null) {
			DOMEvent.removeListener(this.closeButtonHandler);
		}
		this.resizeHandler=null;
		this.closeHandler=null;
		this.closeButtonHandler=null;
	},
	
	build: function () {
		var popUpNode;
		this.popupContainerNode=document.createElement("DIV");
		document.body.appendChild(this.popupContainerNode);
		DHTMLApi.CSS.setProperties(document.body,{overflow: "hidden"});
		DHTMLApi.CSS.setProperties(this.popupContainerNode,{position: "absolute", top: "0px", left: "0px", width: this.getPageWidth()+"px", height: this.getPageHeight()+"px", zIndex: this.containerZIndex, overflow:"hidden"});
		this.backgroundNode=document.createElement("DIV");
		this.popupContainerNode.appendChild(this.backgroundNode);
		DHTMLApi.CSS.setProperties(this.backgroundNode,{position: "absolute", top: "0px", left: "0px", zIndex: 1, cursor: "pointer", width: "100%", height: "100%"});
		DHTMLApi.CSS.setClass(this.backgroundNode,new Array(this.backgroundCssClass),new Array());
		
		popUpNode=this.parentpopUpDivNode.removeChild(this.popUpDivNode);
		this.popupContainerNode.appendChild(popUpNode);
		DHTMLApi.CSS.setProperties(popUpNode, {position: "absolute", zIndex: 2, display: "block"});
		DHTMLApi.Visibility.setOpacity(this.backgroundNode,this.backgroundAlpha);
		this.initHandlers();
	},
	
	restorePopUpNode: function() {
		if (this.nextSiblingpopUpDivNode!==null) {
			this.parentpopUpDivNode.insertBefore(this.popUpDivNode,this.nextSiblingpopUpDivNode);
		} else {
			this.parentpopUpDivNode.appendChild(this.popUpDivNode);
		}
		
		DHTMLApi.CSS.setProperties(this.popUpDivNode,this.tempPopUpDivNodeStyles);
	},
	
	centerOnPage: function (targetWidth,targetHeight) {
		var leftPos,topPos,elementWidth,elementHeight;
		elementWidth=(typeof targetWidth=="undefined") ? DHTMLApi.Size.getElementWidth(this.popUpDivNode) : targetWidth;
		elementHeight=(typeof targetHeight=="undefined") ? DHTMLApi.Size.getElementHeight(this.popUpDivNode) : targetHeight;
		leftPos=Math.round((DHTMLApi.Browser.getViewportWidth()-elementWidth)/2+DHTMLApi.Browser.getScrollX());
		topPos=Math.round((DHTMLApi.Browser.getViewportHeight()-elementHeight)/2+DHTMLApi.Browser.getScrollY());
		if (topPos+elementHeight>DHTMLApi.Size.getPageHeight()) {
			topPos=DHTMLApi.Size.getPageHeight()-elementHeight;
		}
		DHTMLApi.CSS.setProperties(this.popUpDivNode, {left: leftPos+"px", top: topPos+"px"});
		DHTMLApi.CSS.setProperties(this.popupContainerNode, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: DHTMLApi.Size.getPageHeight()+"px"});
	},
	
	display: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.init(popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback);
		this.build();
		this.centerOnPage();
	},
	
	hide: function () {
		this.removeHandlers();
		this.restorePopUpNode();
		document.body.removeChild(this.popupContainerNode);
		DHTMLApi.CSS.setProperties(document.body,{overflow: "auto"});
	},
	
	getPageHeight: function () {
		return DHTMLApi.Size.getPageHeight();
	},
	
	getPageWidth: function () {
		return DHTMLApi.Size.getPageWidth();
	}
	
}

//////////////////////////////
// class StudioUpInfoButton //
//////////////////////////////

function StudioUpInfoButton(buttonElement,popupWindow) {
	this.buttonElement=buttonElement;
	this.popupWindow=popupWindow
	this.init();
	this.fontSizeAreaRatio=0.06;
	this.borderAreaRatio=0.008;
}

StudioUpInfoButton.prototype.init=function () {
	var obj=this;
	DOMEvent.addDomListener(this.buttonElement,"click",function () {
		PopUpLayer.display(obj.popupWindow,"popup_background",1,null,null);
		obj.setFontSize();
	});
	
	DOMEvent.addDomListener(window,"resize",function () {
		DHTMLApi.CSS.setProperties(obj.popupWindow,{width: (DHTMLApi.Browser.getViewportWidth()-210)+"px", height: (DHTMLApi.Browser.getViewportHeight()-150)+"px"});											
		obj.setFontSize();
	});
}

StudioUpInfoButton.prototype.setFontSize=function () {
	var fontSize=Math.floor(DHTMLApi.Size.getElementWidth(this.popupWindow)*this.fontSizeAreaRatio);
	var borderWidth=Math.floor(DHTMLApi.Size.getElementWidth(this.popupWindow)*this.borderAreaRatio);
	DHTMLApi.CSS.setProperties(this.popupWindow,{fontSize: fontSize+"px", lineHeight: fontSize+"px"});
	var links=this.popupWindow.getElementsByTagName("A");
	for (var i=0; i<links.length; i++) {
		if (links[i].className!="no_underline") {
			DHTMLApi.CSS.setProperties(links[i],{borderBottom: "solid "+borderWidth+"px black"});
		}
	}
}
