
function PIS (){
	try{
		this.url = "";
		this.compos = new Array();
		this.safetyMargin = 0;
		this.safetyMarginMagicNumber = 2;
		this.xPadding = 0;
		this.yPadding = 0;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.crop = function(wdth,hite,centered,cntrx,cntry){
	try{
		if ( centered ){
			cntrx = "(0.5*W)";
			cntry = "(0.5*H)";
		}
		var string = "|crop&cntrx="+cntrx+"&cntry="+cntry+"&wdth="+Math.round(wdth)+"&hite="+Math.round(hite);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.crop]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.imageCropping = function(wdth,hite,zoomFactor,cropX,cropY){
	try{
		var cntrx = "("+cropX+"*W)";
		var cntry = "("+cropY+"*H)";
		var cropWidth  = "("+wdth+"/("+zoomFactor+"*((W*"+(hite/wdth)+")%3C=H?("+wdth+"/W):("+hite+"/H))))";
		var cropHeight = "("+hite+"/("+zoomFactor+"*((W*"+(hite/wdth)+")%3C=H?("+wdth+"/W):("+hite+"/H))))";
		var string = "|crop&cntrx="+cntrx+"&cntry="+cntry+"&wdth="+cropWidth+"&hite="+cropHeight;
		this.url += string;
		this.zoom(wdth,hite);
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.imageCropping]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.trim = function(width, height){
	try{
		var string = "|trim&wdth="+Math.round(width)+"&hite="+Math.round(height);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.trim]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.zoom = function(width, height){
	try{
		var string = "|zoom&wdth="+Math.round(width)+"&hite="+Math.round(height);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.zoom]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.prop = function(wdth,hite,below){
	try{
		var propMethod = below ? "below" : "above";
		var string = "|prop="+propMethod+"&wdth="+Math.round(wdth)+"&hite="+Math.round(hite);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.prop]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawLine = function(bgx, bgy, endx, endy, color){
	try{
		var string = "|draw=line&bgnx="+Math.round(bgx)+"&bgny="+Math.round(bgy)+"&endx="+Math.round(endx)+"&endy="+Math.round(endy)+"&wdth=1&color="+color;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawLine]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawPolygon = function(x, y, borderColor, fillColor, lineWidth){
	try{
		var string = "|draw=polygon";
		for ( var i = 0; i < x.length; i++)
			string += "&x=" + Math.round(x[i]) + "&y=" + Math.round(y[i]);
		string += "&wdth="+rndtoEvenOrOne(lineWidth)+"&color="+borderColor;
		if ( fillColor )
			string += "&fill="+fillColor;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawPolygon]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawDiamond = function(x0, y0, h, w, borderColor, fillColor, lineWidth){
	try{
		var x = [ x0 + lineWidth ,     w/2 + x0    ,  w + x0 - lineWidth,    w/2 + x0        ];
		var y = [   h/2 +  y0    , y0 + lineWidth  ,       h/2 + y0     , h + y0 - lineWidth ];
		return this.drawPolygon(x,y,borderColor, fillColor, lineWidth);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawDiamond]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawRect = function(lx, ly, rx, ry, borderColor, fillColor, lineWidth){
	try{
		var string = "|draw=rect&leftx="+Math.round(lx)+"&lefty="+Math.round(ly)+"&ritex="+Math.round(rx)+"&ritey="+Math.round(ry)+( lineWidth ? "&wdth="+rndtoEvenOrOne(lineWidth) : "" )+"&color="+borderColor;
		if ( fillColor )
			string += "&fill="+fillColor;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawRect]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawEllipse = function(cx, cy, haxis, vaxis, borderColor, fillColor, lineWidth){
	try{
		var string = "|draw=ellipse&cntrx="+cx+"&cntry="+cy+"&haxis="+Math.round(haxis)+"&vaxis="+Math.round(vaxis)+"&wdth="+rndtoEvenOrOne(lineWidth)+"&color="+borderColor;
		if ( fillColor )
			string += "&fill="+fillColor;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawEllipse]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.fill = function(color, x, y, borderColor){
	try{
		var string = "|draw=fill&fill="+color+"&locx="+Math.round(x)+"&locy="+Math.round(y)+"&border=" + borderColor;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.fill]</B> ' + e + '</FONT>' ); return false; } 
}

//REPLACED FOR fremegoo
PIS.prototype.frame = function(framePath, wdth, hite, color){
	try{
		if ( !color )
			color = "FF.00.FF.FF";
		var string = "|frame="+framePath+"&color="+color;
		this.url += string;
		this.zoom(wdth, hite)
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.frame]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.framegoo = function(framePath, wdth, hite, color){
	try{
		if ( !color )
			color = "FF.00.FF.FF";
		var string = "|framegoo="+framePath+"&color="+color;
		this.url += string;
		this.prop(wdth, hite)
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.frame]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.drawOpening = function(width, height, shape, borderColor, fillColor, lineWidth, margin){
	try{
		if ( !lineWidth )
			lineWidth = 1;
		else
			lineWidth = rndtoEvenOrOne(lineWidth);
		if ( !margin )
			margin = 0;
		var string;
		// the '- 1' corrections were used, because the 0,0 point is the first pixel in an image
		// and we want the rectangle to end at that position, that pixel should not be painted,
		// it should only be used as the limit.
		if ( shape == "rect" || shape == "rectangle")
			string = this.drawRect(margin, margin, width + margin - 1, height + margin - 1, borderColor, fillColor, lineWidth);
		if ( shape == "diamond" )
			string = this.drawDiamond(margin, margin, height, width, borderColor, fillColor, lineWidth);
		if ( shape == "oval" )
			string = this.drawEllipse("(0.5*W)", "(0.5*H)", width - lineWidth, height - lineWidth, borderColor, fillColor, lineWidth);
		if ( shape == "circle" )
			string = this.drawEllipse("(0.5*W)", "(0.5*H)", width - lineWidth, height - lineWidth, borderColor, fillColor, lineWidth);
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.drawOpening]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.border = function(borderColor, horizLineWidth, vertLineWidth){
	try{
		if ( !vertLineWidth )
			vertLineWidth = horizLineWidth;
		var string = "|bordr&wdth="+Math.round(horizLineWidth)+"&hite="+Math.round(vertLineWidth)+"&color="+borderColor;
		this.url += string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.border]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.load = function(image,history){
	try{
		var string = "|load="+image+(history?"":"&nohist=yes");
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.load]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.addPISCommand = function(pisCommand){
	try{
		this.url += pisCommand;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.addPISCommand]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.create = function(color, width, height){
	try{
		var string = "|creat&color="+color+"&wdth="+Math.round(width)+"&hite="+Math.round(height);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.create]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.flop = function(){
	try{
		var string = "|flop"; // |flop&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.flop]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.flip = function(){
	try{
		var string = "|flip"; // |flip&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.flip]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.annotate = function(caption, fontSize, fontFamily, fontColor){
	try{
		var string = "|annot=" + replace( replace( encodeURIComponent(caption), '%25', '%2525'), '%26', '%2526') + "&font=" + fontFamily + "&size=" + fontSize + "&color=" + fontColor + "&x0=-1&y0=-1&";
		//creat&wdth=90&hite=9&color=transparent|annot=Hola&font=Century-Gothic-Bold&size=20&x0=-1&y0=-1&color=black|hold=$o1
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.annotate]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.annoe = function(caption, width, height, fontSize, fontFamily, fontColor, fontUnderline, fontAlign, fontDpi, fontOpacity, fontEffectType, fontEffectColor, fontEffectStrokeWeight, metricsDpi){
	try{
		var string = "|annoe=" + replace( replace( encodeURIComponent(caption), '%25', '%2525'), '%26', '%2526') + "&inchwdth=" + width + "&inchhite=" + height + "&x0=0&y0=0&align=" + fontAlign + "&font=" + fontFamily + "&size=" + fontSize + "&color=" + fontColor + "&underline=" + fontUnderline + "&drawdpi=" + fontDpi + '&metricsdpi=' + metricsDpi;
		if (fontEffectType != null) {
			if (fontEffectType == 'stroke' && fontEffectStrokeWeight != null && fontEffectStrokeWeight > 0) { string += '&effect=' + fontEffectType + '&strokec=' + fontEffectColor + '&strokew=' + fontEffectStrokeWeight; }
		}
		string += '|trans=' + fontOpacity
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.annoe]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.brighten = function(times){
	try{
		var string = "";
		if ( !times )
			times = 1;
		for ( var i = 0; i < times; i++ )
			string += "|admin.brighten";  // |admin.brighten&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.brighten]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.darken = function(times){
	try{
		var string = "";
		if ( times == null )
			times = 1;
		for ( var i = 0; i < times; i++ )
			string += "|admin.darken"; // |admin.darken&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.darken]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.sharpen = function(){
	try{
		var string = "|admin.sharpen"; // |admin.sharpen&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.sharpen]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.contrast = function(){
	try{
		var string = "|admin.contrast"; // |admin.contrast&user=admin
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.contrast]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.tone = function(tone){ //  tone = desaturate or sepia
	try{
		var string = "|admin."+tone;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.tone]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.desaturate = function(){
	try{
		var string = "|admin.desaturate";
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.desaturate]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.sepia = function(){
	try{
		var string = "|admin.sepia";
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.sepia]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.rotate = function(angle, backColor){
	try{
		var string = "|rotat="+angle +( backColor ? "&color="+backColor : "" );
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.rotate]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.flush = function(){
	try{
		var string = "|flush";
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.flush]</B> ' + e + '</FONT>' ); return false; } 
}



PIS.prototype.hold = function(variable){
	try{
		var string = "|hold=$"+variable;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.hold]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.compo = function(variable, centered, x, y, operator, refPoint){
	try{
		x = Math.round(x);
		y = Math.round(y);
		if ( centered ){
			x = -1;
			y = -1;
		}
		else{
			if ( x == -1 )
				x = -2;
			if ( y == -1 )                                                          
				y = -2;
		}                                                                                  
		if ( !operator )
			operator = "over";
		var string = "|compo=$"+variable+"&op="+operator+"&x0="+x+"&y0="+y+(refPoint==null?'':'&coords='+refPoint);
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.compo]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.compose = function(pisObject, variable, centered, x, y, operator, coords){
	try{
		if ( centered ){
			x = -1;
			y = -1;
		}
		else{
			if ( x == -1 )
				x = -2;
			if ( y == -1 )
				y = -2;
		}
		this.compos.push({ pis: pisObject, variable: variable, centered: centered, x0: x, y0 : y, operator: operator, coords: coords });
		return this;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.compose]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.getPISCommand = function(parcial){
	try{
		if ( !parcial ){
			this.consolidateCompos();
			this.flush();
			return this.url.substring(1);
		}
		return this.url;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.getPISCommand]</B> ' + e + '</FONT>' ); return false; } 
}


PIS.prototype.consolidateCompos = function(){
	try{
		var urlTemp = this.url;
		this.url = "";
		for ( var i = 0 ; i < this.compos.length; i++){
			this.url += this.compos[i].pis.getPISCommand(true)
			this.hold(this.compos[i].variable);
		}
		this.url += urlTemp;
		for ( var i = 0 ; i < this.compos.length; i++){
			this.compo(this.compos[i].variable,this.compos[i].centered,this.compos[i].x0,this.compos[i].y0,this.compos[i].operator,this.compos[i].coords);
		}
		this.compos = new Array();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.consolidateCompos]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.fetch = function( variable ){
	try{
		var string = "|fetch=$" + variable;
		this.url += string;
		return string;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.fill]</B> ' + e + '</FONT>' ); return false; } 
}

PIS.prototype.applySafetyMargin = function( actualHeight, actualWidth, rotation, shape, color ){
	try
	{
		var safetyMargin = Math.ceil(this.getSafetyMargin());

		if (shape == "rect")
		{
			this.hold('image');
			this.create( 'transparent', actualWidth, actualHeight );

			/* 	The width of safety margin is applied 4 pixels bigger in order to solve problems with some
				resolutions. Rect size is 2 pixels bigger then the margin over the opening is the 
				same size of the original SafetyMargin */

			var leftX = safetyMargin / 2 - (this.safetyMarginMagicNumber + 1);
			var leftY = safetyMargin / 2 - (this.safetyMarginMagicNumber + 1);
			var rightX = actualWidth - safetyMargin / 2 + this.safetyMarginMagicNumber;
			var rightY = actualHeight - safetyMargin / 2 + this.safetyMarginMagicNumber;

			this.drawRect(leftX, leftY, rightX, rightY, color, null, safetyMargin / 2 + (this.safetyMarginMagicNumber * 2) );

			if (rotation > 0.0)
			{
				this.rotate( rotation, 'transparent' );
			}

			this.hold( 'shape' );
			this.fetch( 'image' );
			this.compo( 'shape', true, null, null, 1, null );
		}
		else if (shape == "oval")
		{
			this.drawEllipse("(0.5*W)", "(0.5*H)", actualWidth , actualHeight , color, null, safetyMargin );
		}
		else if (shape == "diamond")
		{
			// On "dist" calculation "1" is substracted to SafetyMargin in order to correct rounding problems.
			var dist = Math.round(Math.sqrt(Math.pow(safetyMargin,2) + Math.pow(safetyMargin,2)) - safetyMargin - 1);	//** the -1 is another magic number
			this.drawDiamond( dist, dist, actualHeight + safetyMargin, actualWidth + safetyMargin, color, null, safetyMargin / 2);
		}
		else if (shape == "circle")
		{
			this.drawEllipse("(0.5*W)", "(0.5*H)", actualWidth , actualHeight , color, null, safetyMargin);
		}

		//Correct paddings for PIS
		this.xPadding = ((actualHeight > actualWidth) ? 1 : 2);
		this.yPadding = ((actualHeight > actualWidth) ? 2 : 1);

	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.applySafetyMargin]</B> ' + e + '</FONT>' ); return false; }
}

PIS.prototype.getSafetyMargin = function(){
	try
	{
		return this.safetyMargin;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.getSafetyMargin]</B> ' + e + '</FONT>' ); return false; }
}

PIS.prototype.setSafetyMargin = function ( safetyMargin, magicNumber ){
	try
	{
		this.safetyMargin = safetyMargin;
		if (magicNumber != null) { this.safetyMarginMagicNumber = magicNumber; }
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.setSafetyMargin]</B> ' + e + '</FONT>' ); return false; }


}

PIS.prototype.getSafetyMarginMagicNumber = function() {
	return this.safetyMarginMagicNumber;
}

PIS.prototype.getXPadding = function(){
	try
	{
		return this.xPadding;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.getXPadding]</B> ' + e + '</FONT>' ); return false; }
}

PIS.prototype.getYPadding = function(){
	try
	{
		return this.yPadding;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PIS.getYPadding]</B> ' + e + '</FONT>' ); return false; }
}

/**
 * This function compensates for PIS problems when drawing lines
 * a line with an even thickness will be drawn as the next odd
 * but drawing an odd thickness will cause artifacts, except for width=1
 * line widths need to be the previous even number to the nearest odd
 */
function rndtoEvenOrOne(number){
	var floor = Math.floor(number);
	if ( floor == 1 )
		return floor;
	var ceil = Math.ceil(number);
	if ( ceil == 1 )
		return ceil;
	var belowEven = ( ( floor%2 == 0 )? floor : (floor-1) );
	var aboveEven = ( ( ceil%2 == 0 )? ceil : (ceil+1) );
	var result = ( ( (number - (belowEven+1)) ) < ((aboveEven+1) - number) ? belowEven : aboveEven);
	return result;
}

