 /**
  * Crée un sprite cubique zoomable. Ce type de sprite sert dans les affichages en pseudo-3D
  * (affichage 2D avec zoom plan sans rotation).
  * En plus de la possibilité de zoomer, il offre deux faces latérales "vues de côté" qui simulent
  * une impression de profondeur, comme un cube vu depuis une hauteur constante.
  * Ces faces supplémentaires sont optionnelles. En fonction de l'angle de vue, seule l'une ou l'autre
  * est affichée à un instant donné.
  *
  *                     +------->
  *                       hotSpotX
  *                    ,+--------------------+,
  *                ,,°° |                    | °°,,
  *            ,,°°     |                    |     °°,,
  *           |   face  |   partie plane     |   face  |
  *           |  gauche |                    |  droite |
  *            °°,,     |  (sprite à plat)   |     ,,°°
  *                °°,, |                    | ,,°°
  *                    °+--------------------+°
  *
  *           <- side --> 
  *              width
  *           <---------------- width ----------------->
  *
  * Il peut également être animé via le principe du "sprite CSS"
  * (utilisation d'une image comprenant des frames d'animation juxtaposées).
  * 
  * 
  * Les paramètres sont les suivants :
  * 	width 		 : largeur en pixels d'une frame non zoomée (pas de l'image complète)
  *     height		 : hauteur en pixels d'une frame non zoomée (pas de l'image complète)
  *     sideWidth    : largeur en pixels d'une face latérale (largeur gauche et droite sont identiques)
  *     hotSpotX     : point de référence en pixels de la partie plane, à partir duquel
  *     hotSpotY     : l'image sera positionnée.
  *     imageFile    : chemin vers le fichier image (utilisé comme url pour la propriété CSS background-position)
  *     frameCountX  : nombre de frames dans la largeur de l'image
  *     frameCountY  : nombre de frames dans la hauteur de l'image
  *
  * A noter que l'image doit avoir les dimensions suivantes :
  *   - largeur : width*frameCountX
  *   - hauteur : height*frameCountY
  *   - la largeur de la partie plane est donc width-2*lateralWidth
  * 
  * La création n'ajoute pas le sprite dans le document, un appel à appendChild() sera nécessaire.
  */
 function CubicSprite(width, height, sideWidth, hotSpotX, hotSpotY, imageFile, frameCountX, frameCountY)
 {
	this.width = width;
	this.height = height;
	this.sideWidth = sideWidth;
	this.frontWidth = width-2*sideWidth;
	this.frameCountX = frameCountX;
	this.frameCountY = frameCountY;
	this.hotSpotX = hotSpotX;
	this.hotSpotY = hotSpotY;
	this.animationFrameX = 0;
	this.animationFrameY = 0;
	this.leftSideShown = true; // true pour afficher le côté gauche, false pour le droit (la perspective fait qu'on ne voit jamais les deux à la fois)
	
	this.frontBox = document.createElement('div');
	this.frontBox.style.position="absolute";
	this.frontBox.style.overflow="hidden";
	this.frontBox.style.visibility="hidden";
	//this.frontBox.style.display="none";
	this.frontBox.style.width=this.frontWidth+"px";
	this.frontBox.style.height=height+"px";
	this.frontImage = document.createElement('img');
	this.frontImage.style.position="absolute";
	this.frontImage.style.width=(100*frameCountX)+"%";
	this.frontImage.style.height=(100*frameCountY)+"%";
	this.frontImage.style.top="0%";
	this.frontImage.style.left=Math.round(-100*sideWidth/width)+"%";
	this.frontImage.setAttribute("src", imageFile);
	this.frontBox.appendChild(this.frontImage);

	this.sideBox = document.createElement('div');
	this.sideBox.style.position="absolute";
	this.sideBox.style.overflow="hidden";
	this.sideBox.style.visibility="hidden";
	//this.sideBox.style.display="none";
	this.sideBox.style.width=this.sideWidth+"px";
	this.sideBox.style.height=height+"px";
	this.sideImage = document.createElement('img');
	this.sideImage.style.position="absolute";
	this.sideImage.style.width=(100*frameCountX)+"%";
	this.sideImage.style.height=(100*frameCountY)+"%";
	this.sideImage.style.top="0%";
	this.sideImage.style.left="0%";
	this.sideImage.setAttribute("src", imageFile);
	this.sideBox.appendChild(this.sideImage);	
}
 
 
 CubicSprite.prototype = {
 
	/**
	 * Ajoute les composantes du sprite au container DOM qui va permettre leur affichage
	 */
	appendToGraphicContainer : function (container) {
		container.appendChild(this.frontBox);
		container.appendChild(this.sideBox);
	},
 
	/**
	 * Renvoie l'objet <div>, instanciation du sprite dans le document
	 */
	getSpriteObject : function() {
		return this.mainBox;
	},
 
	/**
	 * Modifie l'image et le contenu du sprite, à partir d'une entrée SceneryObject
	 * issue de la description du circuit (road.sceneryMaster[i])
	 */
	setSpriteFromSceneryObject : function(sceneryObject) {
		this.width = sceneryObject.w;
		this.height = sceneryObject.h;
		this.sideWidth = sceneryObject.sideW;
		this.frontWidth = this.width-2*this.sideWidth;
		this.frameCountX = 1;
		this.frameCountY = 1;
		this.hotSpotX = this.frontWidth/2;
		this.hotSpotY = this.height;
		this.animationFrameX = 0;
		this.animationFrameY = 0;
		
		this.frontBox.style.width=this.frontWidth+"px";
		this.frontBox.style.height=this.height+"px";
		this.frontImage.style.width=Math.round(100*this.frameCountX*(this.width/this.frontWidth))+"%";
		this.frontImage.style.height=(100*this.frameCountY)+"%";
		this.frontImage.style.top="0px";
		this.frontImage.style.left=Math.round(-100*this.sideWidth/this.frontWidth)+"%";
		this.frontImage.setAttribute("src", sceneryObject.src);	

		this.sideBox.style.width=this.sideWidth+"px";
		this.sideBox.style.height=this.height+"px";
		this.sideImage.style.width=(100*this.frameCountX)+"%";
		this.sideImage.style.height=(100*this.frameCountY)+"%";
		this.sideImage.style.top="0px";
		this.sideImage.style.left="0px";
		this.sideImage.setAttribute("src", sceneryObject.src);

	},
 
	/**
	 * Déplace et zoome le sprite.
	 * Les coordonnées sont celles du hot spot.
	 *   x     : abscisse en pixels du hot spot
	 *   y     : ordonnée en pixels du hot spot
	 *   z     : z-index du sprite
	 *   zoom  : niveau de zoom, 1 = taille par défaut
	 *   leftSideWidth : largeur précalculée du côté gauche, en pixels. N'est affiché que si >0.
	 *   rightSideWidth : largeur précalculée du côté droit, en pixels. N'est affiché que si >0.
	 *   clipTop : position de clipping en haut, pour le haut de l'écran
	 *   clipLeft : position de clipping à gauche, pour les tunnels et le bord de l'écran
	 *   clipBottom : position de clipping en bas, pour le sol au premier plan ou le haut de l'écran
	 *   clipRight : position de clipping à gauche, pour les tunnels et le bord de l'écran
	 */
	moveSpriteTo : function(x, y, z, zoom, leftSideWidth, rightSideWidth, clipTop, clipRight, clipBottom, clipLeft) {
		var frontPixelWidth = Math.round(zoom*this.frontWidth);
		var pixelHeight = Math.round(zoom*this.height);
		
		var zoomedHotSpotX = zoom*this.hotSpotX;
		var zoomedHotSpotY = zoom*this.hotSpotY;
		
		// on recalcule les coordonnées en haut à gauche
		// pour que le hot spot se trouve en (x, y)
		var px = Math.round(x-zoomedHotSpotX);
		var py = Math.round(y-zoomedHotSpotY);
		this.frontBox.style.left=px+"px";
		this.frontBox.style.top=py+"px";
		this.frontBox.style.zIndex=Math.round(z);
		this.frontBox.style.width=frontPixelWidth+"px";
		this.frontBox.style.height=pixelHeight+"px";
		this.frontBox.style.clip = "rect("+(py<clipTop?(clipTop-py):0)+"px "
									   +(px+frontPixelWidth>clipRight?clipRight-px:frontPixelWidth)+"px "
									   +(py+pixelHeight>clipBottom?(clipBottom-py):pixelHeight)+"px "
									   +(px<clipLeft?(clipLeft-px):0)+"px)";
		
		if (this.sideWidth>0) {
			leftSideWidth = Math.round(leftSideWidth);
			rightSideWidth = Math.round(rightSideWidth);
			if (leftSideWidth>0) {	// côté gauche visible
				var lateralZoom = leftSideWidth/this.sideWidth;
				var psx = px-leftSideWidth;
				this.leftSideShown = true;
				this.sideBox.style.left=psx+"px";
				this.sideBox.style.top=py+"px";
				this.sideBox.style.zIndex=Math.round(z);
				this.sideBox.style.width=leftSideWidth+"px";
				this.sideBox.style.height=pixelHeight+"px";
				this.sideBox.style.clip = "rect("	+(py<clipTop?(clipTop-py):0)+"px "
													+(psx+leftSideWidth>clipRight?clipRight-psx:leftSideWidth)+"px "
													+(py+pixelHeight>clipBottom?(clipBottom-py):pixelHeight)+"px "
													+(psx<clipLeft?(clipLeft-psx):0)+"px)";
				this.sideImage.style.left=(-this.animationFrameX*lateralZoom*this.width)+"px";
				this.sideImage.style.width=Math.round(this.width*this.frameCountX*lateralZoom)+"px";
			} else if (rightSideWidth>0) { // côté droit visible, la perspective nous garantit que le gauche ne sera pas visible
				var lateralZoom = rightSideWidth/this.sideWidth;
				this.leftSideShown = false;
				var psx = px+frontPixelWidth;
				this.sideBox.style.left=psx+"px";
				this.sideBox.style.top=py+"px";
				this.sideBox.style.zIndex=Math.round(z);
				this.sideBox.style.width=rightSideWidth+"px";
				this.sideBox.style.height=pixelHeight+"px";
				this.sideBox.style.clip = "rect("	+(py<clipTop?(clipTop-py):0)+"px "
													+(psx+rightSideWidth>clipRight?clipRight-psx:rightSideWidth)+"px "
													+(py+pixelHeight>clipBottom?(clipBottom-py):pixelHeight)+"px "
													+(psx<clipLeft?(clipLeft-psx):0)+"px)";
				this.sideImage.style.left=(-lateralZoom*(this.animationFrameX*this.width+this.frontWidth+this.sideWidth))+"px";
				this.sideImage.style.width=Math.round(this.width*this.frameCountX*lateralZoom)+"px";
			} else { // aucun des deux n'est visible
				this.leftSideShown = false;
				this.sideBox.style.width="0px";
			}
		}
	},
	
	/**
	  * Change l'image du sprite (la frame affichée)
	  * x et y sont les index horizontaux et verticaux de l'image à afficher, à partir de 0
	  */
	setAnimationFrame : function(x, y) {
		this.animationFrameX = x;
		this.animationFrameY = y;
		this.frontImage.style.left=(-x*this.width-this.sideWidth)+"px";
		this.frontImage.style.top=(-100*y)+"%";
		this.sideImage.style.left=(-x*this.width-(this.leftSideShown?0:this.frontWidth+this.sideWidth))+"px";
		this.sideImage.style.top=(-100*y)+"%";
	},
	
	/**
	 * Affiche (true) ou masque (false) le sprite
	 */
	 setVisible : function(shown) {
		this.frontBox.style.visibility=(shown?"visible":"hidden");
		this.sideBox.style.visibility=((shown&&this.sideWidth > 0)?"visible":"hidden");
	}
}