
function Fulfiller (album, unitsConv, unitsConvWork, gutter, frontInsideCoverPath, backInsideCoverPath, openingPath, ghostPagePath, bordersPath, borderManager, useAnnotateExtendedForPIS, metricsDpi){
	try{
		this.album = album;
		this.unitsConv = unitsConv;
		this.unitsConvWork = (unitsConvWork ? unitsConvWork : this.unitsConv);
		this.borderManager = borderManager;
		this.gutter = gutter;
		this.frontInsideCoverPath = ( frontInsideCoverPath ? frontInsideCoverPath : "/home/image/assets/paa/images/dumy_inside_cover.jpg");
		this.backInsideCoverPath = ( backInsideCoverPath ? backInsideCoverPath : "/home/image/assets/paa/images/dumy_inside_cover.jpg");
		this.openingPath = ( openingPath ? openingPath : "/home/image/assets/paa/images/dumy_opening_image.jpg");
		this.ghostPagePath = ( ghostPagePath ? ghostPagePath : "/home/image/assets/paa/images/ghost_page.jpg");
		this.bordersPath = ( bordersPath ? bordersPath : "/home/image/assets/borders/");
		this.pages = new Array();
		this.albumOperations = new Object();
		this.openingData = null;
		this.useAnnotateExtendedForPIS = false;
		if (useAnnotateExtendedForPIS != null) { this.useAnnotateExtendedForPIS = useAnnotateExtendedForPIS; }
		this.metricsDpi = 25; if (metricsDpi != null) { this.metricsDpi = metricsDpi; }
		var dataPIS = new PIS();
		this.safetyMarginMagicNumber = dataPIS.getSafetyMarginMagicNumber();
		this.fillPages(); // pages[pageNumber] == insert for page also position in album.insertList
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.GHOSTPAGE = "ghost";
Fulfiller.prototype.INSIDECOVER = "IC";
Fulfiller.prototype.ODDSIDEOFPANO = "oddSideOfPano";

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

Fulfiller.prototype.setUnitsConverter = function(unitsConv, unitsConvWork) {
	try{
		this.unitsConv = unitsConv;
		this.unitsConvWork = (unitsConvWork ? unitsConvWork : unitsConv);	//** should check if work.factor < normal.factor
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setUnitsConverter]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getUnitsConverters = function() {
	return { display: this.unitsConv, work: this.unitsConv };
}

Fulfiller.prototype.canInsertBefore = function(pageNumber) {
	try{
		if ( this.pageIsFirstInsideCover(pageNumber) )
			return false;
		return true;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.canInsertBefore]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.canInsertAfter = function(pageNumber){
	try{
		if ( this.pageIsLastInsideCover(pageNumber) )
			return false;
		return true;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.canInsertAfter]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.canDeletePage = function(pageNumber){
	try{
		if ( this.pageIsGhostPage(pageNumber) || this.pageIsInsideCover(pageNumber) )
			return false;
		return true;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.canDeletePage]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.canRotatePage = function(pageNumber){
	try{
		if ( pageNumber == null )
			return Boolean(this.albumOperations.MR)
		else{
			if ( this.albumOperations.MR ){
				var insert = this.getInsertFromPage(pageNumber);
				if ( insert )
					return ( insert.getWidth() == insert.getHeight() );
			}
			else
				return false;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.canRotatePage]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingSizingAllowed = function(){
	try{
		return Boolean(this.albumOperations.OS);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingSizingAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingMovingAllowed = function(){
	try{
		return Boolean(this.albumOperations.OP);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingMovingAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingRotationAllowed = function(){
	try{
		return Boolean(this.albumOperations.OR);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingRotationAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingBorderAllowed = function(pageNumber, openingId, borderId){
	try{
		if (!this.albumOperations.OB)
			return false;
		if ( openingId == null )
			return true;
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening.getShape() == "rect" || opening.getShape() == "rectangle" )
			return true
		else{
			if ( borderId == 'Bleed' || borderId == 'White_Keyline' || borderId == 'Black_Keyline' )
				return true;
			else
				return false;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingBorderAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingShapeAllowed = function(pageNumber, openingId, shape){
	try{
		return Boolean(this.albumOperations.SH);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingShapeAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingTransparencyAllowed = function(){
	try{
		return Boolean(this.albumOperations.OT);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingTransparencyAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.openingOpacityAllowed = function(){
	try{
		return Boolean(this.albumOperations.OO);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingOpacityAllowed]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.openingZOrderAllowed = function(){
	try{
		return Boolean(this.albumOperations.SO);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.openingZOrderAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.backgroundImageAllowed = function(){
	try{
		return Boolean(this.albumOperations.BI);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.backgroundImageAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.backgroundColorUnrestricted = function(){
	try{
		return Boolean(this.albumOperations.BC);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.backgroundColorUnrestricted]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.backgroundTransparencyAllowed = function(){
	try{
		return null; /* operation not included */
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.backgroundTransparencyAllowed]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.matAllowedForInserting = function(insert, pageNumber){
	try{
		var OOB, RIC, JP, OK;
		if ( data ){
			OOB = data.pageOperationErrors.OUT_OF_BOUNDARIES;
			RIC = data.pageOperationErrors.REPLACING_IC;
			JP = data.pageOperationErrors.JUST_PANOS;
		}

		if ( pageNumber <= this.getPageNumberOfFirstInsideCover() || pageNumber > this.getPageNumberOfLastInsideCover() )
			return { result: false, reason: OOB };
		if ( !Boolean(this.albumOperations.JP) ){
			return { result: true, reason: OK };
		}
		else{
			// RULES: SIDES CAN ONLY BE INSERTED:
			//									ON FIRST PAGE IF THE SIDE IS MISSING
			//									ON FIRST PAGE IF ONLY ONE SIDE ON THE ALBUM
			//									ON LAST PAGE IF THE SIDE IS MISSING
			//									NOT ON ANYWHERE ELSE
			//		PANOS CAN ONLY BE INSERTED:
			//									ON FIRST PAGE IF THE SIDE IS MISSING
			//									ON LAST PAGE IF THE SIDE IS MIISING
			//									ON ANYWHERE ELSE

			var firstICPage = this.getPageNumberOfFirstInsideCover();
			var lastICPage = this.getPageNumberOfLastInsideCover();

			var thereArePanos = this.pageIsPano( firstICPage + 2 );

			var page1IsSide = this.pageIsSide(firstICPage + 1);
			var lastPageIsSide = this.pageIsSide(lastICPage - 1);

			var insertObject = new BaseInsert();
			insertObject.readInsertParam(insert);

			dbg.add('<FONT COLOR="green">matAllowedForInserting() - pageNumber: ' + pageNumber,'thereArePanos: ' + thereArePanos, 'page1IsSide: ' + page1IsSide, 'lastPageIsSide: ' + lastPageIsSide+'</FONT>');

			if ( insertObject.isPano() ){
				if ( pageNumber < 2 && page1IsSide )
					return { result: false, reason: JP };
				if ( pageNumber > (lastICPage - 1) && lastPageIsSide )
					return { result: false, reason: JP };
				return { result: true, reason: OK };
			}
			else{
				if ( pageNumber <= 2 && !page1IsSide )
					return { result: true, reason: OK };
				else if ( pageNumber <= 2 && page1IsSide && !thereArePanos && !lastPageIsSide )
					return { result: true, reason: OK };
				else if ( pageNumber > (lastICPage - 2) && !lastPageIsSide )
					return { result: true, reason: OK };
				return { result: false, reason: JP };
			}
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.matAllowedForInserting]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.matAllowedForReplacement = function(insert, pageNumber){
	try{
		var OOB, RIC, JP, OK;
		if ( data ){
			OOB = data.pageOperationErrors.OUT_OF_BOUNDARIES;
			RIC = data.pageOperationErrors.REPLACING_IC;
			JP = data.pageOperationErrors.JUST_PANOS;
		}

		if ( pageNumber <= this.getPageNumberOfFirstInsideCover() || pageNumber >= this.getPageNumberOfLastInsideCover() )
			return { result: false, reason: RIC }
		if ( !Boolean(this.albumOperations.JP) ){
			return { result: true, reason: OK };
		}
		else{
			// RULES: SIDES CAN ONLY REPLACE:
			//									WHEN REPLACING ANOTHER SIDE
			//									WHEN REPLACING A GHOST
			//									WHEN REPLACING A PANO IF RIGHT BEFORE OR AFTER IT THERE'S A GHOST
			//									NOT ON ANYWHERE ELSE
			//		PANOS CAN ALWAYS REPLACE

			var insertObject = new BaseInsert();
			insertObject.readInsertParam(insert);
			var insertingWithPano = insertObject.isPano();
			var replacingAGhost = this.pageIsGhostPage(pageNumber);
			var replacingASide = this.pageIsSide(pageNumber);
			var thereIsAGhostBefore = this.pageIsGhostPage(pageNumber-1);
			var thereIsAGhostAfter = this.pageIsGhostPage(pageNumber+1);

			dbg.add('<FONT COLOR="green">matAllowedForReplacement() - pageNumber: ' + pageNumber,'insertingWithPano: ' + insertingWithPano, 'replacingAGhost: ' + replacingAGhost, 'replacingASide: ' + replacingASide, 'thereIsAGhostBefore: ' + thereIsAGhostBefore ,'thereIsAGhostAfter: '+ thereIsAGhostAfter + '</FONT>');

			if ( insertObject.isPano() )
				return { result: true, reason: OK };
			else{
				if ( this.pageIsSide(pageNumber) )
					return { result: true, reason: OK };
				else if ( this.pageIsGhostPage(pageNumber) )
					return { result: true, reason: OK };
				else if ( this.pageIsGhostPage(pageNumber-1) || this.pageIsGhostPage(pageNumber+2) )
					return { result: true, reason: OK };
				else
					return { result: false, reason: JP };
			}
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.matAllowedForReplacement]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageCanBeMovedToPage = function(fromPageNumber, toPageNumber, replace){
	try{
		var OOB, RIC, JP, PCBM, OK;
		if ( data ){
			OOB = data.pageOperationErrors.OUT_OF_BOUNDARIES;
			RIC = data.pageOperationErrors.REPLACING_IC;
			JP = data.pageOperationErrors.JUST_PANOS;
			PCBM = data.pageOperationErrors.PAGE_CANT_BE_MOVED;
		}

		var insertFrom = this.getInsertFromPage(fromPageNumber);
		var insertTo = this.getInsertFromPage(toPageNumber);
		if ( !insertFrom ){
			return { result: false, reason: PCBM };
		}
		var fromPosition = this.getInsertPositionInAlbumFromPage(fromPageNumber).insertPosition;
		var toPosition = this.getInsertPositionInAlbumFromPage(toPageNumber).insertPosition;
		if ( ( toPosition == fromPosition ) || ( ( (toPosition - 1) == fromPosition ) && !replace ) ){
			return { result: false, reason: OK };
		}
		//dbg.add('<FONT COLOR="green">pageCanBeMovedToPage() - fromPageNumber: ' + fromPageNumber,'toPageNumber: ' + toPageNumber,'replace: ' + replace,'thereIsAGhostBefore: ' + this.pageIsGhostPage(toPageNumber-1), 'thereIsAGhostAfter: ' + this.pageIsGhostPage(toPageNumber+2), 'replacingAGhost: ' + this.pageIsGhostPage(toPageNumber), 'replacingASide: ' + this.pageIsSide(toPageNumber) ,'insertingAPano: '+ insertFrom.isPano() + '</FONT>');
		if ( replace ){
			if ( this.pageIsInsideCover(toPageNumber) )
				return { result: false, reason: RIC };
			if ( (toPageNumber  == fromPageNumber + 1) || ((toPageNumber == fromPageNumber - 2) && insertTo.isPano() )){
				return { result: true, reason: OK };	// This replace is just like deleting page number: toPageNumber
			}
			if ( insertFrom.isPano() )
				return { result: true, reason: OK };
			else{
				if ( this.pageIsSide(toPageNumber) || this.pageIsGhostPage(toPageNumber) )
					return { result: true, reason: OK };
				else if ( this.pageIsGhostPage(toPageNumber-1) || this.pageIsGhostPage(toPageNumber+2) )
					return { result: true, reason: OK };
				else if ( toPageNumber  == fromPageNumber + 1 )
					return { result: true, reason: OK };
				return { result: false, reason: JP };
			}
		}
		else{
			return this.matAllowedForInserting(insertFrom.toString(), toPageNumber);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageCanBeMovedToPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.pageIsGhostPage = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		return ( pageInfo == this.GHOSTPAGE );
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsGhostPage]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsPano = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		if ( pageInfo != null && pageInfo.isPano )
			return pageInfo.isPano();
		return false;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsPano]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsSide = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		if ( pageInfo != null && pageInfo.isSide )
			return pageInfo.isSide();
		return false;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsSide]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsOddSideOfPano = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		return ( pageInfo == this.ODDSIDEOFPANO );
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsOddSideOfPano]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsInsideCover = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		return ( pageInfo == this.INSIDECOVER );
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsInsideCover]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsFirstInsideCover = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		return ( pageInfo == this.INSIDECOVER && pageNumber == this.getPageNumberOfFirstInsideCover() );
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsFirstInsideCover]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageIsLastInsideCover = function(pageNumber){
	try{
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		return ( pageInfo == this.INSIDECOVER && pageNumber == this.getPageNumberOfLastInsideCover() );
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageIsLastInsideCover]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getOpeningFromPageAndId = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert )
			return insert.getOpeningById(openingId);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFromPageAndId]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningIdFromPageAndTemplateId = function(pageNumber, templateId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert )
			return insert.getOpeningByTemplateId(templateId);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningIdFromPageAndTemplateId]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getImageFromPageAndOpeningId = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert )
			return insert.getOpeningById(openingId).getImage();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getImageFromPageAndOpeningId]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getImageFromBackgroundPage = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert )
			return insert.getBackgroundImage();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getImageFromBackgroundPage]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getInsertFromPage = function(pageNumber){
	try{
		if ( this.pageIsOddSideOfPano(pageNumber) )
			pageNumber--;
		var pageInfo = (this.pages[pageNumber]).pageInfo;
		if (typeof(pageInfo) == "object")
			return pageInfo;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getInsertFromPage]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getInsertPositionInAlbumFromPage = function(pageNumber){
	try{
		if ( this.pageIsOddSideOfPano(pageNumber) )
			pageNumber--;
		if ( this.pageIsGhostPage(pageNumber) )
			pageNumber++;
		var position = (this.pages[pageNumber]).insertPosition;
		if ( !position ){
			if ( this.pageIsLastInsideCover(pageNumber) )
				position = this.album.getInsertQuantity();
			else if ( this.pageIsFirstInsideCover(pageNumber) )
				position = 0;
		}
		return { insertPosition: position, insertPageNumber: pageNumber };
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getInsertPositionInAlbumFromPage]</B> ' + e + '</FONT>' ); return false; }
}


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

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


Fulfiller.prototype.getPageQuantity = function(){
	try{
		return this.pages.length - 2;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPageQuantity]</B> ' + e + '</FONT>' ); return false; }
}

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

Fulfiller.prototype.getGhostPageQuantity = function(){
	try{
		var ghostQty = 0;
		for ( var pageNumber = 0; pageNumber < this.pages.length ; pageNumber ++ )
			if ( this.pageIsGhostPage(pageNumber) )
				ghostQty++;
		return ghostQty;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getGhostPageQuantity]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getEmptyOpeningQuantity = function(){
	try{
		var emptyOps = 0;
		var inserts = this.album.getInserts();
		for ( var i = 0; i < inserts.length; i++){
			var openings = inserts[i].getOpenings();
			for ( var j = 0; j < openings.length; j++){
				if ( !openings[j].hasImage() && !openings[j].isCaption() ){
					emptyOps++;
				}
			}
		}
		return emptyOps;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getEmptyOpeningQuantity]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getOpeningQuantityInPage = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert )
			return insert.getOpenings().length;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningQuantityInPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getImageQuantity = function(){
	try{
		var result = 0;
		var inserts = this.album.getInserts();
		for ( var i = 0; i < this.album.getInsertQuantity(); i++)
			result += inserts[i].getImageQuantity();
		return result;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getImageQuantity]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getUsedImages = function(){
	try{
		var result = new Object();
		var inserts = this.album.getInserts();
		for ( var i = 0; i < inserts.length; i++){
			if ( inserts[i].backgroundIsImage() ){
				if ( result[inserts[i].getBackgroundImage().getScannum()] )
					result[inserts[i].getBackgroundImage().getScannum()]++;
				else
					result[inserts[i].getBackgroundImage().getScannum()] = 1;
			}
			var openings = inserts[i].getOpenings();
			for ( var j = 0; j < openings.length; j++){
				if ( openings[j].hasImage() ){
					if ( result[openings[j].getImage().getScannum()] )
						result[openings[j].getImage().getScannum()]++;
					else
						result[openings[j].getImage().getScannum()] = 1;
				}
			}
		}
		return result;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getUsedImages]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getUsedImagesInPage = function(pageNumber){
	try{
		var result = new Object();
		var insert = this.getInsertFromPage(pageNumber);
		if ( !insert )
			return result;
		if ( insert.backgroundIsImage() ){
			if ( result[insert.getBackgroundImage().getScannum()] )
				result[insert.getBackgroundImage().getScannum()]++;
			else
				result[insert.getBackgroundImage().getScannum()] = 1;
		}
		var openings = insert.getOpenings();
		for ( var j = 0; j < openings.length; j++){
			if ( openings[j].hasImage() ){
				if ( result[openings[j].getImage().getScannum()] )
					result[openings[j].getImage().getScannum()]++;
				else
					result[openings[j].getImage().getScannum()] = 1;
			}
		}
	return result;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getUsedImagesInPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getPageNumberOfLastInsideCover = function(){
	try{
		return this.pages.length - 1;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPageNumberOfLastInsideCover]</B> ' + e + '</FONT>' ); return false; }
}


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


Fulfiller.prototype.getMatSize = function(){
	try{
		return {height: this.album.getHeight(), width: this.album.getWidth()};
		// ** TODO ** fix - if the album.size and insert.size are different this doesn't work
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getMatSize]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getPagePair = function(pageNumber,noOpeningData){
	try{
		pageNumber = ( pageNumber % 2 == 0 ? pageNumber : pageNumber - 1)
		var evenPage = this.getPageInPageNumber (pageNumber, noOpeningData);
		var oddPage = this.getPageInPageNumber (pageNumber+1, noOpeningData);
		return {even:  evenPage, odd: oddPage};
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPagePair]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getPagePairs = function(noOpeningData){
	try{
		var pagePairs = new Array();
		for ( var i = 0; i < this.pages.length; i+=2)
			pagePairs.push( this.getPagePair(i,noOpeningData) );
		return pagePairs;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPagePairs]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getCroppingData = function(pageNumber, openingId){
	try{
		var image;
		var width;
		var height;
		var shape;
		var borderColor = null;
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			if ( openingId || openingId == 0 ){
				var opening = insert.getOpeningById(openingId);
				image = opening.getImage();
				if ( !image )
					return null;
				
				width = opening.getWidth();
				height = opening.getHeight();
				
				shape = opening.getShape();
				borderColor = this.borderManager.getBorderObject( opening.getBorderType(), width, height).getColor();
			}
			else{
				image = insert.getBackgroundImage();
				if ( !image )
					return null;
				width = insert.getWidth();
				height = insert.getHeight();
				shape = "rect";
			}
		}
		var croppingData = { width: width, height: height, shape: shape, borderColor: borderColor, scannum: image.getScannum(), history: image.getHistoryString(), zoomFactor: image.getZoomFactor(), cropX: image.getCropX(), cropY: image.getCropY() }
		return croppingData;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getCroppingData]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getBoundingBoxData = function(pageNumber, openingId){
	try{
		opening = this.getOpeningFromPageAndId(pageNumber, openingId);
		if ( opening )
			return { x: opening.getBoundingBoxX0(), y: opening.getBoundingBoxY0(), w: opening.getBoundingBoxWidth(), h: opening.getBoundingBoxHeight() };
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getBoundingBoxData]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getPageInPageNumber = function(pageNumber, noOpeningData){
	try{
		var page = null;
		if ( this.pageIsInsideCover(pageNumber) ){
			page = new InsideCoverPage(pageNumber);
			page.setValues( {height: this.album.getHeight(), width: this.album.getWidth() }, this.getUserDataForPage(pageNumber) );
		}
		else if ( this.pageIsGhostPage(pageNumber) ){
			page = new GhostPage(pageNumber);
			page.setValues( {height: this.album.getHeight(), width: this.album.getWidth() }, this.getUserDataForPage(pageNumber) );
		}
		else if ( this.pageIsOddSideOfPano(pageNumber) ){
			page = null;
		}
		else{
			var insert = this.getInsertFromPage(pageNumber);
			if ( insert ){
				if ( insert.isPano() )
					page = new PanoPage(pageNumber, insert);
				else
					page = new Page(pageNumber, insert);
				page.setValues( {height: insert.getHeight(), width: insert.getWidth() }, this.getUserDataForPage(pageNumber), ( noOpeningData ? null : insert.getOpenings() ) );
			}
		}
		return page;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPageInPageNumber]</B> ' + e + '</FONT>' ); return false; }
}


													/** Pages Operations **/

Fulfiller.prototype.insertPage = function(insert, pageNumber){
	try{
		var positionObject = this.getInsertPositionInAlbumFromPage(pageNumber);
		var position = positionObject.insertPosition;
		pageNumber = positionObject.insertPageNumber;
		if ( position || position == 0){
			this.album.addInsert(insert, position);
			this.fillPages();
			return this.findInsert(this.album.getInsert(position));
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.insertPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.replacePage = function(insert, pageNumber){
	try{
		if ( this.pageIsGhostPage(pageNumber) )
			return this.insertPage(insert, pageNumber);
		var positionObject = this.getInsertPositionInAlbumFromPage(pageNumber)
		var position = positionObject.insertPosition;
		pageNumber = positionObject.insertPageNumber;
		if ( position || position == 0 ){
			this.album.replaceInsert(insert, position);
			this.fillPages();
			return this.findInsert(this.album.getInsert(position));
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.replacePage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.deletePage = function(pageNumber){
	try{
		var positionObject = this.getInsertPositionInAlbumFromPage(pageNumber)
		var position = positionObject.insertPosition;
		pageNumber = positionObject.insertPageNumber;
		if ( position || position == 0 ){
			var deletedInsert = this.album.deleteInsert(position)
			this.fillPages();
			return deletedInsert;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.deletePage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.movePage = function(fromPageNumber, toPageNumber, replace){
	try{
		var insert = this.getInsertFromPage(fromPageNumber);

		var fromPosition = this.getInsertPositionInAlbumFromPage(fromPageNumber).insertPosition;
		var toPosition = this.getInsertPositionInAlbumFromPage(toPageNumber).insertPosition;
		this.album.moveInsert(fromPosition,toPosition,replace);
		this.fillPages();

		var newPageNumber = this.findInsert(insert);

		return { 'newPageNumber': newPageNumber, 'fromPosition': fromPosition, 'toPosition': toPosition };
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.movePage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.moveInsert = function(fromPosition, toPosition, replace){
	try{
		this.album.moveInsert(fromPosition,toPosition,replace);
		this.fillPages();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.moveInsert]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setUserDataForPage = function(pageNumber,dataName, dataValue){
	try{
		(this.pages[pageNumber]).userData[dataName] = dataValue;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setUserDataForPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getUserDataForPage = function(pageNumber){
	try{
		return (this.pages[pageNumber]).userData;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getUserDataForPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.findUserData = function(insert, page){
	try{
		if ( this.pages.length == 0 ){
			return new Object();
		}
		if ( insert == this.ODDSIDEOFPANO || insert == this.GHOSTPAGE )
			return null;
		if ( page != null ){
			return this.pages[page].userData;
		}
		for ( var i = 1; i< this.pages.length ; i++)
			if ( this.pages[i].pageInfo === insert )
				return this.pages[i].userData;
		return new Object();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.findUserData]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.findInsert = function(insert){
	try{
		if (typeof(insert) != "object")
			return null;
		for ( var currentPage = 1; currentPage< this.pages.length ; currentPage++){
			if ( this.getInsertFromPage(currentPage) === insert ){
				return currentPage;
			}
		}
		return null;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.findInsert]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.fillPages = function(){
	try{
		var newPages = new Array();
		newPages.push({pageInfo: this.INSIDECOVER, insertPosition: null, userData: this.findUserData(this.INSIDECOVER,0)}); // the inside cover
		var inserts = this.album.getInserts();
		var evenPosition = false;
		for ( var i = 0; i < this.album.getInsertQuantity(); ){
			if ( ( evenPosition && inserts[i].canBeOnEven() ) || ( !evenPosition && inserts[i].canBeOnOdd() ) ){
				if ( inserts[i].isPano() ){
					newPages.push({pageInfo: inserts[i], insertPosition: i,userData: this.findUserData(inserts[i++])});
					newPages.push({pageInfo: this.ODDSIDEOFPANO, insertPosition: null, userData: this.findUserData(this.ODDSIDEOFPANO)}); // the odd side of the pano
					evenPosition = !evenPosition;
				}
				else
					newPages.push({pageInfo: inserts[i], insertPosition: i, userData: this.findUserData(inserts[i++])});
			}
			else
				newPages.push({pageInfo: this.GHOSTPAGE, insertPosition: null, userData: this.findUserData(this.GHOSTPAGE)}); // the ghost page before a pano
			evenPosition = !evenPosition;
		}
		if ( evenPosition )
			newPages.push({pageInfo: this.GHOSTPAGE, insertPosition: null, userData: this.findUserData(this.GHOSTPAGE)}); // ghost page before last inside cover
		newPages.push({pageInfo: this.INSIDECOVER, insertPosition: null, userData: this.findUserData(this.INSIDECOVER, this.pages.length - 1)}); // the inside cover
		this.pages = newPages;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.fillPages]</B> ' + e + '</FONT>' ); return false; }
}

													/** Opening Operations **/
Fulfiller.prototype.insertOpening = function(pageNumber, string){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			openingId = insert.insertOpening(string);
			insert.resetTimestamp();
			return openingId;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.insertOpening]</B> ' + e + '</FONT>' ); return false; }

}

Fulfiller.prototype.deleteOpening = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.deleteOpening(openingId);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.deleteOpening]</B> ' + e + '</FONT>' ); return false; }

}

Fulfiller.prototype.rotateOpening = function(pageNumber, openingId, angle){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).assignRotation(angle);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.rotateOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getRotationOpening = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return opening.getRotation();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getRotationOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setPositionOpening = function(pageNumber, openingId, newPosition){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).changePosition(newPosition);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setPositionOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getPositionOpening = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return { x: opening.getPositionX(), y: opening.getPositionY() };
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPositionOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setDimensionsOpening = function(pageNumber, openingId, newDimensions){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).changeDimensions(newDimensions);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setDimensionsOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getDimensionsOpening = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return { width: opening.getWidth(), height: opening.getHeight() };
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getDimensionsOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.changeShapeOpening = function(pageNumber, openingId, newShape){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).changeShape(newShape);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.changeShapeOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.changeBorderOpening = function(pageNumber, openingId, borderId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).assignBorderType(borderId);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.changeBorderOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getBorderOpening = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return opening.getBorderType();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getBorderOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getShapeOpening = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return opening.getShape();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getShapeOpening]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.pageHasBorder = function(pageNumber, borderId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( !insert )
			return false;
		return insert.hasBorder(borderId);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.pageHasBorder]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setOpeningOpacity = function(pageNumber, openingId, opacity){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).setOpacity(opacity);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpacity]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningOpacity = function(pageNumber, openingId){
	try{
		var opening = this.getOpeningFromPageAndId(pageNumber,openingId);
		if ( opening ){
			return opening.getOpacity();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpacity]</B> ' + e + '</FONT>' ); return false; }
}



Fulfiller.prototype.setOpeningCaption = function(pageNumber, openingId, caption){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setCaption(caption);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningCaption]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningCaption = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getCaption();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningCaption]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setOpeningFontFace = function(pageNumber, openingId, fontFace){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontFace(fontFace);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontFace]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontFace = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontFace();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontFace]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setOpeningFontSize = function(pageNumber, openingId, fontSize){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontSize(fontSize);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontSize]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontSize = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontSize();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontSize]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setOpeningFontColor = function(pageNumber, openingId, fontColor){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontColor(fontColor);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontColor]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontColor = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontColor();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontColor]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setOpeningFontBackgroundColor = function(pageNumber, openingId, fontColor){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setBackgroundColor(fontColor);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontBackgroundColor]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setOpeningFontUnderline = function(pageNumber, openingId, fontUnderline){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontUnderline(fontUnderline);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontUnderline]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontUnderline = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontUnderline();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontUnderline]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setOpeningFontAlign = function(pageNumber, openingId, fontAlign){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontAlign(fontAlign);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontAlign]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontAlign = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontAlign();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontAlign]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setOpeningFontEffectType = function(pageNumber, openingId, fontEffectType){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontEffectType(fontEffectType);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontEffectType]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontEffectType = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontEffectType();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontEffectType]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.setOpeningFontEffectColor = function(pageNumber, openingId, fontEffectColor){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontEffectColor(fontEffectColor);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontEffectColor]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontEffectColor = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontEffectColor();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontEffectColor]</B> ' + e + '</FONT>' ); return false; }
}



Fulfiller.prototype.setOpeningFontEffectStrokeWeight = function(pageNumber, openingId, fontEffectStrokeWeight){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.getOpeningById(openingId).getText().setFontEffectStrokeWeight(fontEffectStrokeWeight);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setOpeningFontEffectStrokeWeight]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningFontEffectStrokeWeight = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			textData = insert.getOpeningById(openingId).getText();
			if ( textData )
				return textData.getFontEffectStrokeWeight();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningFontEffectStrokeWeight]</B> ' + e + '</FONT>' ); return false; }
}









Fulfiller.prototype.bringOpeningForward = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.resetTimestamp();
			return insert.bringOpeningForward(openingId);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.bringOpeningForward]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.sendOpeningBackward = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.resetTimestamp();
			return insert.sendOpeningBackward(openingId);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.sendOpeningBackward]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.bringOpeningtoFront = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.resetTimestamp();
			return insert.bringOpeningtoFront(openingId);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.bringOpeningtoFront]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.sendOpeningtoBack = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.resetTimestamp();
			return insert.sendOpeningtoBack(openingId);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.sendOpeningtoBack]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.getOpeningsZIndex = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			return insert.getAllZIndexes();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getOpeningsZIndex]</B> ' + e + '</FONT>' ); return false; }
}

													/** Image Operations **/

Fulfiller.prototype.assignOpeningImage = function(pageNumber, openingId, image){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId)).assignImage(image);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.assignOpeningImage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.removeOpeningImage = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			var RemovedScannum = (insert.getOpeningById(openingId)).removeImage();
			insert.resetTimestamp();
			return RemovedScannum;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.assignOpeningImage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getBackgroundColor = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			if ( insert.backgroundIsColor() )
				return insert.getColor();
			return false;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.rotateInsertClockWise]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.assignBackgroundImage = function(pageNumber, image){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.assignBackgroundImage(image);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.assignBackgroundImage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.removeBackgroundImage = function(pageNumber, newColor){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			var RemovedScannum = insert.removeBackgroundImage(newColor);
			insert.resetTimestamp();
			return RemovedScannum;
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.assignBackgroundImage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.cropImageInOpening = function(pageNumber, openingId, zoom_factor, crop_x, crop_y){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId).getImage()).cropImg(zoom_factor, crop_x, crop_y);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.cropImageInOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.cropImageInBackground = function(pageNumber, zoom_factor, crop_x, crop_y){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getBackgroundImage()).cropImg(zoom_factor, crop_x, crop_y);
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.cropImageInBackground]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.flopImageInOpening = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId).getImage()).flopImg();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.flopImageInOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.flopImageInBackground = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getBackgroundImage()).flopImg();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.flopImageInBackground]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.sepiaImageInOpening = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId).getImage()).sepia();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.sepiaImageInOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.sepiaImageInInsert = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getBackgroundImage()).sepia();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.sepiaImageInInsert]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.desaturateImageInOpening = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId).getImage()).desaturate();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.desaturateImageInOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.desaturateImageInInsert = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getBackgroundImage()).desaturate();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.desaturateImageInInsert]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.resetToningForImageInOpening = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getOpeningById(openingId).getImage()).resetToning();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.resetToningForImageInOpening]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.resetToningForImageInInsert = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			(insert.getBackgroundImage()).resetToning();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.resetToningForImageInInsert]</B> ' + e + '</FONT>' ); return false; }
}

													/** Inserts Operation **/

Fulfiller.prototype.rotateInsertClockWise = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.rotateClockWise();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.rotateInsertClockWise]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.rotateInsertCounterClockWise = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.rotateCounterClockWise();
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.rotateInsertCounterClockWise]</B> ' + e + '</FONT>' ); return false; }
}



Fulfiller.prototype.flipInsert = function(pageNumber, flipOrientation){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			var openings = insert.getOpenings();
			for ( var i = 0; i < openings.length; i++){
				if (flipOrientation == 'horizontal') {
					openings[i].setPositionX(insert.getWidth() - openings[i].getPositionX());
				}
				else if (flipOrientation == 'vertical') {
					openings[i].setPositionY(insert.getHeight() - openings[i].getPositionY());
				}
			}
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.flipInsert]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getMaskTransparency = function(pageNumber, openingId){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			if (openingId != null) {
				return (insert.getOpeningById(openingId)).getMaskTransparency();
			}
			else {
				return insert.getMaskTransparency();
			}
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getMaskTransparency]</B> ' + e + '</FONT>' ); return false; }
}

Fulfiller.prototype.setMaskTransparency = function(pageNumber, openingId, maskTransparency){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			if (openingId != null) {
				(insert.getOpeningById(openingId)).setMaskTransparency(maskTransparency);
			}
			else {
				insert.setMaskTransparency(maskTransparency);
			}
			insert.resetTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setMaskTransparency]</B> ' + e + '</FONT>' ); return false; }
}


													/** PIS Drawing Operations **/

Fulfiller.prototype.getPISCommandForPage = function(pageNumber){
	try{
		if ( this.pageIsFirstInsideCover(pageNumber) ){
			var url = this.getInsideCoverPISCommand( this.frontInsideCoverPath, this.album.getInsertSize() );
		}
		else if ( this.pageIsLastInsideCover(pageNumber) ){
			var url = this.getInsideCoverPISCommand( this.backInsideCoverPath, this.album.getInsertSize() );
		}
		else if ( this.pageIsGhostPage(pageNumber) ){
			var url = this.getGhostPagePISCommand( this.album.getInsertSize() );
		}
		else{
			var insert = this.getInsertFromPage(pageNumber);
			var url = this.getInsertPISCommand(insert);
		}
		return url;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPISCommandForPage]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getInsertPISCommand = function(insert){
	try{
		var insertPIS = new PIS();
		if ( insert.backgroundIsColor() ){
			insertPIS.create(insert.getColor(),this.unitsConvWork.toPixels(insert.getWidth()),this.unitsConvWork.toPixels(insert.getHeight()));
		}
		if ( insert.backgroundIsImage() ){
			insertPIS = this.getImagePIS( insert.getBackgroundImage(), this.unitsConvWork.toPixels(insert.getWidth()), this.unitsConvWork.toPixels(insert.getHeight()))
			var maskPIS = new PIS();
			var maskT = "FF.FF.FF." + percentToHexa(insert.getMaskTransparency());
			maskPIS.create(maskT,this.unitsConvWork.toPixels(insert.getWidth()),this.unitsConvWork.toPixels(insert.getHeight()));
			insertPIS.compose(maskPIS,"mask", true);
		}

		var openings = insert.getOpenings();
		for ( var i = 0; i < openings.length; i++){
			var openingPIS = this.getOpeningPIS(openings[i]);

			//To adjust differences between PIS and Bounding box
			var adjustment = 0
			if ( ( openings[i].shapeIsOval() || openings[i].shapeIsDiamond() ) && openings[i].hasSignificantRotation() )
				adjustment = 0.0;
			//To adjust differences between PIS and Bounding box

			var x0 = this.unitsConvWork.toPixels( /*openings[i].getTotalPositionX0()*/  openings[i].getPositionX() - adjustment) - openingPIS.getXPadding();
			var y0 = this.unitsConvWork.toPixels(/*openings[i].getTotalPositionY0()*/   openings[i].getPositionY() - adjustment) - openingPIS.getYPadding();

			insertPIS.compose(openingPIS, "op"+(i+1), false, x0, y0, null, "center");
		}
		insertPIS.consolidateCompos();
		// If the working resolution is different from the display resolution, resize to the display resolution
		if (this.unitsConvWork.getFactor() != this.unitsConv.getFactor()) {
			insertPIS.prop(this.unitsConv.toPixels(insert.getWidth()),this.unitsConv.toPixels(insert.getHeight()));
		}
		var visualLinesColor = "FF.71.08.00";
		if ( insert.isPano() )
			insertPIS.drawLine(this.unitsConv.toPixels(insert.getWidth()/2), 0, this.unitsConv.toPixels(insert.getWidth()/2), this.unitsConv.toPixels(insert.getHeight()), visualLinesColor);
		if ( this.gutter != null )
			insertPIS.drawRect(this.unitsConv.toPixels(this.gutter), this.unitsConv.toPixels(this.gutter), this.unitsConv.toPixels(insert.getWidth()-this.gutter), this.unitsConv.toPixels(insert.getHeight()-this.gutter), visualLinesColor, null);
		return insertPIS.getPISCommand();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getInsertPISCommand]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getInsideCoverPISCommand = function(imagePath, size){
	try{
		var imageUrl = imagePath;
		var insertPIS = new PIS();
		insertPIS.load(imageUrl,true);
		insertPIS.zoom(this.unitsConv.toPixels(size.width),this.unitsConv.toPixels(size.height));
		return insertPIS.getPISCommand();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getInsideCoverPISCommand]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getGhostPagePISCommand = function(size){
	try{
		var imageUrl = this.ghostPagePath;
		var insertPIS = new PIS();
		insertPIS.load(imageUrl,true);
		insertPIS.prop(this.unitsConv.toPixels(size.width),this.unitsConv.toPixels(size.height));
		insertPIS.crop(this.unitsConv.toPixels(size.width),this.unitsConv.toPixels(size.height),true);
		return insertPIS.getPISCommand();
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getGhostPagePISCommand]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getOpeningPIS = function(opening){
	try{
		// The 'true' parameter forces rounding up. Sizes are rounded up but positions are not; this is to compensate for precision problems
		// on the web view's low resolution (which aren't noticeable during fulfillment at 3000x3000). Check bug 7158 for more information
		var width = parseInt(this.unitsConvWork.toPixels(opening.getWidth(), 0), 10);
		var height = parseInt(this.unitsConvWork.toPixels(opening.getHeight(), 0), 10);

		var borderType = opening.getBorderType();
		
		if ( opening.hasImage() )
			var image = opening.getImage();
		else
			var image = this.openingPath;
		
		var borderWidth;
		var borderHeight;
		if( opening.getCalculateBorderFromImage() && opening.hasImage() && image.getPictureWidth() && image.getPictureHeight() ){
			borderWidth = image.getPictureWidth();
			borderHeight = image.getPictureHeight();
		}
		else{
			borderWidth = opening.getWidth();
			borderHeight = opening.getHeight();
		}

		if( opening.needsInversion() )
		{
			var aux = borderHeight;
			borderHeight = borderWidth;
			borderWidth = aux;
		}			
		
		var borderObject = this.borderManager.getBorderObject( borderType, borderWidth, borderHeight);
		
		if (opening.isCaption() == true) {
			var imagePIS = this.getCaptionPIS( opening, width, height);
		}
		else if( opening.getCalculateBorderFromImage() && opening.hasImage() && image.getPictureWidth() && image.getPictureHeight() ){
			var imagePIS = this.getImagePIS( image, borderWidth, borderHeight, !opening.isRestrictive() );
		}
		else {
			var imagePIS = this.getImagePIS( image, width, height, !opening.isRestrictive() );
		}
		
		
		var openingShape = new PIS();

		var lineWidth = this.unitsConvWork.toPixels(borderObject.getLineWidth());

		// the different treatment for the rectangular shaped openins had to be
		// added to prevent artifacts that were randomly appearing.
		// the calculations for the first drawOpening should be fixed and then
		// the checks for rectangular shaped openings could be removed

		if ( !borderObject.isFramed() && !opening.shapeIsRectangular() )
			opening.setMarginUsed(borderObject.getLineWidth() * 3);
		else
			opening.setMarginUsed(0);
		var margin = this.unitsConvWork.toPixels(opening.getMarginUsed());

		if ( (opening.getOpacity() != 100 || !borderObject.isFramed()) && opening.isCaption() != true && opening.isRestrictive() ){
			var openingOpacity = "00.00.00." + ( percentToHexa( 100 - opening.getOpacity() ) );
			var creatColor = ( !opening.shapeIsRectangular() ? "transparent" : openingOpacity )
			openingShape.create( creatColor, width + 2*margin, height + 2*margin );
			var openingOpacity = "00.00.00." + ( percentToHexa( 100 - opening.getOpacity() ) );
			if ( !opening.shapeIsRectangular() )
				openingShape.drawOpening(width, height, opening.getShape(), "transparent", openingOpacity, lineWidth, margin);
			var openingPIS = openingShape.compose(imagePIS, "img", true, null, null, "add");
			openingPIS.consolidateCompos();
		}
		else
			var openingPIS = imagePIS;
		if ( opening.getMaskTransparency() != 100 ){
			var maskPIS = new PIS();
			var maskT = "FF.FF.FF." + percentToHexa(opening.getMaskTransparency());
			maskPIS.create( "transparent", width + 2*margin, height + 2*margin );
			maskPIS.drawOpening(width, height, opening.getShape(), "transparent", maskT, lineWidth, margin);
			openingPIS.compose(maskPIS,'op'+opening.getId()+'mask', true);
			openingPIS.consolidateCompos();
		}

		if ( borderObject.isVisible() ){
			if ( borderObject.isFramed() )
				openingPIS.framegoo( ( this.bordersPath + borderObject.getBorderFile() ), width, height);
			else if ( opening.isRestrictive() )
				openingPIS.drawOpening(width, height, opening.getShape(), borderObject.getColor(), null, lineWidth, margin);
			else
				openingPIS.border( borderObject.getColor(), lineWidth )
		}
		if ( opening.hasRotation() )
			openingPIS.rotate(opening.getRotation(), "transparent");

		if ( this.needsSafetyMargin() ) //Apply safety margin
		{
			openingPIS.setSafetyMargin( this.unitsConvWork.toPixels( data.safetyMargin.width ));
			openingPIS.applySafetyMargin( height, width, opening.getRotation(), opening.getShape(), '00.00.00.0' );
		}
		else {
			openingPIS.setSafetyMargin(0, 0);
		}

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


Fulfiller.prototype.getImagePIS = function(image, finalWidth, finalHeight, ignoreSizeRestrictions){
	try{
		var imagePIS = new PIS();
		if (typeof(image) == "string"){
			imagePIS.load(image, true);
			imagePIS.prop(finalWidth, finalHeight);
			imagePIS.crop(finalWidth, finalHeight,true);
			return imagePIS;
		}
		
		if ( image.isAutoHistory() )
		{
			imagePIS.load(image.getPath(),true);
		}
		else
		{
			imagePIS.load(image.getPath(),false);
			imagePIS.addPISCommand(image.getHistoryString());
		}
		if ( image.isCropped() ){
			imagePIS.imageCropping(finalWidth,finalHeight,image.getZoomFactor(),image.getCropX(),image.getCropY());
		}
		else{
			imagePIS.prop(finalWidth, finalHeight, ignoreSizeRestrictions);
			if ( !ignoreSizeRestrictions )
				imagePIS.crop(finalWidth, finalHeight,true);
		}
		return imagePIS;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getImagePIS]</B> ' + e + '</FONT>' ); return false; }
}


Fulfiller.prototype.getCaptionPIS = function(opening, finalWidth, finalHeight){
	try{
		textData = opening.getText();
		var imagePIS = new PIS();
		imagePIS.create(textData.getBackgroundColor(), this.unitsConvWork.toPixels(opening.getWidth()), this.unitsConvWork.toPixels(opening.getHeight()));
		if (textData.getCaption() != '' && textData.getCaption() != null) {
			if (this.useAnnotateExtendedForPIS == true) {
				iSideSize = (this.album.getWidth() > this.album.getHeight() ? this.album.getWidth() : this.album.getHeight());
				fontDpi = parseInt((this.unitsConvWork.toPixels(iSideSize) / iSideSize), 10);
				imagePIS.annoe(textData.getCaption(), opening.getWidth(), opening.getHeight(), parseInt(textData.getFontSize(), 10), textData.getFontFace(), textData.getFontColor(), textData.getFontUnderline(), textData.getFontAlign(), fontDpi, parseInt(((opening.getOpacity()*255)/100), 10), textData.getFontEffectType(), textData.getFontEffectColor(), textData.getFontEffectStrokeWeight(), this.metricsDpi);
			}
			else {
				imagePIS.annotate(textData.getCaption(), (Math.round(this.unitsConvWork.relPoints(textData.getFontSize()) * 100) / 100), textData.getFontFace(), textData.getFontColor());
			}
		}
		return imagePIS;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getCaptionPIS]</B> ' + e + '</FONT>' ); return false; }
}


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

}

Fulfiller.prototype.needsSafetyMargin = function(){
	try{
		return (!this.openingMovingAllowed() && this.album.getNeedsSafetyMargin());	//** change this when getting album type (flush/matted) from backend
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.needsSafetyMargin]</B> ' + e + '</FONT>' ); return false; }

}

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

Fulfiller.prototype.getPageTimestamp = function(pageNumber){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			return insert.getTimestamp();
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.getPageTimestamp]</B> ' + e + '</FONT>' ); return false; }
}

// Used to restore a timestamp when using Undo/Redo
Fulfiller.prototype.setPageTimestamp = function(pageNumber, timestamp){
	try{
		var insert = this.getInsertFromPage(pageNumber);
		if ( insert ){
			insert.setTimestamp(timestamp);
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Fulfiller.setPageTimestamp]</B> ' + e + '</FONT>' ); return false; }
}

													/*********  Page *********/

function Page(pageNumber, insert){
	try{
		this.setInsert(insert);
		this.pageNumber = pageNumber;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Page]</B> ' + e + '</FONT>' ); return false; }
}


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


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


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


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


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


Page.prototype.setValues = function( size, userData, openings) {
	try{
		this.size = size;
		this.userData = userData;
		if ( openings ){
			this.openingData = new Array();
			for ( var i = 0; i < openings.length ; i++){
				this.openingData.push({x: openings[i].getBoundingBoxX0(), y: openings[i].getBoundingBoxY0(), w: openings[i].getBoundingBoxWidth(), h: openings[i].getBoundingBoxHeight(), id: openings[i].getId() });
			}
		}
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[Page.setValues]</B> ' + e + '</FONT>' ); return false; }
}


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

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


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


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


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


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

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



GhostPage.prototype = new Page;
GhostPage.prototype.constructor = GhostPage;
GhostPage.superclass = Page.prototype;

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


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


InsideCoverPage.prototype = new Page;
InsideCoverPage.prototype.constructor = InsideCoverPage;
InsideCoverPage.superclass = Page.prototype;

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

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


PanoPage.prototype = new Page;
PanoPage.prototype.constructor = PanoPage;
PanoPage.superclass = Page.prototype;

function PanoPage(pageNumber, insert){
	try{
		this.setInsert(insert);
		this.pageNumber = pageNumber;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[PanoPage]</B> ' + e + '</FONT>' ); return false; }
}

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

													/*********  UnitsConverter *********/

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

// ie: factor = 300/12 // 12 in * 300/12 = 300 px



UnitsConverter.prototype.relPoints = function(points){
	try{
		//1 inches = 72 PostScript point
		return (points / 96) * this.factor;
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[UnitsConverter.toPixels]</B> ' + e + '</FONT>' ); return false; }
}


UnitsConverter.prototype.toPixels = function(inches, roundUp){
	try{
		return Math.floor(inches * this.factor);
		if (roundUp == true)
			return Math.ceil(inches * this.factor);
		else
			return Math.round(inches * this.factor);
	}
	catch(e){ dbg.add ( '<FONT COLOR="red"><B>[UnitsConverter.toPixels]</B> ' + e + '</FONT>' ); return false; }
}

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

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

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

UnitsConverter.prototype.getFactor = function() {
	return this.factor;
}

