
/*************************************************************************
*
* 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.
* 
*
**************************************************************************/

AOM.AMG = {};

// a smattering of configuration items
AOM.AMG.trackDocId = false;
AOM.AMG.disableColorpickerGetErrorMessages = true;
AOM.AMG.placeLogFileInUserHome = false;
AOM.AMG.verbose = false;
// enable the next line to override the default color of the design window background
//AOM.AMG.designWindowBackground =  [0.2706, 0.2706, 0.2706];


AOM.AMG.localize = function (s)
{
	// TODO - Add code to set up proper locale translation file.
	// Note - This gets called for lots of strings that do not
	//		  need to be localized. It may be faster to test
	//		  for '$$$/' at the start of the line. Of course,
	//		  it may also be much faster to continue to let the
	//		  native localize figure it out for us...
	return AOM.localize(s); 
}
/*
 *  AMG 2.0: To Do:
 *    The following function is an adaption of AMG.eventHandler(). Since in 2.0 AMG
 *    is no longer an application exclusively owns an entire tabbed palette, the
 *    event handler need to be change.  
 */ 
AOM.AMG.switchTo = function(tabbedPalette, container, showCabinet)
{
    var f = new Folder(AOM.AMG.Paths.user);
    if (!f.exists) {
    	if (!f.create())
    		alert("Could not create workarea (" + f.fsName + ")");
    }

	var document = tabbedPalette.content.document;
	if (document.jsFuncs == undefined)
		document.jsFuncs = {};
	
	if (!AOM.AMG.userInputCreated(document))
	{
		var error = function (s) {return AOM.AMG.Log.writeError("AOM.AMG.switchTo - " + s);}
		
		var amgUserInput = new AOM.AmgUserInput();
		if (amgUserInput == undefined)
			return error("userInput is undefined");
		document.jsFuncs.amgUserInput = function () {return amgUserInput;}
	}
	if (AOM.AMG.ftpPresetUserInput == undefined) {
		var ftpPresetUserInput = new AOM.AmgFTPPresetUserInput();
		if (ftpPresetUserInput == undefined)
			return AOM.AMG.Log.writeError("AOM.AMG.switchTo - ftpPresetUserInput is undefined");
		
		AOM.AMG.ftpPresetUserInput = function() {
			return ftpPresetUserInput;
		}
	}

	/* 
     * AMG 2.0: Move the following section out of the if-branch.
     *          In 1.0, AMG has its own tabbed palette exclusively so all controls
     *          need to be created only once. In 2.0, AMG share one palette with
     *          Contact Sheet and the switch between the two is performed on user's
     *          demand.                    
	 */
	var amgDesignWindow = new AOM.AmgDesignWindow(tabbedPalette, container, showCabinet);
	if (amgDesignWindow == undefined)
		return error("designWindow is undefined");
	document.jsFuncs.designWindow = function () {return amgDesignWindow;}
}

// shortcuts to the document specific functions stored in the jsFuncs property
AOM.AMG.userInputCreated = function (document) {return (document.jsFuncs.amgUserInput != undefined);}

