
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
*  Copyright 2008 Adobe Systems Incorporated
*  All Rights Reserved.
*
* NOTICE:  All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any.  The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and may be covered by U.S. and Foreign Patents,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
*
* $DateTime: 2008/04/10 13:35:00 $
*
* Adobe Output Module 2.0
*
* MediaGallery Originally Written by Quality Process Incorporated, Enhanced by
* Adobe System China. Contact Sheet written by Adobe System China.
* 
*
**************************************************************************/


/**
 *  Parameter "name" is the index used by the task-scheduling. The name of a task
 *  manager must be unique among all existing task manager instances, or be undefined.
 *  When it is undefined, the task manager does not perform tasks by scheduling but
 *  instead invokes the tasks in order directly. So an anonymous task manager means
 *  a synchronized task chain, as opposite a named task manager manages an
 *  asynchronized task chain.
 *
 *  TO DO: anonymous task managers doenot support retry tasks for now. So applications
 *         like Web Gallery that needs to retry a task can not use anonymous task manager.
 */
AOM.TaskManager = function(name, description)
{
	this.id = undefined;
	this.lastTask = undefined;
	this.state = undefined;
	this.tasks = new Array();
	this.lastTask = undefined; // see configureLastTask
	this.maxTaskCount = 0;
	
	if(name) {
		if(AOM.TaskManager.taskList[name] != undefined) {
			// bug 3047028, defer the destruction of dialog until here
			// because doing so on close causes crash
			AOM.TaskManager.taskList[name].progress = undefined;
			AOM.TaskManager.taskList[name].onStop = undefined;
		}
		AOM.TaskManager.taskList[name] = this;
		this.taskName = name;
		this.progress = new AOM.ProgressDialog();
		this.progress.title(description == undefined ? "..." : description);
		var that = this;
		this.progress.cancelAction(function () {that.killTasks();}, AOM.AMG.localize("$$$/MediaGallery/JavaScript/Cancel=Cancel"));
		this.showProgressOnStop = true;
		this.timer = new AOM.AmgTimer();
		this.interactive = true;
	}
}
AOM.TaskManager.taskList = {};
AOM.TaskManager.find = function (taskName)
{
	return AOM.TaskManager.taskList[taskName];
}
AOM.TaskManager.processTasks = function (taskName)
{
	var taskManager = this.find(taskName);
	if (taskManager != undefined)
		return taskManager.instanceProcessTask();
	return AOM.AMG.Log.writeError("AOM.TaskManager.processTasks - no taskManager for '"+taskName+"'");
}
AOM.TaskManager.resumeTasks = function (taskName)
{
	var taskManager = this.find(taskName);
	if (taskManager != undefined && taskManager.state != "stopped")
		taskManager.start();
}
AOM.TaskManager.prototype.configureOnStop = function (descriptionDetailButtonAction)
{
	// textButtonAction is an object with one or more of the following properties
	// description - progress dialog description
	// detail - progress dialog detail (function or text)
	// button - cancel button text
	// action - function called in button.onClick
	this.onStop = descriptionDetailButtonAction;
}
AOM.TaskManager.prototype.configureCancel = function (buttonAction)
{
	if(this.interactive != true) return;

	// textButtonAction is an object with one or more of the following properties
	// button - cancel button text
	// action - function called in button.onClick
	var that = this;
	var action = typeof buttonAction.action == "function" ? buttonAction.action : function () {;};
	var f = function ()
	{
		action();
		that.pause();
		that.killTasks();
		that.progress.close();
	}
	that.progress.cancelAction(f, buttonAction.button == undefined ?
        AOM.AMG.localize("$$$/MediaGallery/JavaScript/OK=OK") : buttonAction.button);
}
AOM.TaskManager.prototype.start = function ()
{
	if(this.interactive != true) {
		while(this.instanceProcessTask());
		return;
	}

	this.id = app.scheduleTask("AOM.TaskManager.processTasks(\""+this.taskName+"\")", 1, true);
	if (this.id != undefined)
		this.state = "running";
	else
	{
		this.state = undefined;
		AOM.AMG.Log.writeError("AOM.TaskManager.start - id is undefined");
	}
}
AOM.TaskManager.prototype.pause = function ()
{
	if (this.state != "paused")
	{
		app.cancelTask(this.id);
		this.state = "paused";
		//AOM.AMG.Log.writeLine("AOM.TaskManager.pause...");
	}
}
AOM.TaskManager.prototype.stop = function (descriptionDetailButtonAction)
{
	// there are three ways we can stop. one, use the descriptionDetailButtonAction
	// object provided. two, use a previously provided onStop object. three,
	// simply shut everything down.
	this.pause();
	this.killTasks();
	this.et();
	if (this.progress != undefined) {
	    var oldTitle = this.progress.title();
		this.progress.close();
	} else {
		oldTitle = "dialog";
	}
	
	this.progress = new AOM.ProgressDialog("dialog", false);
    this.progress.noMeter();
    this.progress.title(oldTitle);

	var that = this;	
	var configureProgress = function (descriptionDetailButtonAction)
	{
		that.progress.description(descriptionDetailButtonAction.description);
		if (descriptionDetailButtonAction.title != undefined)
			that.progress.title(descriptionDetailButtonAction.title);
		var detail = "";
		if (descriptionDetailButtonAction.detail != undefined)
		{
			if (typeof descriptionDetailButtonAction.detail == "function")
				detail = descriptionDetailButtonAction.detail();
			else
				detail = descriptionDetailButtonAction.detail;
		}
		that.progress.detail(detail, false);
		var f = function ()
		{
			that.progress.close();
			that.progress = undefined;
		}
		that.progress.cancelAction(f, descriptionDetailButtonAction.button == undefined ?
            AOM.AMG.localize("$$$/MediaGallery/JavaScript/OK=OK") : descriptionDetailButtonAction.button);
		if(that.showProgressOnStop)
		    that.progress.dialog.show();
		else
		    that.progress.dialog.close();
	
		if ((descriptionDetailButtonAction.action != undefined)
			&& (typeof descriptionDetailButtonAction.action == "function")) {
			//add scheduleTask to assure UI redraw normally. 
			AOM.TaskManager.onStopProcessFunction = descriptionDetailButtonAction.action;
			app.scheduleTask("AOM.TaskManager.onStopProcessFunction()", 0, false);
		}
		
	}
	if (descriptionDetailButtonAction != undefined)
		return configureProgress(descriptionDetailButtonAction);

	if (this.onStop != undefined)
		return configureProgress(this.onStop);
	
	this.progress.close();
	this.progress = undefined;
}
AOM.TaskManager.prototype.abort = function ()
{
	this.onStop = undefined;
	this.stop();
}
AOM.TaskManager.prototype.killTasks = function ()
{
	for (var i = 0; i < this.tasks.length; i++)
		this.tasks[i] = null;
	this.tasks.length = 0;
	this.state = "stopped";
}
AOM.TaskManager.prototype.et = function ()
{
	AOM.AMG.Log.writeNote("AOM.TaskManager/"+this.taskName+" et was " + this.timer.elapsed());
}
AOM.TaskManager.prototype.name = function ()
{
	return this.taskName;
}
AOM.TaskManager.prototype.instanceProcessTask = function ()
{
	if (this.tasks.length == 0) {
		if (this.taskName)
			return this.stop();
		else
			return false;
	}
	this.lastTask = null;
	this.lastTask = this.tasks.shift();
	try {
		this.lastTask();
	} catch(e) {
		if(this.taskName == undefined)
			throw e;
		
		// if we catch an error, display the error and stop task processing
		if (e.action != undefined) {
			switch (e.action) {
				case "stop":
					this.stop({title:e.title, description:e.description})
					return true;
				case "cancel":
					this.abort();
					return true;
				default:
					AOM.AMG.Log.writeError("instanceProcessTask - unknown action");
					break;
			}
		} else {
			AOM.AMG.Log.writeError("instanceProcessTask - caught \"" + e + "\"");
		}
		var errorMsg = "" + e;
		var description;
		if (errorMsg.indexOf("Out of disk") >= 0)
		{
			description = (e.description != undefined && e.description != "undefined") ? e.description : 
				AOM.AMG.localize("$$$/MediaGallery/JavaScript/notEnoughStorage=There is insufficient disk space to complete this operation.");
		}
		else
		{
			description = (e.description != undefined && e.description != "undefined") ? e.description : 
           		AOM.AMG.localize("$$$/MediaGallery/JavaScript/CreateGalleryUnkownReason=Gallery creation stopped due to unknown error - sorry.");
        }
		this.stop({description:description});
	}
	return true;
}
/*
AOM.TaskManager.prototype.configureNoMoreTasks = function (text, button)
{
	this.noMoreTasksText = (text == undefined ? "" : text);
	this.noMoreTasksButton = (button == undefined ?
        AOM.AMG.localize("$$$/MediaGallery/JavaScript/OK=OK") : button);
}
*/
AOM.TaskManager.prototype.startGroup = function (groupName, taskCount)
{
	if(this.taskName == undefined) return;

	// TODO - tally calls to addTask after a group is started
	// and not require the count
	this.progress.description(groupName, taskCount);
	this.progress.detail("", false);
}
AOM.TaskManager.prototype.addTask = function (task, description)
{
	// put a new task at the end of the task list
	if (typeof task != "function")
		return AOM.AMG.Log.writeError("AOM.TaskManager.addTask - task not a function");

	var that = this;
	if(this.taskName)
		this.tasks.push(function (){that.progress.detail(description);});

	this.tasks.push(task);
	//this.checkMaxTaskCount();
	//AOM.AMG.Log.writeLine("addTask - " + this.tasks.length + ", " + description);
}
AOM.TaskManager.prototype.insertTask = function (task, description, incProgress)
{
	// put a new task at the start of the task list
	if (typeof task != "function")
		return AOM.AMG.Log.writeError("AOM.TaskManager.insertTask - task not a function");
	var that = this;
	this.tasks.unshift(task);
	this.tasks.unshift(function (){that.progress.detail(description, incProgress);});
	//this.checkMaxTaskCount();
	//AOM.AMG.Log.writeLine("insertTask - " + this.tasks.length + ", " + description);
}
AOM.TaskManager.prototype.removeTask = function(count)
{
    var i;
    for(i = 0; i < count; ++i) {
        if(this.tasks.length == 0)
            break;
        this.tasks.shift();
        this.tasks.shift();
        ++(this.progress.dialog.progress.value);
    }
}
AOM.TaskManager.prototype.checkMaxTaskCount = function ()
{
	if (this.tasks.length > this.maxTaskCount)
	{
		this.maxTaskCount = this.tasks.length;
		AOM.AMG.Log.writeLine("new maxTaskCount is " + this.maxTaskCount);
	}
}
AOM.TaskManager.prototype.retryLastTask = function (description, delay)
{
	this.pause();
	this.insertTask(this.lastTask, description, false); // put the last task back in the queue
	app.scheduleTask("AOM.TaskManager.resumeTasks(\""+this.taskName+"\")", delay, false);
}

