/*
 * ==================================================================================================
 * This file is to be used by photoUploadTool clients.
 * ==================================================================================================
 */
var ProgressControl  = Class.create();
ProgressControl.prototype = {
	initialize: function() {
	},
	baseInitialize: function() {	
	},
	setPercentage: function(pPercentage) {
		throw "Must implement setPercentage()";
	},
	setError: function(pMessage) {
		throw "Must implement setError()";
	}
}

var ProgressManager = Class.create();
ProgressManager.prototype = {
	initialize: function() {
		this.baseInitialize();
	},
	baseInitialize: function() {
		this.mControls = [];
	},
	register: function(pControl) {
		this.mControls[pControl.getID()] = pControl;		
	},
	setProgress: function(pID, pFileName, pPercentage) {
		var oControl = this.mControls[pID];
		if (oControl) {
			oControl.setPercentage(pPercentage);
		}
	},
	setError: function(pID, pFileName, pMessage) {
		var oControl = this.mControls[pID];
		if (oControl) {
			oControl.setError(pMessage);
		}
	}
}

ProgressManager.getInstance = function() {
	if (this.mInstance == null) {
		this.mInstance = new ProgressManager();
	}
	return this.mInstance;
}

var ProgressMonitorListener = Class.create();
ProgressMonitorListener.prototype = {
	onMonitorStateChange: function(pState, pLastReports) {
		throw "Must implement onStateChange()";
	}
}

var ProgressMonitor = Class.create();
ProgressMonitor.Constants = {
	STATE_WAITINGFOR_REPORTS:'S0',
	STATE_CHECKING_REPORTS:'S1',
	STATE_NOMORE_REPORTS:'TS',
	STATE_STOPPED:'TS1',
	MAX_WAITFOR_REPORTS:2000,
	EVENT_STATECHANGED:'onMonitorStateChange'
}

ProgressMonitor.prototype = {
	initialize: function(pProgressManager, pJobID) {
		this.mProgressManager = pProgressManager;
		this.mJobID = pJobID;
		this.mObservers = [];
		this.mLastReports = null;
		this.mStopped = false;
		this.mTimer = null;
	},
	addObserver: function(pObserver) {
		this.mObservers.push(pObserver);
	},
	removeObserver: function(pObserver) {
		for(var i = 0; i < this.observers.length; i++) {
      		if(this.mObservers[i] == pObserver) {
        		this.mObservers.splice(i,1);
        	}
        }
	},
	notify: function(eventName) {
		for(var i = 0; i < this.mObservers.length; i++) {
			for (var j = 0; j < this.mObservers[i].length; j++) {
				alert(this.mObservers[i][j].toString());	
			}
			if (this.mObservers[i][eventName] && typeof this.mObservers[i][eventName] == 'function') {
      			if (eventName == ProgressMonitor.Constants.EVENT_STATECHANGED) {
	      			this.mObservers[i][eventName](this.mState, this.mLastReports);
	      		}
      		}
      	}
	},
	getStat: function() {
		return this.mState;
	},
	start: function() {
		this.mState = ProgressMonitor.Constants.STATE_WAITINGFOR_REPORTS;
		this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
		this.mNbWait = 1;
		this.mCompleted = -1;
		this.mStopped = false;
		this.mTimer = setTimeout(this.update.bind(this), 1*500);
	},
	stop: function() {
		this.mStopped = true;
	},
	update: function() {
		if (this.mState == ProgressMonitor.Constants.STATE_NOMORE_REPORTS || this.mState == ProgressMonitor.Constants.STATE_STOPPED) {
			clearTimeout(this.mTimer);
			return;
		}
		AjaxPhotoBO.getUploadReport(this.mJobID, this._getReportsCallBack.bind(this));
	},
	_updateControls: function(pReports) {
		if (!pReports) return;
		// update controls
		var oControl;
		this.mCompleted = 0;
		for (var i = 0; i < pReports.length; i++) {
			oReport = pReports[i];
			if (!oReport.HasError) {
				this.mProgressManager.setProgress(oReport.ID, oReport.FileName, oReport.Message);
				if (parseInt(oReport.Message) == 1) {					
					this.mCompleted++;
				}
			} else {
				this.mProgressManager.setError(oReport.ID, oReport.FileName, oReport.Message);
				this.mCompleted++;
			}
		}
	},
	_getReportsCallBack: function(pResponse) {
		var oReports = pResponse.value.Reports;
		// run state automate
		this.runStateAutomate(oReports);
		if (this.mState == ProgressMonitor.Constants.STATE_WAITINGFOR_REPORTS || !oReports) {
			// wait for reports
			this._incWait();
			this.mTimer = setTimeout(this.update.bind(this), 1*250);
		} else if (this.mState == ProgressMonitor.Constants.STATE_NOMORE_REPORTS) {
			this._updateControls(this.mLastReports);			
		} else if (oReports && oReports.length > 0 && this.mState == ProgressMonitor.Constants.STATE_CHECKING_REPORTS) {
			this.mLastReports = oReports;
			this._updateControls(oReports);
			this.mTimer = setTimeout(this.update.bind(this), 1*250);			
		}
	},
	_incWait: function() {
		this.mNbWait++;
	},
	runStateAutomate: function(pReports) {
		if (this.mStopped) {
			this.mState = ProgressMonitor.Constants.STATE_STOPPED;			
			this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
			return;
		}
		// check first if we exceed the max number of wait
		if (this.mNbWait > ProgressMonitor.Constants.MAX_WAITFOR_REPORTS) {
			// should sent a report to server
			this.mState = ProgressMonitor.Constants.STATE_NOMORE_REPORTS;
			this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
			return;
		}
		
		if (pReports && this.mCompleted == pReports.length) {
			this.mState = ProgressMonitor.Constants.STATE_NOMORE_REPORTS;
			this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
		}
		// go through automate
		if (this.mState == ProgressMonitor.Constants.STATE_WAITINGFOR_REPORTS && (!pReports || pReports.length == 0)) {
			return;
		} else if (pReports && pReports.length > 0 && this.mState == ProgressMonitor.Constants.STATE_WAITINGFOR_REPORTS) {
			this.mState = ProgressMonitor.Constants.STATE_CHECKING_REPORTS;
			this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
		} else if (pReports && pReports.length == 0 && this.mState == ProgressMonitor.Constants.STATE_CHECKING_REPORTS) {
			this.mState = ProgressMonitor.Constants.STATE_NOMORE_REPORTS;
			this.notify(ProgressMonitor.Constants.EVENT_STATECHANGED);
		}
	}
}