AOM.AMG.userInput = function (document) {
    if(document == undefined || !(document instanceof Document)) {
        alert("Undeterminable document: " + $.stack);
        document = app.document;
    }
    return document.jsFuncs.amgUserInput();
}
AOM.AMG.amgCreateGallerySection = function(document) {
	if(document == undefined || !(document instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		document = app.document;
	}
	return document.jsFuncs.amgCreateGallerySection;
}


/* Any hit to app.document in is now considered a bug. Shout it out! */
AOM.AMG.designWindow = function (doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	return doc.jsFuncs.designWindow();
}

AOM.AMG.updateStyleSection = function (doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.updateStyleSection();
}

AOM.AMG.updateImageOptionsSection = function (doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.updateImageOptionsSection();
}

AOM.AMG.updateCreateGallerySection = function (doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.updateCreateGallerySection();
}

AOM.AMG.updateCreateGalleryRadioButtons = function (hasSaveToDisk, doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.updateCreateGalleryRadioButtons(hasSaveToDisk);
}

AOM.AMG.loadStyles = function(doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.loadStyles();
}

AOM.AMG.userCustomizeStyle = function(id, doc) {
	if(doc == undefined || !(doc instanceof Document)) {
		alert("Undeterminable document: " + $.stack);
		doc = app.document;
	}
	doc.jsFuncs.userCustomizeStyle(id);
}


AOM.AMG.createGallery = function (data)
{
	if (!data.valid)
		return false;
	
	var galleryType = AOM.AmgPreviewSection.galleryType(data.document);
	var galleryCreator = new AOM.AmgGalleryCreator(galleryType, data, data.document.selections);
	
	/* Disallow task reentry */	
	if (galleryCreator.taskManager == undefined)
		return;

	if (galleryCreator.create())
		AOM.AmgUserInput.persist(data.document);
}


AOM.AMG.galleryMakerData = function(document)
{
    if(document == undefined || !(document instanceof Document)) {
    	alert("Undeterminable document: " + $.stack);
        document = app.document; 
    }
    return document.jsFuncs.amgGalleryMakerData;
}

AOM.AMG.userFolder = function(document)
{
	if(document == undefined || !(document instanceof Document))
		alert("Undeterminable document: " + $.stack);
    return AOM.AMG.Paths.user + "document" + document.id + "/";
}


AOM.AmgDesignWindow = function(tabbedPalette, container, showCabinet)
{
    /*
     * AMG 2.0: No longer has its own tabbed palette.
     *     
     * var tabbedPalette = AOM.AmgDesignWindow.create(document);
	 * tabbedPalette.visible = false; */
	tabbedPalette.content.populated = false;

	tabbedPalette.content.designGroup = container;
	tabbedPalette.content.maximumSize.height = 2000;
	tabbedPalette.content.designGroup.maximumSize.height = 2000;
	tabbedPalette.content.designGroup.document = tabbedPalette.content.document;
	
	AOM.AmgGalleryMaker.initialize();
	AOM.AmgDesignWindow.populate(tabbedPalette.content.designGroup, showCabinet);
	
	/* Work-around for #1840160 */
	AOM.AMG.userInput(tabbedPalette.content.document).window = tabbedPalette.content.window;
}
AOM.AmgDesignWindow.maximumSizeHeight = 10000;
AOM.AmgDesignWindow.create = function(document)
{
	var title = "Adobe Web Gallery";
	if (AOM.AMG.trackDocId)
		title += " ("+document.id+")";
	return AOM.AmgTabbedPalette.create(document, title, "amgDesign", "script", undefined);
}
AOM.AmgDesignWindow.populate = function (group, showCabinet)
{
	try
	{
		AOM.AMG.Tests.isGroup(group);
		group.orientation = "column";
		group.margins = 5;
		if (AOM.AMG.designWindowBackground != undefined)
		{
			var graphics = group.graphics;
			graphics.backgroundColor = graphics.newBrush(graphics.BrushType.SOLID_COLOR, this.background);
		}

		var currentUserInput = AOM.AMG.userInput(group.document);
		var template = currentUserInput.get("t_template");
		if (template == undefined)
		{
			template = AOM.AmgGalleryMaker.defaultTemplate();
			currentUserInput.set("t_template", template);
		}
		var styleOverwrite = false
		var style = currentUserInput.get("si_style");
		if (style == undefined)
		{
			style = AOM.AmgGalleryMaker.defaultStyle(group.document);
			currentUserInput.set("si_style", style);
			// if there was no style in the user input data store
			// make sure we the this styles values get loaded
			styleOverwrite = true; 
		}
		
		var foldableSet;
		if(!showCabinet) {
			foldableSet = new AOM.Accordion(group);
			foldableSet.document = group.document;
			
			//write foldableSet onClickFoldableSection callback
			foldableSet.onClickFoldableSection = function(openCloseButton) {
				var selectedSection = this.getSelectedSectionByName(openCloseButton.name);
				AOM.userInput(this.document).set("mgselectedSection", selectedSection);  
			}

			group.headSectionGroup = foldableSet.addSection(
                "group { \
				    orientation: 'column', \
				    alignment:['fill', 'top'],\
				    margins:0, spacing:0 \
			     }");
			
			var insertHeaderSection = function(resource) {
				return group.headSectionGroup.add(resource);
			}
			AOM.AmgTemplateSection.create(insertHeaderSection, template, group);
			AOM.AmgLoadStyleSection.create(insertHeaderSection, template, group);
			AOM.AmgPreviewSection.create(insertHeaderSection);
			
			group.layout = new AOM.AccordionLayoutManager(group);
		} else {
			
			group.headSectionGroup = group.add("group { \
				orientation: 'column', \
				alignment:['fill', 'top'],\
				margins:0, spacing:0 \
			}");
			foldableSet = new AOM.Cabinet(group);
			foldableSet.document = group.document;
			
			//set foldableSet onClickFoldableSection callback
			foldableSet.onClickFoldableSection  = function(openCloseButton) {
				AOM.userInput(this.document).set(openCloseButton.name, openCloseButton.isOpen);   
			}
			
			var insertHeaderSection = function(resource, name, title) {
				return group.headSectionGroup.add(resource);
			}
			
			AOM.AmgTemplateSection.create(insertHeaderSection, template, group);
			AOM.AmgLoadStyleSection.create(insertHeaderSection, template, group);
			AOM.AmgPreviewSection.create(insertHeaderSection);
			
			//add separate line, for new UI required.
			group.headSectionGroup.linegrp = group.headSectionGroup.add(
			"group{\
					alignment:['left', 'bottom'], margins:0, \
					line:StaticText{text:'', margins:0, alignment:['left', 'bottom'], preferredSize:[100, 1], themeType:'spline'},\
			}");
			
			group.layout = new AOM.CabinetLayoutManager(group);
		}
		
        group.document.jsFuncs.updateStyleSection = function() {
            foldableSet.removeAllFoldableSections();
        	var initialSectionName = AOM.AmgStyleSection.loadUi(foldableSet);
        	AOM.AmgCreateGallerySection.create(foldableSet);
		    AOM.AMG.updateCreateGallerySection(foldableSet.document);
		    AOM.theme(group.document).applyTheme(group, true);
		    
		    if(!showCabinet) {
				//set open/close status
				var selectedSection = AOM.userInput(group.document).get("mgselectedSection");
				if (selectedSection == undefined || selectedSection.length == 0) {
					group.selectedSection = initialSectionName;
				} else {
					if (AOM.Accordion.hasSectionName(group, selectedSection))  {
						group.selectedSection = selectedSection;
					} else {
						group.selectedSection = initialSectionName;
					}
				}
			}
        }
		
		AOM.AmgTemplateSection.currentTemplate(foldableSet.document, template);
		/* Was a bug since if "styleOverwrite" is true, the user input will be
		 * updated while the UI does not change accordingly.
		 *
		 * AOM.AmgGalleryMaker.loadStyle(template, style, styleOverwrite); */
		AOM.AmgStyleSection.currentStyle(group.document, style, styleOverwrite);
		AOM.AMG.updateCreateGallerySection(group.document);
		group.visible = true;
	}
	catch (e)
	{
		alert(e + ": " + $.stack);
		AOM.AMG.Log.writeError(e);
	}
}
AOM.AmgDesignWindow.defaultControlWidth = 260;
AOM.AmgDesignWindow.loadUi = function (uiItems, foldableSet)
{
	var add = function (item, group)
	{
		switch (item.type)
		{
		 case "checkbox":
			addCheckbox(item.attributes, group);
			break;
		 case "colorpicker":
			addColorpicker(item.attributes, group);
			break;
		 case "combobox":
			addCombobox(item.attributes, item.values, item.labels, group);
			break;
		 case "hrule":
			addHRule(item.attributes, group);
			break;
		 case "hslider":
			addHSlider(item.attributes, group);
			break;
		 case "label":
			addLabel(item.attributes, group);
			break;
		 case "spacer":
			//addSpacer(item.attributes, group);
			break;
		 case "textarea":
			addTextarea(item.attributes, group);
			break;
		 case "textinput":
			addTextinput(item.attributes, group);
			break;
		 default:
			AOM.AMG.Log.writeError("DesignWindow.loadUi - at default switch with " + item.type);
			break;
		}
	}
	var nop = function () {;} // nop function for attributes we do not support
	var addAttributes = function (attributes, attributeFunctions)
	{
		for (var a in attributes)
		{
			if (attributeFunctions[a] != undefined)
				attributeFunctions[a]();
			else
				AOM.AMG.Log.writeError(attributeFunctions._caller + " - unhandled attribute '" + a + "'");
		}
	}
	var addCheckbox = function (attributes, group)
	{
		var control = group.add("checkbox");
		control.alignment = "left";
		var attributeFunctions = {
			_caller: "addCheckbox",
			id: nop,
			label: function () {control.text = AOM.AMG.localize(attributes.label);},
			'ag:layout': nop,
			width: function () {control.preferredSize = [attributes.width, control.preferredSize.height];}
		};
		addAttributes(attributes, attributeFunctions);
		if (attributes.id != undefined)
		{
			var value = AOM.AMG.userInput(AOM.AmgDesignWindow.currentDocument).get(attributes.id);
			if (value != undefined)
			{
				// when the user input store is loaded via persisted user input or an xml file,
				// it is a string. if the user changes the checkbox state, it becomes a boolean.
				// while "control.value = (value == true || value == 'true')" should do the trick, 
				// the switch will let us know if there is some unexpected value type...
				switch (typeof value)
				{
				 case 'boolean':
					control.value = value;
					break;
				 case 'string':
					control.value = (value == "true"); // Do not try to assign a string. It does not work. I promise...
					break;
				 default:
					AOM.AMG.Log.writeError("addCheckbox - unknown value type ("+typeof value+")");
					control.value = true; // or should it default to false?
					break;
				}
			}
			else
				control.value = false;
			
			control.document = AOM.AmgDesignWindow.currentDocument;
			control.onClick = function () {
                AOM.AMG.userInput(this.document).set(attributes.id, "" + this.value);
                AOM.AMG.userCustomizeStyle(attributes.id, this.document);
            }
		}
	}
	var addColorpicker = function (attributes, group)
	{
		var control = undefined;
		if (attributes.title == undefined)
		{
			control = group.add("button");
			control.themeType = "colorpnl";
			var attributeFunctions = {
				_caller: "addColorpicker",
				id: nop,
				'ag:style': nop,
				title: nop
			};
			addAttributes(attributes, attributeFunctions);
			control.preferredSize = [20, 20];
			
			control.graphics.customBgColor = control.graphics.newBrush(
							control.graphics.BrushType.SOLID_COLOR,
							AOM.AMG.Colorpicker.rgb(
								AOM.AMG.Colorpicker.get(
									attributes.id,
									AOM.AmgDesignWindow.currentDocument)));
			if (attributes.id != undefined)
			{
				control.document = AOM.AmgDesignWindow.currentDocument;
				control.onClick = function () {
					var newColor = AOM.AMG.Colorpicker.pick(
						AOM.AMG.Colorpicker.get(attributes.id, this.document));
					if(newColor != -1) {
						AOM.AMG.Colorpicker.set(attributes.id, newColor, this.document);
						this.graphics.customBgColor = this.graphics.newBrush(
							this.graphics.BrushType.SOLID_COLOR,
							AOM.AMG.Colorpicker.rgb(newColor));
						AOM.AMG.userCustomizeStyle(attributes.id, this.document);
					}
				}
			}
		}
		else
		{
			// Lightroom specifies the colorpicker label in the text attribute
			// so we need to put the colorpicker and label in an hbox.
			// NOTE - there probably should be a way to have alternatives implemented
			// in (e.g.) flashgallery.jsxinc...
			var uiItems = new Array();
			uiItems.push({type: "hbox", children: [
				{type: "colorpicker", attributes: {id: attributes.id}},
				{type: "label", attributes: {text: attributes.title}}
			]});
			addUiItems(uiItems, group);
		}
	}
	var addCombobox = function (attributes, values, labels, group)
	{
		var control = group.add("dropdownlist");
		var attributeFunctions = {
			_caller: "addCombobox",
			id: nop,
			'ag:layout': nop,
			defaultData: nop,
			width: function () {control.preferredSize = [attributes.width, control.preferredSize.height];},
		};
		addAttributes(attributes, attributeFunctions);
		var seperateLabels = (labels.length == 0 ? false : true);
		var defaultData = AOM.AMG.userInput(AOM.AmgDesignWindow.currentDocument).get(attributes.id);
		if (defaultData == undefined)
			defaultData = attributes.defaultData;
		
		for (var i = 0; i < values.length; i++)
		{
			var label = undefined;
			var data = undefined;
			if (seperateLabels)
			{
				label = labels[i].title; // label is in its own array
				data = values[i];
			}
			else
			{
				label = values[i].label; // label and data are properties of the value
				data = values[i].data;
			}
			var item = control.add("item", AOM.AMG.localize(label));
			item.data = data;
			if (data == defaultData)
				item.selected = true;
		}
		// Call UserInput.set with the data that corresponds to the combobox label selection.
		if (attributes.id != undefined) {
			control.document = AOM.AmgDesignWindow.currentDocument;
			control.onChange = function () {
                if (this.selection != null) {
                    AOM.AMG.userInput(this.document).set(attributes.id, this.selection.data);
                    if(AOM.AmgStyleSection.loadingUi != true)
                        AOM.AMG.userCustomizeStyle(attributes.id, this.document);
                }
            }
        }
		if (control.items.length > 0)
		{
			if (control.selection == null)
				control.items[0].selected = true;
			control.onChange();
		}
	}
	var addHRule = function (attributes, group)
	{
		//control = group.add("panel", {alignment:'left', orientation:'row', preferredSize:[attributes.width, 0]});
		//control = group.add("panel", {x:0, y:0, width:attributes.width, height:0});
	/* DWR - the rule doesn't show and goofs the window height (scrollbar is affected...)
		control = group.add("panel");
		control.preferredSize = [AOM.AmgAccordionSection.accordionButtonWidth - 40, 0]; // DWR - constant width adjustment
		control.orientation = "row";
		control.alignment = "left";
	*/
	}
	var addHSlider = function (attributes, group)
	{
		/* Replace the ordinary ScriptUI Slider with the customized Numeric Stepper.
		 * ScriptUI slider causes Bridge dead-lock and customize its onDraw is
		 * damn difficult.
		var control = group.add("slider"); */
		
		var control = new AOM.AmgNumericStepper();
		control.createControl(group);
		control.alignment = ['left', 'center'];
		
		var attributeFunctions = {
			_caller: "addHSlider",
			id: nop,
			minimum: function () {
				control.setSlider({
					minvalue: attributes.minimum,
					maxvalue: attributes.maximum,
					stepdelta: 1,
					preferredSize:[attributes.width, 20]
				});
				control.setEditText({preferredSize:[25, 18]});
			},
			maximum: nop,
			// textLeft: function() {control.setHeadLabel({text:AOM.AMG.localize(attributes.textLeft)});},
			textRight: function() {control.setFootLabel({
				text:AOM.AMG.localize(attributes.textRight)
			});},
			width: nop
		}
		addAttributes(attributes, attributeFunctions);
		if (attributes.id != undefined) {
		    control.document = AOM.AmgDesignWindow.currentDocument;
		    control.setValue(AOM.AMG.userInput(control.document).get(attributes.id) * 100);
		    control.onChange = function () {
                AOM.AMG.userInput(this.document).set(attributes.id, this.value / attributes.ratio);
                if(AOM.AmgStyleSection.loadingUi != true)
                	AOM.AMG.userCustomizeStyle(attributes.id, this.document);
            }
        }
        
		/* 1.0 didn't load value from last session. Not correct.
		control.value = attributes.minimum;
		control.onChange(); */
	}
	var addLabel = function (attributes, group)
	{
		var control = group.add("statictext");
		var attributeFunctions = {
			_caller: "addLabel",
			fontWeight: nop,
			id: nop,
			'ag:layout': nop,
			'ag:style': nop,
			text: function () {control.text = AOM.AMG.localize(attributes.text);},
			width: function () {
				if(attributes.height == undefined)
					control.preferredSize = [attributes.width, control.preferredSize.height];
				else
					control.preferredSize = [attributes.width, attributes.height];
			},
			height: function () {
				if(attributes.width == undefined)
					control.preferredSize = [control.preferredSize.width, attributes.height];
				else
					control.preferredSize = [attributes.width, attributes.height];
			},
			alignment: function() {control.alignment = [attributes.alignment, "center"];}
		};
		control.alignment = ["left", "center"];
		addAttributes(attributes, attributeFunctions);
		// Note - some labels have an id. Do we need to do something with it?
	}
	var addTextarea = function (attributes, group)
	{
		var width = attributes.width == undefined ? AOM.AmgDesignWindow.defaultControlWidth : attributes.width;
		var control = group.add("edittext", {x:0, y:0, width:width, height:attributes.height}, "", {multiline: true, borderless:true, scrolling:false});
		if (attributes.id != undefined)
		{
			var text = AOM.AMG.userInput(AOM.AmgDesignWindow.currentDocument).get(attributes.id);
			control.text = (text == undefined ? "" : text);
			control.document = AOM.AmgDesignWindow.currentDocument;
			control.onChange = function () {AOM.AMG.userInput(this.document).set(attributes.id, this.text);}
		}
		
		//add new AutoIncrementEditText class
		new AOM.AutoIncrementEditText(control, AOM.tabbedPalette(AOM.AmgDesignWindow.currentDocument).content);
	}
	var addTextinput = function (attributes, group)
	{
		var width = attributes.width == undefined ? AOM.AmgDesignWindow.defaultControlWidth : attributes.width;
		var control = group.add("edittext", {x:0, y:0, width:width, height:18}, "", {multiline: false, borderless:true});
		var attributeFunctions = {
			_caller: "addTextinput",
			editable: nop,
			id: nop,
			'ag:layout': nop,
			maxChars: nop,
			maximum: nop,
			'ag:maximumLength': nop,
			minimum: nop,
			'ag:resizeToFitTextHeight': nop,
			validate: nop,
			width: nop
		};
		addAttributes(attributes, attributeFunctions);
		control.preferredSize = [(attributes.width == undefined ? AOM.AmgDesignWindow.defaultControlWidth : attributes.width), control.preferredSize.height];
		if (attributes.id != undefined)
		{
			var value = AOM.AMG.userInput(AOM.AmgDesignWindow.currentDocument).get(attributes.id);
			if (value != undefined)
				control.text = value;
			else
				control.text = "";
			
			control.document = AOM.AmgDesignWindow.currentDocument;
            control.onChange = function () {
			    var oldValue = AOM.AMG.userInput(this.document).get(attributes.id);
				var currentValue = (this.text == undefined) ? undefined : this.text.amgTrim();
			    var valid = AOM.AMG.userInput(this.document).set(attributes.id, currentValue);
                if(!valid && oldValue != undefined)
                    this.text = oldValue;
                else
                    AOM.AMG.userCustomizeStyle(attributes.id, this.document);
            }
		}
		
		//TODO, add event listener if necessary
		if (attributes.keyboardListener != undefined) {
            if (attributes.keyboardListener == "number") {
                control.addEventListener('keydown', AOM.CS.Keyboards.rowAndColumnEditKeyBoardHandler);
            } 
        }
	}
	var addUiItems = function (viewList, group)
	{
		try
		{
			for (var i = 0; i < viewList.length; i++)
			{
				var vi = viewList[i]; // view item
				switch (vi.type)
				{
				 case "hbox":
				 case "vbox":
					var box = group.add("group");
					box.alignment = "left";
					box.maximumSize.height = 2000;
					box.orientation = (vi.type == "hbox" ? "row" : "column");
					if(vi.attributes != undefined) {
						if(vi.attributes.alignment != undefined)
							box.alignment = vi.attributes.alignment;
						if(vi.attributes.width != undefined)
							box.preferredSize.width = vi.attributes.width;
						if(vi.attributes.height != undefined)
							box.preferredSize.height = vi.attributes.height;
					}
					box.spacing = 6;
					
					addUiItems(vi.children, box);
					break;
				 default:
					add(vi, group);
					break;
				}
			}
		}
		catch (e)
		{
			alert(e);
			AOM.AMG.Log.writeError("DesignWindow.loadUi/addUitItems caught - " + e);
		}
	}
	var addUiSections = function(viewList, foldableSet)
	{
	    try
	    {
	    	AOM.AmgDesignWindow.currentDocument = foldableSet.document;
	    	var initialSectionName;
	        for(var i = 0; i < viewList.length; ++i) {
	            var vi = viewList[i];
	            var type = vi.attributes["ag:style"];
	            if(type == undefined)
	                continue;
	            
	            var title = AOM.AMG.localize(vi.attributes["title"]);
	            var id = vi.attributes["id"];
	            if(initialSectionName == undefined)
	            	initialSectionName = id;
	            var group = foldableSet.addFoldableSection(AOM.AmgStyleSection.foldResourceContents, id, title);
	            group.maximumSize.height = 2000;
	            addUiItems(vi.children, group);
				
				// Set the open/close status
				AOM.AmgDesignWindow.setOpenCloseStatus(group.parent.parent);
	        }
	        AOM.AmgDesignWindow.currentDocument = undefined;
	        return initialSectionName;
        }
        catch(e)
        {
        	alert(e);
            AOM.AMG.Log.writeError("DesignWindow.loadUi/addUitSections caught - " + e);
        }
    }
	
	var initialSectionName = addUiSections(uiItems, foldableSet);
	return initialSectionName;
}


AOM.AmgDesignWindow.setOpenCloseStatus = function(group) {
	for (var i = 0; i < group.children.length; i++) {
		var child = group.children[i];
		if (child instanceof Group) {
			AOM.AmgDesignWindow.setOpenCloseStatus(child);
		} else {
			var name = child.name;
			
			if (name != undefined) {
				var type = child.type;
				if (child.themeType != undefined)  {type = child.themeType;}
								
				if (type.toLowerCase() == "openclosebtn") {
					var value = AOM.userInput(AOM.AmgDesignWindow.currentDocument).get(child.name);
					if(value == "true" || value == true || value == undefined) {
						child.isOpen = true;
					} else {
						child.isOpen = false;
					}
				}
			}
		}
	}
}

AOM.AmgTabbedPalette = function() {}
AOM.AmgTabbedPalette.create = function (document, title, id, type, url)
{
	var error = function (s) {return AOM.AMG.Log.writeError("AOM.AMG.TabbedPalette.create - " + s);}
	AOM.AMG.Tests.isDocument(document);

	var result = undefined;
	try
	{
		if (url != undefined)
			result = new TabbedPalette(document,  title, id, type, url);
		else
			result = new TabbedPalette(document,  title, id, type);
		if (result == undefined)
			return error("new TabbedPalette returned undefined");
		return result;
	}
	catch (e)
	{
		alert(e);
		return error("caught: " + e);
	}
}

AOM.AMG.Paths = {};
AOM.AMG.Paths.app = Folder.commonFiles + "/Adobe/Bridge CS4 Extensions/Adobe Output Module/mediagallery/"; // TODO - change to "Media Gallery" in RIBS...
AOM.AMG.Paths.resources = AOM.AMG.Paths.app + "resources/";
AOM.AMG.Paths.templates = AOM.AMG.Paths.resources + "templates/";
AOM.AMG.Paths.scripts = AOM.AMG.Paths.resources + "scripts/";
AOM.AMG.Paths.images = AOM.AMG.Paths.resources + "images/";
AOM.AMG.Paths.user = Folder.userData + "/Adobe/Bridge CS4/Adobe Output Module/MediaGallery/";
AOM.AMG.Paths.log = Folder.userData + "/Adobe/Bridge CS4/Adobe Output Module/";
AOM.AMG.Paths.preview = AOM.AMG.Paths.user + "preview";
AOM.AMG.Paths.persistedUserData = AOM.AMG.Paths.user + "userInput.json";
AOM.AMG.Paths.persistedFTPPresetUserData = AOM.AMG.Paths.user + "ftpPresetUserInput.json";

AOM.AmgAccordionSection = {};
AOM.AmgAccordionSection.accordionButtonWidth = 300;
AOM.AmgAccordionSection.accordionButtonHeight = 20;

AOM.AmgTemplateSection = function() {}
AOM.AmgTemplateSection.currentTemplate = function (doc, template, refresh)
{
	var currentUserInput = AOM.AMG.userInput(doc);
	if (template != undefined)
	{
		refresh = (refresh != undefined) ? refresh : false;
		if (refresh)
		{
			currentUserInput.initialize();
		}
		// copy the template to the user input data store
		currentUserInput.set("t_template", template);
	    AOM.AmgGalleryMaker.loadTemplate(template, doc);
		// can we use the current style with this template?
	    var style = AOM.AmgStyleSection.currentStyle(doc);
	    var styleList = AOM.AmgGalleryMaker.styleList(doc);
	    if (styleList[style] == undefined)
			style = AOM.AmgGalleryMaker.defaultStyle(doc); // no, so use the default template
		
		var custom = currentUserInput.get("si_style_custom");
		AOM.AmgStyleSection.currentStyle(doc, style, custom != "true");
		AOM.AmgUserInput.loadSizes(doc);
		AOM.AMG.loadStyles(doc);
	}
	return (currentUserInput.get("t_template"));
}
AOM.AmgTemplateSection.create = function (insertFunction, selectedTemplate, parent)
{
	var group = insertFunction(AOM.AmgTemplateSection.resource);
	var dropdown = group.templateDropdown;
	AOM.AmgGalleryMaker.loadTemplateDropdown(dropdown, selectedTemplate);
    group.templateDropdown.preferredSize = [AOM.AmgDesignWindow.defaultControlWidth * 2 / 3, group.templateDropdown.preferredSize.height];
    dropdown.document = parent.document;
	dropdown.onChange = function ()
	{
		if (this.selection != null) { // sometimes we get called when the window is begin destroyed..
		    /* The new template should not have a "Custom" style */
		    AOM.AMG.userInput(this.document).set("si_style_custom", "false");
			AOM.AmgTemplateSection.currentTemplate(this.document, this.selection.template);
		}
		parent.layout.layout(true);
	}
	return "template";
}
AOM.AmgTemplateSection.resource = new String(
"Group \
 { \
	orientation: 'row', \
	alignment: 'right', \
	margins: [20, 5, 5, 3], \
	templateLabel: StaticText { \
    	alignment: ['right', 'center'], \
    	text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/template=Template:") + "' \
      } \
    templateDropdown: DropDownList {alignment:['right', 'center']} \
 }"
);