AOM.ProgressDialog = function(type, show)
{
	var width = 400; var height = 20;
	if(type == undefined)
	    this.dialog = new Window('palette', "");
	else
	    this.dialog = new Window(type, "");
    
    if (app.document != undefined) {
        var docWinWidth = app.document.width;
        var docWinHeight = app.document.height;
        var docWinPosition = app.document.position;
        var aOffsetX = docWinPosition.x + (docWinWidth - width) / 2.0;
        var aOffsetY = docWinPosition.y + (docWinHeight - height) / 2.0;
        this.dialog.location = [aOffsetX, aOffsetY];
    }
     
	this.dialog.orientation = "column";
	this.dialog.description = this.dialog.add("statictext", undefined, " ", {multiline: true});
	this.dialog.description.alignment = "fill";

	this.dialog.detail = this.dialog.add("statictext", undefined, " ", {multiline: true});
	this.dialog.detail.alignment = "fill";

	this.dialog.progress = this.dialog.add("progressbar");
	this.dialog.progress.value = 0;
	this.dialog.progress.maxvalue = 100;
	this.dialog.progress.preferredSize = {width:width, height:height};
	this.dialog.progress.alignment = "left";
	this.dialog.cancel = this.dialog.add("button");
	this.dialog.cancel.text = AOM.AMG.localize("$$$/MediaGallery/JavaScript/Cancel=Cancel");
	this.dialog.cancel.alignment = "right";
	this.dialog.cancel.active = true;
	
	var that = this;
	this.keyListener = function(key)
	{
		if (key.keyIdentifier == "Enter" || key.keyIdentifier == "U+001B")
		{
			if (that.dialog.cancel.onClick != undefined)
				that.dialog.cancel.onClick();
		}
	};
	this.dialog.cancel.addEventListener("keydown", this.keyListener);
	
	/*fixed #1718827, #1718784*/
	this.dialog.defaultElement = this.dialog.cancel;
	this.dialog.cancelElement = this.dialog.cancel;
	
	if(show == undefined || show) {
	    this.dialog.show();
	}

	/* Workaround: Manual call this function, to force bringing the Bridge Windown to front. */
	if (File.fs == "Windows") {
		app.bringToFront();
	}
}
AOM.ProgressDialog.prototype.title = function (title)
{
    if(title != undefined)
	    this.dialog.text = title;
	return this.dialog.text;
}
AOM.ProgressDialog.prototype.description = function (description, detailCount)
{
	this.dialog.description.text = description;
	this.dialog.progress.value = 0;
	this.dialog.progress.maxvalue = (detailCount != undefined) ? detailCount : 0;
}
AOM.ProgressDialog.prototype.detail = function (detail, incrementProgress)
{
	this.dialog.detail.text = detail != undefined ? detail : "";
	if (incrementProgress != false)
		this.dialog.progress.value++;
	if (this.dialog.progress.value > this.dialog.progress.maxvalue)
		this.dialog.progress.value = 0;
}
AOM.ProgressDialog.prototype.cancelAction = function (action, button)
{
	this.dialog.cancel.text = (button != undefined ? button :
        AOM.AMG.localize("$$$/MediaGallery/JavaScript/Cancel=Cancel"));
	if (typeof action == "function" || action == undefined)
	{
		this.dialog.cancel.onClick = action;
		this.dialog.onClose = action;
		return;
	}
	// not sure what action is...
	this.dialog.cancel.onClick = undefined;
	this.dialog.onClose = undefined;
	AOM.AMG.Log.writeError("AOM.ProgressDialog.cancelAction - action not a function");
}
AOM.ProgressDialog.prototype.close = function ()
{
	this.dialog.cancel.removeEventListener("keydown", this.keyListener);
	this.keyListener = undefined;
	this.dialog.onClose = undefined;
	this.dialog.close();
}
AOM.ProgressDialog.prototype.noMeter = function ()
{
	this.dialog.progress.visible = false;
}