//
// This View uses table to display controls
//
var ProgressViewManager = Class.create();
Object.extend(ProgressViewManager.prototype, ProgressMonitorListener.prototype);
Object.extend(ProgressViewManager.prototype, {
	initialize: function(pContainer) {
		this.mContainer = $(pContainer);
		this.initContainer();
		this.mControls = [];
	},
	initContainer: function() {
		var oTable = document.createElement("table");
		oTable.border=0;
		this.mBody = document.createElement("tbody");
		oTable.appendChild(this.mBody);
		this.mContainer.appendChild(oTable);
	},
	addControl: function(pControl) {
		var oRow = document.createElement("tr");
		this.mBody.appendChild(oRow);
		var oCaption = document.createElement("td");
		oRow.appendChild(oCaption);
		oCaption.appendChild(pControl.getCaptionDrawElement());
		var oProgressBar = document.createElement("td");
		oRow.appendChild(oProgressBar);
		oProgressBar.appendChild(pControl.getBarDrawElement());
		
		this.mControls[pControl.getID()] = pControl;
	},
	removeControl: function(pControl) {
		var oControl = this.mControls[pControl.getID()];
		oControl.parentNode.removeChild(pControl);
		this.mControls[pControl.getID()] = null;
	},
	onMonitorStateChange: function(pState, pReports) {
		if (pState == ProgressMonitor.Constants.STATE_NOMORE_REPORTS) {
			try {
				this.mContainer.removeChild(this.mContainer.firstChild);
			} catch (e) {
				IgoUgoJS.Util.Log.LogManager.getLogger().fatal('Error while removing view' + e);
			}
		}
	}
});

var PhotoUploadProcessListener = Class.create();
Object.extend(PhotoUploadProcessListener.prototype, ProgressMonitorListener.prototype);
Object.extend(PhotoUploadProcessListener.prototype, {
	initialize: function(pOptions) {
		this.options = pOptions;
		this.onStart = pOptions.onStart;
		this.onFinish = pOptions.onFinish;
		this.onStopped = pOptions.onStopped;
	},
	onUploadStart: function() {
		if (this.onStart) {
			if (typeof(this.onStart) == 'function') {
				this.onStart();
			} else {
				eval(this.onStart);
			}
		}
	},
	onUploadFinish: function(pReports) {
		if (this.onFinish) {
			if (typeof(this.onFinish) == 'function') {
				this.onFinish(pReports);
			} else {
				eval(this.onFinish + '(' + pReports + ')');
			}
		}
	},
	onUploadStopped: function(pReports) {
		if (this.onStopped) {
			if (typeof(this.onStopped) == 'function') {
				this.onStopped(pReports);
			} else {
				eval(this.onStopped + '(' + pReports + ')');
			}
		}
	},
	// Implements ProgressMonitorListener
	onMonitorStateChange: function(pState, pReports) {
		if (pState == ProgressMonitor.Constants.STATE_WAITINGFOR_REPORTS) {
			this.onUploadStart();
			return;
		} else if (pState == ProgressMonitor.Constants.STATE_NOMORE_REPORTS) {
			this.onUploadFinish(pReports);
			return;
		} else if (pState == ProgressMonitor.Constants.STATE_STOPPED) {
			this.onUploadStopped(pReports);
			return;
		}
	}
});