AOM.AmgPreviewSection = function() {}
AOM.AmgPreviewSection.create = function (insertFunction)
{
	group = insertFunction(AOM.AmgPreviewSection.resource);
	group.previewControls.amgPreviewButton.onClick = function ()
	{
		// on the Mac a button does not take the focus by default. If another control is 
		// in the midst of being edited it's onChange handler is not called. Grab the
		// focus now to force any pending onChange.
		//
		/* Comment this because it casue Bridge crash after integrate with
		 * Contact Sheet    *
		 * 		 
		 * this.active = true; */
		 
		/* Active document must be captured at this point. A user may switch
		 * window at any later point. */
		var document = app.document;
		
		var f = function (index) { AOM.previewPalette(document).display(index.fsName); }
		var data = new AOM.PreviewFormData(false, f, document, AOM.AmgGalleryCreator.createModes.preview);
		
		//check preview palette has initialized.
		AOM.PreviewPanel.checkPreviewPalette(document);
		
		AOM.AMG.createGallery(data);
	}
	group.previewControls.browserPreviewButton.onClick = function ()
	{
		/* Cause crash!
		 *
         * this.active = true; */
        
        /* Active document must be captured at this point. A user may switch
		 * window at any later point. */
		var document = app.document;
		
		var f = function (index) { index.execute(); };
		var data = new AOM.PreviewFormData(false, f, document, AOM.AmgGalleryCreator.createModes.previewInBrowser);
		AOM.AMG.createGallery(data);
	}
	return "preview";
}
AOM.AmgPreviewSection.galleryType = function (doc)
{
	// At the moment jardinePro is the only html gallery - everything else is a flash gallery.
	return (AOM.AMG.galleryMakerData(doc).models.identifier == "com.adobe.wpg.templates.jardinePro" ?
            AOM.AmgGalleryCreator.galleryTypes.html : AOM.AmgGalleryCreator.galleryTypes.flash);
}
AOM.AmgPreviewSection.resource = new String(
"group \
 { \
	orientation: 'column', \
	alignment: 'left', \
	margins: [20, 5, 5, 15], \
	previewControls: Group \
	{ \
		orientation: 'row', \
		alignment: ['left','top'], \
		amgPreviewButton: Button { \
            text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/preview=Refresh Preview") + "', \
            alignment:'left', \
            preferredSize: [115, 22] \
        }, \
		browserPreviewButton: Button { \
            text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/browserPreview=Preview in Browser") + "', \
            alignment:'left', \
            preferredSize: [136, 22] \
        } \
	} \
 }"
);