// ################################
// Implementations
// ################################
var ProgressBarControl = Class.create();
Object.extend(Object.extend(ProgressBarControl.prototype, ProgressControl.prototype), {
	initialize: function(pID, pCaption, pWidth, pHeight, pVertical) {
		this.mID = pID;
		this.mOriginalWidth = pWidth;
		this.mOriginalHeight = pHeight;
		this.mIsVertical = pVertical;
		this.mCaption = pCaption;
		this.mHasError = false;
		// create UI element
		function createDrawElement(pHolder) {
			// Caption
			var oCaption = document.createElement("div");
			oCaption.innerHTML = pCaption;
			oCaption.className="pb_caption";
			// Canvas
			var oCanvas = document.createElement("div");
			oCanvas.className="pb_canvas";
			oCanvas.style.width=pWidth + 'px';
			oCanvas.style.height=pHeight + 'px';
			// Indicator
			var oIndicator = document.createElement("div");
			oIndicator.className = 'pb_indicator';
			oIndicator.style.width=pWidth + 'px';
			oIndicator.style.height=pHeight + 'px';
			oCanvas.appendChild(oIndicator);
			// Bar
			var oFFFix = document.createElement("div");
			oFFFix.className="pb_fffix";
			var oBar = document.createElement("div");
			oFFFix.appendChild(oBar);
			oBar.innerHTML="&nbsp;";
			oBar.className="pb_bar";
			oCanvas.appendChild(oFFFix);
			oBar.style.width=pWidth + 'px';
			oBar.style.height=pHeight + 'px';
			if (!pVertical) {
				oBar.style.left=-pWidth;
				oBar.style.top=0;
			} else {
				oBar.style.left=0;
				oBar.style.top=pHeight;
			}
			pHolder.mCaptionDrawElement = oCaption;
			pHolder.mBarDrawElement = oCanvas;
			pHolder.mMobileBarDrawElement = oBar;
			pHolder.mBarIndicator = oIndicator;
		}
		createDrawElement(this);
	},
	getID: function() {
		return this.mID;
	},
	getBarDrawElement: function() {
		return this.mBarDrawElement;
	},
	getCaptionDrawElement: function() {
		return this.mCaptionDrawElement;
	},
	setCaption: function(pCaption) {
		this.mCaption = pCaption;
		if (this.mCaptionDrawElement) {
			this.mCaptionDrawElement.innerHTML = pCaption;
		}
	},
	getCaption: function() {
		return this.mCaption
	},
	setPercentage: function(pPercentage) {
		if (pPercentage < 0) return;
		if (pPercentage > 1) return;
		this.mBarIndicator.innerHTML = Math.floor(pPercentage*100) + "%";
		if (!this.mIsVertical) {
			var oWidth = parseInt(this.mOriginalWidth);
			var oLeft = oWidth - (pPercentage * oWidth);
			this.mMobileBarDrawElement.style.left="" + (-oLeft) + "px";
		} else {
			var oHeight = this.mBarDrawElement.style.height.replace('px', '');
			var oTop = oHeight - (pPercentage * oHeight);
			this.mMobileBarDrawElement.style.top=oTop;
		}
	},
	setError: function(pMessage) {
		if (this.mHasError) return;
		this.mHasError = true;		
		function createError() {
			var oErrorContainer = document.createElement("div");
			oErrorContainer.className='error';
			oErrorContainer.innerHTML = pMessage;
			return oErrorContainer;
		}
		for (var i = 0; i < this.mBarDrawElement.childNodes.length; i++) {
			this.mBarDrawElement.removeChild(this.mBarDrawElement.childNodes[i]);
		}
		this.mBarDrawElement.appendChild(createError());
	}
});

var ProgressManagerView = Class.create();
Object.extend(ProgressManagerView.prototype, ProgressManager.prototype);
Object.extend(ProgressManagerView.prototype, {
	initialize: function(pViewManager) {
		this.baseInitialize();
		this.mViewManager = pViewManager;				
	},
	register: function(pControl) {
		this.mControls[pControl.getID()] = pControl;
		this.mViewManager.addControl(pControl);
	},
	setProgress: function(pID, pFileName, pPercentage) {
		var oControl = this.mControls[pID];
		if (!oControl) {
			oControl = new ProgressBarControl(pID, pFileName, 100, 25);
			this.register(oControl);
		}
		oControl.setPercentage(pPercentage);
	},
	setError: function(pID, pFileName, pMessage) {
		var oControl = this.mControls[pID];
		if (!oControl) {
			oControl = new ProgressBarControl(pID, pFileName, 100, 25);
			this.register(oControl);
		}
		oControl.setError(pMessage);
	}
});

IgoUgoJS.Load('/guidetools/photoUploadTool.js');