AOM.AmgLoadStyleSection = function() {}
AOM.AmgLoadStyleSection.create = function (insertFunction, selectedTemplate, parent)
{
	var group = insertFunction(AOM.AmgLoadStyleSection.resource);
	var dropdown = group.styleDropdown;
	dropdown.preferredSize = [AOM.AmgDesignWindow.defaultControlWidth * 2 / 3, dropdown.preferredSize.height];
	dropdown.document = parent.document;
	
	dropdown.setSelected = function(selected) {
	     var i;
	     var items = this.items;
	     this.programSetSelected = true;
	     for(i = 0; i < items.length; ++i)
	         if(items[i].style == selected) {
	             items[i].selected = true;
	             this.programSetSelected = false;
	             return;
	         }
	     this.programSetSelected = false;
    }
	
	parent.document.jsFuncs.loadStyles = function() {
	    AOM.AmgLoadStyleSection.loadStyles(dropdown, parent);
    }
    
    parent.document.jsFuncs.userCustomizeStyle = function(id) {
        /* Determine if the control with *id* is part of a style definition.
         * ID naming convention: <control ID> + "_style_Modified", agree with
         * that defined in AOM.AmgGalleryMaker.updateUserInputFromModels(). 
         * 
         * If the control just-changed is part of a style definition, change
         * the dropdown list display and the user input. We should not change
         * "si_style" since it is also used by gallery generation code, so
         * we use a new "si_style_display" entry. */

		
		if (AOM.AMG.userInput(parent.document).get(id + "_style_Modified") == "true") {
			var selectionItem = dropdown.selection;
			if (selectionItem.style != "customized") {
				var listItem = dropdown.add("item", AOM.AMG.localize("$$$/MediaGallery/JavaScript/SectionTitle/CustomizedStyle=Custom"));
				listItem.style = "customized";
				
				AOM.AMG.userInput(parent.document).set("si_style_custom", "true");
				dropdown.setSelected("customized");
			}
		}
    }
	
	return "loadStyle";
}
AOM.AmgLoadStyleSection.resource = new String(
"Group \
 { \
	orientation: 'row', \
	alignment: 'right', \
	margins: [20, 3, 5, 5], \
	templateLabel: StaticText { \
		alignment: ['right', 'center'], \
		text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/style=Style:") + "' \
	} \
	styleDropdown: DropDownList {alignment:['right', 'center']} \
 }"
);
AOM.AmgStyleSection = function() {}
AOM.AmgStyleSection.create = function (foldableSet)
{
    var foldGroup = foldableSet.addFoldableSection(AOM.AmgStyleSection.foldResourceContents, "style", AOM.AMG.localize("$$$/MediaGallery/JavaScript/SectionTitle/StyleInformation=Style Information"));
	foldGroup.maximumSize.height = 2000;
	return foldGroup;
}
AOM.AmgLoadStyleSection.loadStyles = function (dropdown, parent)
{
    dropdown.onChange = undefined;
    dropdown.removeAll();

	// add a dropdown with the current list of styles
	var styleList = AOM.AmgGalleryMaker.styleList(dropdown.document);
	if (styleList.__count__ < 1) // don't show a style list if only one style. can this ever happen?
		return;

	dropdown.changing = false;	
	var currentStyle = AOM.AmgStyleSection.currentStyle(dropdown.document);
	var currentStyleDisplay = AOM.AMG.userInput(dropdown.document).get("si_style_custom");

	if (currentStyleDisplay == "true") {
		var listItem = dropdown.add("item", AOM.AMG.localize("$$$/MediaGallery/JavaScript/SectionTitle/CustomizedStyle=Custom"));
		listItem.style = "customized";
		listItem.selected = true;
	}

	for (var i in styleList)
	{
		listItem = dropdown.add("item", styleList[i]);
		listItem.style = i;
		if(listItem.style == currentStyle && currentStyleDisplay != "true")
		    listItem.selected = true;
	}

	dropdown.onChange = function ()
	{
	    if(this.programSetSelected == true)
	        return;
	    
	    var oldStyle = AOM.AmgStyleSection.currentStyle(this.document);
		var newStyle = this.selection.style;
		
		if(newStyle == "customized") {
		    this.setSelected(oldStyle);
		    return;
        }
	
		for (var i = 0; i < this.items.length; i++) {
			var currentItem = this.items[i];
			if (currentItem.style == "customized") {
				this.remove (currentItem);
			}
		}
		
		//AOM.AMG.Log.writeLine("AOM.AmgStyleSection.dropdown.onChange - new style is "+newStyle);
		// the upcoming call to currentStyle() will hammer this dropdown object. 
		// use schedule task if the object is needed past that point?
		AOM.AmgStyleSection.currentStyle(this.document, newStyle, true);
		AOM.AMG.userInput(this.document).set("si_style_custom", "false");
		parent.layout.layout("true");
	}
}
AOM.AmgStyleSection.currentStyle = function (doc, style, overwrite)
{
	var currentUserInput = AOM.AMG.userInput(doc);
	if (style != undefined)
	{
	    // if we are given a style, copy it to the user input data store
		currentUserInput.set("si_style", style);
		// and then update the style section
		var template = currentUserInput.get("t_template");
		if (template == undefined)
			return AOM.AMG.Log.writeError("AOM.AmgStyleSection.currentStyle - could not get template");
		
		if(style != "customized")
		    AOM.AmgGalleryMaker.loadStyle(template, style, overwrite, doc);
		AOM.AMG.updateStyleSection(doc);
	}
	// return the user input style
	return currentUserInput.get("si_style");
}
AOM.AmgStyleSection.loadUi = function (foldableSet)
{
    var amgGalleryMakerData = AOM.AMG.galleryMakerData(foldableSet.document);
    
    /* loadingUi is the indicator that prevent the dropdown list onChange
     * event during the UI loading. */
    AOM.AmgStyleSection.loadingUi = true;
	var initialSectionName = AOM.AmgDesignWindow.loadUi(amgGalleryMakerData.views, foldableSet);
	AOM.AmgStyleSection.loadingUi = false;
	
	return initialSectionName;
}
AOM.AmgStyleSection.foldResourceContents = new String(
"group \
 { \
	orientation: 'column', \
		alignment: 'left', \
		margins: 5 \
 }"
);
/* AMG 1.0 Code: AMG 2.0 REMOVE
 *     Image Option Section is now fully defined in gallerymaker.xml.
AOM.AmgImageOptionsSection = function() {}
AOM.AmgImageOptionsSection.create = function (insertFunction)
{
	var group = insertFunction(AOM.AmgImageOptionsSection.foldResourceContents, "imageOption", AOM.AMG.localize("$$$/MediaGallery/JavaScript/SectionTitle/ImageOptions=Image Options"));
	app.document.jsFuncs.updateImageOptionsSection = function()
	{
		var sizeDropdown = function(id, label)
		{
			var combobox = {type: "combobox", "attributes": {id: id, defaultData: "medium"}, values: new Array(), labels: new Array()};
			combobox.values.push({label: AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsExtraLarge=Extra large"), data: "extraLarge"});
			combobox.values.push({label: AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsLarge=Large"), data: "large"});
			combobox.values.push({label: AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsMedium=Medium"), data: "medium"});
			combobox.values.push({label: AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsSmall=Small"), data: "small"});
			var hbox = {type: "hbox", attributes: {verticalAlign: "middle"}, children: new Array()};
			hbox.children.push({type: "label", attributes: {text: label, width: 75}});
			hbox.children.push(combobox);
			return hbox;
		}
		var uiItems = new Array();
		uiItems.push(sizeDropdown("io_preview", AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsPreview=Preview Size:")));
		if (AOM.AmgPreviewSection.galleryType() != AOM.AmgGalleryCreator.galleryTypes.html)
			uiItems.push(sizeDropdown("io_thumbnail", AOM.AMG.localize("$$$/MediaGallery/JavaScript/Label/ImageOptionsThumbnail=Thumbnail Size:")));
		while (group.children.length)
		{
			group.remove(0);
		}
		AOM.AmgDesignWindow.loadUi(uiItems, group);
	}
}
AOM.AmgImageOptionsSection.foldResourceContents = new String(
"group \
 { \
    orientation: 'column' , \
	alignment: 'left', \
	margins: 5 \
 }"
); */

AOM.AmgCreateGallerySection = function() {}
AOM.AmgCreateGallerySection.hasProgramInteract = false;
AOM.AmgCreateGallerySection.hasValid = true;
AOM.AmgCreateGallerySection.setEnabledProps = function(group, enabled, doc) {
	for (var i = 0; i < group.children.length; i++) {
		var child = group.children[i];
		if (child instanceof Group) {
			AOM.AmgCreateGallerySection.setEnabledProps(child, enabled, doc);
		} else {
			if (child.type == "edittext") {
				child.gsEnabled = child.enabled = enabled;
				var theme = AOM.theme(doc);
				theme.setEditTextDisableBgColor(child);
			} else {
				child.gsEnabled = child.enabled = enabled;
			}
		}
	}
}
AOM.AmgCreateGallerySection.getListIndexByText = function(ddl, keyword, hasCaseSensitive) {
		if (hasCaseSensitive == undefined) hasCaseSensitive = false;
		var index = -1;
		var items = ddl.items;
		if (!hasCaseSensitive) {keyword = keyword.toLowerCase();}
		for (var i = 0; i < items.length; i++) {
			var text = items[i].text;
			if (!hasCaseSensitive) {
				text = text.toLowerCase();
			}
			if (text == keyword) {
				index = i;
			}
		}
		return index;
	}
AOM.AmgCreateGallerySection.loadDataToFTPDropDownList = function(ftpDropDownList, userInput) {
	if(userInput == undefined)
		alert("Undefined User Input: " + $.stack);

	AOM.AmgCreateGallerySection.hasProgramInteract = true;
	//Get the default selected value from userInput file.
	var defaultSelectedValue = userInput.get("cg_ftpTemplate");
		
	ftpDropDownList.removeAll();
	ftpDropDownList.add("item", AOM.localize("$$$/AMG/javascript/ftp/presetCustom=Custom"));
	ftpDropDownList.add("separator", "-");
	ftpDropDownList.selection = 0; 
	
	var ftpPresetItems = AOM.AMG.ftpPresetUserInput().getItems();
	for(var idx = 0; idx <ftpPresetItems.length; idx++) {
		var itm = ftpPresetItems[idx];
		var newItem = ftpDropDownList.add("item", itm.id);
		if (defaultSelectedValue == itm.id) {
			ftpDropDownList.selection = newItem;
		}
	}
	if (ftpDropDownList.selection.text != defaultSelectedValue) {
		userInput.set(ftpDropDownList.name, ftpDropDownList.selection.text);
	}
	AOM.AmgCreateGallerySection.hasProgramInteract = false;
}
AOM.AmgCreateGallerySection.loadDataToFTPGroup = function(group, userInput) {
	var isEmpty = function(s) {
		return (s== undefined || s.length == 0);
	}
	var strToBoolean = function(s) {
		if (s == undefined) return false;
		if (s == "true") 
			return true;
		else 
			return false;
	}

	for (var i = 0; i < group.children.length; i++) {
		var child = group.children[i];	
		if (child instanceof Group) {
			AOM.AmgCreateGallerySection.loadDataToFTPGroup(child, userInput);
		} else {
			var name = child.name;
			if (name != undefined) {
				var type = child.type;
				var value =userInput.get(child.name);
				switch(type.toLowerCase()) {
				case "checkbox" :
					if (isEmpty(value)) {
						child.value = false;
						userInput.set(child.name, child.value.toString());
					} else {
						child.value = strToBoolean(value);
					}
					break;
				case "edittext" :
					if (isEmpty(value)) {
						var defaultValue = (child.defaultValue == undefined ? "" : child.defaultValue);
						child.text = defaultValue;
						userInput.set(child.name, child.text);
					} else {
						child.text = value;
					}
					break;
				case "dropdownlist" :
					AOM.AmgCreateGallerySection.loadDataToFTPDropDownList(child, userInput);
					break;
				}
			}
		}
	}
}
AOM.AmgCreateGallerySection.addItemInfoFromFTPGroup = function(newItem, group) {
	for (var i = 0; i < group.children.length; i++) {
		var child = group.children[i];	
		if (child instanceof Group) {
			AOM.AmgCreateGallerySection.addItemInfoFromFTPGroup(newItem, child);
		} else {
			var name = child.name;
			if (name != undefined) {
				var value = undefined;
				switch(child.type.toLowerCase()) {
					case "edittext" :
						value = child.text;
						break;
					case "checkbox" :
						value = child.value;
						break;
					default:
						break;
				}
				if (value != undefined) {
					newItem[name] = value;
				}
			}
		}
	}
}
AOM.AmgCreateGallerySection.persistFTPGroupValues = function(group, userInput) {
	for (var i = 0; i < group.children.length; i++) {
		var child = group.children[i];	
		if (child instanceof Group) {
			AOM.AmgCreateGallerySection.persistFTPGroupValues(child, userInput);
		} else {
			var name = child.name;
			if (name != undefined) {
				var type = child.type;
				switch(type.toLowerCase()) {
				case "checkbox" :
					userInput.set(child.name, child.value.toString());
					break;
				case "edittext" :
					userInput.set(child.name, child.text);
					break;
				}
			}
		}
	}
}
AOM.AmgCreateGallerySection.openSaveDialog = function() {
	var saveDialog = new Window("dialog", AOM.localize("$$$/AMG/javascript/ftp/presetTitle=New Preset"), undefined);
	var sdGroup = saveDialog.add(
	"group{\
		orientation:'column',\
		nameGroup:Group{\
			alignment:['right', 'center'], \
			st:StaticText{text:'" + AOM.localizeEsc("$$$/AMG/javascript/ftp/presetNameLabel=Preset Name:") + "'},\
			edt:EditText{text:'', preferredSize:[160, 20]},\
		},\
		btnGroup:Group{\
			alignment:['right', 'center'],\
			createBtn:Button{text:'" + AOM.localizeEsc("$$$/AMG/javascript/ftp/createPresetButton=Create") + "'},\
			cancelBtn:Button{text:'" + AOM.localizeEsc("$$$/AMG/javascript/ftp/cancelPresetButton=Cancel") + "'},\
		},\
	}\
	");
		
	saveDialog.defaultElement = sdGroup.btnGroup.createBtn;
	saveDialog.cancelElement = sdGroup.btnGroup.cancelBtn;
	sdGroup.nameGroup.edt.active = true;

	sdGroup.btnGroup.cancelBtn.onClick = function() {
		saveDialog.hasCanceled = true;
		saveDialog.close();
	}
	sdGroup.btnGroup.createBtn.onClick = function() {
		var presetName = this.parent.parent.nameGroup.edt.text.amgTrim();
		if (presetName == undefined || presetName.length == 0) {
			alert(AOM.localize("$$$/AMG/javascript/ftp/emptyPresetName=Preset Name is required, please input preset name."));
			return;
		}
		if(presetName.length > 255) {
			alert(AOM.localize("$$$/AMG/javascript/ftp/tooLongPresetName=Preset Name is too long, please input preset name again."));
			return;
		}
		
		saveDialog.hasCanceled = false;
		saveDialog.presetName = presetName;
		saveDialog.close();
	}
	saveDialog.show();
		
	return saveDialog;
}

AOM.AmgCreateGallerySection.create = function (foldableSet)
{
	var group = foldableSet.addFoldableSection(AOM.AmgCreateGallerySection.foldResourceContents, "createGallery", AOM.AMG.localize("$$$/MediaGallery/JavaScript/SectionTitle/CreateGallery=Create Gallery"));
	
	//Set the open/close status
	AOM.AmgDesignWindow.currentDocument = foldableSet.document;
	AOM.AmgDesignWindow.setOpenCloseStatus(group.parent.parent);
	AOM.AmgDesignWindow.currentDocument = undefined;
	
	var myConfirm = function(msg) {
		return confirm(AOM.localize(msg));
	};
	
	foldableSet.document.jsFuncs.amgCreateGallerySection = group;
	foldableSet.document.jsFuncs.updateCreateGalleryRadioButtons = function(hasSaveToDisk) {
		var saveRadioButton = group.saveRadioButton;
		var ftpRadioButton = group.ftpRadioButton;
		
		if (hasSaveToDisk) {
			ftpRadioButton.value = false;
			if (saveRadioButton.value != true)  saveRadioButton.value = true;                                                                                                                                                                                                                                                                                                                            
		} else {
			saveRadioButton.value = false;
			if (ftpRadioButton.value != true) ftpRadioButton.value = true;
		}
	
		AOM.AmgCreateGallerySection.setEnabledProps(
			group.saveGroup, saveRadioButton.value, foldableSet.document);
		AOM.AmgCreateGallerySection.setEnabledProps(
			group.ftpGroup, ftpRadioButton.value, foldableSet.document);
		
		var currentUserInput = AOM.AMG.userInput(foldableSet.document);
		currentUserInput.set("cg_saveRadioButton", saveRadioButton.value.toString());
		currentUserInput.set("cg_ftpRadioButton", ftpRadioButton.value.toString());
	}
	foldableSet.document.jsFuncs.updateCreateGallerySection = function() {
		var userInput = AOM.AMG.userInput(foldableSet.document);
		
		//init radiobuttons
		var save = userInput.get("cg_saveRadioButton");
		AOM.AMG.updateCreateGalleryRadioButtons(save == "true", foldableSet.document);
		
		//init edittext and checkbox
		group.galleryText.defaultValue = "Adobe Web Gallery";
		AOM.AmgCreateGallerySection.loadDataToFTPGroup(group, userInput);
	}

	group.saveRadioButton.document = foldableSet.document;
	group.saveRadioButton.onClick = function () {
		AOM.AMG.updateCreateGalleryRadioButtons(true, this.document);
	}

	group.ftpRadioButton.document = foldableSet.document;
	group.ftpRadioButton.onClick = function () {
		AOM.AMG.updateCreateGalleryRadioButtons(false, this.document);
	}

	group.galleryText.document = foldableSet.document;
	group.galleryText.onChange = function () {
		var currentUserInput = AOM.AMG.userInput(this.document);
		var isValid = currentUserInput.set("cg_galleryText", this.text);
		if (isValid) {
			AOM.AmgCreateGallerySection.hasValid = true;
		} else {
			this.text = currentUserInput.get("cg_galleryText");
			AOM.AmgCreateGallerySection.hasValid = false;
		}
	}

	group.saveGroup.saveFolderText.document = foldableSet.document;
	group.saveGroup.saveFolderText.onChange = function ()
	{
		AOM.AMG.userInput(this.document).set("cg_saveFolderText", this.text);
	}

	group.saveGroup.saveLocationGroup.saveBrowseButton.onClick = function ()
	{
		var folder = Folder.selectDialog(AOM.AMG.localize("$$$/MediaGallery/JavaScript/SelectLocation=Select location for Adobe Web Gallery"));
		if (folder == null) return;
		
		group.saveGroup.saveFolderText.text = folder.fsName;
		group.saveGroup.saveFolderText.onChange();
	}

	group.saveGroup.saveLocationGroup.saveButton.document = foldableSet.document;
	group.saveGroup.saveLocationGroup.saveButton.onClick = function ()
	{
		//workaround process mac edittext and button issue.
		if (File.fs == "Macintosh") {
			if (AOM.AmgCreateGallerySection.hasValid == false) {
				AOM.AmgCreateGallerySection.hasValid = true;
				return;
			}
		}
	
		var userInput = AOM.AMG.userInput(this.document); 
		var data = new AOM.SaveToDiskFormData(
            userInput.get("cg_galleryText"), userInput.get("cg_saveFolderText"), this.document);
		if (!data.valid) {return;}
		AOM.AMG.createGallery(data);
	}
	
	var uploadInfoChange = function(ele) {
		if (ele.type.toLowerCase() == "edittext") {
			AOM.AMG.userInput(foldableSet.document).set(ele.name, ele.text);
		} else {
			AOM.AMG.userInput(foldableSet.document).set(ele.name, ele.value.toString());
		}
	
		AOM.AmgCreateGallerySection.hasProgramInteract = true;
		var ftpDropDownList = group.ftpGroup.tGroup.ftpTemplate;
		ftpDropDownList.selection = ftpDropDownList.items[0];
		AOM.AmgCreateGallerySection.hasProgramInteract = false;
	}
	group.ftpGroup.ftpServerText.onChange = function () {
		uploadInfoChange(this);
	}
	group.ftpGroup.nameGroup.userNameText.onChange = function () {
		uploadInfoChange(this);
	}
	group.ftpGroup.passGroup.passwordText.onChange = function () {
		uploadInfoChange(this);
	}
	group.ftpGroup.foldGroup.uploadFolderText.onChange = function () {
		uploadInfoChange(this);
	}
	group.ftpGroup.cpassGroup.ftpHasSavePass.onClick = function() {
		uploadInfoChange(this);
	}
	group.ftpGroup.ftpButton.document = foldableSet.document;
	group.ftpGroup.ftpButton.onClick = function ()
	{
		//workaround process mac edittext and button issue.
		if (File.fs == "Macintosh") {
			if (AOM.AmgCreateGallerySection.hasValid == false) {
				AOM.AmgCreateGallerySection.hasValid = true;
				return;
			}
		}
		var userInput = AOM.AMG.userInput(this.document); 	 
		var data = new AOM.UploadFormData(userInput.get("cg_galleryText"), userInput.get("cg_ftpServerText"),
			userInput.get("cg_userNameText"), userInput.get("cg_passwordText"), userInput.get("cg_uploadFolderText"),
            this.document);
		if (!data.valid){return;} 
		
		AOM.AMG.createGallery(data);
	}

	//FTP Preset event-handlers.
	group.ftpGroup.tGroup.ftpSaveBtn.document = foldableSet.document;
	group.ftpGroup.tGroup.ftpSaveBtn.onClick = function() {
		//validate
		if (File.fs == "Macintosh") {
			if (AOM.AmgCreateGallerySection.hasValid == false) {
				AOM.AmgCreateGallerySection.hasValid = true;
				return;
			}
		}
		var currentUserInput = AOM.AMG.userInput(this.document);
		var data = new AOM.UploadFormData(
						currentUserInput.get("cg_galleryText"), currentUserInput.get("cg_ftpServerText"),
						currentUserInput.get("cg_userNameText"), currentUserInput.get("cg_passwordText"), 
						currentUserInput.get("cg_uploadFolderText"), this.document);				
		if (!data.valid){return;}		
		
		//confirm has remember password
		var ftpGroup = this.parent.parent.parent.ftpGroup;
		if (ftpGroup.cpassGroup.ftpHasSavePass.value) {
			if(!myConfirm("$$$/AMG/javascript/ftp/storePasswordPlain=The password will be stored in plain text. Do you want to continue?")) {
				return;
			} 
		}
		
		//call save dialog
		var saveDialog = AOM.AmgCreateGallerySection.openSaveDialog();
		if (saveDialog.hasCanceled) { return; }
		var newPresetName = saveDialog.presetName;

		//check is duplicate
		var duplicateIndex = AOM.AMG.ftpPresetUserInput().indexOf(newPresetName);
		if (duplicateIndex >= 0) {
			if (myConfirm("$$$/AMG/javascript/ftp/duplicateFTPInfo=The specified preset already exists. Do you want to overwrite it?") == false) {
				return;
			}
		}
		
		//check has save pass?
		if (!ftpGroup.cpassGroup.ftpHasSavePass.value) {
			ftpGroup.passGroup.passwordText.text = "";
		}
		
		//restore
		var newItem = {id:newPresetName}; 
		AOM.AmgCreateGallerySection.addItemInfoFromFTPGroup(newItem, group.ftpGroup);
		var index = (duplicateIndex >= 0 ? duplicateIndex : AOM.AMG.ftpPresetUserInput().size());
		AOM.AMG.ftpPresetUserInput().add(newItem, index);
		
		//add to dropDownlist if necessary
		AOM.AmgCreateGallerySection.hasProgramInteract = true;
		var ftpDropDownList = ftpGroup.tGroup.ftpTemplate;
		if (duplicateIndex >= 0) {
			var item = ftpDropDownList.items[AOM.AmgCreateGallerySection.getListIndexByText(ftpDropDownList, newPresetName)];
			item.text = newPresetName;
			ftpDropDownList.selection = item;
		} else {
			var newItem = ftpDropDownList.add("item", newPresetName);
			ftpDropDownList.selection = newItem;
		}
		AOM.AmgCreateGallerySection.hasProgramInteract = false;
	}

	group.ftpGroup.tGroup.ftpTemplate.document = foldableSet.document;
	group.ftpGroup.tGroup.ftpTemplate.onChange= function() {
		var currentUserInput = AOM.AMG.userInput(this.document);
		if (this.selection != undefined) {
			var selectedPresetName = this.selection.text;
			currentUserInput.set(this.name, selectedPresetName);
			
			if (AOM.AmgCreateGallerySection.hasProgramInteract) {
				//
			} else {
				if (this.selection.index == 0) {
					return;
				}
				var selectedItem= AOM.AMG.ftpPresetUserInput().getById(selectedPresetName);
				if (selectedItem == undefined) {
					alert(AOM.localize("$$$/AMG/javascript/ftp/noloaditem=No item selected, please select it first."));
					return;
				}

				var ftpGroup = group.ftpGroup;
				ftpGroup.ftpServerText.text = selectedItem.cg_ftpServerText;
				ftpGroup.nameGroup.userNameText.text = selectedItem.cg_userNameText;
				ftpGroup.passGroup.passwordText.text = selectedItem.cg_passwordText;
				ftpGroup.cpassGroup.ftpHasSavePass.value = selectedItem.cg_ftpHasSavePass;
				ftpGroup.foldGroup.uploadFolderText.text = selectedItem.cg_uploadFolderText;

				//persist
				AOM.AmgCreateGallerySection.persistFTPGroupValues(ftpGroup, currentUserInput);
			}
		}
	}

	group.ftpGroup.tGroup.ftpDeleteBtn.document = foldableSet.document;
	group.ftpGroup.tGroup.ftpDeleteBtn.onClick = function() {
		var ftpDropDownList = group.ftpGroup.tGroup.ftpTemplate;

		if (ftpDropDownList.selection == undefined || ftpDropDownList.selection.index == 0) {
			alert(AOM.localize("$$$/AMG/javascript/ftp/nodeleteitem=No item selected, please select it first."));
			return;
		}
		
		var selectedPresetName = ftpDropDownList.selection.text;
		var selectedItem= AOM.AMG.ftpPresetUserInput().getById(selectedPresetName);
		if (selectedItem == undefined) {
			alert(AOM.localize("$$$/AMG/javascript/ftp/nodeleteitem=No item selected, please select it first."));
			return;
		}
	
		if(!myConfirm("$$$/AMG/javascript/ftp/reallydelete=Delete current  FTP preset?")) {
			return;
		}
		
		//move from dropdownlist
		AOM.AmgCreateGallerySection.hasProgramInteract = true;
		ftpDropDownList.remove(ftpDropDownList.selection.index);
		ftpDropDownList.selection = 0;
		AOM.AmgCreateGallerySection.hasProgramInteract = false;
		
		//delete from memory.
		AOM.AMG.ftpPresetUserInput().remove(selectedItem);
		app.document = this.document;
	}
}

AOM.AmgFTPPresetUserInput = function() {
	this.ftpPresetItems = new Array();
	return this.restore();
}
AOM.AmgFTPPresetUserInput.prototype.getItems = function() {
	return this.ftpPresetItems;
}
AOM.AmgFTPPresetUserInput.prototype.setItems = function(newPresetItems) {
	this.ftpPresetItems = newPresetItems;
}
AOM.AmgFTPPresetUserInput.prototype.size = function() {
	return this.ftpPresetItems.length;
}
AOM.AmgFTPPresetUserInput.prototype.getById = function(presetName) {
	var keyword = presetName.toLowerCase();
	for (var i = 0; i < this.ftpPresetItems.length; i++) {
		var item = this.ftpPresetItems[i];
		if (item.id.toLowerCase() == keyword) {
			return item;
		}
	}
	return undefined;
}
AOM.AmgFTPPresetUserInput.prototype.add = function(item, index) {
	if (index == undefined) {
		index = this.size();
	} 
	this.ftpPresetItems[index] = item;
}
AOM.AmgFTPPresetUserInput.prototype.remove = function(what) {
	var index= -1;
	if (what instanceof Object) {
		index = this.indexOf(what.id);
	} else {
		index = what;
	}
	this.ftpPresetItems.splice(index, 1);
}
AOM.AmgFTPPresetUserInput.prototype.indexOf = function(newPresetName) {
	var findIndex = -1;
	var keyword = newPresetName.toLowerCase();
	for (var i = 0; i < this.ftpPresetItems.length; i++) {
		var item = this.ftpPresetItems[i];
		if (item.id.toLowerCase() == keyword) {
			findIndex = i;
			break;
		}
	}
	return findIndex;
}
AOM.AmgFTPPresetUserInput.prototype.restore = function() {
	var file = new File(AOM.AMG.Paths.persistedFTPPresetUserData);
	file.lineFeed = "unix";
	if (!file.open("r") || file.length == 0) {return undefined;}
	
	var json = File.decode(file.read());
	file.close();
	var persistedPresets = eval(json);
	if (persistedPresets instanceof Array) {
		this.ftpPresetItems = persistedPresets;
	}
	return true;
}
AOM.AmgFTPPresetUserInput.prototype.persist = function() {
	var file = new File(AOM.AMG.Paths.persistedFTPPresetUserData);
	file.lineFeed = "unix";
	if (!file.open("w"))
		return AOM.AMG.Log.writeError("DesignWindow.UserInput.persist - could not open file ("+file.fsName+")");
	AOM.Utils.writePersistFileHeader(file)
	file.writeln(File.encode(this.ftpPresetItems.toSource()));
	file.close();
}

// TODO - create these controls dynamically rather than via script
// TODO - change the control label text so they better describe their function
AOM.AmgCreateGallerySection.foldResourceContents = new String(
"group \
 {  \
 	orientation: 'column', \
	alignment: 'left',\
	margins: 5, spacing:6, \
	galleryLabel: StaticText {text: '" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/galleryName=Gallery Name:") + "', alignment: 'left'}, \
	galleryText: EditText {preferredSize:["+(AOM.AmgAccordionSection.accordionButtonWidth - 40)+", 18], properties:{borderless:true}, name:'cg_galleryText'}, \
	spacer1: Group {preferedSize: [0, 0]} \
	saveRadioButton: RadioButton {text: '" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/SaveToDisk=Save to Disk") + "', alignment: 'left', name:'cg_saveRadioButton'}, \
	saveGroup: Group \
	{ \
		orientation: 'column', \
		alignment: 'right', spacing:6, \
		saveFolderText: EditText {preferredSize:[" + (AOM.AmgAccordionSection.accordionButtonWidth - 52) + ", 18], properties:{borderless:true}, name:'cg_saveFolderText'}, \
		saveLocationGroup: Group \
		{ \
			alignment: ['fill', 'center'], \
			saveBrowseButton: Button {text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/Browse=Browse...") + "', alignment: ['left', 'center']} \
			saveButton: Button {text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/save=Save") + "', alignment: ['right', 'center']} \
		}, \
	}, \
	spacer2: Group {preferedSize: [0, 0]} \
	ftpRadioButton: RadioButton { text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/upload=Upload") + "', alignment: 'left', name:'cg_ftpRadioButton'}, \
	ftpGroup: Group \
	{ \
		orientation: 'column', \
		alignment: 'right', spacing:6,\
		tGroup:Group{\
			alignment:'left', spacing:5,\
			alignChildren:'left', \
			ftpTemplate:DropDownList{preferredSize:[196, 22], name:'cg_ftpTemplate'},\
			ftpSaveBtn:IconButton{\
				text:'',\
				preferredSize:[20, 20],\
				normalImagePath:'" + AOM.AMG.Paths.images + "new_normal.png" + "',\
				rolloverImagePath:'" + AOM.AMG.Paths.images + "new_rollover.png" + "',\
				disableImagePath:'" + AOM.AMG.Paths.images + "new_disable.png" + "',\
				themeType:'swapbutton',\
				helpTip:' " + AOM.localizeEsc("$$$/AMG/javascript/ftp/savePresetName=Save Preset Name") + "', \
			},\
			ftpDeleteBtn: IconButton{\
				text:'', \
				preferredSize:[20, 20],\
				normalImagePath:'" + AOM.AMG.Paths.images + "delete_normal.png" + "',\
				rolloverImagePath:'" + AOM.AMG.Paths.images + "delete_rollover.png" + "',\
				disableImagePath:'" + AOM.AMG.Paths.images + "delete_disable.png" + "',\
				themeType:'swapbutton',\
				helpTip:' " + AOM.localizeEsc("$$$/AMG/javascript/ftp/deletePresetName=Delete Selected Preset Name") + "', \
			},\
		},\
		ftpServerLabel: StaticText { text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/ftpserver=FTP Server:") + "', alignment: 'left'}, \
		ftpServerText: EditText {preferredSize:[248, 18], alignment:'fill', properties:{borderless:true}, name:'cg_ftpServerText'}, \
		nameGroup:Group{\
			alignment:'right', alignChildren:'right', spacing:5,\
			userNameLabel: StaticText { text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/username=User Name:") + "'}, \
			userNameText: EditText {preferredSize:[168, 18], properties:{borderless:true}, name:'cg_userNameText'}, \
		}\
		passGroup:Group{\
			alignment:'right', alignChildren:'right', spacing:5, \
			passwordLabel: StaticText { text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/password=Password:") + "'}, \
			passwordText: EditText {preferredSize:[168, 18], properties: {noecho: true, borderless:true}, name:'cg_passwordText'}, \
		}\
		cpassGroup:Group{\
			alignment:'right', alignChildren:'right', spacing:5, \
			hasLabel:StaticText{text:''},\
			ftpHasSavePass:Checkbox{\
				text:'" + AOM.localizeEsc("$$$/AMG/javascript/ftp/rememberPassword=Remember Password") + "', \
				preferredSize:[168, 18], \
				helpTip:' " + AOM.localizeEsc("$$$/AMG/javascript/ftp/storePasswordPlainHint=If you checked Remember Password, The password will be stored in plain text.") + "', \
				name:'cg_ftpHasSavePass',\
			},\
		}\
		foldGroup:Group{\
			alignment:'right', alignChildren:'right', spacing:5, \
			uploadFolderLabel: StaticText { text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/uploadfolder=Folder:") + "'}, \
			uploadFolderText: EditText {preferredSize:[168, 18], properties:{borderless:true}, name:'cg_uploadFolderText'}, \
		}\
		ftpButton: Button {text:'" + AOM.localizeEsc("$$$/MediaGallery/JavaScript/uploadViaFTP=Upload") + "', alignment: 'right'}, \
	} ,\
 }"
);

AOM.AmgPreviewWindow = function(document)
{
	this.tabbedPalette = AOM.AmgPreviewWindow.create(document);
	this.tabbedPalette.visible = false;
}
AOM.AmgPreviewWindow.create = function(document)
{
	var tabbedPalette = AOM.AmgTabbedPalette.create(document, "AMG Preview", "amgPreview", "web", undefined);
	return tabbedPalette;
}
AOM.AmgPreviewWindow.prototype.display = function (path)
{
	this.tabbedPalette.url = path;
}

AOM.AmgUserInput = function()
{
	this.initialize();
}
AOM.AmgUserInput.prototype.initialize = function()
{
	this.data = {};
	this.restore();
	// error values start with an underscore - make sure a few always exist
	this.data._idTranslationUndefined = "id translation undefined";
	this.data._bindingMapUndefined = "binding map undefined";
}
AOM.AmgUserInput.prototype.get = function (id)
{
	// Return a value from the user input data store.
	// Returns undefined if id is undefind or there is no value for
	// the given id.
	if (id == undefined)
		return undefined;

	var value = this.data[id];
	return value;
}
AOM.AmgUserInput.prototype.set = function (id, value)
{
	if (id == undefined || value == undefined)
	{
		AOM.AMG.Log.writeError("AOM.AMG.userInput().set - one or more input undefined (id: " + id + ", value:" + value + ")");
		return;
	}
	var valid = this.isValid(id, value);

	if (valid)
		this.data[id] = value;
	// TODO - If value is bad, should we clear out the previous value? Or should we leave the old value?
	// TODO - does anyone need to know if this is valid?
	return valid;
}
AOM.AmgUserInput.prototype.cleanUpdateMark = function(mark)
{
    for(var i in this.data) {
        if(this.data[i] != undefined) {
            if(i.indexOf(mark + "_Modified") > 0)
                this.data[i] = undefined;
        }
    }
}

AOM.AmgUserInput.validationRules = {};
AOM.AmgUserInput.validationRules.cg_galleryText		= [{name:"notEmpty", msg:AOM.localize("$$$/MediaGallery/JavaScript/ftp/requireGalleryName=A gallery name is required.")}, {name:"filename", msg:AOM.localize("$$$/MediaGallery/JavaScript/ftp/galleryNameUseFolder=Gallery name is used as the folder name when the gallery is written to disk or transferred via ftp.\nGallery Name is also used as the value of the <title> element in the gallery's index.html file.")}];
//AOM.AmgUserInput.validationRules.cg_saveFolderText	= [{name:"path"}, {name:"notEmptyIf", id:"cg_saveRadioButton", value:"true", msg:AOM.localize("$$$/MediaGallery/JavaScript/ftp/requireGalleryFoloder=The path for the gallery folder is required.")}];
//AOM.AmgUserInput.validationRules.cg_ftpServerText	= [{name:"notEmptyIf", id:"cg_ftpRadioButton", value:"true", msg:AOM.localize("$$$/MediaGallery/JavaScript/ftp/requrieFTPServer=FTP server is required.")}];
//AOM.AmgUserInput.validationRules.cg_userNameText	= [{name:"notEmptyIf", id:"cg_ftpRadioButton", value:"true", msg:AOM.localize("$$$/MediaGallery/JavaScript/ftp/requireUserName=A user name is required.")}];
AOM.AmgUserInput.doNotPersist = {};
AOM.AmgUserInput.doNotPersist.cg_passwordText = true;
AOM.AmgUserInput.doNotPersist._idTranslationUndefined = true;
AOM.AmgUserInput.doNotPersist._bindingMapUndefined = true;

//TODO
//AOM.AmgUserInput.validationRules.contactInfoLink = [{name:"email", msg:"Contact Info Link is not a correct format"}];

AOM.AmgUserInput.doNotPersistIf = {};
AOM.AmgUserInput.doNotPersistIf.cg_passwordText = { ifcond:"false", ref:"cg_ftpHasSavePass"};
/*
// TODO - dynamically modify the thumb and large values for HTML galleries
AOM.AmgUserInput.validationRules.io_thumbHeight		= [{name:"numberRange", minimum:24, maximum:192}];
AOM.AmgUserInput.validationRules.io_thumbWidth		= [{name:"numberRange", minimum:24, maximum:192}];
AOM.AmgUserInput.validationRules.io_smallHeight		= [{name:"numberRange", minimum:200, maximum:680}];
AOM.AmgUserInput.validationRules.io_smallWidth		= [{name:"numberRange", minimum:200, maximum:680}];
AOM.AmgUserInput.validationRules.io_mediumHeight	= [{name:"numberRange", minimum:300, maximum:900}];
AOM.AmgUserInput.validationRules.io_mediumWidth		= [{name:"numberRange", minimum:300, maximum:900}];
AOM.AmgUserInput.validationRules.io_largeHeight		= [{name:"numberRange", minimum:420, maximum:1275}];
AOM.AmgUserInput.validationRules.io_largeWidth		= [{name:"numberRange", minimum:420, maximum:1275}];
*/

AOM.AmgUserInput.prototype.isValid = function (id, value)
{
	var that = this;
	var checkRules = function (id, value, rules)
	{
		var notValid = function (defaultMsg, ruleMsg)
		{
			/* Work-around for #1840160: In ideal situation, the alert should be displayed by
			 *                           a direct invocation to alert(). It is now the following
			 *                           complicated process, that is, to detect the active status
			 *                           of the window and, in the case of inactive, use a scheduled
			 *                           task in order to avoid Bridge crash. */
			if(that.window.active) {
				alert(defaultMsg + (ruleMsg != undefined ? "\n\n"+ruleMsg : ""));
			} else {
				AOM.AmgUserInput.popupAlert = function() {
					alert(defaultMsg + (ruleMsg != undefined ? "\n\n"+ruleMsg : ""));
				};
				app.scheduleTask("AOM.AmgUserInput.popupAlert()", 0, false);
			}
			valid = false;
		}
		
		for (var i = 0; i < rules.length; i++)
		{
			var rule = rules[i]
			switch (rule.name)
			{
			 case "email":
				if (!AOM.AMG.Tests.isEmail(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidEmail=Does not appear to be a valid email address."));// 
				break;
			case "emailOrURL" :
				if (!AOM.AMG.Tests.isEmailOrURL(value)) {
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidEmailOrURL=Does not appear to be a valid email address or url address."));
				}
				break;
			 case "filename":
				if (!AOM.AMG.Tests.isFilename(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidFileName=Not a valid filename."), rule.msg);
				break;
			 case "filenamePath":
				if (!AOM.AMG.Tests.isFilenamePath(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidFileNameOrPath=Not a valid filename/path."));
				break;
			 case "notEmpty":
				if (!AOM.AMG.Tests.isNotEmpty(value)) {
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/fieldNotEmpty=Field cannot be empty."), rule.msg);
					valid = false;
				}
				break;
			 case "notEmptyIf":
				if (that.get(rule.id).toString() == rule.value.toString())
				{
					if (!AOM.AMG.Tests.isNotEmpty(value))
						notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/fieldNotEmpty=Field cannot be empty."), rule.msg);
				}
				break;
			 case "number":
				if (!AOM.AMG.Tests.isNumber(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/notNumber=Not a number."));
				break;
			 case "numberRange":
				if (!AOM.AMG.Tests.isWithinRange(value, rule.minimum, rule.maximum))
					notValid(AOM.localizeWithArgs("$$$/MediaGallery/JavaScript/validation/invalidRange=Must be a number in the range (1) - (2). ", rule.minimum, rule.maximum));
				break;
			 case "path":
				if (!AOM.AMG.Tests.isPath(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidPath=Not a valid path."));
				break;
			 default:
				AOM.AMG.Log.writeError("DesignWindow.UserInput.isValid - unhandled rule ("+rule.name+")");
				break;
			}
		
			//TODO, if current rule check is fail,  it's better return, otherwise it may pop up two or more alerts.
			if (valid == false) {
				return false;
			}
		}
		return valid;
	}

	var valid = true;
	var rules = AOM.AmgUserInput.validationRules[id];
	if (rules != undefined)
		valid = checkRules(id, value, rules);
	if (valid == true)
	{
		rules = AOM.AmgGalleryMaker.validationRules[id];
		if (rules != undefined)
			checkRules(id, value, rules);
	}
	return valid;
}
AOM.AmgUserInput.loadSizes = function(doc)
{
    var amgGalleryMakerData = AOM.AMG.galleryMakerData(doc);
    var currentUserInput = AOM.AMG.userInput(doc);

	// TODO - this is probably not the best way to set up the 
	// user input size value...
	var thumb = amgGalleryMakerData.sizes.values.thumb;
	if (thumb != undefined)
	{
		currentUserInput.set("io_thumbHeight", thumb.height);
		currentUserInput.set("io_thumbWidth", thumb.width);
	}
	var small = amgGalleryMakerData.sizes.values.small;
	if (small != undefined)
	{
		currentUserInput.set("io_smallHeight", small.height);
		currentUserInput.set("io_smallWidth", small.width);
	}
	var medium = amgGalleryMakerData.sizes.values.medium;
	if (medium != undefined)
	{
		currentUserInput.set("io_mediumHeight", medium.height);
		currentUserInput.set("io_mediumWidth", medium.width);
	}
	var large = amgGalleryMakerData.sizes.values.large;
	if (large != undefined)
	{
		currentUserInput.set("io_largeHeight", large.height);
		currentUserInput.set("io_largeWidth", large.width);
	}
}
AOM.AmgUserInput.persist = function(doc)
{
	// Step through the user input data store and write to disk
	var file = new File(AOM.AMG.Paths.persistedUserData);
	file.lineFeed = "unix";
	if (!file.open("w"))
		return AOM.AMG.Log.writeError("DesignWindow.UserInput.persist - could not open file ("+file.fsName+")");
		
	var write = function(id, value)
	{
		// TODO - escape any double quotes in value...
		file.writeln("{id:\""+id+"\",value:\""+File.encode(value)+"\"},");
	}
	
	AOM.Utils.writePersistFileHeader(file);
	file.writeln("AOM.AmgUserInput.persistedData = [");
	var data = AOM.AMG.userInput(doc).data;
	for (var i in data)
	{
	    if (data[i] == undefined)
	        continue;
		if (AOM.AmgUserInput.doNotPersist[i] == undefined) {
			write(i, data[i]);
		} else {
			var condition = AOM.AmgUserInput.doNotPersistIf[i];
			if (condition != undefined) {
				//if condition has value, get condition value, compare condtion value is equal to real value, if true do not persist, else persist.
				var refValue = data[condition.ref];
				if (data[condition.ref] == condition.ifcond) {
					//alert('do not persist');
				} else {
					//alert('persist');
					write(i, data[i]);
				}
			}
			//if (condition != undefined) {
				//var refValue = data[condition.ref];
				//alert('refvalue=' + refValue);
			//} 
		}
	}
	file.writeln("];\n");
	file.close();
	return true;
}
AOM.AmgUserInput.prototype.restore = function()
{
	var file = new File(AOM.AMG.Paths.persistedUserData);
	//file.lineFeed = "unix";
	if (!file.open("r") || file.length == 0) {
		return undefined;
	}
	var json = file.read();
	file.close();
	eval(json);
	
	var exclude = {};
	//exclude.t_template = true;
	//exclude.si_style = true;
	
	var data = AOM.AmgUserInput.persistedData;
	for (var i = 0; i < data.length; i++)
	{
		var d = data[i];
		if (exclude[d.id] == undefined)
			this.set(d.id, File.decode(d.value));
	}
	return true;
}
AOM.AmgUserInput.deletePersistedData = function()
{
	var file = new File(AOM.AMG.Paths.persistedUserData);
	if (file.exists)
		return file.remove()
	return true;
}
AOM.AmgUserInput.dump = function ()
{
	AOM.AMG.Log.writeLine("AOM.AmgUserInput.dump...");
	try
	{
		var dump = function (data)
		{
			for (var i in data)
				AOM.AMG.Log.writeLine(i + ": " + data[i]);
		}
		dump(AOM.AMG.userInput().data);
	}
	catch (e)
	{
		alert(e);
		AOM.AMG.Log.writeError("AOM.AmgUserInput.dump caught - " + e);
	}
	AOM.AMG.Log.writeLine("...AOM.AmgUserInput.dump");
}
AOM.AmgUserInput.htmlEncoding = function(value) {
	if (value == undefined || value.length == 0) return value;
	
	value = value.replace(/&/g, "&amp;"); 
	value = value.replace(/</g, "&lt;");
	value = value.replace(/>/g, "&gt;");
	value = value.replace(/\'/g, "&#39;");
	value = value.replace(/\"/g, "&quot;");
	return value;
}

AOM.AmgValidator = function() {};
AOM.AmgValidator.reset = function ()
{
	this.problemsFound = false;
	this.problemsDescription = "";
	this.errorStrings = new Array();
}
AOM.AmgValidator.testIdValue = function (id, value)
{
	var valid = true;
	var rules = AOM.AmgUserInput.validationRules[id];
	if (rules != undefined)
		valid = this.testValue(value, rules);
		
	rules = AOM.AmgGalleryMaker.validationRules[id];
	if (rules != undefined)
		valid = this.testValue(value, rules);
		
	return valid;
}
AOM.AmgValidator.testIdValueList = function (idValueList)
{
	for (var i = 0; i < idValueList.length; i++)
	{
		ivi = idValueList[i]; // id value item
		this.testIdValue(ivi.id, ivi.value);
	}
}
AOM.AmgValidator.testValueList = function (valueList)
{
	for (var i = 0; i < valueList.length; i++)
	{
		vli = valueList[i];
		this.testValue(vli.value, vli.rules);
	}
}
AOM.AmgValidator.errors = function ()
{
	var s = "";
	for (var i = 0; i < this.errorStrings.length; i++)
	{
		e = errorStrings.shift();
		s += e.error + " (" + e.detail + ")\n\n";
	}
	return s;
}
AOM.AmgValidator.testValue = function (value, rules)
{
	var valid = true;
	var notValid = function (defaultMsg, ruleMsg)
	{
		this.errorStrings.push({error:defaultMsg, detail:ruleMsg});
		valid = false;
	}
	for (var i = 0; i < rules.length; i++)
	{
		var rule = rules[i]
		switch (rule.name)
		{
		 case "email":
			if (!AOM.AMG.Tests.isEmail(value))
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidEmail=Does not appear to be a valid email address."));// 
			break;
		case "emailOrURL" :
			if (!AOM.AMG.Tests.isEmailOrURL(value)) {
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidEmailOrURL=Does not appear to be a valid email address or url address."));
			}
			break;
		 case "filename":
			if (!AOM.AMG.Tests.isFilename(value))
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidFileName=Not a valid filename."), rule.msg);
			break;
		 case "filenamePath":
			if (!AOM.AMG.Tests.isFilenamePath(value))
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidFileNameOrPath=Not a valid filename/path."));
			break;
		 case "notEmpty":
			if (!AOM.AMG.Tests.isNotEmpty(value))
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/fieldNotEmpty=Field cannot be empty."), rule.msg);
			break;
		 case "notEmptyIf":
			if (AOM.AMG.userInput().get(rule.id).toString() == rule.value.toString())
			{
				if (!AOM.AMG.Tests.isNotEmpty(value))
					notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/fieldNotEmpty=Field cannot be empty."), rule.msg);
			}
			break;
		 case "number":
			if (!AOM.AMG.Tests.isNumber(value))
				notValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/notNumber=Not a number."));
			break;
		 case "numberRange":
			if (!AOM.AMG.Tests.isWithinRange(value, rule.minimum, rule.maximum))
				notValid(AOM.localizeWithArgs("$$$/MediaGallery/JavaScript/validation/invalidRange=Must be a number in the range (1) - (2). ", rule.minimum, rule.maximum));
			break;
		 case "path":
			if (!AOM.AMG.Tests.isPath(value))
				otValid(AOM.AMG.localize("$$$/MediaGallery/JavaScript/validation/invalidPath=Not a valid path."));
			break;
		 default:
			AOM.AMG.Log.writeError("DesignWindow.UserInput.isValid - unhandled rule ("+rule.name+")");
			break;
		}
	
		//TODO, if current rule check is fail,  it's better return, otherwise it may pop up two or more alerts.
		if (valid == false) {
			return false;
		}
	}
	return valid;
}


AOM.AMG.ExternalObject= {};
AOM.AMG.ExternalObject.lastPath = undefined;
AOM.AMG.ExternalObject.create = function (file)
{
	AOM.AMG.ExternalObject.lastPath = AOM.AMG.Paths.resources + "plugins/" + file;
	var f = new File(AOM.AMG.ExternalObject.lastPath);
	if (f.exists)
	{
		var externalObject = new ExternalObject("lib:" + f.fsName);
		//if (typeof externalObject == "object")
		if (externalObject instanceof ExternalObject)
			return externalObject;
	}
	return undefined
}

AOM.AMG.WebAccess = {}
AOM.AMG.WebAccess.externalObject = undefined;
AOM.AMG.WebAccess.ftp = function ()
{
	// returns an ftp object
	if (AOM.AMG.WebAccess.externalObject == undefined)
	{
		if (AOM.AMG.WebAccess.open() == undefined)
			return undefined;
	}
	return new AOM.Ftp();
}
AOM.AMG.WebAccess.open = function ()
{
	AOM.AMG.WebAccess.externalObject = AOM.AMG.ExternalObject.create(File.fs == "Macintosh" ? "FtpConnection.bundle" : "FtpConnection.dll");
	if (typeof AOM.AMG.WebAccess.externalObject == "object")
		return true;
	AOM.AMG.Log.writeError("WebAccess.initialize - could not get external object (" + AOM.AMG.ExternalObject.lastPath + ")");
	return false;
}
AOM.AMG.WebAccess.unload = function ()
{
	if (AOM.AMG.WebAccess.externalObject != undefined)
	{
		AOM.AMG.WebAccess.externalObject.unload();
		AOM.AMG.WebAccess.externalObject = undefined;
		AOM.AMG.Log.writeLine("WebAccess.unload()...");
	}
}

AOM.AMG.Xslt = {};
AOM.AMG.Xslt.externalObject = undefined;
AOM.AMG.Xslt.transform = function (xml, xslt, out)
{
	if (AOM.AMG.Xslt.externalObject == undefined)
	{
		if (AOM.AMG.Xslt.initialize() == false)
		{
			alert("Could not open XSLT");
			return false;
		}
	}
	var filesExist = function (files)
	{
		var ok = true;
		for (var i = 0; i < files.length; i++)
		{
			var f = files[i];
			if (!f.exists)
			{
				AOM.AMG.Log.writeError("Xslt.transform - can't find '" + f.fsName + "'");
				ok = false;
			}
		}
		return ok;
	}
	if (filesExist([xml, xslt]))
	{
		// xslt return 0 if all's okay...
		return AOM.AMG.Xslt.externalObject.xslt(xml.fsName, xslt.fsName, out.fsName) == 0 ? true : false;
	}
	return false;
}
AOM.AMG.Xslt.initialize = function ()
{
	if (AOM.AMG.Xslt.externalObject != undefined)
	{
		AOM.AMG.Log.writeError("Xslt.initialize - externalObject not undefined");
		return true; // DWR - can we test that it is actually the an xslt?
	}
	AOM.AMG.Xslt.externalObject = AOM.AMG.ExternalObject.create(File.fs == "Macintosh" ? "XSLT.bundle" : "XSLT.dll");
	if (typeof AOM.AMG.Xslt.externalObject == "object")
		return true;
	AOM.AMG.Log.writeError("Xslt.initialize - could not get external object (" + AOM.AMG.ExternalObject.lastPath + ")");
	return false;
}
AOM.AMG.Xslt.unload = function ()
{
	if (AOM.AMG.Xslt.externalObject != undefined)
	{
		AOM.AMG.Xslt.externalObject.unload();
		AOM.AMG.Xslt.externalObject = undefined;
		AOM.AMG.Log.writeLine("Xslt.unload()...");
	}
}

AOM.AMG.Colorpicker = {};
AOM.AMG.Colorpicker.pick = function(color)
{
	return $.colorPicker(color);
}
AOM.AMG.Colorpicker.rgb = function (color)
{
	var blue  = (color & 0xFF)/255.0; color = color >>> 8;
	var green = (color & 0xFF)/255.0; color = color >>> 8;
	var red   = (color & 0xFF)/255.0;
	return [red, green, blue];
}
AOM.AMG.Colorpicker.get = function (id, doc)
{
	var color = 0x123456;
	var x = AOM.AMG.userInput(doc).get(id);
	if (x == undefined)
	{
		if (!AOM.AMG.disableColorpickerGetErrorMessages)
		{
			msg = "Colorpicker.get - id returned undefined ("+id+")";
			if (AOM.AMG.trackDocId)
				msg += ", doc.id = " + doc.id;
			AOM.AMG.Log.writeError(msg);
		}
	}
	else
		color = parseInt(x, 16);
	return color
}
AOM.AMG.Colorpicker.set = function (id, color, doc)
{
	var s = color.toString(16);
	while (s.length < 6)
	{
		s = "0" + s;
	}
	AOM.AMG.userInput(doc).set(id, s);
}

// TODO - decide if test shoud throw an exception or just return false
AOM.AMG.Tests = {};
AOM.AMG.Tests.isGroup = function (o)
{
	// For our purposes a group or a panel is considered a group...
	if (o instanceof Group || o instanceof Panel)
		return true;
	throw "AOM.AMG.Tests.isGroup - o was not a Group or Panel";
}
AOM.AMG.Tests.isString = function (s)
{
	if (s instanceof String == false)
		throw "AOM.AMG.Tests.isString - s was not a String";
	return true;
}
AOM.AMG.Tests.isDocument = function (d)
{
	if (d instanceof Document == false)
		throw "AOM.AMG.Test.isDocument - d was not a Docuement";
	return true;
}

/*
AOM.AMG.Tests.isEmail = function (s)
{
	var str = new String(s);
	// an empty string is ok for our purposes...
	if (str.amgIsEmpty())
		return true;
	// allow almost anything in the local portion of the address and restrict to alphanumeric, dash and period in the domain portion
	var r1 = /^[a-zA-Z0-9!#\$%&'\*+-=?^_`{\|}\.]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9-]+$/;
	return str.match(r1);
}
*/

AOM.AMG.Tests.isEmail = function(data) {
	if(data == "")
		return true;
    return /^[a-zA-Z0-9_\-.]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]+$/.test(data);
}


AOM.AMG.Tests.isURL = function(data) {
	/*
    var e=/((http|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)(([\w\-\.]+\.[^#?\s]+)(#[\w\-]+)?)?/;

    if (data.match(e)) {
        return  true;
	} else {
        return  false;
    }
	*/
	//loose validation
	var regTextUrl = /^(file|http|https|ftp|mms|telnet|news|wais|mailto):\/\/(.+)$/;
	return regTextUrl.test(data);
}

AOM.AMG.Tests.isSupportedURL = function(data) {
	/*
    var e=/((http|ftp):\/)?\/?([^:\/\s]+)((\/\w+)*\/)(([\w\-\.]+\.[^#?\s]+)(#[\w\-]+)?)?/;

    if (data.match(e)) {
        return  true;
	} else {
        return  false;
    }
	*/
	//loose validation
	var regTextUrl = /^(http|mailto):\/\/(.+)$/;
	return regTextUrl.test(data);
}

AOM.AMG.Tests.isEmailOrURL = function(data) {
	if (AOM.AMG.Tests.isEmail(data)) {
		return true;
	} 

	if (AOM.AMG.Tests.isSupportedURL(data)) {
		return true;
	}
	
	if (AOM.AMG.Tests.isURL(data)) {
		return false;
	}

	return true;
}


AOM.AMG.Tests.isFilename = function (s)
{
	var str = new String(s);
	return str.amgIsValidFile();
}
AOM.AMG.Tests.isNotEmpty = function (s)
{
	// this returns true for s == undefined. is that ok?
	var str = new String(s);
	return (str.amgIsEmpty() ? false : true);
}
AOM.AMG.Tests.isNumber = function (v)
{
	return (v == v * 1.0)
}
AOM.AMG.Tests.isWithinRange = function (v, min, max)
{
	if (!AOM.AMG.Tests.isNumber(v))
		return false;
	return (v >= min && v <= max);
}
AOM.AMG.Tests.isPath = function (s)
{
	var str = new String(s);
	// Bridge can't write to root of Mac so watch for that too
	if (File.fs == "Macintosh" && str.amgTrim() == "/")
	{
		alert("Gallery cannot be saved at the root");
		return false
	}
	return str.amgIsValidPath();
}


AOM.AMG.Log = {}
AOM.AMG.Log.logFile = undefined;
AOM.AMG.Log.initializeLogFile = function ()
{
	if (AOM.AMG.placeLogFileInUserHome)
		this.logFile = new File("~/amg.log");
	else
		this.logFile = new File(AOM.AMG.Paths.log + "amg.log"); 
	this.logFile.lineFeed = "unix"; // use unix line endings so it works with utilities like tail
	if (this.logFile.open("w", "TEXT", "????"))
	{
		this.logFile.close();
		return;
	}
	alert("AOM.AMG.Log.openLogFile - could not open logFile (" + this.logFile.fsName + ")");
	this.logFile = undefined;
}
AOM.AMG.Log.writeLine = function (line)
{
	// the log is not written immediately on Windows, so we 
	// open and close each time to flush the buffer...
	if (this.logFile == undefined)
		return;
	if (!this.logFile.open("e", "TEXT", "????"))
		return;
	this.logFile.seek(0, 2); // seek to the end of the file
	this.logFile.writeln(line);
	this.logFile.close();
}
AOM.AMG.Log.errorsDetected = false;
AOM.AMG.Log.writeError = function (error)
{
	this.writeLine("Error:  "  + error);
	AOM.AMG.Log.errorsDetected = true;
	return undefined;
}
AOM.AMG.Log.writeNote = function (note)
{
	this.writeLine("Note:   "  + note);
}
AOM.AMG.Log.dumpObject = function (object, text)
{
	if (object == undefined)
	{
		AOM.AMG.Log.writeError("dumpObject - object was undefined");
		return;
	}

	AOM.AMG.Log.writeLine("dumpObject...");

	if (text != undefined)
		AOM.AMG.Log.writeLine(text);

	var properties = object.reflect.properties;
	for (var i = 0; i < properties.length; i++)
	{
		if (properties[i] != undefined)
			AOM.AMG.Log.writeLine(object.reflect.name + "." + properties[i].name + " == " + object[properties[i].name]);
	}
	var methods = object.reflect.methods;
	for (i = 0; i < methods.length; i++)
	{
		if (methods[i] != undefined)
			AOM.AMG.Log.writeLine(object.reflect.name + "." + methods[i].name + "()");
	}

	AOM.AMG.Log.writeLine("...dumpObject");
}

AOM.AmgTimer = function()
{
	this.startTime = new Date();
}
AOM.AmgTimer.prototype.elapsed = function ()
{
	return (new Date()).getTime() - this.startTime;
}

