(function() {
    Ext.BLANK_IMAGE_URL = 'http://static.pictosys.se/1x1.gif';

    /* Turn off loading indicator to reduce flicker. */
    Ext.Updater.defaults.showLoadIndicator = false;


})();
/**
	Usage:
	Event.observe(window, "load", new Dialog(container, handle).makeDraggable);
	
	container is the div to move. optionally a handle may be provided (null
	otherwise) if a separate drag handle is included in the container.
 */

var Dialog = Class.create();
Dialog.prototype = {
	initialize: function(sContainer, sHandle) {
		this.containerName = sContainer;
		this.handle = sHandle;
		this.makeDraggable = this.onMakeDraggable.bind(this);
	},
	
	onMakeDraggable: function() {
		var container = $(this.containerName);
		var handle = $(this.handle);
		var dd = null;
		if (container && PictosysElement.isPropertyAvailable("YAHOO.util.DD")) {
			dd = new YAHOO.util.DD(container);
			if (handle) {
				dd.setHandleElId(handle);
			} else {
				console.log("handle was null");
			}
		} else {
			console.log("container was null or YAHOO.util.DD is not available");
		}
	},
	
	show: function(bEffect) {
		Effect.Appear(this.containerName, {duration:0.5});
	},
	
	hide: function(bEffect) {
		bEffect = (bEffect === undefined ? true : bEffect);
		if (this.containerName && $(this.containerName)) {
			if (bEffect) {
				if (Element.visible(this.containerName)) {
					Effect.Fade(this.containerName);
				}
			} else {
				Element.hide(this.containerName);				
			}
		}
	},

	toggle: function(dialog) {
		/* parenthesises around tertiary expression below to avoid jslint warning. */
		if (Element.visible(this.containerName)) {
			(dialog !== undefined ? dialog.hide() : this.hide());
		} else {
			(dialog !== undefined ? dialog.show() : this.show());
		}
	}
	
};
/*
 * Ext JS Library 2.1 Copyright(c) 2006-2008, Ext JS, LLC. licensing@extjs.com
 *
 * http://extjs.com/license
 *
 *
 * Adapted from http://extjs.com/deploy/dev/examples/shared/examples.js
 *
 */
Ext.namespace("B");

(function() {

    function QuickNotification()  {
    }

    var animConfig = {
            easing : 'easeOut',
            duration: 0.5
        };


    var msgCt;

    var msgWrapper;

    function createBox(t, s) {
        return ['<div class="message-wrapper">',
                '<div class="msg">',
                '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>',
                t,
                '</h3><p>',
                s,
                '</p></div></div></div>',
                '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                '</div>',
                '</div>'].join('');
    }


    QuickNotification.prototype = {
        /**
         * Usage QuickNotification("Note header", "Message with {0}",
         * "parameter0")
         */
        formatMessage : function(title, format) {

            if (!msgWrapper) {
                msgWrapper = Ext.DomHelper.insertFirst(document.body, {
                    id : 'msg-wrapper'
                });
            }

            if (!msgCt) {
                msgCt = Ext.DomHelper.insertFirst(msgWrapper, {
                    id : 'msg-div'
                }, true);
            }

            msgCt.alignTo(msgWrapper, 't-t');
            var s = String.format.apply(String, Array.prototype.slice.call(
                    arguments, 1));
            var m = Ext.DomHelper.append(msgCt, {
                html : createBox(title, s)
            }, true);
            m.hide().slideIn('t', animConfig).pause(6).ghost("t", {
                remove : true
            });
        }

    };


    B.QuickNotification = new QuickNotification();

})();
Ext.namespace("P");

(function() {

    function TestMode() {
    }

    TestMode.prototype = {

        isTestMode : function() {
            return !!(Ext.fly("username"));
        },

        isLoggedIn : function() {
            return !this.isTestMode();
        }

    };

    P.TestMode = new TestMode();

})();
var AddToSheetAnimation = Class.create();

AddToSheetAnimation.prototype = {
    initialize : function(source, target, sheetsize) {
        this.source = $(source);
        this.target = $(target);
        this.sheetsize = sheetsize;
    },

    createMovingElement : function() {

        var img = ImageHelper.copyFromParent(this.source.parentNode,
                this.sheetsize);


        this.movingElement = new Element("div").setStyle( {
            "position" :"absolute",
            "zIndex" :"100",
            "display" :"none"
        }).update(img);

        window.document.body.appendChild(this.movingElement);
    },

    onBegin : function() {
        this.createMovingElement();
        /*
         * Create an empty image in the target slot while the animation is
         * running so that the slot will be marked as taken.
         */
        this.target.appendChild(new Element("img").hide());

    },

    onComplete : function() {
        this.target.update(ImageHelper.copy($(this.movingElement).down("img")));
        this.movingElement.remove();
    },

    animate : function() {

        this.onBegin();

        /* On progress callback */
        var sourceDimension = new Dimension(this.source);
        var targetDimension = new Dimension(this.target);
        var source = this.movingElement;
        var target = this.target;
        var sheetsize = this.sheetsize;
        var sourcesize = 60; /* Size of source image */

        this.movingElement.show().absolutize();

        var onProgress = function(percentage) {
            var x = sourceDimension.left() +
                    (targetDimension.left() - sourceDimension.left()) *
                    percentage;
            var y = sourceDimension.top() +
                    (targetDimension.top() - sourceDimension.top()) *
                    percentage;

            var img = source.select("img")[0];

            source.setStyle( {
                left :x,
                top :y
            });

            img.setStyle( {
                height :sourcesize + (sheetsize - sourcesize) * percentage,
                width :sourcesize + (sheetsize - sourcesize) * percentage
            });

        };

        /* On complete callback */
        var onComplete = this.onComplete.bind(this);

        var transition = new Transition(SineCurve, 250, onProgress, onComplete);
        transition.run();

    }
};

var SliderAddToSheetAnimation = Class.create(AddToSheetAnimation, {
    initialize : function($super, pictogramPk, index, sheetsize) {
        $super("pk" + pictogramPk, "target" + index, sheetsize);

        this.pictogramPk = pictogramPk;
        this.index = index;
    },

    onComplete : function() {
        P.SliderSheet.replaceSlot(this.index, this.pictogramPk);
        this.movingElement.remove();
    }

});


var UserImageAddToSheetAnimation = Class.create(AddToSheetAnimation, {
    initialize : function($super, userImagePk, index, sheetsize) {
        $super("pk_ui_" + userImagePk, "target" + index, sheetsize);

        this.userImagePk = userImagePk;
        this.index = index;
    },

    onComplete : function() {
        P.SliderSheet.replaceSlotWithUserImage(this.index, this.userImagePk);
        this.movingElement.remove();
    }


});

var PictogramList =
function() {
	var downloadListId = "downloadList";
	var downloadListSelectId = "listRows";
	return {
		update: function(action, parameters) {
		    (new Ajax.Updater(downloadListId, action,
				{'parameters': parameters,
				'evalScripts': true}));

		},

		add: function(sPictogramId) {
		    if (P.TestMode.isTestMode() && Ext.select("#listRows option").getCount() > 0) {
		        B.QuickNotification.formatMessage("", DownloadListTranslations.maxList);
		        return;
		    }

			var parameters = {"pictogramId": sPictogramId};
			this.update("/pictogram/list/addItem", parameters);
		},

		addAll: function() {
			var parameters = {"date": (new Date().getTime()).toString()};
			this.update("/pictogram/list/addSearchResult", parameters);
		},

		remove: function() {
			var selection = $F(downloadListSelectId);
			var parameters = null;
			if (selection.length > 0) {
			    parameters = {"pictogramId" : selection};
    			this.update("/pictogram/list/deleteItem", parameters);
			}
		},

		removeAll: function() {
			this.update("/pictogram/list/emptyList", {"date": (new Date().getTime()).toString()});
		},

		showAll: function(itemsperpage) {
			var params = {"itemsperpage": itemsperpage};
			var targetDivId = "searchresults";
			var url = "/pictogram/list/showAll";

            (new Ajax.Updater(targetDivId, url,
				{parameters:params,
				 evalScripts: true,
				 onComplete: Search.registerMouseDown}));

		}

	};
} /* note function call here */ ();
var PictosysSheetItem = Class.create({
			initialize : function(url, eventNameToFireAfterSave) {
				this.url = url;
                this.eventName = eventNameToFireAfterSave
			},

            fireSavedEvent: function() {
                YAHOO.Bubbling.fire(this.eventName);  
            },
            
			save : function(sPictogramId, aPositions) {
				var params;
				if (aPositions.length > 0 && Sheet.Metrics.autoSave) {
					params = {
						'pictogramId' : sPictogramId,
						"position" : aPositions
					};

					(new Ajax.Request(this.url, {
								method : "post",
								parameters : params,
                                onSuccess : this.fireSavedEvent.bind(this)
							}));
				}
			},
			saveUserImage : function(sUserImageId, aPositions) {
				var params = {
					userImageId : sUserImageId,
					position : aPositions
				};

				(new Ajax.Request(this.url, {
							method : "post",
							parameters : params,
                            onSuccess : this.fireSavedEvent.bind(this)
						}));

			},
			DELETE : -1
		});

var SheetItem = new PictosysSheetItem("/print/control/sheet/save", "/sheet/labels/changes/saved");
var SliderSheetItem = new PictosysSheetItem("/print/edit/slidersheet/save", "/sheet/slider/changes/saved");

function getAcrobatVersion() {
   var acrobatVersion = 0;
   var acrobatVersion_DONTKNOW = -1;
   var agent = navigator.userAgent.toLowerCase(); 
   var plugin, i;
   
   // NS3+, Opera3+, IE5+ Mac, Safari (support plugin array):  check for Acrobat plugin in plugin array
   if (navigator.plugins !== null && navigator.plugins.length > 0) {
      for (i=0; i < navigator.plugins.length; i++ ) {
         plugin = navigator.plugins[i];
         if (plugin.name.indexOf("Adobe Acrobat") > -1) {
            acrobatVersion = parseFloat(plugin.description.substring(30));
         }
      }
   }
   
   // IE4+ Win32:  attempt to create an ActiveX object using VBScript
   else if (agent.indexOf("msie") !== -1 && 
   			parseInt(navigator.appVersion, 10) >= 4 && 
			agent.indexOf("win") !== -1 && agent.indexOf("16bit") === -1) {

      acrobatVersion = checkAdobeVersion();
  }

   // Can't detect in all other cases
   else {
      acrobatVersion = acrobatVersion_DONTKNOW;
   }

   return acrobatVersion;
   
}

function displayAdobeReaderNotice() {
	var ie = navigator.userAgent.toLowerCase().indexOf("msie") !== -1;
	if (getAcrobatVersion() < 5 || (ie && getAcrobatVersion() < 6)) {
		$("readerNotice").show();
	}
}
if (!se) {
	var se = {};
}

if (!se.pictosys) {
	se.pictosys = {};
}

(function() {
	var Dom = YAHOO.util.Dom;
	var Y = YAHOO.lang;

	se.pictosys.PictoSlider = function(name, options) {
		this.init(name, options);
	};

	se.pictosys.PictoSlider.prototype = {

		init : function(name, options) {

			this.initOptions(options);

			/* Pixels per millimeter for slider. */
			this.pixelsPerMillimeter = 1;

			if (!name) {
				throw "Slider name must be specified";
			}

			var sliderBg = name + "-slider";
			var sliderThumb = name + "-thumb";

			if (!Dom.get(sliderBg)) {
				throw "Could not find slider background";
			}

			if (!Dom.get(sliderThumb)) {
				throw "Could not find slider thumb";
			}

			this.template = new Template(this.options.template);

			this.slider = YAHOO.widget.Slider.getHorizSlider(sliderBg,
					sliderThumb, this.options.min, this.options.max,
					this.options.step);
			this.slider.subscribe("change", function(offset, target) {
						/*
						 * note: "this" will point to the slider in this event
						 * listener
						 */
						$(name + "-info").update(target.getFormattedText());
					}, this);
		},

		initOptions : function(options) {
			options = options || {};

			if (!Y.isNumber(options.min)) {
				options.min = 0;
			}

			if (!Y.isNumber(options.max)) {
				options.max = 100;
			}

			if (!Y.isNumber(options.step)) {
				options.step = 1;
			}

			if (!Y.isNumber(options.minPixelValue)) {
				options.minPixelValue = 0;
			}

			options.template = options.template || "#{value} mm";

			var template = new Template(options.template);

			this.options = options;

		},

		getSliderValue : function() {
			return this.slider.getValue();
		},

		setSliderValue : function(value) {
			this.slider.setValue(value, true /* skip anim */,
					true /* force */, false /*
											 * skip fire events
											 */);
		},
		getRealValue : function() {
			return this.getAdjustedSliderValue() / this.pixelsPerMillimeter;
		},

		setRealValue : function(mm) {
			var pixels = Math.max(0, mm * this.pixelsPerMillimeter
							- this.options.minPixelValue);
			// console.log(this);
			this.setSliderValue(pixels);
		},

		getFormattedText : function() {
			return this.template.evaluate({
						value : this.getRealValue()
					});
		},
		getAdjustedSliderValue : function() {
			return this.getSliderValue() + this.options.minPixelValue;
		},

		/* Pixels for preview slots in web GUI. */
		getPixelValue : function() {
			return this.getRealValue() * 2;

		}

	};

	/**
	 * Size slider
	 */
	se.pictosys.SizeSlider = function(name, options) {
		options = options || {};
		options.template = options.template || "#{value}x#{value} mm";
		if (!Y.isNumber(options.step)) {
			options.step = 2;
		}

		if (!Y.isNumber(options.minPixelValue)) {
			options.minPixelValue = 20;
		}
		
		se.pictosys.SizeSlider.superclass.constructor.call(this, name, options);

		var that = this;

		this.slider.subscribe("change", function(offsetFromStart, target) {
					YAHOO.Bubbling.fire('previewSizeSlider', {
								realValue : target.getRealValue(),
								pixelValue : target.getPixelValue()
							});

				}, this);

		this.slider.subscribe("slideEnd", function() {
					YAHOO.Bubbling.fire('changeSizeSlider', {
								realValue : that.getRealValue(),
								pixelValue : that.getPixelValue()
							});
				});

	};

	YAHOO.lang.extend(se.pictosys.SizeSlider, se.pictosys.PictoSlider, {});

	/**
	 * Horizontal Spacing Slider.
	 */
	se.pictosys.HorizontalSpacingSlider = function(name, options) {
		se.pictosys.HorizontalSpacingSlider.superclass.constructor.call(this,
				name, options);
		var that = this;
		this.slider.subscribe("change", function(offsetFromStart, target) {
					YAHOO.Bubbling.fire('previewHorizontalSlider', {
								realValue : target.getRealValue(),
								pixelValue : target.getPixelValue()
							});

				}, this);

		this.slider.subscribe("slideEnd", function() {

					YAHOO.Bubbling.fire('changeHorizontalSlider', {
								realValue : that.getRealValue(),
								pixelValue : that.getPixelValue()
							});

				});

	};

	YAHOO.lang.extend(se.pictosys.HorizontalSpacingSlider,
			se.pictosys.PictoSlider, {});

	/**
	 * Vertical Spacing Slider.
	 */
	se.pictosys.VerticalSpacingSlider = function(name, options) {
		se.pictosys.VerticalSpacingSlider.superclass.constructor.call(this,
				name, options);

		var that = this;
		this.slider.subscribe("change", function(offsetFromStart, target) {

					YAHOO.Bubbling.fire('previewVerticalSlider', {
								realValue : target.getRealValue(),
								pixelValue : target.getPixelValue()
							});

				}, this);

		this.slider.subscribe("slideEnd", function() {
					YAHOO.Bubbling.fire('changeVerticalSlider', {
								realValue : that.getRealValue(),
								pixelValue : that.getPixelValue()
							});

				});

	};

	YAHOO.lang.extend(se.pictosys.VerticalSpacingSlider,
			se.pictosys.PictoSlider, {});

})();
var Sheet = function() {
	var containerName = "pictogramsheet";
	var leftOffset = 390;
    
    function getTopOffset() {
        return $(containerName).cumulativeOffset().top;
    }

	var singleton = {

		init : function() {
			Sheet.resetSheet();
			YAHOO.util.Event.addListener(document, "keydown",
					Sheet.eventKeyDown);
		},

		resetSheet : function() {
			Sheet.registerDropTargets();
			Sheet.Selection.reset();
		},

		onRegisterDropTargets : function() {
			$$("#slots .slot").each(function(element) {
				(new YAHOO.util.DDTarget(element));
			});
		},

		isInside : function(left, top) {
			return (new Dimension(containerName).region()
					.contains(new YAHOO.util.Region(top, left, top, left)));
		},

		getSlotIndex : function(left, top) {
			var sheetsize = Sheet.Metrics.slotSize;
			var sheetcols = Sheet.Metrics.columns;
			return Math.floor((top - getTopOffset()) / sheetsize) * sheetcols
					+ Math.floor((left - leftOffset) / sheetsize);
		},

		selectSlotByIndex : function(iIndex) {
			Sheet.Selection.setSelected(iIndex, true);
			var target = $("target" + iIndex);
			if (target) {
				target.style.border = "1px teal solid";
				target.style.zIndex = "100";
				Element.setOpacity(target, 0.5);
			}

		},

		deselectSlotByIndex : function(iIndex) {
			Sheet.Selection.setSelected(iIndex, false);
			var target = $("target" + iIndex);
			if (target) {
				target.style.border = "none";
				target.style.borderLeft = "solid 1px white";
				target.style.borderTop = "solid 1px white";
				target.style.zIndex = "10";
				Element.setOpacity(target, 1.0);
			}
		},

		/*
         * @param bSelect Optional parameter, true by default
         */
		selectSlotByPosition : function(iLeft, iTop, bSelect) {
			var selecting = bSelect === undefined || bSelect;
			var index;
			if (this.isInside(iLeft, iTop)) {
				index = this.getSlotIndex(iLeft, iTop);
				if (selecting) {
					this.selectSlotByIndex(index);
				} else {
					this.deselectSlotByIndex(index);
				}
			}
		},

		selectSlotsByRegion : function(region, size) {

		},

		/*
         * @param start Start point @param end End point @param bSelect Optional
         * parameter, true by default
         */
		selectSlotsByPoints : function(start, end, bSelect) {
			var selecting = bSelect === undefined || bSelect;
			var slotSize = Sheet.Metrics.slotSize;
			var x, y;

			if (slotSize === 0) {
				throw "slotSize cannot be 0";
			}

			for (y = start.y; y < end.y; y += slotSize) {
				for (x = start.x; x < end.x; x += slotSize) {
					this.selectSlotByPosition(x, y, selecting);
				}
				this.selectSlotByPosition(end.x, y, selecting);
			}

			for (x = start.x; x < end.x; x += slotSize) {
				this.selectSlotByPosition(x, end.y, selecting);
			}

			this.selectSlotByPosition(end.x, end.y, selecting);
		},

		toggleSlotByIndex : function(index) {
			if (Sheet.Selection.isSelected(index)) {
				this.deselectSlotByIndex(index);
			} else {
				this.selectSlotByIndex(index);
			}
		},

		toggleSlotByPosition : function(iLeft, iTop) {
			var index;
			if (this.isInside(iLeft, iTop)) {
				index = this.getSlotIndex(iLeft, iTop);
				this.toggleSlotByIndex(index);
			}
		},

		onDeleteSelectedSlots : function(event) {
			Sheet.Selection.deleteSelected();
		},

		replaceSlot : function(iSlot, sPictogramKey) {
			var replacement = this.getReplacement(sPictogramKey);
			Element.update("target" + iSlot, replacement);
			SheetItem.save(sPictogramKey, [iSlot]);
		},

		replaceAllSelectedSlotsAnimated : function(elPictogram) {
			return Sheet.Selection.replaceSelectedAnimated(elPictogram);
		},

		replaceAllSelectedSlots : function(sPictogramId) {
			var replacement = this.getReplacement(sPictogramId);
			return Sheet.Selection.replaceSelected(sPictogramId, replacement);
		},

		add : function(sPictogramKey) {
			var pictogram = this.getPictogramElement(sPictogramKey);
			var divs, imgs, i, animation;
			if (!this.replaceAllSelectedSlotsAnimated(pictogram)) {
				/* no selection found, try to find available slot */
				divs = Sheet.Slots.getSlots();
				for (i = 0; i < divs.length; i++) {
					imgs = divs[i].getElementsByTagName("img");
					if (imgs.length === 0) {
						animation = new AddToSheetAnimation(pictogram, "target"
								+ i, Sheet.Metrics.slotSize);
						animation.animate();
						SheetItem.save(sPictogramKey, [i]);
						break;
					}
				}
			}
		},

		fill : function(sPictogramKey) {
			var divs = Sheet.Slots.getSlots();
			var positions = [];
			var i;
			for (i = 0; i < divs.length; i++) {
			    $("target" + i).update(this.getReplacement(sPictogramKey));
				positions.push(i);
			}
			SheetItem.save(sPictogramKey, positions);
		},

		getPictogramElement : function(sPictogramKey) {
			return $("pk" + sPictogramKey);
		},

		getReplacement : function(sPictogramKey) {
			var pictogram = this.getPictogramElement(sPictogramKey);
			return ImageHelper.copyFromParent(pictogram.parentNode,
					Sheet.Metrics.slotSize);
		},

		onKeyDown : function(e) {
			var evt = e || window.event;
			var keycode = null;

			if (evt.keyCode) {
				keycode = evt.keyCode;
			} else if (evt.which) {
				keycode = evt.which;
			}

			if (keycode === 46) { // delete
				Sheet.eventDeleteSelectedSlots(evt);
			}
		}

	};
	singleton.registerDropTargets = singleton.onRegisterDropTargets
			.bind(singleton);
	singleton.eventDeleteSelectedSlots = singleton.onDeleteSelectedSlots
			.bindAsEventListener(singleton);
	singleton.eventKeyDown = singleton.onKeyDown.bindAsEventListener(singleton);
	singleton.deleteSelectedSlots = singleton.onDeleteSelectedSlots
			.bind(singleton);
	return singleton;

} /* note function call here */();

/* Helper class for Sheet. Should ideally not be called from any other class. */
Sheet.Selection = function() {
	var selected = [];
	
	function replaceContents(slot, image) {
		$(slot).update(ImageHelper.copy(image));
	}
	
	return {
		reset : function() {
			selected = [];
		},

		/* Counts number of selected slots. */
		count : function() {
			var count = 0;
			for (var i = 0; i < selected.length; i++) {
				if (selected[i]) {
					count++;
				}
			}
			return count;
		},

		isSelected : function(iIndex) {
			return selected[iIndex];
		},

		isSelectedById : function(sId) {
            try {
    			var index = parseInt(Sheet.Slots.slotIdToIndex(sId), 10);
	       		return this.isSelected(index);
            } catch (e) {
                console.log("returning false");
                return false;
            }
		},

		isSelectedByPosition : function(iLeft, iTop) {
			var index = Sheet.getSlotIndex(iLeft, iTop);
			return this.isSelected(index);
		},

		isSelectedByPoint : function(point) {
			return this.isSelectedByPosition(point.x, point.y);
		},

		setSelected : function(iIndex, bSelected) {
			selected[iIndex] = bSelected;
		},

		deleteSelected : function() {
			var divs = Sheet.Slots.getSlots();
			var positions = [];
			for (var i = 0; i < divs.length; i++) {
				if (this.isSelected(i)) {
					Sheet.deselectSlotByIndex(i);
					Element.update("target" + i, "");
					positions.push(i);
				}
			}

			SheetItem.save(SheetItem.DELETE, positions);
		},

		replaceSelected : function(sPictogramId, replacement) {
			var usedSelected = false;
			var positions = [];
			for (var i = 0; i < selected.length; i++) {
				if (this.isSelected(i)) {
				    $("target" + i).update(ImageHelper.copy(replacement));
					usedSelected = true;
					Sheet.deselectSlotByIndex(i);
					positions.push(i);
				}
			}
			SheetItem.save(sPictogramId, positions);
			return usedSelected;

		},

		replaceSelectedAnimated : function(elPictogram, iThreshold) {
			var threshold = iThreshold || 10;
		    
			var replacementImage = ImageHelper.copyFromParent(elPictogram.parentNode, Sheet.Metrics.slotSize);
			var usedSelected = false;
			var animate = this.count() <= threshold;
			var positions = [];
			var animation;
			for (var i = 0; i < selected.length; i++) {
				if (this.isSelected(i)) {
					if (animate) {
						animation = new AddToSheetAnimation(elPictogram,
								"target" + i, Sheet.Metrics.slotSize);
						animation.animate();
					} else {
						replaceContents("target" + i, replacementImage);
					}
					usedSelected = true;
					Sheet.deselectSlotByIndex(i);
					positions.push(i);
				}
			}
			SheetItem.save(Misc.removeNonDigits(elPictogram.id), positions);
			return usedSelected;
		}
	};

} /* note function call here */();

Sheet.Slots = function() {
	var singleton = {
		getSlots : function() {
			return $$("div#slots div.slot");
		},

		slotIdToIndex : function(sSlotId) {
			return sSlotId.replace("target", "");
		}
	};
	return singleton;
} /* note function call here */();

Sheet.Metrics = {
	slotSize : 0,
	columns : 0,
	autoSave : true
};

Sheet.Management = function() {

	var sheetSizeSelectId = 'sheetChangeSizeSelect';
	var managementContainerId = 'sheetManagementBlock';
	var sheetContainerId = "pictogramsheet";
	var editor = null; // in-place rename editor
	var singleton = {
		create : function() {
			Sheet.Management.sizeHelper("/print/control/sheet/create", this.createHandler
					.bind(this));
		},
        
        createHandler: function() {
            this.update();
            YAHOO.Bubbling.fire("/sheet/created");
        },

		save : function(createSheet) {
			if (createSheet) {

				Ext.app.SheetTreePanel.save();

			} else {
				createMessageShowAndHiderOnTimeout("sheetSaved")();
			}
		},

		onChange : function(e) {
			Sheet.Management.sizeHelper("/print/control/sheet/changeSize",
					this.addRenameAndUpdate.bind(this));
            
            var classNames = {
                1: 'fixed-small',
                2: 'fixed-medium',
                3: 'fixed-large'
            };

            var newClassName = classNames[$F(sheetSizeSelectId)];
            $(document.body).removeClassName('fixed-small').removeClassName('fixed-medium').removeClassName('fixed-large').addClassName(newClassName);
		},

		sizeHelper : function(url, callback) {
			var size = $F(sheetSizeSelectId);
			var params = {
				'sheetSize' : size
			};

			(new Ajax.Updater(managementContainerId, url, {
				parameters : params,
				evalScripts : true,
				onComplete : callback
			}));

		},
        
        disableRenameEditor : function() {
            if (editor) {
                editor.dispose();
            }
        },

		addRenameEditor : function() {
            var enableRenameEditor = false; /* Disable until it works properly for unsaved sheets. */
			if (enableRenameEditor && $("sheet-name")) {
				editor = new Ajax.InPlaceEditor("sheet-name",
						"/print/control/sheet/rename", {
							okButton : false,
							cancelLink : false,
							submitOnBlur : true,
							highlightcolor : '#FFFFBB'
						});
			}

		},

		openRename : function() {
			this.addRenameEditor();
			if (editor) {
				editor.enterEditMode();
			}
		},

		openRenameAndUpdate : function() {
			this.openRename();
			Sheet.Management.update();
		},

		addRenameAndUpdate : function() {
			this.addRenameEditor();
			Sheet.Management.update();
		},

		update : function() {
			(new Ajax.Updater(sheetContainerId, '/print/control/sheet/update', {
				evalScripts : true,
				onComplete : Sheet.resetSheet.bind(Sheet)
			}));
		},

		remove : function() {
			(new Ajax.Updater(managementContainerId, "/print/control/sheet/delete", {
				evalScripts : true,
				onComplete : Sheet.Management.update
			}));
		},

		load : function(sheetPk) {
			var params = {
				'sheetPrimaryKey' : sheetPk
			};

			(new Ajax.Updater(managementContainerId, "/print/control/sheet/load", {
				parameters : params,
				evalScripts : true,
				onComplete : this.addRenameAndUpdate.bind(this)
			}));
		},

		open : function() {
			Ext.app.SheetTreePanel.load();
		}

	};
	singleton.change = singleton.onChange.bindAsEventListener(singleton);
	return singleton;

} /* note function call here */();
/* Some functions which probably will show up in prototype's Element later. */

var PictosysElement = {
    enable : function() {
        this.setDisabled(false, arguments);
    },

    disable : function() {
        this.setDisabled(true, arguments);
    },

    setDisabled : function(disabled, elements) {
        for ( var i = 0; i < elements.length; i++) {
            element = elements[i];
            if (typeof element === 'string') {
                element = document.getElementById(element);
            }

            element.disabled = disabled ? "true" : "";
        }
    },

    isPropertyAvailable : function(sProperty, parent) {
        parent = parent || window;
        var dot, first, rest;
        if (sProperty === "") {
            return true;
        }
        if (sProperty.indexOf(".") >= 0) {
            dot = sProperty.indexOf(".");
            first = sProperty.substring(0, dot);
            rest = sProperty.substring(dot + 1);
            return parent[first] &&
                    this.isPropertyAvailable(rest, parent[first]);
        } else {
            return parent[sProperty];
        }
    },

    /**
     * Deprecated. Use Prototype instead:
     * 
     * new Element(type, attributes).setStyle(style).update(text);
     * 
     * Creates a new HTML element. The parameters attributes and style are maps
     * {key:value, ...} of HTML and style attributes respectively. Text is an
     * optional text to add as a child to the created element.
     * 
     * Code from
     * http://www-128.ibm.com/developerworks/xml/library/x-matters41.html
     */
    create : function(type, attributes, style, text) {

        var e = document.createElement(type);

        if (attributes) {
            for (key in attributes) {
                if (key === 'class') {
                    e.className = attributes[key];
                } else if (key === 'id') {
                    e.id = attributes[key];
                } else {
                    e.setAttribute(key, attributes[key]);
                }
            }
        }

        if (style) {
            for (key in style) {
                e.style[key] = style[key];
            }
        }

        if (text) {
            e.appendChild(document.createTextNode(text));
        }

        return e;
    }

};
/*
 * Ext JS Library 2.1 Copyright(c) 2006-2008, Ext JS, LLC. licensing@extjs.com
 * 
 * http://extjs.com/license
 * 
 * 
 * Adapted from http://extjs.com/deploy/dev/examples/shared/examples.js
 * 
 */

SheetNotification = function() {
	var msgCt;
    var messageTimer;

	function createBox(t, s) {
		return [
				'<div class="msg" style="text-align: center;">',
				//'<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
				'<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">' +
                //'<h3>',
				//t,
				//'</h3>',
                '<span>',
				s,
                '</span>',
				'</div></div></div>',
				'<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
				'</div>'].join('');
	}
	var singleton =  {
		/**
		 * Usage QuickNotification("Note header", "Message with {0}",
		 * "parameter0")
		 */
		formatMessage : function(title, format) {
			if (!msgCt) {
				msgCt = Ext.DomHelper.insertFirst(document.body, {
					id : 'msg-div'
				}, true);
			}
            
            /* Align twice or it won't work in IE6. */
			msgCt.alignTo("margins", 'tr-br');
			msgCt.alignTo("margins", 'tr-br');
            
			var s = String.format.apply(String, Array.prototype.slice.call(
					arguments, 1));
			var m = Ext.DomHelper.append(msgCt, {
				html : createBox(title, s)
			}, true);
			m.slideIn('t').pause(3).slideOut("t", {
				remove : true
			});
            
        
		},
        
        cancelMessage : function() {
            if (messageTimer) {
                clearTimeout(messageTimer);
            }
        },
        
        scheduleSavedNotification : function() {
            this.cancelMessage();
	        messageTimer = this.formatMessage.bind(this, "", TreeTranslations.changesSaved).defer(5000);
        }

	};
    
    YAHOO.Bubbling.on("/sheet/saved", function(name, array) {
        var param = array[1];
        
        $("sheet-name").removeClassName("unnamed").update(param.name);
    }, singleton);
    
    YAHOO.Bubbling.on("/sheet/created", function(name, array) {
        $("sheet-name").addClassName("unnamed").update(TreeTranslations.untitledSheet);
        this.cancelMessage();
    }, singleton);
    
    YAHOO.Bubbling.on("/sheet/slider/changes/saved", function(name, array) {
        if (!$("sheet-name").hasClassName("unnamed")) {
            this.scheduleSavedNotification();
        }
    }, singleton);

    YAHOO.Bubbling.on("/sheet/schedule/changes/saved", function(name, array) {
        if (!$("sheet-name").hasClassName("unnamed")) {
            this.scheduleSavedNotification();
        }
    }, singleton);

    YAHOO.Bubbling.on("/sheet/schedule/week/changes/saved", function(name, array) {
        if (!$("sheet-name").hasClassName("unnamed")) {
            this.scheduleSavedNotification();
        }
    }, singleton);

    YAHOO.Bubbling.on("/sheet/labels/changes/saved", function(name, array) {
        if (!$("sheet-name").hasClassName("unnamed")) {
            this.scheduleSavedNotification();
        }
    }, singleton);
    
    
    return singleton;
} ();
var CountryCodeListener = Class.create({
	/* source = country select id, target = state id */
	initialize : function(source, target) {
		this.source = $(source);
		this.target = $(target);

		var that = this;
		
		Event.observe(window, "load", function() {
			that.checkIfStateRequired();
			Event.observe(that.source, "change", that.checkIfStateRequired
					.bind(that));
		});

	},

	
	
	checkIfStateRequired : function() {
		var country = $F(this.source);

		if (country === "CA" || country === "US") {
			$(this.target).show();
		} else {
			$(this.target).hide();
		}
	}

});
function submitForm(form) {
	form.submit();
}

function checkUsername(form, suggestedUsername) {
	if (form.username.value === suggestedUsername) {
		form.username.value = '';
		form.passwordtext.style.display  = "none";
		form.passwordpassword.style.display = "inline";
	} else if (form.username.value === '') {
		form.username.value = suggestedUsername;
		form.passwordtext.style.display  = "inline";
		form.passwordpassword.style.display = "none";
	}
}


function checkPassword(form) {
	if (form.passwordpassword.style.display === "none") {
		form.passwordtext.style.display  = "none";
		form.passwordpassword.style.display = "inline";
		form.passwordpassword.focus();
	} else if (form.passwordpassword.value === '') {
		form.passwordtext.style.display  = "inline";
		form.passwordpassword.style.display = "none";
	}
}

function checkEnter(form) {
	if (event.keyCode === 13) {
		form.submit();
    }
}

/* Sets selected value in a select (dropdown control) */
function setSelectedValue(selectId, value) {
	var select = $(selectId);
	var options, i;
	if (select) {
		options = select.options;
		for (i = 0; i < options.length; i++) {
			if (options[i].value === value) {
				options[i].selected = true;
				return;
			}
		}
		select.selectedIndex = 0;
	}
}

/**
 * Creates a function which displays the given div, and then registers
 * some input events to hide it.
 */
function createMessageShowAndHider(messageDivId) {
	return function() {
	    Effect.Appear(messageDivId, {"to":0.9});
	    var hideEvents = ["mousedown", "keydown", "mousemove"];
		var target = window;
		var addHideEvents = function() {
	    hideEvents.each(function(eventName) {
	       Event.observe(target, eventName, 
	           function(e) {
	              /* arguments.callee is the calling function, i.e. this function. */
	              Event.stopObserving(target, eventName, arguments.callee, false);
	              Effect.Fade(messageDivId, {duration:3.0});
	           });
	       });
		};
		setTimeout(addHideEvents.bind(this), 10000);
		};
}

/**
 * Creates a function which displays the given div, and then
 * hides it after a timeout.
 */
function createMessageShowAndHiderOnTimeout(messageDivId) {
    return function() {
        Effect.Appear(messageDivId, {"to":0.9});
        setTimeout(
            function() {
                Effect.Fade(messageDivId, {duration:2.5});
            }
            , 10000);
    };

}

function shortcut(shortcut,callback,opt) {
	//Provide a set of default options
	var default_options = {
		'type':'keydown',
		'propagate':false,
		'target':document
	}
	if(!opt) opt = default_options;
	else {
		for(var dfo in default_options) {
			if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
		}
	}

	var ele = opt.target
	if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
	var ths = this;

	//The function to be called at keypress
	var func = function(e) {
		e = e || window.event;
		
		//Find Which key is pressed
		if (e.keyCode) code = e.keyCode;
		else if (e.which) code = e.which;
		var character = String.fromCharCode(code).toLowerCase();

		var keys = shortcut.toLowerCase().split("+");
		//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
		var kp = 0;
		
		//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
		var shift_nums = {
			"`":"~",
			"1":"!",
			"2":"@",
			"3":"#",
			"4":"$",
			"5":"%",
			"6":"^",
			"7":"&",
			"8":"*",
			"9":"(",
			"0":")",
			"-":"_",
			"=":"+",
			";":":",
			"'":"\"",
			",":"<",
			".":">",
			"/":"?",
			"\\":"|"
		}
		//Special Keys - and their codes
		var special_keys = {
			'esc':27,
			'escape':27,
			'tab':9,
			'space':32,
			'return':13,
			'enter':13,
			'backspace':8,

			'scrolllock':145,
			'scroll_lock':145,
			'scroll':145,
			'capslock':20,
			'caps_lock':20,
			'caps':20,
			'numlock':144,
			'num_lock':144,
			'num':144,
			
			'pause':19,
			'break':19,
			
			'insert':45,
			'home':36,
			'delete':46,
			'end':35,
			
			'pageup':33,
			'page_up':33,
			'pu':33,

			'pagedown':34,
			'page_down':34,
			'pd':34,

			'left':37,
			'up':38,
			'right':39,
			'down':40,

			'f1':112,
			'f2':113,
			'f3':114,
			'f4':115,
			'f5':116,
			'f6':117,
			'f7':118,
			'f8':119,
			'f9':120,
			'f10':121,
			'f11':122,
			'f12':123
		}


		for(var i=0; k=keys[i],i<keys.length; i++) {
			//Modifiers
			if(k == 'ctrl' || k == 'control') {
				if(e.ctrlKey) kp++;

			} else if(k ==  'shift') {
				if(e.shiftKey) kp++;

			} else if(k == 'alt') {
					if(e.altKey) kp++;

			} else if(k.length > 1) { //If it is a special key
				if(special_keys[k] == code) kp++;

			} else { //The special keys did not match
				if(character == k) kp++;
				else {
					if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
						character = shift_nums[character]; 
						if(character == k) kp++;
					}
				}
			}
		}

		if(kp == keys.length) {
			callback(e);

			if(!opt['propagate']) { //Stop the event
				//e.cancelBubble is supported by IE - this will kill the bubbling process.
				e.cancelBubble = true;
				e.returnValue = false;

				//e.stopPropagation works only in Firefox.
				if (e.stopPropagation) {
					e.stopPropagation();
					e.preventDefault();
				}
				return false;
			}
		}
	}

	//Attach the function with the event	
	if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
	else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
	else ele['on'+opt['type']] = func;
}
var DDMovable = function(id, sGroup, config) {
	if (id) {
		this.init(id, sGroup, config);
	}
};

YAHOO.lang.extend(DDMovable, YAHOO.util.DD, {
	/*
     * Sets up config options specific to this class. Overrides
     * YAHOO.util.DD, but all versions of this method through the
     * inheritance chain are called
     */
    applyConfig: function() {
        DDMovable.superclass.applyConfig.call(this);
        this.setDragElId("movable");
        this.isTarget = false;
    },
    
    setSourceId : function(el) {
    	/* Primary key of source element, for example pictogram 
    	 * primary key or user image primary key. */
		this.sourceId = Misc.removeNonDigits(el.id);    	
    },
    
    getSourceId : function() {
    	return this.sourceId;
    },

    /* adjusts the drag element position relative to the pointer */
    adjustPointerPosition: function(x, y) {
        var dragEl = this.getDragEl();
        
        /* Must show before calculating dimensions. */
        var dim = new Dimension(dragEl);

        /* Adjust position relative to pointer. */
        this.setDelta(dim.width()/2, dim.height()/2);

        /* Adjust starting position. */
        dragEl.style.left = x - dim.width()/2;
        dragEl.style.top = y - dim.height()/2;

    },
    
    createDraggingImage : function() {
        var el = this.getEl(); // img element
        return new ImageCopy($(el.parentNode).down("img")).plainCopy();
    },
    
    b4StartDrag: function(x, y) {

        this.setSourceId(this.getEl());

    	$(this.getDragEl()).update(this.createDraggingImage()).show();

        this.adjustPointerPosition(x, y);
    },

    
    replaceTargetSlot: function(index) {

    	var pictogramId = this.getSourceId();
    	
        if (Sheet.Selection.isSelected(index)) {
	 		Sheet.replaceAllSelectedSlots(pictogramId);
	 	} else {
			Sheet.replaceSlot(index, pictogramId);
		}
    },

    getIndexForId : function(id) {
          var index = id.replace("target", "");
          return index;
    },
    
    isTargetSlot : function(id) {
        return id.startsWith("target");
    },
    
    replaceTargetId : function(id) {
        //console.log("Replacing id %s", id);

        var index = this.getIndexForId(id);
        this.replaceTargetSlot(index);
    },
    
    onDragDrop : function(e, id) {
        // center it in the square
   		Element.setOpacity(id, 1.0);
        YAHOO.util.Dom.setXY(this.getDragEl(), YAHOO.util.Dom.getXY(id));

        this.replaceTargetId(id);
        
        this.getDragEl().hide();

		/* The tooltip is removed when a drag starts, so it is added back again. */
        try {
            if (this.getEl().alt) {
		        (new Tooltip(this.getEl(), this.getEl().alt));
            }
        } catch(e) {
            /* ignored */
        }
	},

	onInvalidDrop: function(e) {
        /* return to the start position*/
        var startPos = YAHOO.util.Dom.getXY(this.getEl());
        var dragEl = this.getDragEl();

		// The tooltip is removed when a drag starts, so it is added back again.
		(new Tooltip(this.getEl(), this.getEl().alt));


        var animation =
        	new YAHOO.util.Motion(dragEl,
        	    				 {points: {"to": startPos}},
				                  0.500,
				                  YAHOO.util.Easing.easeBothStrong);

        animation.onComplete.subscribe(function() {
        	dragEl.hide();
        });

		animation.animate();

	},

	onDragEnter: function(e, id) {
		Element.setOpacity(id, (Sheet.Selection.isSelectedById(id) ? 0.3: 0.5));
	},

	onDragOut: function(e, id) {
		Element.setOpacity(id, (Sheet.Selection.isSelectedById(id) ? 0.5: 1.0));
	}
});



var SliderMovable = function(id, sGroup, config) {
	if (id) {
		this.init(id, sGroup, config);
	}
};

YAHOO.lang.extend(SliderMovable, DDMovable, {
	/*
     * Sets up config options specific to this class. Overrides
     * YAHOO.util.DD, but all versions of this method through the
     * inheritance chain are called
     */
    applyConfig: function() {
        SliderMovable.superclass.applyConfig.call(this);
        this.setDragElId("slidermovable");
        this.isTarget = false;
    },

    getTargetSize : function() {
        return $("target0").getWidth();
    },

    createDraggingImage : function() {
        var el = this.getEl(); // img element
        return new ImageCopy($(el.parentNode).down("img"))
                .withSize(this.getTargetSize());
    },
    
   replaceTargetSlot: function(index) {
   		var pictogramId = this.getSourceId();
        P.SliderSheet.dropOnSlot(index, pictogramId);   	
   },
   
   isMainImageTarget : function(id) {
        return id === "main-image";
   },
   
   isAdditionalImageTarget : function(id) {
        return id === 'additional-image';    
   },
   
   addAdditionalImage : function() {
        P.SliderSheet.addAdditionalPictogram(this.getSourceId());    
   },
   
   addMainImage : function() {
        P.SliderSheet.addMainPictogram(this.getSourceId());
   },
   
   replaceTargetId : function(id) {
        if (this.isTargetSlot(id)) {
            this.replaceTargetSlot(this.getIndexForId(id))
        } else if (this.isMainImageTarget(id)) {
            this.addMainImage();
        } else if (this.isAdditionalImageTarget(id)) {
            this.addAdditionalImage();
        } else {
            console.log("Don't know what to do with %s", id);
        }
   }

});


var UserImageMovable = function(id, sGroup, config) {
	if (id) {
		this.init(id, sGroup, config);
	}
};


YAHOO.lang.extend(UserImageMovable, SliderMovable, {

	replaceTargetSlot : function(index) {
		var userImagePk = this.getSourceId();
		P.SliderSheet.dropOnSlotUserImage(index, userImagePk);
	},

   addAdditionalImage : function() {
        P.SliderSheet.addAdditionalUserImage(this.getSourceId());    
   },

    addMainImage : function() {
        P.SliderSheet.addMainUserImage(this.getSourceId());
    }

});
Ext.namespace("P");

(function() {

	P.SchedulePictogramMovable = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.SchedulePictogramMovable, DDMovable, {
				applyConfig : function() {
					P.SchedulePictogramMovable.superclass.applyConfig.call(this);
					this.setDragElId("schedulemovable");
					this.isTarget = false;
				},

                getTargetSize : function() {
                    return $("row0").getHeight();
                },

                getDraggingImage : function() {
                    return this.getDragEl().down("img");
                },
                
                calculateIndicatorWidth : function(targetId) {
                    return this.getDraggingImage().getWidth() - 2;
                },

                calculateIndicatorHeight : function(targetId) {
                    return this.getDraggingImage().getHeight() - 2;
                },

                
				createDraggingImage : function() {
					var el = this.getEl(); // img element
					return new ImageCopy($(el.parentNode).down("img"))
							.withSize(this.getTargetSize());
				},

				/*
				 * Returns associated element for a drag and drop instance.
				 */
				getTargetDomRef : function(oDD) {
					if (oDD.player) {
						return oDD.player.getEl();
					} else {
						return oDD.getEl();
					}
				},

				rowToIndex : function(sRowId) {
					return sRowId.replace(/^row/g, "");
				},

				getTargetElements : function() {
					return YAHOO.util.DDM
							.getRelated(this, true /* targets only */)
							.map(this.getTargetDomRef);
				},

				addPossibleTargetsHighlight : function() {
					this.getTargetElements().invoke("addClassName", "dragging");
				},

				removePossibleTargetsHighlight : function() {
					this.getTargetElements().invoke("removeClassName",
							"dragging");
				},

				startDrag : function(x, y) {
					// this.addPossibleTargetsHighlight();
				},

				endDrag : function(e) {
					// this.removePossibleTargetsHighlight();
				},

				calculatePositionForDrop : function(evt, targetId) {

					var height = $(targetId).getHeight();
					var targetX = $(targetId).cumulativeOffset().left;

					var calculatedLeft = evt.clientX - targetX
							- this.getEl().getWidth() / 2;

					return {
						left : calculatedLeft,
						top : $(targetId).positionedOffset().top
					};
				},

				createIndicator : function(evt, targetId) {
					if (!this.indicator) {
						this.indicator = new Element("div")
								.addClassName("indicator");
					}

					$(targetId).appendChild(this.indicator);

					this.indicator.setStyle({
								height : this
										.calculateIndicatorHeight(targetId),
								width : this.calculateIndicatorWidth(targetId),
								opacity : 0.4
							});

					this.updateIndicator(evt, targetId);
				},

				/* Update indicator position */
				updateIndicator : function(evt, targetId) {
					if (!this.indicator) {
						this.createIndicator(evt, targetId);
					}

					this.indicator.setStyle(this.calculatePositionForDrop(evt,
							targetId));

                    /* Re-parent the indicator. */                            
                    $(targetId).appendChild(this.indicator);
				},

				onDragOver : function(evt, targetId) {
					this.updateIndicator(evt, targetId);
				},

				removeIndicator : function() {
					if (this.indicator) {
					    this.indicator.remove();
                        this.indicator = null;
					}
				},

				onDragOut : function(evt, targetId) {
					this.removeIndicator();
				},

				onDragEnter : function(evt, targetId) {
					this.createIndicator(evt, targetId);
				},

				onDragDrop : function(evt, targetId) {
					this.removeIndicator();
					$(this.getDragEl()).hide();

					/* Copy image and add to target element */
					var height = $(targetId).getHeight();
					var image = new ImageCopy(this.getEl()).withSize(height);
					var nextId = P.ScheduleSheet.nextId();
					var position = this.calculatePositionForDrop(evt, targetId);
					image.setStyle(position);
					image.setAttribute("id", nextId);
					$(targetId).appendChild(image);

					/* Make image movable */
					var mv = new P.MovableImage(image);
					mv.sourceId = nextId;

					P.ScheduleSheet.saveAddPictogram(nextId, this
									.rowToIndex(targetId), position.left, this
									.getSourceId());
				}

			});

	P.ScheduleUserImageMovable = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.ScheduleUserImageMovable, P.SchedulePictogramMovable, {
				applyConfig : function() {
					P.ScheduleUserImageMovable.superclass.applyConfig.call(this);
				},

				onDragDrop : function(evt, targetId) {
					this.removeIndicator();
					$(this.getDragEl()).hide();

					/* Copy image and add to target element */
					var height = $(targetId).getHeight();
					var image = new ImageCopy(this.getEl()).withSize(height);
					var nextId = P.ScheduleSheet.nextId();
					var position = this.calculatePositionForDrop(evt, targetId);
					image.setStyle(position);
					image.setAttribute("id", nextId);
					$(targetId).appendChild(image);

					/* Make image movable */
					var mv = new P.MovableImage(image);
					mv.sourceId = nextId;

					P.ScheduleSheet.saveAddUserImage(nextId, this
									.rowToIndex(targetId), position.left, this
									.getSourceId());
				}

			});

	P.MovableImage = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.MovableImage, P.SchedulePictogramMovable, {
				applyConfig : function() {
					P.MovableImage.superclass.applyConfig.call(this);
				},

				b4StartDrag : function(x, y) {

					var dragEl = this.getDragEl();

					dragEl.update("");
					dragEl.appendChild(this.getEl());

					dragEl.show();

					this.adjustPointerPosition(x, y);
				},

				/* adjusts the drag element position relative to the pointer */
				adjustPointerPosition : function(x, y) {

					var dragEl = this.getDragEl();

					/* Must show before calculating dimensions. */
					var dim = new Dimension(this.getEl());

					/*
					 * Adjust position relative to pointer, with border
					 * adjustment.
					 */
					this.setDelta(dim.width() / 2 - 1, dim.height() / 2 - 1);

					/* Adjust starting position. */
					dragEl.style.left = x - dim.width() / 2;
					dragEl.style.top = y - dim.height() / 2;

				},

				onDragDrop : function(evt, targetId) {
					/* drop position must be calculated when the image is shown */
					var position = this.calculatePositionForDrop(evt, targetId);

					this.removeIndicator();
					$(this.getDragEl()).hide();

					var image = this.getEl();

					image.setStyle(position);
					$(targetId).appendChild(image);

					var imageId = this.getSourceId();
					var rowId = this.rowToIndex(targetId);
					P.ScheduleSheet.saveMovePictogram(imageId, rowId,
							position.left);
				},

				onInvalidDrop : function(e) {
					P.ScheduleSheet.saveRemoveSlot(this.getSourceId());
					this.getDragEl().update("").hide();
				}

			});

})();
/*
 * En klass som representerar en punkt i ett koordinatsystem.
 */
function Point(x,y) {
	this.x = x;
	this.y = y;
	this.getX = function() { return this.x; };
	this.getY = function() { return this.y; };
}
Ext.namespace("P");

(function() {
    var size = 90;
    var hz = 0; // horizontal spacing
    var vz = 0; // vertical spacing
    var pictogramImagePath = new Template("/static/images/#{language}/size#{size}/#{imageId}.jpg");

    var userImagePath = new Template("/print/userImage/fit/#{imageId}/size#{width}/#{height}");

    var mainPictogramPrefix = "main-pictogram-";
    var additionalPictogramPrefix = "additional-pictogram-";
    var mainUserImagePrefix = "main-userimage-";
    var additionalUserImagePrefix = "additional-userimage-";
    var mainImageRegexp = /main-[a-z]+-([0-9]+)/;
    var additionalImageRegexp = /additional-[a-z]+-([0-9]+)/;

    var realSize = 0, realHorizontalSpacing = 0, realVerticalSpacing = 0;

    var saveTimer = null;
    var layoutTimer = null;

    var layout_landscape = "landscape";

    var mainImageSlotId = "main-image";
    var additionalImageSlotId = "additional-image";

    function isLandscape() {
        return $(document.body).hasClassName(layout_landscape);
    }

    function getPageLayout() {
        var body = $("contents");
        var i;
        var layouts = ["two-large", "one-large", "no-large"];

        for (i = 0; i < layouts.length; i++) {
            if (body.hasClassName(layouts[i])) {
                return layouts[i];
            }
        }

        console.warn("Could not find page layout");
        return "no-large";
    }

    function isMainImageVisible() {
        var layout = getPageLayout();
        return layout === "two-large" || layout === "one-large";
    }

    function isSecondaryImageVisible() {
        var layout = getPageLayout();
        return layout === "two-large";
    }

    function getContainerHeight() {
        var borderWidth = 1;
        return $("primary-sheet").getHeight() - 2 * borderWidth;
    }

    function getContainerWidth() {
        var borderWidth = 1;
        var width = $("primary-sheet").getWidth() - 2 * borderWidth;
        return width;
    }

    function getLargeImageContainerDimensions() {
        var layout = getPageLayout();
        var height = layout === 'two-large' ? 160 : 240;

        var dim = null;

        if (!isLandscape()) {
            dim = {
                height : height,
                width: 360
            };
        } else {
            var width = isSecondaryImageVisible() ? 270 : 540;

            dim = {
                height: height,
                width: width
            };
        }

        return {
            height : dim.height - 4 /* make room for border */,
            width: dim.width - 4 /* make room for border */

        }

    }


    function fireSheetChangesSaved() {
        YAHOO.Bubbling.fire("/sheet/slider/changes/saved");
    }

    function getCurrentMainImage() {
        var img = $(mainImageSlotId).down("img");
        var userImage;
        if (!img) {
            return null;
        }

        userImage = img.id.startsWith(mainUserImagePrefix);

        imageId = img.id.match(mainImageRegexp)[1];

        return {
            imageId : imageId,
            isUserImage : userImage
        }
    }

    function getCurrentAdditionalImage() {
        var img = $(additionalImageSlotId).down("img");
        var userImage;
        if (!img) {
            return null;
        }

        userImage = img.id.startsWith(additionalUserImagePrefix);

        imageId = img.id.match(additionalImageRegexp)[1];

        return {
            imageId : imageId,
            isUserImage : userImage
        }
    }


    function updateBodyLayoutClass(layout) {
        $("contents").removeClassName("two-large").removeClassName("one-large").removeClassName("no-large").addClassName(layout);
    }


    function isMainSlotSelected() {
        return $(mainImageSlotId).hasClassName("selected");
    }

    function isAdditionalSlotSelected() {
        return $(additionalImageSlotId).hasClassName("selected");
    }

    function getSlotsTop() {
        var mainImage = $(mainImageSlotId);
        if (isMainImageVisible()) {
            return mainImage.getHeight() + 10;
        } else {
            return 0;
        }
    }


    function centerImage(containerId, img) {
        // console.log("Centering %s", containerId);

        var imgWidth = img.getWidth();

        // console.log("image width %s", imgWidth);

        /* Prevent 0 width if img hasn't loaded yet. */
        var currentContainerWidth = $(containerId).getWidth();
        // console.log("current container width %s", currentContainerWidth);
        var newContainerWidth = Math.max(imgWidth, currentContainerWidth);

        // console.log("new container width %s", newContainerWidth);

        var width = Math.min(newContainerWidth, getContainerWidth() - 4 /* extra space for selection border */);

        // console.log("using width %s", width);

        $(containerId).setStyle({
            width: width
        });

        /* Center image vertically. */
        img.setStyle({
            marginTop: ($(containerId).getHeight() - img.getHeight())/2
        });
    }

    function targetIdToIndex(element) {
		return element.id.replace(/^target/, "");
	}

    var getColumns = function() {
        /* columns = how many elements fits per row */
        var columns = Math.floor((getContainerWidth() + hz) / (size + hz));
        return columns;
    };

    var getMaxRows = function() {
        var maxRows = Math.floor((getContainerHeight() + vz - getSlotsTop()) / (size + vz));
        return maxRows;
    };

    /* Private constructor. */
    function SliderSheet() {
    }

    SliderSheet.prototype = {
        init : function() {
            this.registerDropTargets();
            this.registerSelectListeners();
            this.registerKeyListener();
            this.initialSelection();


            //this.centerMainImage();
            this.resetLargeImages.bind(this).defer();


            this.fireMainImageChanged();
            this.fireAdditionalImageChanged();
        },

        registerDropTargets : function() {
            function addDropTarget(element) {
                (new YAHOO.util.DDTarget(element));
            }

            this.getSlots().each(addDropTarget);

            /* Registering separately or it wouldn't work on Safari 3.2.1 */
            (new YAHOO.util.DDTarget($("main-image")));


            this.getSecondarySlots().each(addDropTarget);

            (new YAHOO.util.DDTarget($("additional-image")));


        },

        registerSelectListeners : function() {
            var that = this;

			reg.click("#slots .slot, #secondary-slots .slot", function(e) {
				$(this).toggleClassName("selected");
                that.clearLargeSlotSelection();
			});

            reg.click(".large-image-slot", function(e) {
				$(this).toggleClassName("selected");
                that.clearSlotSelection();
			});
        },

        registerKeyListener : function() {
        		$(document).observe("keydown", P.SliderSheet.deleteEventHandler.bind(this));
        },

        initialSelection : function() {
            this.clearSelection();

	        if ($(document.body).hasClassName("userImages")) {
	            $(mainImageSlotId).addClassName("selected");
	        } else {
	            var slot = this.getFirstAvailableSlot();
	            if (slot) {
	                $(slot).addClassName("selected");
	            }
	        }
        },

        centerMainImage: function() {
            $$("#main-image img").map(centerImage.curry(mainImageSlotId));
            $$("#additional-image img").map(centerImage.curry(additionalImageSlotId));
        },

        deleteEventHandler: function(event) {
        	var code = event.which || event.keyCode;
        	if (code === Event.KEY_DELETE) {
       			this.deleteSelected();
        	}

        },

        deleteSelected : function() {
            var largeImageSelections = null;
        	var selectedSlots = this.getSelectedSlots();

        	var slotIds = selectedSlots.map(targetIdToIndex);

            SliderSheetItem.save(SliderSheetItem.DELETE, slotIds);
            //fireSheetChangesSaved();

        	/* remove images from selected slots */
			selectedSlots.invoke("update", "");


            /* Delete selected main image */
            largeImageSelections = $$("#main-image.selected img");
            if (largeImageSelections.length > 0) {
                largeImageSelections.invoke("remove");
                this.fireMainImageChanged();
                this.saveDeleteMainImage();
            }

            /* Delete selected additional image */
            largeImageSelections = $$("#additional-image.selected img");
            if (largeImageSelections.length > 0) {
                largeImageSelections.invoke("remove");
                this.fireAdditionalImageChanged();
                this.saveDeleteAdditionalImage();
            }


            this.clearSelection();
        },


        clearSlotSelection : function() {
			this.getSelectedSlots().invoke("removeClassName", "selected");
        },

        clearLargeSlotSelection : function() {
            $$(".large-image-slot").invoke("removeClassName", "selected");
        },

		/* remove selection markers */
        clearSelection : function() {
            this.clearSlotSelection();
            this.clearLargeSlotSelection();
        },

        getSlots : function() {
            return $$("#pictogramsheet #slots .slot");
        },

        getSecondarySlots : function() {
            return $$("#pictogramsheet #secondary-slots .slot");
        },

        getSelectedSlots : function() {
        	return $$("#pictogramsheet .slot.selected");
        },

        isSelected : function(index) {
            return $("target" + index).hasClassName("selected");
        },

        rotate : function() {
            $("slidersheet").toggleClassName(layout_landscape);
            $("slidersheet").toggleClassName("portrait");
            this.scheduleDoLayout();
            this.scheduleSaveSettings();

            this.resetLargeImages.bind(this).delay(0.05);
        },

        resetLargeImages : function() {
            var currentMainImage = getCurrentMainImage();
            if (currentMainImage) {
                if (currentMainImage.isUserImage) {
                    this.addMainUserImage(currentMainImage.imageId);
                } else {
                    this.addMainPictogram(currentMainImage.imageId);
                }
            }

            var currentAdditionalImage = getCurrentAdditionalImage();

            if (currentAdditionalImage) {
                if (currentAdditionalImage.isUserImage) {
                    this.addAdditionalUserImage(currentAdditionalImage.imageId);
                } else {
                    this.addAdditionalPictogram(currentAdditionalImage.imageId)
                }
            }

            /* Do another layout after main image has been positioned. */
            this.scheduleDoLayout();
        },

        fireMainImageChanged: function() {
            YAHOO.Bubbling.fire('slidersheet/image/main/changed');
        },

        fireAdditionalImageChanged: function() {
            YAHOO.Bubbling.fire('slidersheet/image/additional/changed');
        },

        doLayout : function() {

            var columns = getColumns();
            var maxRows = getMaxRows();
            var slotsTop = getSlotsTop();
            // console.log("columns %s", columns);
            // console.log("maxRows %s", maxRows);
            var slots = this.getSlots();

            var offsetLeft = (getContainerWidth() + hz - columns * (size + hz)) / 2;

            function layoutSlot(element, counter) {
                // console.log(counter);
                    var top = (size + vz) * Math.floor(counter / columns) + slotsTop;
                    var left = (size + hz) * (counter % columns);
                    // console.log("%s, %s", top, left);

                    element.setStyle( {
                        top :top + "px",
                        left : offsetLeft + left + "px",
                        height :size + "px",
                        width :size + "px",
                        opacity :"1.0"
                    });

                    // console.log("counter/columns", counter/columns);
                    if (counter / columns >= maxRows) {
                        element.setStyle( {
                            opacity :"0.4"
                        });
                    }
                }

            slots.each(layoutSlot);

            if (isSecondaryImageVisible()) {
                this.getSecondarySlots().each(layoutSlot);
            }

        },

        setSize : function(newSize) {
            size = newSize;
        },

        setHorizontalSpacing : function(newHorizontalSpacing) {
            hz = newHorizontalSpacing;
        },

        setVerticalSpacing : function(newVerticalSpacing) {
            vz = newVerticalSpacing;
        },

        setRealSize : function(newSize) {
            realSize = newSize;
            this.scheduleSaveSettings();
        },

        setRealHorizontalSpacing : function(newHorizontalSpacing) {
            realHorizontalSpacing = newHorizontalSpacing;
            this.scheduleSaveSettings();
        },

        setRealVerticalSpacing : function(newVerticalSpacing) {
            realVerticalSpacing = newVerticalSpacing;
            this.scheduleSaveSettings();
        },


        updateMainImageSlot : function (imageAttributes) {
            var img = new Element("img", imageAttributes);
            img.observe("load", centerImage.curry("main-image", img));

            $(mainImageSlotId).update(img);

            this.fireMainImageChanged();
        },

        updateAdditionalImageSlot : function (imageAttributes) {
            var img = new Element("img", imageAttributes);
            img.observe("load", centerImage.curry("additional-image", img));

            $(additionalImageSlotId).update(img);

            this.fireAdditionalImageChanged();
        },

        addMainPictogram : function(sImageId) {
            var dim = getLargeImageContainerDimensions();

            var templateSettings = {
                imageId : sImageId,
                size : dim.height,
                language : Ext.fly("languageSelect").getValue()
            };

            var attributes = {
                src:  pictogramImagePath.evaluate(templateSettings),
                id: mainPictogramPrefix + sImageId
            };

            this.updateMainImageSlot(attributes);

            this.saveAddMainPictogram(sImageId);
        },

        addAdditionalPictogram : function(sImageId) {
            var dim = getLargeImageContainerDimensions();

            var templateSettings = {
                imageId : sImageId,
                size : dim.height,
                language : Ext.fly("languageSelect").getValue()
            };

            var attributes = {
                src:  pictogramImagePath.evaluate(templateSettings),
                id: additionalPictogramPrefix + sImageId
            };

            this.updateAdditionalImageSlot(attributes);

            this.saveAddAdditionalPictogram(sImageId);
        },

        addMainUserImage : function(sImageId) {
            var dim = getLargeImageContainerDimensions();

            var templateSettings = {
                imageId : sImageId,
                width : dim.width - 4 /* room for selection border */,
                height: dim.height
            };

            var attributes = {
                src:  userImagePath.evaluate(templateSettings),
                id : mainUserImagePrefix + sImageId
            };

            this.updateMainImageSlot(attributes);

            this.saveAddMainUserImage(sImageId);
        },

        addAdditionalUserImage : function(sImageId) {
            var dim = getLargeImageContainerDimensions();

            var templateSettings = {
                imageId : sImageId,
                width : dim.width - 4 /* room for selection border */,
                height: dim.height
            };

            var attributes = {
                src:  userImagePath.evaluate(templateSettings),
                id : additionalUserImagePrefix + sImageId
            };

            this.updateAdditionalImageSlot(attributes);

            this.saveAddAdditionalUserImage(sImageId);
        },


        changeLayout : function(layout) {
            updateBodyLayoutClass(layout);
            this.scheduleDoLayout();
            this.scheduleSaveSettings();

            this.resetLargeImages.bind(this).delay(0.05);
        },

        saveDeleteMainImage : function() {
            var url = "/print/edit/slidersheet/removeMainImage";
            (new Ajax.Request(url, {
                method :"post",
                onComplete: fireSheetChangesSaved

            }));
        },

        saveDeleteAdditionalImage : function() {
            var url = "/print/edit/slidersheet/removeAdditionalImage";
            (new Ajax.Request(url, {
                method :"post",
                onComplete: fireSheetChangesSaved

            }));
        },

        saveAddMainUserImage : function(sUserImagePk) {
            var params = {
                imageId :sUserImagePk
            };
            var url = "/print/edit/slidersheet/addMainImage";

            (new Ajax.Request(url, {
                method :"post",
                parameters :params,
                onComplete: fireSheetChangesSaved
            }));
        },

        saveAddAdditionalUserImage : function(sUserImagePk) {
            var params = {
                imageId :sUserImagePk
            };
            var url = "/print/edit/slidersheet/addAdditionalImage";

            (new Ajax.Request(url, {
                method :"post",
                parameters :params,
                onComplete: fireSheetChangesSaved
            }));
        },

        saveAddMainPictogram : function(sPictogram) {
            var params = {
                imageId :sPictogram
            };
            var url = "/print/edit/slidersheet/addMainPictogram";

            (new Ajax.Request(url, {
                method :"post",
                parameters :params,
                onComplete: fireSheetChangesSaved
            }));
        },

        saveAddAdditionalPictogram : function(sPictogram) {
            var params = {
                imageId :sPictogram
            };
            var url = "/print/edit/slidersheet/addAdditionalPictogram";

            (new Ajax.Request(url, {
                method :"post",
                parameters :params,
                onComplete: fireSheetChangesSaved
            }));
        },

        addUserImage : function(sUserImagePk) {
            var i, imgs;

            if (this.addUserImageToSelectedSlots(sUserImagePk)) {
            	return;
            }

            var divs = P.SliderSheet.getSlots();

            for (i = 0; i < divs.length; i++) {
                imgs = divs[i].getElementsByTagName("img");

                if (imgs.length === 0) {
                    (new UserImageAddToSheetAnimation(sUserImagePk, i, size))
                            .animate();

                    break;
                }
            }
        },

        addUserImageToSelectedMainSlot: function(sUserImagePk) {
            if (isMainSlotSelected()) {
                this.addMainUserImage(sUserImagePk);

                $(mainImageSlotId).removeClassName("selected");
                $(additionalImageSlotId).addClassName("selected");

                return true;
            }

            if (isAdditionalSlotSelected()) {
                this.addAdditionalUserImage(sUserImagePk);
                this.clearSelection();
                return true;
            }

            return false;

        },

        addUserImageToSelectedSlots : function(sUserImagePk) {
        	return this.addUserImageToSelectedMainSlot(sUserImagePk) || this.invokeOnSelectedSlots(function(index) {
                (new UserImageAddToSheetAnimation(sUserImagePk, index, size))
                        .animate();
        	});

        },

        getFirstAvailableSlot : function() {
            var divs = P.SliderSheet.getSlots();
            for (i = 0; i < divs.length; i++) {
                imgs = divs[i].getElementsByTagName("img");
                if (imgs.length === 0) {
                    return divs[i];
                }
            }
            return null;
        },

        addPictogram : function(sPictogramPk) {
            var i, imgs;

            if (this.addPictogramToSelectedSlots(sPictogramPk)) {
            	return;
            }

            var divs = P.SliderSheet.getSlots();
            for (i = 0; i < divs.length; i++) {
                imgs = divs[i].getElementsByTagName("img");

                if (imgs.length === 0) {
                    (new SliderAddToSheetAnimation(sPictogramPk, i, size))
                            .animate();

                    break;
                }

            }
        },

        addPictogramToSelectedMainSlot : function(sPictogramPk) {
            if (isMainSlotSelected()) {
                this.addMainPictogram(sPictogramPk);
                $(mainImageSlotId).removeClassName("selected");
                $(additionalImageSlotId).addClassName("selected");
                return true;
            }

            if (isAdditionalSlotSelected()) {
                this.addAdditionalPictogram(sPictogramPk);
                this.clearSelection();
                return true;
            }

            return false;
        },

        addPictogramToSelectedSlots : function(sPictogramPk) {


			return this.addPictogramToSelectedMainSlot(sPictogramPk) ||
                    this.invokeOnSelectedSlots(function(index) {
                        (new SliderAddToSheetAnimation(sPictogramPk, index, size))
                            .animate();
			         });
        },


        /*
         * fn : function(index) where index is the index of a selected slot.
         */
        invokeOnSelectedSlots : function(fn) {
        	var selectedSlots = this.getSelectedSlots();
        	var i, index;

        	if (selectedSlots.length === 0) {
        		/* no selections - nothing to do */
        		return false;
        	}

			for (i = 0; i < selectedSlots.length; i++) {
				index = targetIdToIndex(selectedSlots[i]);
				fn(index);
			}

			this.clearSelection();

			return true;

        },

        dropOnSlot : function(index, pictogramPk) {
            if (this.replaceAllIfSelected(index, pictogramPk)) {
                return;
            }

            this.replaceSlot(index, pictogramPk);

        },

        replaceAllIfSelected : function(index, pictogramPk) {
            if (!this.isSelected(index)) {
                return false;
            }

            var that = this;
            return this.invokeOnSelectedSlots(function(index) {
                that.replaceSlot(index, pictogramPk);
            });
        },

        replaceSlot : function(index, pictogramPk) {
            var elPictogram = $("pk" + pictogramPk);

            $("target" + index).update(new ImageCopy(elPictogram).withSize(size));

            SliderSheetItem.save(pictogramPk, [ index ]);
            //fireSheetChangesSaved();

            this.scheduleDoLayout();
        },

        dropOnSlotUserImage : function(index, userImagePk) {
            if (this.replaceAllIfSelectedWithUserImage(index, userImagePk)) {
                return;
            }

            this.replaceSlotWithUserImage(index, userImagePk);

        },

        replaceAllIfSelectedWithUserImage : function(index, userImagePk) {
            if (!this.isSelected(index)) {
                return false;
            }

            var that = this;
            return this.invokeOnSelectedSlots(function(index) {
                that.replaceSlotWithUserImage(index, userImagePk);
            });

        },

        replaceSlotWithUserImage : function(index, userImagePk) {
            var elUserImage = $("pk_ui_" + userImagePk);

            if (!elUserImage) {
            	console.warn("User image element could not be found.");
            	return;
            }

            $("target" + index).update(new ImageCopy(elUserImage).withSize(size));

            SliderSheetItem.saveUserImage(userImagePk, [index]);
            //fireSheetChangesSaved();

        },

        updateImageSizes : function() {

            $$("#pictogramsheet .slot img").each( function(element) {
                var src = element.src.replace(/size[0-9]+/g, "size" + size);
                var replacement = new Element("img", {
                    alt :element.alt,
                    src :src
                });

                element.replace(replacement);
            });
            // console.log("Done updating image sizes");

    },

    scheduleDoLayout : function() {
        if (layoutTimer) {
            clearTimeout(layoutTimer);
        }
        layoutTimer = this.doLayout.bind(this).delay(0.05);
    },

    scheduleSaveSettings : function() {
        if (saveTimer) {
            clearTimeout(saveTimer);
        }
        saveTimer = setTimeout(this.saveSettings.bind(this), 750);
    },

    saveSettings : function() {
        var params = {
            'size' :realSize,
            'verticalSpacing' :realVerticalSpacing,
            'horizontalSpacing' :realHorizontalSpacing,
            'pageOrientation' :isLandscape() ? "landscape" : "portrait",
            'pageLayout' : getPageLayout()
        };

        (new Ajax.Request("/print/control/slidersheet/saveSettings", {
            parameters :params,
            onSuccess : function(response) {
                onComplete: fireSheetChangesSaved
        }
        }));
    },

    clear : function() {
        $$("#pictogramsheet .slot img, .large-image-slot img").invoke("remove");
        (new Ajax.Request("/print/control/slidersheet/clearSheet", {
            onSuccess : function(response) {
                P.SliderSheet.doLayout();
                YAHOO.Bubbling.fire("/sheet/created");
            }
        }));

        this.fireMainImageChanged();
        this.fireAdditionalImageChanged();
        this.clearSelection();
    }

    };


    P.SliderSheet = new SliderSheet();

    YAHOO.Bubbling.on("userimages/toggle", function(name, array) {
        this.initialSelection();
    }, P.SliderSheet);


    YAHOO.Bubbling.on('slidersheet/image/main/changed', function(name, array) {
        var img = $(mainImageSlotId).down("img");

        /* Use two separate classes to work around limitations in IE6. */
        if (img) {
            $(mainImageSlotId).addClassName("has-image");
            $(mainImageSlotId).removeClassName("no-image");
        } else {
            $(mainImageSlotId).addClassName("no-image");
            $(mainImageSlotId).removeClassName("has-image");
        }
    }, P.SliderSheet);

    YAHOO.Bubbling.on('slidersheet/image/additional/changed', function(name, array) {
        var img = $(additionalImageSlotId).down("img");

        /* Use two separate classes to work around limitations in IE6. */
        if (img) {
            $(additionalImageSlotId).addClassName("has-image");
            $(additionalImageSlotId).removeClassName("no-image");
        } else {
            $(additionalImageSlotId).addClassName("no-image");
            $(additionalImageSlotId).removeClassName("has-image");
        }
    }, P.SliderSheet);

    YAHOO.Bubbling.on('previewSizeSlider', function(name, array) {
        var param = array[1];
        this.setSize(param.pixelValue);
        this.scheduleDoLayout();
    }, P.SliderSheet);

    YAHOO.Bubbling.on('changeSizeSlider', function(name, array) {
        var param = array[1];
        this.updateImageSizes();
        this.setRealSize(param.realValue);
    }, P.SliderSheet);

    YAHOO.Bubbling.on('previewHorizontalSlider', function(name, array) {
        var param = array[1];

        this.setHorizontalSpacing(param.pixelValue);
        this.scheduleDoLayout();

    }, P.SliderSheet);

    YAHOO.Bubbling.on('changeHorizontalSlider', function(name, array) {
        var param = array[1];
        this.setRealHorizontalSpacing(param.realValue);
    }, P.SliderSheet);

    YAHOO.Bubbling.on('previewVerticalSlider', function(name, array) {
        var param = array[1];

        this.setVerticalSpacing(param.pixelValue);
        this.scheduleDoLayout();

    }, P.SliderSheet);

    YAHOO.Bubbling.on('changeVerticalSlider', function(name, array) {
        var param = array[1];
        this.setRealVerticalSpacing(param.realValue);
    }, P.SliderSheet);




}());
Ext.namespace("P");

(function() {

    function updateMessage() {

        var textarea = $('message');
        var checked = $('writeOwnMessage').checked;
        var template, friend, recipient;
        if (!checked) {
            template = $('mailTemplate').innerHTML;
            friend = $('fromName').value || '';
            recipient = $('toName').value || '';

            textarea.value = template.replace(/\{0\}/g, " " + recipient).replace(/\{1\}/g, " " + friend);
        }

        updateTextAreaStyle(checked);

    }

    function updateTextAreaStyle(checked) {
        var textarea = $('message');
        if (checked) {
            Element.setStyle(textarea, {
                "border" : "1px solid #ccc"
            });
        } else {
            Element.setStyle(textarea, {
                "border" : "none"
            });
        }
    }

    function conditionallyClearTextarea() {
        var textarea = $('message');
        var checked = $('writeOwnMessage').checked;
        if (checked) {
            // textarea.value = '';
            textarea.focus();
            updateTextAreaStyle(true);
        } else {
            updateMessage();
        }
    }

    function TellAFriend() {
    }

    TellAFriend.prototype = {
        init : function() {

            Ext.get("toName").on( {
                keyup : updateMessage,
                change : updateMessage
            });

            Ext.get("fromName").on( {
                keyup : updateMessage,
                change : updateMessage
            });

            Ext.get("writeOwnMessage").on( {
                change: conditionallyClearTextarea
            });


            updateMessage();
        },
        refresh : updateMessage
    };

    P.TellAFriend = new TellAFriend();

})();
/**
 * Code adapted from
 * http://www.experts-exchange.com/Web/Web_Languages/JavaScript/Q_21128638.html.
 */
var Dimension = Class.create();
Dimension.prototype = {
    initialize: function(elem) {
    	 var element = $(elem);
         this._left = -1;
         this._top = -1;
         this._width = 0;
         this._height = 0;
		 var e = null, left = null, top = null;
         if (element === document) {
              this._left = element.body.scrollLeft;
              this._top = element.body.scrollTop;
              this._width = element.body.clientWidth;
              this._height = element.body.clientHeight;
         } else if (element !== null) {
              e = element;
              left = e.offsetLeft;
              
              while ((e = e.offsetParent) !== null && e !== undefined) {
                   left += e.offsetLeft;
              }
              
              e = element;
              top = e.offsetTop;
              
              while ((e = e.offsetParent) !== null && e !== undefined) {
                   top += e.offsetTop;
              }
              
              this._left = left;
              this._top = top;
              this._width = element.offsetWidth;
              this._height = element.offsetHeight;
         }
	},
	
	top: function() {
    	return this._top;
    },
    
    bottom: function() {
        return this._top + this._height;
    },
    
    right: function() {
        return this._left + this._width;
    },
    
    left: function() {
        return this._left;
    },
    
    width: function() {
         return this._width;
    },
    
    height: function() {
        return this._height;
    },
    
    region: function() {
    	return new YAHOO.util.Region(this.top(), this.right(), this.bottom(), this.left());
    }
};
/* Singleton for handling PrintSettings dialog on sheet page */

var PrintSettings = function() {
    var containerName = "printSettings";
    var dialog = new Dialog(containerName, containerName + "Handle");
    var singleton = {

        onInit : function() {
            dialog.makeDraggable();
        },

        show : function() {
            this.load();
            SheetHelp.hide(false);
            dialog.show(true);
        },

        hide : function(bEffect) {
            dialog.hide(bEffect);
        },

        toggle : function() {
            dialog.toggle(this);
        },

        hideAllInstructions : function() {
            $$("#printSettings tr.validationMessage").each(function(element) {
                element.hide();
            });
        },

        save : function() {
            var form, sheetType, url, params;
            if (this.validate()) {
                form = $("printSettingsForm");
                sheetType = $("sheetTypeSettingsForm").sheetSize.value;
                url = "/sheetPrintSettings/save";
                params = {
                    "top" : form.topMarginString.value,
                    'left' : form.leftMarginString.value,
                    'spacing' : form.spacingString.value,
                    'sheettype' : sheetType
                };
                (new Ajax.Request(url, {
                    parameters : params,
                    onComplete : this.hide.bind(this)
                }));
            }
        },

        load : function() {
            var form = $("sheetTypeSettingsForm");
            var url = "/sheetPrintSettings/load";
            var params = {
                "sheetType" : form.sheetSize.value
            };

            (new Ajax.Request(url, {
                method : 'get',
                parameters : params,
                onSuccess : this.loadSettingsHandler.bind(this)
            }));
        },

        reset : function() {
            var form = $("sheetTypeSettingsForm");
            var url = "/sheetPrintSettings/load";
            var params = {
                "sheetType" : form.sheetSize.value,
                'reset' : 'true'
            };
            (new Ajax.Request(url, {
                parameters : params,
                onSuccess : this.loadSettingsHandler.bind(this)
            }));

        },

        loadSettingsHandler : function(req) {
            var form = $("printSettingsForm");

            var map = req.responseText.evalJSON();

            if (map.status !== "ok") {
                return;
            }

            var effectOptions = {
                startcolor : '#eeffee'
            };

            if (form.topMarginString.value !== map.topMargin) {
                form.topMarginString.value = map.topMargin;
                (new Effect.Highlight(form.topMarginString, effectOptions));
            }

            if (form.leftMarginString.value !== map.leftMargin) {
                form.leftMarginString.value = map.leftMargin;
                (new Effect.Highlight(form.leftMarginString, effectOptions));
            }

            if (form.spacingString.value !== map.spacing) {
                form.spacingString.value = map.spacing;
                (new Effect.Highlight(form.spacingString, effectOptions));
            }

            this.hideAllInstructions();
        },

        validateRange : function(value, lowerBound, upperBound, instructionsId) {
            var topMargin;
            var validated = false;

            if (Validation.matchesNumber(value)) {
                topMargin = parseFloat(value.replace(",", "."));
                validated = lowerBound <= topMargin && topMargin <= upperBound;
            }

            if (validated) {
                Element.hide(instructionsId);
            } else {
                Element.show(instructionsId);
            }

            return validated;
        },

        validateTopMargin : function() {
            var form = $("printSettingsForm");
            var topMarginString = form.topMarginString.value;

            return this.validateRange(topMarginString, 0, 50,
                    "topMarginInstructions");
        },

        validateLeftMargin : function() {
            var form = $("printSettingsForm");
            var leftMarginString = form.leftMarginString.value;

            return this.validateRange(leftMarginString, 0, 50,
                    "leftMarginInstructions");
        },

        validateSpacing : function() {
            var form = $("printSettingsForm");
            var spacingString = form.spacingString.value;

            return this.validateRange(spacingString, 0, 50,
                    "spacingInstructions");
        },

        validate : function() {
            /*
             * Run all tests first so all error messages are shown at once
             */
            var top = this.validateTopMargin();
            var left = this.validateLeftMargin();
            var spacing = this.validateSpacing();

            return top && left && spacing;
        }
    };
    singleton.init = singleton.onInit.bind(singleton);
    return singleton;
} /* note function call here */();
/*
 * Copyright (c) 2006 Jonathan Weiss <jw@innerewut.de>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */


/* tooltip-0.2.js - Small tooltip library on top of Prototype 
 * by Jonathan Weiss <jw@innerewut.de> distributed under the BSD license. 
 *
 * This tooltip library works in two modes. If it gets a valid DOM element 
 * or DOM id as an argument it uses this element as the tooltip. This 
 * element will be placed (and shown) near the mouse pointer when a trigger-
 * element is moused-over.
 * If it gets only a text as an argument instead of a DOM id or DOM element
 * it will create a div with the classname 'tooltip' that holds the given text.
 * This newly created div will be used as the tooltip. This is usefull if you 
 * want to use tooltip.js to create popups out of title attributes.
 * 
 *
 * Usage: 
 *   <script src="/javascripts/prototype.js" type="text/javascript"></script>
 *   <script src="/javascripts/tooltip.js" type="text/javascript"></script>
 *   <script type="text/javascript">
 *     // with valid DOM id
 *     var my_tooltip = new Tooltip('id_of_trigger_element', 'id_of_tooltip_to_show_element')
 *
 *     // with text
 *     var my_other_tooltip = new Tooltip('id_of_trigger_element', 'a nice description')
 *
 *     // create popups for each element with a title attribute
 *    Event.observe(window,"load",function() {
 *      $$("*").findAll(function(node){
 *        return node.getAttribute('title');
 *      }).each(function(node){
 *        new Tooltip(node,node.title);
 *        node.removeAttribute("title");
 *      });
 *    });
 *    
 *   </script>
 * 
 * Now whenever you trigger a mouseOver on the `trigger` element, the tooltip element will
 * be shown. On o mouseOut the tooltip disappears. 
 * 
 * Example:
 * 
 *   <script src="/javascripts/prototype.js" type="text/javascript"></script>
 *   <script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
 *   <script src="/javascripts/tooltip.js" type="text/javascript"></script>
 *
 *   <div id='tooltip' style="display:none; margin: 5px; background-color: red;">
 *     Detail infos on product 1....<br />
 *   </div>
 *
 *   <div id='product_1'>
 *     This is product 1
 *   </div>
 *
 *   <script type="text/javascript">
 *     var my_tooltip = new Tooltip('product_1', 'tooltip')
 *   </script>
 *
 * You can use my_tooltip.destroy() to remove the event observers and thereby the tooltip.
 */

var Tooltip = Class.create();
Tooltip.prototype = {
  initialize: function(element, tool_tip) {
    var options = Object.extend({
      default_css: false,
      margin: "0px",
	    padding: "5px",
	    backgroundColor: "#d6d6fc",
	    min_distance_x: 5,
      min_distance_y: 5,
      delta_x: 0,
      delta_y: 0,
      zindex: 1000
    }, arguments[2] || {});

    this.element      = $(element);

    this.options      = options;
    
    // use the supplied tooltip element or create our own div
    if($(tool_tip)) {
      this.tool_tip = $(tool_tip);
    } else {
      this.tool_tip = $(document.createElement("div")); 
      document.body.appendChild(this.tool_tip);
      this.tool_tip.addClassName("tooltip");
      this.tool_tip.appendChild(document.createTextNode(tool_tip));
    }

    // hide the tool-tip by default
    this.tool_tip.hide();

    this.eventMouseOver = this.showTooltip.bindAsEventListener(this);
    this.eventMouseOut   = this.hideTooltip.bindAsEventListener(this);
    this.eventMouseMove  = this.moveTooltip.bindAsEventListener(this);
	this.eventMouseDown = this.destroy.bindAsEventListener(this);

    this.registerEvents();
  },

  destroy: function() {
  	this.eventMouseOut();
    Event.stopObserving(this.element, "mouseover", this.eventMouseOver);
    Event.stopObserving(this.element, "mouseout", this.eventMouseOut);
    Event.stopObserving(this.element, "mousedown", this.eventMouseDown);
    Event.stopObserving(this.element, "mousemove", this.eventMouseMove);
  },

  registerEvents: function() {
    Event.observe(this.element, "mouseover", this.eventMouseOver);
    Event.observe(this.element, "mouseout", this.eventMouseOut);
    Event.observe(this.element, "mousedown", this.eventMouseDown);
    Event.observe(this.element, "mousemove", this.eventMouseMove);
  },

  moveTooltip: function(event){
	  Event.stop(event);
	  // get Mouse position
    var mouse_x = Event.pointerX(event);
	  var mouse_y = Event.pointerY(event);
	
	  // decide if wee need to switch sides for the tooltip
	  var dimensions = Element.getDimensions( this.tool_tip );
	  var element_width = dimensions.width;
	  var element_height = dimensions.height;
	
	  if ( (element_width + mouse_x) >= ( this.getWindowWidth() - this.options.min_distance_x) ){ // too big for X
		  mouse_x = mouse_x - element_width;
		  // apply min_distance to make sure that the mouse is not on the tool-tip
		  mouse_x = mouse_x - this.options.min_distance_x;
	  } else {
		  mouse_x = mouse_x + this.options.min_distance_x;
	  }
	
	  if ( (element_height + mouse_y) >= ( this.getWindowHeight() - this.options.min_distance_y) ){ // too big for Y
		  mouse_y = mouse_y - element_height;
	    // apply min_distance to make sure that the mouse is not on the tool-tip
		  mouse_y = mouse_y - this.options.min_distance_y;
	  } else {
		  mouse_y = mouse_y + this.options.min_distance_y;
	  } 
	
	  // now set the right styles
	  this.setStyles(mouse_x, mouse_y);
  },
	
		
  showTooltip: function(event) {
    Event.stop(event);
    this.moveTooltip(event);
    (new Element.show(this.tool_tip));
  },
  
  setStyles: function(x, y){
    // set the right styles to position the tool tip
	  Element.setStyle(this.tool_tip, { position:'absolute',
	 								    top:y + this.options.delta_y + "px",
	 								    left:x + this.options.delta_x + "px",
									    zindex:this.options.zindex
	 								  });
	
	  // apply default theme if wanted
	  if (this.options.default_css){
	  	  Element.setStyle(this.tool_tip, { margin:this.options.margin,
		 		  						                    padding:this.options.padding,
		                                      backgroundColor:this.options.backgroundColor,
										                      zindex:this.options.zindex
		 								    });	
	  }	
  },

  hideTooltip: function(event){
	  (new Element.hide(this.tool_tip));
  },

  getWindowHeight: function(){
    var innerHeight;
	  if (navigator.appVersion.indexOf('MSIE')>0) {
		  innerHeight = document.body.clientHeight;
    } else {
		  innerHeight = window.innerHeight;
    }
    return innerHeight;	
  },
 
  getWindowWidth: function(){
    var innerWidth;
	  if (navigator.appVersion.indexOf('MSIE')>0) {
		  innerWidth = document.body.clientWidth;
    } else {
		  innerWidth = window.innerWidth;
    }
    return innerWidth;	
  }

};
/**
 * Prevents IE from generating error messages about missing objects.
 */

if (!window.console) {
    window.console = {};
}

if (!window.console.log) {
    window.console.log = function() {
    };
}

/**
 * Tell Yahoo logger to use firebug or Safaris debug console.
 */
// YAHOO.widget.Logger.enableBrowserConsole();
Ext.namespace("P");

(function() {
	P.ScheduleHelp = function() {
	};

	P.ScheduleHelp.prototype = {

		registerHelpListeners : function() {
			YAHOO.Bubbling.on('/schedule/event/imageAdded', function(name,
							array) {
						// var param = array[1];
						this.hideHelp();
					}, this);

			YAHOO.Bubbling.on('/schedule/event/imageRemoved', function(name,
							array) {
						// var param = array[1];
						this.checkHelp();
					}, this);

			YAHOO.Bubbling.on('/schedule/week/event/imageAdded', function(name,
							array) {
						// var param = array[1];
						this.hideHelp();
					}, this);

			YAHOO.Bubbling.on('/schedule/week/event/imageRemoved', function(name,
							array) {
						// var param = array[1];
						this.checkHelp();
					}, this);

		},

		/*
		 * Removes help text after at least one image has been loaded - request
		 * from Henry
		 */
		checkHelp : function() {
			if ($$(".content-band img").length) {
				this.hideHelp();
			} else {
				this.showHelp();
			}
		},

		hideHelp : function() {
			$$(".content-band span").invoke("hide");
		},

		showHelp : function() {
			$$(".content-band span").invoke("show");
		}
	};
}());
Ext.namespace("P");

(function() {

    var days = $w("monday tuesday wednesday thursday friday saturday sunday");

    function fireSheetChangesSaved() {
        YAHOO.Bubbling.fire("/sheet/schedule/changes/saved");
    }

    function getSize() {
        return Ext.fly("row0").getHeight();
    }

    function isLandscape() {
        return $(document.body).hasClassName("landscape");
    }

    function getBaseUnit() {
		return isLandscape() ? 60 : 96;
	}

    function getRowHeightWithMargin() {
        return Ext.fly("row0").getHeight() * 5 / 4;
    }

    function calculateRowCount() {
        var count = (Ext.fly("pictogramsheet").getHeight() - 60) / getRowHeightWithMargin();
        return Math.floor(count);
    }

    /**
	 * Private constructor.
	 */
    function ScheduleSheet() {
    }

    ScheduleSheet.prototype =  {
		init : function() {
			this.registerDropTargets();
            this.afterLoad();
            this.registerListeners();
            //this.createRowsMenu();
            P.DayRowSelector.init();
		},

		registerDropTargets : function() {
			$$(".content-band").each(function(element) {
						(new YAHOO.util.DDTarget(element));
					});
		},


        rotate : function() {

			var rows = calculateRowCount();

			$(document.body).toggleClassName("landscape")
					.toggleClassName("portrait");

			/* Save change */
			(new Ajax.Request("/print/edit/schedulesheet/changePageOrientation",
					{
						parameters : {
							pageOrientation : isLandscape()
									? "landscape"
									: "portrait"
						}
					}));

            this.changeRowSize.bind(this).curry(rows).defer();
		},


        changeRowSize : function(rows) {

			var baseUnit = getBaseUnit();
			var containerHeight = Math.ceil(baseUnit * 4 / rows);
			var containerMargin = Math.floor(baseUnit / rows);

			$$(".content-band").invoke("setStyle", {
						height : containerHeight,
						marginBottom : containerMargin
					});

			$$(".content-band span").invoke("setStyle", {
						lineHeight : containerHeight + "px"
					});


            /* Note, a small delay is needed to fix a Safari rendering issue. */
			this.updateImageSizes.bind(this).delay(0.001);
		},

        setRows : function(rows) {
            rows = parseInt(rows, 10);

            /* Save change */
            (new Ajax.Request("/print/edit/schedulesheet/changeRowCount", {
                        parameters : {
                            "rowCount" : rows
                        }
                    }));

            this.changeRowSize.bind(this).curry(rows).defer();
        },

        updateImageSizes : function() {

            var size = getSize();

            function calculateNewStyle(element) {
                return {
                    top : element.up("div").positionedOffset().top,
                    left : element.getStyle("left")
                };
            }

            function resize(element) {
                var src = element.src.replace(/size[0-9]+/g, "size" + size);

                var replacement = new Element("img", {
                            alt : element.alt,
                            src : src,
                            id : element.id
                        }).setStyle(calculateNewStyle(element));

                element.replace(replacement);
            }

            $$("#pictogramsheet .content-band img").each(resize);

            this.makeImagesMovable.bind(this).defer();

        },


        createRowsMenu : function() {

            function onMenuItemEvent(p_sType, p_aArgs, p_oValue) {
                var rows = p_oValue;
                P.ScheduleSheet.setRows(rows);
			}

			var items = [{
						text : "2"
					}, {
						text : "3"
					}, {
						text : "4"
					}, {
						text : "5"
					}, {
						text : "6"
					}];

			var menu = new YAHOO.widget.Menu("row-menu", {
						position : "dynamic",
                        lazyload: true,
                        context : ["change-rows", "tl", "bl"]
					});

            menu.subscribe("itemAdded", function(p_sType, p_aArgs) {
                var oMenuItem = p_aArgs[0];
                var text = oMenuItem.cfg.getProperty("text");
                oMenuItem.subscribe("click", onMenuItemEvent, text);
            });

            menu.addItems(items);
            menu.render(document.body);

            $("change-rows").observe("click", menu.show.bind(menu));

		},

        getImageHeight : function() {
            return $$(".content-band")[0].getHeight();
        },

		nextId : function() {
			return "schedule" + (new Date().getTime()).toString();
		},

		clearSheet : function() {
			$$(".content-band img").invoke("remove");

			this.saveClearSheet();
		},

        registerListeners : function() {

            reg.click("#week-days-menu .day", function() {
                P.ScheduleSheet.selectDay(this);
            });

            this.registerHelpListeners();
        },

        makeImagesMovable : function() {
            $$(".content-band img").each(function(element) {
                var id = element.id;
                (new P.MovableImage(id)).sourceId = id;
            });
        },

        afterLoad : function() {
            /* Fix top positions for images - required for IE6 */
            $$(".content-band").each(function(element) {
                var top = element.positionedOffset().top;
                element.select("img").invoke("setStyle", {top: top});
            });

            this.makeImagesMovable();

            /* Show or hide help */
            this.checkHelp();

            /* Fix opacity for days - required for IE */
            this.updateSelectedDayOpacities();

        },

        updateSelectedDayOpacities : function() {
            $$("#week-days-menu .day").each(function(element) {
                if (element.hasClassName("selected-day")) {
                    element.setStyle({opacity: 1.0});
                } else {
                    element.setStyle({opacity: 0.25});
                }
            });
        },

        selectDay: function(dayElement) {

            /* Change selected day */
            $$("#week-days-menu .day").invoke("removeClassName", "selected-day");
            dayElement.addClassName("selected-day");
            this.updateSelectedDayOpacities();


            /* Change color for header band */
            var day = this.getDayFromElement(dayElement.down(".day-block"));

            var band = $("header-band");
            days.each(function(day) {
                band.removeClassName(day);
            });

            band.addClassName(day);

            /* Change header band image */
            $("header-band").update('<img src="/pictogram/view/day/' + day + '/size50"></img>');

            /* Save change */
            (new Ajax.Request("/print/edit/schedulesheet/changeDay", {
                        parameters : {
                            "day" : day
                        }
                    }));
        },

        /* Takes a block element with a class which determines name. */
        getDayFromElement : function(blockElement) {
            var days = $w("monday tuesday wednesday thursday friday saturday sunday");
            var day = null;
            days.each(function(dayName) {
               if (blockElement.hasClassName(dayName)) {
                    day = dayName;
               }
            });
            return day;
        },


		saveClearSheet : function() {
            (new Ajax.Request("/print/control/schedulesheet/clearSheet", {
                onSuccess: function(response) {
                    YAHOO.Bubbling.fire("/sheet/created");
                }
            }));

            this.showHelp();
		},

		/* Saves adding a pictogram. */
		saveAddPictogram : function(imageId, iRow, iLeftPx, sPictogramPk) {
			(new Ajax.Request("/print/edit/schedulesheet/addPictogram", {
						parameters : {
							"position.leftPx" : iLeftPx,
							"position.row" : iRow,
							"position.positionId" : imageId,
							pictogramId : sPictogramPk
						},
                        onComplete: fireSheetChangesSaved
					}));


            YAHOO.Bubbling.fire('/schedule/event/imageAdded', {
                                positionId : imageId
                            });

		},

        saveRemoveSlot: function(positionId) {

            (new Ajax.Request("/print/edit/schedulesheet/removeSlot", {
                parameters: {
                    "position.positionId" : positionId
                },
                onComplete: fireSheetChangesSaved
            }));

            YAHOO.Bubbling.fire('/schedule/event/imageRemoved', {
                    positionId : positionId
            });

        },

        saveAddUserImage : function(positionId, iRow, iLeftPx, sUserImagePk) {
            (new Ajax.Request("/print/edit/schedulesheet/addUserImage", {
                        parameters : {
                            "position.leftPx" : iLeftPx,
                            "position.row" : iRow,
                            "position.positionId" : positionId,
                            userImageId : sUserImagePk
                        },
                        onComplete: fireSheetChangesSaved
                    }));

            YAHOO.Bubbling.fire('/schedule/event/imageAdded', {
                positionId : positionId
            });
        },

		saveMovePictogram : function(imageId, iRow, iLeftPx) {

			(new Ajax.Request("/print/edit/schedulesheet/movePictogram", {
						parameters : {
							"position.leftPx" : iLeftPx,
							"position.row" : iRow,
							"position.positionId" : imageId
						},
                        onComplete: fireSheetChangesSaved
					}));
		}
	};

    YAHOO.lang.augment(ScheduleSheet, P.ScheduleHelp);

    P.ScheduleSheet = new ScheduleSheet();

}());
Ext.namespace("P");

(function() {

	var srcChangeTimer = null;

	var selected = "/images/print/dayschedule/selected.png";
	var selectedHover = "/images/print/dayschedule/selected-hover.png";
	var deselected = "/images/print/dayschedule/deselected.png";
	var deselectedHover = "/images/print/dayschedule/deselected-hover.png";

	function isSelected(element) {
		return $(element).hasClassName("selected");
	}

	function changeImageSource(src, imgElement) {
		$(imgElement).src = src;
	}

	function hoverAddedRow(imgElement) {
		$(imgElement).src = selectedHover;
	}

    function resetHover(imgElement) {
        if ($(imgElement).hasClassName("selected")) {
            $(imgElement).src = selected;
        } else {
            $(imgElement).src = deselected;
        }
    }
    
	function hoverRemovedRow(imgElement) {
        $(imgElement).src = deselected;
	}

	function toRowId(index) {
		return "#row-" + index;
	}

	function rowIdsUpTo(upTo) {
		return $R(1, upTo).map(toRowId);
	}

	function rowIdsFrom(from) {
		return $R(from, 6).map(toRowId);
	}

    function allRows() {
        return rowIdsFrom(1);
    }
    
	function removeHover() {
		var rows = allRows();
		$$(rows).each(resetHover);
	}

	function selectUpTo(upTo) {
		var rows = rowIdsFrom(1);
		$$(rows).invoke("removeClassName", "selected");

		rows = rowIdsUpTo(upTo)
		$$(rows).invoke("addClassName", "selected");
        
        removeHover.defer();
	}

	function applyHover(upTo) {
		var rows = rowIdsUpTo(upTo);
		$$(rows).each(hoverAddedRow);

		rows = rowIdsFrom(upTo + 1);
		$$(rows).each(hoverRemovedRow);
	}

	function scheduleHover(upTo) {
		if (srcChangeTimer) {
			clearTimeout(srcChangeTimer);
		}

		// console.log("adding up to " + upTo);
		srcChangeTimer = applyHover.curry(upTo).delay(0.05);
	}

	function scheduleRemoveHover() {
		if (srcChangeTimer) {
			clearTimeout(srcChangeTimer);
		}

		// console.log("removing hover from all");
		srcChangeTimer = removeHover.delay(0.15);
	}
    
    function scheduleSelect(upTo) {
        if (srcChangeTimer) {
            clearTimeout(srcChangeTimer);
        }

        srcChangeTimer = selectUpTo.curry(upTo).delay(0.15);
    }

	function toRowIndex(elementId) {
		var s = elementId.replace("row-", "");
		var i = parseInt(s);
		/* Just one row is not allowed. */
		return i === 1 ? 2 : i;
	}

	/** Private constructor */
	function DayRowSelector() {
	}

	DayRowSelector.prototype = {
		init : function() {
			// console.log("init day selector");
			this.createDirectSelectionForRows();
		},

		createDirectSelectionForRows : function() {
			function onHover() {
				var upTo = toRowIndex(this.id);
				scheduleHover(upTo);
			}

			function hoverOut() {
				scheduleRemoveHover();
			}

			function changeNumberOfRows() {
				var rows = toRowIndex(this.id);
				P.ScheduleSheet.setRows(rows);
				scheduleSelect(rows);
			}

			reg.hover("#change-rows img", onHover, hoverOut);

			reg.click("#change-rows img", changeNumberOfRows);

		}

	};

	P.DayRowSelector = new DayRowSelector();

})();
/**
 * Code slightly modified from http://ajaxcookbook.org/transitions-animation-effects/
 */
function Transition(curve, milliseconds, callback, onComplete) {
    this.curve_ = curve;
    this.milliseconds_ = milliseconds;
    this.callback_ = callback;
    this.onComplete = onComplete;
    this.start_ = new Date().getTime();
    var me = this;
    this.runCallback_ = function() {
        me.run();
    };
}

Transition.prototype.run = function() {
    if (!this.hasNext()) {
    	this.onComplete();
	} else {
	    this.callback_(this.next());
	    setTimeout(this.runCallback_, 10);
	}
};

Transition.prototype.hasNext = function() {
    if (this.done_) {
        return this.oneLeft_;
    }
    var now = new Date().getTime();
    if ((now - this.start_) > this.milliseconds_) {
        this.done_ = true;
        this.oneLeft_ = true;
    }
    return true;
};

Transition.prototype.next = function() {
    this.oneLeft_ = false;
    var now = new Date().getTime();
    var percentage = Math.min(1, (now - this.start_) / this.milliseconds_);
    return this.curve_(percentage);
};

function SineCurve(percentage) {
    return (1 - Math.cos(percentage * Math.PI)) / 2;
}

function LinearCurve(percentage) {
    return percentage;
}
var ImageCopy = Class.create( {
    initialize : function(element) {
        element = $(element);
        this.image = element.match("img") ? element : element.down("img");

        if (!this.image) {
            console.warn("Could not find img element for element %s", element);
            return;
        }
        
        this.src = this.image.src;
        
    },

    plainCopy : function() {
        return new Element("img", {
            src :this.image.src,
            alt :this.image.alt

        });
    },

    withSize : function(size) {
        var src = this.image.src.replace(/size[0-9]+/g, "size" + size);
        return new Element("img", {
            src :src,
            alt :this.image.alt
        });
    },
    
    setSize : function(size) {
        this.src = this.src.replace(/size[0-9]+/g, "size" + size);
        return this;
    },
    
    setFixedHeight : function() {
        this.src = this.src.replace(/fixedWidth/, "fixedHeight");
        return this;
    },
    
    toElement : function() {
        return new Element("img", {
            src : this.src,
            alt : this.image.alt
        });
    }
    
});

/**
 * Deprecated: use ImageCopy class instead.
 */
var ImageHelper = {

    /**
     * Copies a pictogram or user image. Modifies the size to match the target
     * sheet size.
     */
    copyFromParent : function(parent, sheetsize) {
        var currentImage = $(parent).down("img");

        var src = currentImage.src.replace(/size[0-9]+/g, "size" + sheetsize);

        return new Element("img", {
            src :src,
            alt :currentImage.alt
        });
    },

    copy : function(currentImage) {
        return new Element("img", {
            src :currentImage.src,
            alt :currentImage.alt
        });
    }
};
var SearchBox = function() {
	var searchBoxId = "searchtext";
	var searchSubmitId = "searchsubmit";
	var singleton = {
		focus: function(event) {
		    var element = Event.element(event);
		    if (element.type === 'text' || element.type === 'textarea') {
		        return;
		    }
		
		    var textbox = $(searchBoxId);
		    Event.stop(event);
		    textbox.focus();
		    textbox.select();
		},
		
		init: function() {
			SearchBox.fixWidth();
			shortcut("s", SearchBox.focus, {propagate:true});
		},
		
		fixWidth: function() {
			var width = 126 - $(searchSubmitId).offsetWidth;
			if (width > 30) {
				Element.setStyle($(searchBoxId), {"width":width + "px"});
			}
		}
	};
	return singleton;
} ();
var UserImages = (function() {

	var targetDivId = "searchresults";

	var uploadFormId = "uploadImageForm";

	var uploadFileInputId = "userImageFile";
	var dialogId = "image-upload-dialog";

	var userImageSelectId = "user-image-list";

	var userImagesLayoutClassName = "userImages";

	var dialog = null;

	var dialogVisible = false;

	
	function getSheetType() {
		if ($("slidermovable")) {
			return "slider";
		} else if ($("schedulemovable")) {
			return "schedule";
		} else if ($("weeksheet")) {
            return "week-schedule";
        } else if ($("weeksheet")) {
            return "week-schedule";
        }
		
		return "sheet";
	}
	
    /**
     * Removes img html elements with the given user image pk from the pictogram sheet.
     */
    function removeUserImagesFromSheet(userImagePk) {
        var re = new RegExp("userImage\/[^/]+\/" + userImagePk + "\/");
        var images = $$("#pictogramsheet img").findAll(function(img) {
                    return re.test(img.src);
                });
        images.invoke("remove");
    }

    
	var singleton = {

		displayImage : function(userImagePk) {
			resetMessages();
			var params = {
				userImagePk : userImagePk,
				sheetType : getSheetType()
			};

			(new Ajax.Updater(targetDivId, "/print/userImages/browse", {
						parameters : params,
						method : 'get',
						evalScripts : true,
						onComplete : Search.registerMouseDown
					}));

		},
        
        removeSelected : function() {
            
            var selectedPk = $F(userImageSelectId);
            
            if (!selectedPk) {
                /* No image selected. */
                return;
            }

            var fireUserImagesChanged = this.fireUserImagesChanged;
            
              
            function removeUserImage(userImagePk, selectedIndex) {
                
                var list = $(userImageSelectId);
				var option = list.select("option[value='" + userImagePk + "']")[0];
                
                if (option) {
                    newIndex = list.selectedIndex + 1;
                    if (newIndex > list.length) {
                        /* List is probably empty. Deselect. */
                        list.selectedIndex = -1;
                    } else if (newIndex === list.length) {
                        /* Removing last image. Select second to last. */
                        list.selectedIndex = list.selectedIndex - 1 ;
                    } else {
                        /* Select the next image in the list. */
                        list.selectedIndex = newIndex;
                    }

					option.highlight({
								startcolor : "#ff0000",
								duration : 0.5,
								afterFinish : function() {
									option.remove();
									fireUserImagesChanged();
								}
							})
				}
			}
            
            
            var selectedIndex = $(userImageSelectId).selectedIndex;
            
            (new Ajax.Request("/print/userImages/remove", {
                parameters: {
                    userImagePk : selectedPk
                },
                onComplete : removeUserImage.curry(selectedPk, selectedIndex)
            }));
        },

		browse : function() {
			var userImagePk = $F(userImageSelectId);
			this.displayImage(userImagePk);
		},

		isUserImageLayout : function() {
			return $(document.body).hasClassName(userImagesLayoutClassName);
		},

        showPictograms : function() {
            $(document.body).removeClassName(userImagesLayoutClassName);
            this.fireUserImagesChanged();
        },
        
        showUserImages : function() {
            $(document.body).addClassName(userImagesLayoutClassName);
            this.fireUserImagesChanged();
        },
        
		toggleUserImages : function() {
			$(document.body).toggleClassName(userImagesLayoutClassName);
            this.fireUserImagesChanged();
		},
        
        fireUserImagesChanged : function() {
            YAHOO.Bubbling.fire('global/command/hideDialogs');
            YAHOO.Bubbling.fire("userimages/toggle");
        },

		bindUploadEventListener : function() {

			var uploadHandler = {
				upload : function(o) {
					//console.log(o);

					var response = o.responseText.stripTags();

					//console.log(response);

					var json = null;
					try {
						json = YAHOO.lang.JSON.parse(response);
					} catch (e) {
						json = {
							status : "NOK"
						};
					}

					//console.log(json);

					if (json.status === "OK") {

						//console.log("Displaying image " + json.userImagePk);

						var option = new Element("option", {
									value : json.userImagePk,
									selected : "selected"
								}).addClassName("text").update(json.name);
						$(userImageSelectId).appendChild(option);

						UserImages.displayImage(json.userImagePk);

						dialog.hide();
					}

				}
			};

			function showWarning() {
				$(dialogId).down(".warning").show();
			};

			function hideWarning() {
				$(dialogId).down(".warning").hide();
			}

			function doUpload() {
				//console.log("uploading");
				YAHOO.util.Connect.setForm(uploadFormId, true, true);
				YAHOO.util.Connect.asyncRequest('POST',
						'/print/userImages/uploadAsync', uploadHandler);
			};

			function onFilenameChange(event) {

				//console.log("Uploading");

				//console.log(event);
				//console.log(this);

				var fileValue = this.value;
				var fileName = fileValue
						? fileValue.match(/[^\\]+$/)[0]
						: "(unknown)";
                        
                //console.log(fileName);

                var isImage = /\.(jpg|png|gif)$/.test(fileName.toLowerCase());
                
				if (isImage) {
					//console.log("Uploading image %s", fileName);
					hideWarning();
					doUpload();
				} else {
					showWarning();
					//console.log("This is not an image %s", fileName);
				}

			};

			YAHOO.util.Event.on(uploadFileInputId, 'change', onFilenameChange);

		},

		renderDialog : function() {
			dialog = new YAHOO.widget.Dialog(dialogId, {
						visible : false,
						iframe : true,
						zIndex : 100,
						context : ["userImageUpload", "tl", "tr",
								["beforeshow"]]
					});

			dialog.render();

			/* Hide dialog when showing pictogram controls */
			YAHOO.Bubbling.on('global/command/hideDialogs', function() {
						UserImages.hideDialog();
					});

			/*
			 * Couldn't find a method on dialog to check if it is visible, so
			 * subscribing to the events and doing the book keeping in this file
			 * instead.
			 */
			dialog.hideEvent.subscribe(function(type, args, me) {
						dialogVisible = false;
					});

			dialog.showEvent.subscribe(function(type, args, me) {
						dialogVisible = true;
					});

			/* Register async upload listener. */
			this.bindUploadEventListener();
		},

		toggleDialog : function() {
			if (dialogVisible) {
				this.hideDialog();
			} else {
				this.showDialog();
			}

		},

		hideDialog : function() {
			if (dialog) {
				dialog.hide();
			}
		},

		showDialog : function() {
			if (!dialog) {
				this.renderDialog();
			}

			$('userImageFile').clear();

			dialog.show();

		}
	};
    
    
    YAHOO.Bubbling.on("userimages/toggle", function(name, array) {
        var selectId = $(document.body).hasClassName("userImages") ? userImageSelectId : "list";
        
        var selectedIndex = $(selectId).selectedIndex;
        
        if (selectedIndex < 0 || selectedIndex > $(selectId).length) {
            $(selectId).selectedIndex = 0;
        }
        $(selectId).onchange.defer();
    }, singleton);
    
    return singleton;

}());
var MessageResource = function() {
	
	var messageId = 'messageResourceSavedDiv'; 
	return {
		change: function(resourceId, value) {
			var url = "/translatorChangeMessageResourceAction.do";
			var params = {"value": value,
			              "messageResourcePk":  resourceId};
			
			(new Ajax.Request(url, 
			         {parameters: params,
					  onComplete: MessageResource.showMessageResourceSavedMessage}));


		},
		
		showMessageResourceSavedMessage: function() {
			$(messageId).show();
			window.setTimeout(MessageResource.hideMessageResourceSavedMessage, 2000);
		},
		
		hideMessageResourceSavedMessage: function() {
			$(messageId).hide();
		}
	};
} ();
/* resets messages and closes dialogs */
function resetMessages() {
    PrintSettings.hide(false);
    PictogramDownloadHandler.hide(false);

}

var Search = function() {
    var targetDivId = "searchresults";

    return {
        registerMouseDown : function() {
            var sources, i;
            if (Ext.fly("movable")) {
                Ext.select("div.tooltip").enableDisplayMode().hide();

                sources = Ext.query("#searchresults img");
                for (i = 0; i < sources.length; i++) {
                    (new DDMovable(sources[i]));
                    if (sources[i].alt) {
                        (new Tooltip(sources[i], sources[i].alt));
                    }
                }
            } else if (Ext.fly("slidermovable")) {
                Ext.select("div.tooltip").enableDisplayMode().hide();
                Ext.select("#searchresults img.sliderimage").each(function(element) {
                    (new SliderMovable(element.dom));
                });

                Ext.select("#searchresults img.userimage").each(function(element) {
                    (new UserImageMovable(element.dom));
                });

            } else if (Ext.fly("schedulemovable")) {
                Ext.select("div.tooltip").enableDisplayMode().hide();

                Ext.select("#searchresults img.scheduleimage").each(function(element) {
                    (new P.SchedulePictogramMovable(element.dom));
                });

                Ext.select("#searchresults img.userimage").each(function(element) {
                    (new P.ScheduleUserImageMovable(element.dom));
                });

            } else if (Ext.fly("weeksheet")) {
                Ext.select("div.tooltip").enableDisplayMode().hide();

                Ext.select("#searchresults img.scheduleimage").each(function(element) {
                    (new P.WeekSchedulePictogramMovable(element.dom));
                });

                Ext.select("#searchresults img.userimage").each(function(element) {
                    (new P.WeekScheduleUserImageMovable(element.dom));
                });

            }

        },

        browse : function(searchFragmentId, languageKey) {
            resetMessages();
            var params = {
                pictogrampk : Ext.fly("list").dom.value,
                searchfragment : searchFragmentId,
                languageKey : languageKey
            };

            Ext.get(targetDivId).load( {
                url : "/browse/pictogram/view",
                params : params,
                callback : Search.registerMouseDown
            });

        },
        find : function(form, itemsperpage, searchfragment) {
            resetMessages();
            var url = "/search/pictograms/filter";
            var params = {
                "query" : form.query.value,
                "itemsperpage" : itemsperpage,
                "searchfragment" : searchfragment
            };

            Ext.get(targetDivId).load( {
                url : url,
                params : params,
                callback : Search.registerMouseDown
            });

        },

        findLatest : function(itemsperpage, searchfragment) {
            resetMessages();
            var url = "/search/pictograms/latest";
            var params = {
                "query" : "",
                "itemsperpage" : itemsperpage,
                "searchfragment" : searchfragment
            };

            Ext.get(targetDivId).load({
                url: url,
                params : params
            });

        },

        findLatestRevised : function(itemsperpage, searchfragment) {
            resetMessages();
            var url = "/search/pictograms/revised";
            var params = {
                    "query" : "",
                    "itemsperpage" : itemsperpage,
                    "searchfragment" : searchfragment
            };

            Ext.get(targetDivId).load({
                url: url,
                params : params
            });
        }

    };
} /* note function call */();
var Validation = {
	isNumber: function (a) {
	    return typeof a === 'number' && isFinite(a);
	},
	
	matchesNumber:function (a) {
		return (/^[0-9]+[.,]?[0-9]*$/).test(a);
	}
};
Misc = function() {
	
	var singleton = {
		removeNonDigits: function(s) {
			return s.replace(/[^0-9]*([0-9]+)/, "$1");
		}
	};
	return singleton;
	
} /* note function call here */ ();
/* Event position */
function getPosition(e) {
	var evt = e || window.event;

 	var left = 0;
  	var top = 0;


  	if (evt && (evt.pageX || evt.pageY)) {
  		left = evt.pageX;
  		top = evt.pageY;
  	} else if (event && (event.clientX || event.clientY)) {
  		left = event.clientX +
  		      (document.documentElement.scrollLeft || document.body.scrollLeft) -
  		       document.documentElement.clientLeft;
  		top = event.clientY +
  		     (document.documentElement.scrollTop || document.body.scrollTop) -
  		      document.documentElement.scrollTop;

  	}
	return new Point(left, top);
}


var GridSelection = 
function() {
	var origin = null;
	var bDrawRectangle = false;
	var bSelecting = false;
	var sRectangleId = "selectRectangle";
	var singleton = {
	
		init: function() {
		    YAHOO.util.Event.addListener($("pictogramsheet"), "mousedown", GridSelection.eventMouseDown);
			Element.setOpacity($(sRectangleId), 0.6);
		},
	
	
		showRectangle: function() {
			var selectDiv = $(sRectangleId);
			if (selectDiv) {
				selectDiv.show();
			}
		},

		hideRectangle: function() {
			var selectDiv = $(sRectangleId);
			if (selectDiv) {
				selectDiv.hide();
			}
		},

		startSelect: function(e) {
			var evt = e || event;
			var registerObservers;
			YAHOO.util.Event.preventDefault(evt);
			
			if (Event.isLeftClick(evt)) {
		
				origin = getPosition(evt);
				bDrawRectangle = true;
				bSelecting = !Sheet.Selection.isSelectedByPoint(origin);
				this.setSelectSize(origin, origin);
				
				registerObservers = 
					function() {
						YAHOO.util.Event.addListener(document, "mousemove", GridSelection.eventMouseMove);
						YAHOO.util.Event.addListener(document, "mouseup", GridSelection.eventMouseUp);
					};
				
			
				/* run as soon as possible */	
				setTimeout(registerObservers, 0);
			}
			// must return false to work in firefox!
			// http://forums.devshed.com/t244757/s.html
			return false;
		},
		
		
		 setSelectSize: function(origin, point) {
		
		
			var selectDiv = $(sRectangleId);
			
			var width, height;
			
			if (selectDiv) {
				this.showRectangle();
			
				width = point.x - origin.x;
				if (width > 0) {
					selectDiv.style.left = origin.x;
					selectDiv.style.width = width;
				} else {
					selectDiv.style.left = origin.x + width;
					selectDiv.style.width = -width;
				}
				
				height = point.y - origin.y;
			
				if (height > 0) {
					selectDiv.style.height = height;
					selectDiv.style.top = origin.y;
				} else {
					selectDiv.style.top = origin.y + height;
					selectDiv.style.height = -height;
				}
				
			}
		},
		
		/* handles mouse move events */
		drawRectangle: function(e) {
			var evt = e || event;
			YAHOO.util.Event.preventDefault(evt);

			var point;

			if (bDrawRectangle) {
				point = getPosition(evt);
				this.setSelectSize(origin, point);
			}
			
			return false;
		
		},
		
		
		
		/* handles mouse up events */
		endSelect: function(e) {
			var evt = e || event;
			var point, start, end, width, height, endPoint;
			YAHOO.util.Event.preventDefault(evt);
			if (bDrawRectangle) {

				bDrawRectangle = false;
				YAHOO.util.Event.removeListener(document, "mousemove", GridSelection.eventMouseMove);
				YAHOO.util.Event.removeListener(document, "mouseup", GridSelection.eventMouseUp);
				this.hideRectangle();
				
				point = getPosition(evt);
				start = new Point(0,0);
				end = new Point(0,0);
				width = point.x - origin.x;
				if (width > 0) {
					start.x = origin.x;
					end.x = origin.x + width;
				} else {
					start.x = origin.x + width;
					end.x = start.x - width;
				}
				
				height = point.y - origin.y;
			
				if (height > 0) {
					start.y = origin.y;
					end.y = origin.y + height;
				} else {
					start.y = origin.y + height;
					end.y = start.y - height;
				}
				
				// Check if the mouse really moved.
				// A certain margin is OK (0 means the mouse must not move at all.)
				if (width*width + height*height > 4 ) {
					endPoint = getPosition(evt);
					// handle as dragging
					// handle as select if the slot where the mouse is released is not selected.
					if (bSelecting || !Sheet.Selection.isSelectedByPoint(endPoint)) {
					    // select
						Sheet.selectSlotsByPoints(start, end);
					} else {
					    // deselect
						Sheet.selectSlotsByPoints(start, end, false);
					}
				} else {
					// handle as single click
					Sheet.toggleSlotByPosition(point.x, point.y);
				}
			}
		}
		
	};
	
	singleton.eventMouseDown = singleton.startSelect.bindAsEventListener(singleton);
	singleton.eventMouseMove = singleton.drawRectangle.bindAsEventListener(singleton);
	singleton.eventMouseUp = singleton.endSelect.bindAsEventListener(singleton);
	
	return singleton;

} /* note the function call here */ ();




Ext.namespace("P");

(function() {
	var days = $w("monday tuesday wednesday thursday friday saturday sunday");

	function fireSheetChangesSaved() {
		YAHOO.Bubbling.fire("/sheet/schedule/week/changes/saved");
	}

	function isLandscape() {
		return $(document.body).hasClassName("landscape");
	}

    /**
     * Margin on one side for images.
     */
    function getMargin() {
        return 2;
    }
    
	function getSize() {
		var size = isLandscape() ? $("column-0").getHeight() : $("column-0")
				.getWidth();

		return size - getMargin() * 2;
	}

	/**
	 * Private constructor.
	 */
	function WeekScheduleSheet() {
	}

	WeekScheduleSheet.prototype = {
		init : function() {
			this.registerDropTargets();
			this.registerListeners();
			this.registerHelpListeners();
			this.afterLoad();
		},

		registerDropTargets : function() {
			$$(".content-band").each(function(element) {
						(new YAHOO.util.DDTarget(element));
					});
		},

		registerListeners : function() {
			reg.click(".week-length-option", function() {
						P.WeekScheduleSheet.selectWeekLength(this);
					});

		},

		afterLoad : function() {
			/* Show or hide help */
			this.checkHelp();

			/* Make images movable */
			$$(".content-band img").each(function(element) {
						var id = element.id;
						(new P.WeekMovableImage(id)).sourceId = id;
					});

			this.updateOpacities();

		},

		rotate : function() {

			$(document.body).toggleClassName("landscape")
					.toggleClassName("portrait");

			if (isLandscape()) {
				$$(".day-container").invoke("removeClassName", "column");
				$$(".day-container").invoke("addClassName", "row");
			} else {
				$$(".day-container").invoke("removeClassName", "row");
				$$(".day-container").invoke("addClassName", "column");
			}

			/* Save change */
			(new Ajax.Request("/print/edit/weekschedule/changePageOrientation",
					{
						parameters : {
							pageOrientation : isLandscape()
									? "landscape"
									: "portrait"
						}
					}));

			this.transposeImagePositions.bind(this).defer();
		},

		transposeImagePositions : function() {
            var size = getSize();
            
			function transpose(element) {

				if (isLandscape()) {
					element.src = element.src.replace(/fixedWidth/,
							"fixedHeight");
				} else {
					element.src = element.src.replace(/fixedHeight/,
							"fixedWidth");
				}

				element.src = element.src.replace(/size[0-9]+/g, "size" + size);

				element.setStyle({
							left : element.getStyle("top"),
							top : element.getStyle("left")
						});
			}

			$$("#pictogramsheet .content-band img").each(transpose);

		},

		updateOpacities : function() {
			$$(".week-length-option").each(function(element) {
						if (element.hasClassName("selected-week-length-option")) {
							element.setStyle({
										opacity : 1.0
									});
						} else {
							element.setStyle({
										opacity : 0.25
									});
						}
					});
		},

		nextId : function() {
			return "week-schedule" + (new Date().getTime()).toString();
		},

		clearSheet : function() {
			$$(".content-band img").invoke("remove");
			this.saveClearSheet();
		},

		selectWeekLength : function(weekLengthElement) {

			if ($(weekLengthElement)
					.hasClassName("selected-week-length-option")) {
				/* nothing to do */
				return;
			}

			$$(".week-length-option").invoke("removeClassName",
					"selected-week-length-option");

			$(document.body).removeClassName("five-days")
					.removeClassName("seven-days");

			var weekLength = weekLengthElement.id;
			$(document.body).addClassName(weekLengthElement.id);

			$(weekLengthElement).addClassName("selected-week-length-option");

			/* Save change */
			(new Ajax.Request("/print/edit/weekschedule/changeWeekLength", {
						parameters : {
							"weekLength" : weekLength
						}
					}));

			this.updateImageSizes.bind(this).defer();
		},

		updateImageSizes : function() {

			var size = getSize();

			function calculateNewStyle(element) {
				return isLandscape() ? {
					top : element.up("div").positionedOffset().top,
					left : element.getStyle("left")
				} : {
					top : element.getStyle("top"),
					left : element.up("div").positionedOffset().left
				};
			}

			function resize(element) {
				var src = element.src.replace(/size[0-9]+/g, "size" + size);

				var replacement = new Element("img", {
							alt : element.alt,
							src : src,
							id : element.id
						}).setStyle(calculateNewStyle(element));

				element.replace(replacement);
			}

			$$("#pictogramsheet .column-header img").each(resize);
			$$("#pictogramsheet .content-band img").each(resize);

			this.afterLoad.bind(this).defer();

		},

		saveClearSheet : function() {
			(new Ajax.Request("/print/control/weekschedule/clearSheet", {
						onSuccess : function(response) {
							YAHOO.Bubbling.fire("/sheet/created");
						}
					}));
			this.showHelp();
		},

		saveAddPictogram : function(positionId, columnIndex, position,
				pictogramId) {

			(new Ajax.Request("/print/edit/weekschedule/addPictogram", {
						parameters : {
							"position.topPx" : position.top,
							"position.leftPx" : position.left,
							"position.column" : columnIndex,
							"position.positionId" : positionId,
							pictogramId : pictogramId
						},
						onComplete : fireSheetChangesSaved
					}));

			YAHOO.Bubbling.fire('/schedule/week/event/imageAdded', {
						positionId : pictogramId
					});

		},

		saveAddUserImage : function(positionId, columnIndex, position,
				userImageId) {

			(new Ajax.Request("/print/edit/weekschedule/addUserImage", {
						parameters : {
							"position.topPx" : position.top,
							"position.leftPx" : position.left,
							"position.column" : columnIndex,
							"position.positionId" : positionId,
							userImageId : userImageId
						},
						onComplete : fireSheetChangesSaved
					}));

			YAHOO.Bubbling.fire('/schedule/week/event/imageAdded', {
						positionId : userImageId
					});

		},

		saveRemoveSlot : function(positionId) {

			(new Ajax.Request("/print/edit/weekschedule/removeSlot", {
						parameters : {
							"position.positionId" : positionId
						},
						onComplete : fireSheetChangesSaved
					}));

			YAHOO.Bubbling.fire('/schedule/event/imageRemoved', {
						positionId : positionId
					});

		},

		saveMoveSlot : function(imageId, iColumn, position) {

			(new Ajax.Request("/print/edit/weekschedule/moveSlot", {
						parameters : {
							"position.topPx" : position.top,
							"position.leftPx" : position.left,
							"position.column" : iColumn,
							"position.positionId" : imageId
						},
						onComplete : fireSheetChangesSaved
					}));
		},

		isLandscape : isLandscape,
        getImageSize : getSize,
        getMargin : getMargin

	};

	/*
	 * Add methods from ScheduleHelp.
	 */
	YAHOO.lang.augment(WeekScheduleSheet, P.ScheduleHelp);

	P.WeekScheduleSheet = new WeekScheduleSheet();
}());
Ext.namespace("P");

(function() {

	P.WeekSchedulePictogramMovable = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.WeekSchedulePictogramMovable, P.SchedulePictogramMovable,
			{
				applyConfig : function() {
					P.WeekSchedulePictogramMovable.superclass.applyConfig
							.call(this);
					this.setDragElId("week-schedule-movable");
					this.isTarget = false;
				},

				getTargetSize : function() {
                    return P.WeekScheduleSheet.getImageSize();
				},

				createDraggingImage : function() {
					var el = this.getEl(); // img element
					var size = this.getTargetSize();
					var copy = new ImageCopy($(el.parentNode).down("img"))
							.setSize(size);
                    
                    if (P.WeekScheduleSheet.isLandscape()) {
                        copy = copy.setFixedHeight();
                    }
                            
                    return copy.toElement();
				},

				columnToIndex : function(sColumnId) {
					return sColumnId.replace(/^column-/g, "");
				},

				calculatePositionForDrop : function(evt, targetId) {
					if (P.WeekScheduleSheet.isLandscape()) {
						return this.calculateDropPositionOnRow(evt, targetId);
					}

					return this.calculateDropPositionOnColumn(evt, targetId);

				},

				calculateDropPositionOnColumn : function(evt, targetId) {
					var targetY = $(targetId).cumulativeOffset().top;

					/* evt.pointerY() doesn't work in IE6. */
					var pointerY = Event.pointerY(evt);

					var calculatedTop = pointerY - targetY
							- this.getEl().getHeight() / 2
							+ $(targetId).positionedOffset().top;
                                    
					var position = {
						left : $(targetId).positionedOffset().left,
						top : calculatedTop
					};
                    
                    return P.WeekSnapToGrid.snapInColumn(position);
				},

				calculateDropPositionOnRow : function(evt, targetId) {
					var targetX = $(targetId).cumulativeOffset().left;

					var pointerX = Event.pointerX(evt);

					var calculatedLeft = pointerX - targetX
							- this.getEl().getWidth() / 2
							+ $(targetId).positionedOffset().left;

					var position = {
						left : calculatedLeft,
						top : $(targetId).positionedOffset().top
					}
                    
                    return P.WeekSnapToGrid.snapInRow(position);
				},

				onDragDrop : function(evt, targetId) {

					this.removeIndicator();

					$(this.getDragEl()).hide();

					/* Copy image and add to target element */
					var height = this.getTargetSize();
					var image = new ImageCopy(this.getEl()).withSize(height);
					var nextId = P.WeekScheduleSheet.nextId();
					var position = this.calculatePositionForDrop(evt, targetId);

					image.setStyle(position);
					image.setAttribute("id", nextId);
					$(targetId).appendChild(image);

					/* Make image movable */
					var mv = new P.WeekMovableImage(image);
					mv.sourceId = nextId;

					P.WeekScheduleSheet.saveAddPictogram(nextId, this
									.columnToIndex(targetId), position,
							this.getSourceId());
				}

			});

	P.WeekScheduleUserImageMovable = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.WeekScheduleUserImageMovable,
			P.WeekSchedulePictogramMovable, {
				applyConfig : function() {
					P.WeekScheduleUserImageMovable.superclass.applyConfig
							.call(this);
				},

                createTargetImage : function() {
                    var size = this.getTargetSize();
                    var copy = new ImageCopy(this.getEl()).setSize(size);
                    
                    if (P.WeekScheduleSheet.isLandscape()) {
                        copy = copy.setFixedHeight();
                    }
                            
                    return copy.toElement();
                },
                
				onDragDrop : function(evt, targetId) {
					this.removeIndicator();
					$(this.getDragEl()).hide();

                   
                    var image = this.createTargetImage();
                    
                    
					var nextId = P.WeekScheduleSheet.nextId();
					var position = this.calculatePositionForDrop(evt, targetId);
					image.setStyle(position);
					image.setAttribute("id", nextId);
					$(targetId).appendChild(image);

					/* Make image movable */
					var mv = new P.WeekMovableImage(image);
					mv.sourceId = nextId;

					P.WeekScheduleSheet.saveAddUserImage(nextId, this
									.columnToIndex(targetId), position,
							this.getSourceId());
				}

			});

	P.WeekMovableImage = function(id, sGroup, config) {
		if (id) {
			this.init(id, sGroup, config);
		}
	};

	YAHOO.lang.extend(P.WeekMovableImage, P.WeekSchedulePictogramMovable, {
				applyConfig : function() {
					P.WeekMovableImage.superclass.applyConfig.call(this);
				},

				b4StartDrag : function(x, y) {

					var dragEl = $(this.getDragEl());

					dragEl.update("");
					dragEl.appendChild(this.getEl());

					dragEl.show();

					this.adjustPointerPosition(x, y);
				},

				/* adjusts the drag element position relative to the pointer */
				adjustPointerPosition : function(x, y) {

					var dragEl = this.getDragEl();

					/* Must show before calculating dimensions. */
					var dim = new Dimension(this.getEl());

					/*
					 * Adjust position relative to pointer, with border
					 * adjustment.
					 */
					this.setDelta(dim.width() / 2 - 1, dim.height() / 2 - 1);

					/* Adjust starting position. */
					dragEl.style.left = x - dim.width() / 2;
					dragEl.style.top = y - dim.height() / 2;

				},

				onDragDrop : function(evt, targetId) {
					/* drop position must be calculated when the image is shown */
					var position = this.calculatePositionForDrop(evt, targetId);

					this.removeIndicator();
					$(this.getDragEl()).hide();

					var image = this.getEl();

					image.setStyle(position);
					$(targetId).appendChild(image);

					var imageId = this.getSourceId();
					var columnId = this.columnToIndex(targetId);
					P.WeekScheduleSheet.saveMoveSlot(imageId, columnId,
							position);
				},

				onInvalidDrop : function(e) {
					P.WeekScheduleSheet.saveRemoveSlot(this.getSourceId());
					this.getDragEl().update("").hide();
				}

			})

})();
Ext.namespace("P");

(function() {

	/* private constructor */
	function WeekSnapToGrid() {
	}

	WeekSnapToGrid.prototype = {
		snapInColumn : function(position) {
			var calculatedTop = parseInt(position.top);
			var calculatedLeft = parseInt(position.left);
            
			/* Add margin between header images and images in content. */
			calculatedTop = Math.max(calculatedTop, this.getTopMargin());

			calculatedTop = calculatedTop - (calculatedTop % 7);

			return {
				top : calculatedTop,
				left : calculatedLeft
			}

		},
        
        snapInRow : function(position) {
            var calculatedTop = parseInt(position.top);
            var calculatedLeft = parseInt(position.left);

            calculatedLeft = Math.max(calculatedLeft, this.getLeftMargin());
            
            calculatedLeft = calculatedLeft - (calculatedLeft % 7);
            
            return {
                top : calculatedTop,
                left : calculatedLeft
            }
 
        },
        
        getHeaderSpacing : function () {
            return 14; // 7mm margin
        },
        
        getLeftMargin : function() {
            if (!P.WeekScheduleSheet.isLandscape()) {
                return 0;
            }

            return P.WeekScheduleSheet.getImageSize() + this.getHeaderSpacing()
        },
        
		getTopMargin : function() {
			if (P.WeekScheduleSheet.isLandscape()) {
				return 0;
			}

            return P.WeekScheduleSheet.getImageSize() + this.getHeaderSpacing()
		}
	}

	P.WeekSnapToGrid = new WeekSnapToGrid();

}());
var Pager = function() {

    var targetDivId = "searchresults";
    return {

        add : function(add, searchfragment) {
            resetMessages();
            var url = "/pageFragmentAction.do";
            var params = {
                'add' : add,
                searchfragment : searchfragment
            };

            (new Ajax.Updater(targetDivId, url, {
                parameters : params,
                onComplete : Search.registerMouseDown
            }));
        },

        set : function(page, searchfragment) {
            resetMessages();

            var url = "/pageFragmentAction.do";
            var params = {
                setpage : page,
                searchfragment : searchfragment
            };
            (new Ajax.Updater(targetDivId, url, {
                parameters : params,
                onComplete : Search.registerMouseDown
            }));
        }
    };

}();
Ext.namespace("P");

(function() {

    var url = "/pageFragmentAction.do";

    function PagingCapable(searchfragment, container) {
        this.searchfragment = searchfragment;
        this.container = container;
    }

    PagingCapable.prototype = {
        init : function() {
            this.bindListeners();
        },

        bindListeners : function() {

            if (!Ext.fly(this.container)) {
                return;
            }


            Ext.get(this.container).on("click", this.pageBack, this, {
                delegate : ".page-back"
            });

            Ext.get(this.container).on("click", this.pageForward, this, {
                delegate : ".page-forward"
            });

            Ext.get(this.container).on("click", this.setPage, this, {
                delegate : ".page-set"
            });

        },

        pageBack : function() {
            this.loadAdd(-1);
        },

        pageForward : function() {
            this.loadAdd(1);
        },

        setPage : function(e, el) {
            var page = el.innerHTML.trim();
            this.loadSet(page);
        },

        loadAdd : function(count) {
            Ext.get(this.container).load( {
                url : url,
                method : 'post',
                params : {
                    add : count,
                    searchfragment : this.searchfragment
                }
            });
        },

        loadSet : function(page) {
            Ext.get(this.container).load( {
                url : url,
                method : 'post',
                params : {
                    setpage : page,
                    searchfragment : this.searchfragment
                }
            });
        }
    };

    P.PagingCapable = PagingCapable;

})();
Ext.namespace("P");

/**
 * Support for disabled options in a select element for browsers which doesn't
 * support it natively.
 */
(function() {

	window.select_current = [];

	function prepareSelect(select) {
		select = $(select);
		select.onfocus = function() {
			window.select_current[this.id] = this.selectedIndex;
		};

		select.onchange = function() {
			justValidate(this);
		};

		emulate(select);
	}

	/* General validation. Resets selection if invalid selection is chosen. */
	function justValidate(e) {
		if (e.options[e.selectedIndex].disabled) {
			e.selectedIndex = window.select_current[e.id];
		}
	}

	/* Emulate disabled color for browsers that don't support it. */
	function emulate(e) {
		var i, option;
		for (i = 0; (option = e.options[i]) !== undefined && option !== null; i++) {
			if (option.disabled) {
				option.style.color = "graytext";
			} else {
				option.style.color = "menutext";
			}
		}
	}

	function SelectValidation() {
	}

	SelectValidation.prototype = {
		prepare : prepareSelect
	};

    
    /* Expose singleton. */
    P.SelectValidation = new SelectValidation();
})();
var YuiTooltip = Class.create();

YuiTooltip.prototype = {
	initialize : function(element, text) {
		this.tooltip = new YAHOO.widget.Tooltip(YAHOO.util.Dom.generateId(), {
			context : element,
			text : text,
            showdelay: 1050,
			zIndex: 1000,
			autodismissdelay: 60000
		});
	}
};
/* Singleton for managing downloads on Browse Pictograms page. */

var PictogramDownloadHandler = {

    /* Call setters first and then this method. */
	init: function() {
       this.eventLanguageChange = this.onLanguageChange.bindAsEventListener(this);
       this.eventAjaxReadyState = this.onAjaxReadyState.bindAsEventListener(this);
       this.eventSoundChange = this.onSoundChange.bindAsEventListener(this);
       this.maps = {};
       this.registerEvents();
	},

	registerEvents: function() {
	    Event.observe(this.form.languageId, "change", this.eventLanguageChange);
	    Event.observe(this.form.sound, "change", this.eventSoundChange);
	},

	setContainer: function(container) {
		this.container = $(container);
	},

	setForm: function(form) {
		this.form = $(form);
	},

    setMap: function(pictogramKey, map) {
    	// Map of maps {pictogramKey:{}, pictogramKey:{}, ...}
    	this.maps[pictogramKey] = map;
    },

    hasAnimation: function() {
      	var map = this.maps[this.pictogramKey];
        return map && map.animation;
    },

    hasSound: function(language) {
    	var map = this.maps[this.pictogramKey];
    	return map && map.sound && map.sound[language];
    },

    updateSelections: function() {
    	//console.log("Updating selections.");
    	var select = this.form.languageId;

        if (this.hasSound(select.value)) {
        	this.form.sound.checked = this.form.sound.checked ? "true" : this.previousSoundValue || "";
            PictosysElement.enable(this.form.sound);
        } else {
        	this.previousSoundValue = this.form.sound.checked;
        	this.form.sound.checked = "";
            PictosysElement.disable(this.form.sound);
        }

        if (this.hasAnimation()) {
            PictosysElement.enable(this.form.animation);
        } else {
        	this.form.animation.checked = "";
            PictosysElement.disable(this.form.animation);

        }

	    //console.log("Done updating selections");
    },

    onLanguageChange: function(event) {
    	this.updateSelections();
    },

    onSoundChange: function(event) {
       	this.previousSoundValue = this.form.sound.checked;
    },

    hide: function() {
    	if (this.pictogram) {
	        Element.setOpacity(this.pictogram, 1.0);
	    }
	    if (this.container) {
			this.container.hide();
		}
    },

    show: function() {

        Element.setOpacity(this.pictogram, 0.6);
        var dim = new Dimension(this.pictogram);
        var elem = this.container;
        elem.style.left = dim.left() + 40 + "px";
        elem.style.top = dim.top() + 40 + "px";

    	this.container.style.zIndex = 10000;
    	this.container.show();
    },

    onAjaxReadyState: function(req) {
    	var map = req.responseText.evalJSON();
    	if (map.status === "ok") {
	    	this.setMap(map.pictogram, map.payload);

    		if (this.pictogramKey === map.pictogram) {
	    		this.hide();

		    	P.SelectValidation.prepare(this.form.format);
		        this.updateSelections();
		        this.form.image.checked = "true";
				this.show();
			}
		}
    },

    /* pictogram is a string denoting primary key of pictogram */
    prepareDownload: function(pictogramKey) {

		/* If init hasn't been called externally yet then do it now
		 * with default values.
		 */
    	if (!this.maps) {
            PictogramDownloadHandler.setForm("downloadPictogramForm");
	        PictogramDownloadHandler.setContainer("downloadPictogramDiv");
        	PictogramDownloadHandler.init();
    	}

    	this.hide();
    	this.pictogramKey = pictogramKey;
    	this.form.pictogramId.value = this.pictogramKey;
		this.pictogram = $("pk" + pictogramKey);
		if (this.maps[this.pictogramKey] !== undefined && this.maps[this.pictogramKey] !== null) {
			this.updateSelections();
			this.show();
		} else {
		    (new Ajax.Request("/pictogram/download/prepare", {
                method : "post",
                parameters : {
                    pictogramId : this.pictogramKey
                },
                onComplete : this.eventAjaxReadyState
            }));
		}
    }
};
var SheetHelp = function() {
    var containerName = "sheetHelp";
    var dialog = new Dialog(containerName, containerName + "Handle");
    var singleton = {
        onInit : function() {
            dialog.makeDraggable();
        },

        show : function() {
            PrintSettings.hide(false);
            dialog.show(true);
        },

        hide : function(bEffect) {
            dialog.hide(bEffect);
        },

        toggle : function() {
            dialog.toggle(this);
        }
    };
    singleton.init = singleton.onInit.bind(singleton);
    return singleton;
} /* note the function call here */();
/**
 * Alternative solution which doesn't require ux?
 * 
 * http://extjs.com/forum/showthread.php?t=6153
 * 
 * Ext.get(Ext.get(tb.addSpacer().getEl()).dom.parentNode).setStyle('width', '100%');
 * 
 * Ext.fly(tb.addSpacer().getEl().parentNode).setStyle('width', '100%')
 */

Ext.ux.ToolbarFillingTextField = Ext.extend(Ext.form.TextField, {

	render : function(td) {
		td.style.width = '100%';
		Ext.form.TextField.superclass.render.call(this, td);
		this.el.applyStyles("width: 100%");
	}
});

Ext.reg('tbfilltextfield', Ext.ux.ToolbarFillingTextField);
Ext.namespace("P", "Ext", "Ext.app");

Ext.app.SheetTreePanel = function() {

    function getUrlKey() {
        if ($("schedulemovable")) {
            return "schedule";
        } else if ($("slidermovable")) {
            return "slider";
        } else if ($("labels")){
            return "labels";
        } else if ($("weeksheet")) {
            return "weekschedule";
        }

        return "nullObject";
    }

    var urls = {
        schedule : {
            save: "/print/control/schedulesheet/saveSheet",
            rootTranslation: TreeTranslations.dayScheduleRootTitle
        },
        slider : {
            save: "/print/control/slidersheet/saveSheet",
            rootTranslation: TreeTranslations.sliderRootTitle
        },
        labels : {
            save: "/print/control/sheet/saveSheet",
            rootTranslation: TreeTranslations.labelsRootTitle
        },
        weekschedule : {
            save : "/print/control/weekschedule/saveSheet",
            rootTranslation : TreeTranslations.weekScheduleRootTitle
        }, nullObject : {
            save: "",
            rootTranslation : ""
        }
    };

    function getSaveUrl() {
        return urls[getUrlKey()].save;
    }

    function getRootNodeTitle() {
        return urls[getUrlKey()].rootTranslation;
    }

    function getExploreUrl() {
        return "/document/tree/explore";
    }

    function getLoadUrl(sheetId) {
        return "/print/common/load/" + sheetId;
    }


	// set the root node
	var saveRoot = new Ext.tree.AsyncTreeNode({
		text : getRootNodeTitle(),
		draggable : false,
		id : 'source'
	});

	var loadRoot = new Ext.tree.AsyncTreeNode({
		text : getRootNodeTitle(),
		draggable : false,
		id : 'source'
	});

	var saveWindow = null;
	var loadWindow = null;


	return {

		createWindow : function(save) {

			var getParentNode = function(node) {
				return node.isLeaf() ? node.parentNode : node;
			};

			var getSelectedNode = function() {
				var node = tree.getSelectionModel().getSelectedNode();
				return node || tree.getRootNode();
			};

			function buildParams(node) {
				var params = {
					node : node.id,
					parent : node.parentNode.id,
					leaf : node.isLeaf(),
					text : node.text
				};

                /* Add sheet size for fixed sheets. */
                if (Ext.getDom("sheetChangeSizeSelect")) {
                    params.sheetSize = Ext.getDom("sheetChangeSizeSelect").value;
                }

                return params;
			};

			var openFile = function() {
				// console.log("loading");
				var node = getSelectedNode();

				var sheetId = null;

				if (node.isLeaf()) {
					loadWindow.hide();

					sheetId = node.id;

					//console.log("Loading sheet %s", node.id);

					window.document.location.pathname = getLoadUrl(sheetId);

				} else {
					node.expand();
				}
			};

			var saveFile = function() {
				// console.log("saving");
				var input = Ext.getCmp("filename");
				var value = input.getValue();
				// console.log(value);

				if (value.trim().length === 0) {
					return;
				}

				var node = getSelectedNode();
				// console.log("selected node:");
				// console.log(node);
				var parentNode = getParentNode(node);
				// console.log("parent node:");
				// console.log(parentNode);
				var added = null;

				parentNode.expand(false, false, function(parentNode) {
					var i;
                    for (i = 0; i < parentNode.childNodes.length; i++) {
                        var node = parentNode.childNodes[i];

                        if (value === node.text && node.leaf) {
                            Ext.Msg.show({
		                        modal: false,
		                        msg: TreeTranslations.namingConflictMessage,
		                        buttons: Ext.MessageBox.OK,
                                icon: Ext.MessageBox.INFO
		                    });

                            return;
                        }
                    }

                    added = parentNode.appendChild(new Ext.tree.AsyncTreeNode({
						text : value,
						iconCls : 'file',
						leaf : true
					}));

					// added.ensureVisible();
					added.select();

					input.setValue("");

					Ext.Ajax.request({
						url : getSaveUrl(),
						params : buildParams(added),
						success : function(response, options) {


                            var result = Ext.util.JSON.decode(response.responseText);
                            // console.log(options);
							var node = tree.getNodeById(options.params.node);

							node.setId(result.documentId);

                            createMessageShowAndHiderOnTimeout("sheetSaved")();

                            YAHOO.Bubbling.fire("/sheet/saved", {name: value});

					        saveWindow.hide();
						}
					});


				});

			};

			function onNewFolderComplete(editor, value, startValue) {
				// console.log("create new folder complete");
				// console.log(editor.editNode);
				// console.log("new value is " + value);

				Ext.Ajax.request({
					url : "/document/tree/addFolder",
					params : buildParams(editor.editNode),
					success : function(response, options) {

						var result = Ext.util.JSON.decode(response.responseText);

						if (result.success) {
							var node = tree.getNodeById(result.oldId);
							node.setId(result.newId);
						}
					}
				});
			};

			/*
			 * Adapted from
			 * http://filetree.extjs.eu/source.php?file=js/Ext.ux.FileTreePanel.js
			 */
			var createNewFolder = function(node) {
				var parentNode = getParentNode(node);
				// console.log(parentNode);


				parentNode.expand(false, false, function(parent) {

				    var folder = parent.appendChild(new Ext.tree.AsyncTreeNode({
						text : TreeTranslations.createFolder,
						iconCls : 'folder'
					}));

					folder.ensureVisible();
					folder.select();

					(function() {
					    treeEditor.createFolder = true;
						treeEditor.triggerEdit(folder);
					}).defer(10);

				}.createDelegate(this));

			};

			var deleteNode = function(node) {
				// console.log(node);
				if ("source" !== node.id && !node.hasChildNodes()) {

					Ext.Ajax.request({
						url : "/document/tree/delete",
						params : buildParams(node),
						success : function(response, options) {
							node.remove();

							var result = Ext.util.JSON.decode(response.responseText);
							// reload if we're deleting the currently loaded sheet.
							if (result.reload) {
								Sheet.Management.create();
							}
						}
					});

				} else {
					// console.log("node has children");
				}
			};

			function onRenameNodeComplete (editor, value, startValue) {
				Ext.Ajax.request({
					url : "/document/tree/move",
					params : buildParams(editor.editNode)
				});
			};

			var renameNode = function(node) {


				(function() {
					treeEditor.triggerEdit(node);
				}).defer(0);
			};

			var saveBbar = [{
				xtype : "tbtext",
				text : TreeTranslations.saveAs
			}, " ", {
				xtype : "tbfilltextfield",
				scope : this,
				id : "filename"
			}, {
				cls : 'x-btn-text-icon',
				text : TreeTranslations.save,
				icon : 'http://static.pictosys.se/famfamfam/silk/icons/disk.png',
				handler : saveFile
			}];

			var loadBbar = ["->", {
				cls : 'x-btn-text-icon',
				text : TreeTranslations.open,
				icon : 'http://static.pictosys.se/famfamfam/silk/icons/accept.png',
				handler : openFile
			}];

            var treeLoader = new Ext.tree.TreeLoader({
                    dataUrl : getExploreUrl()
            });

            /* Pass extra parameters to loader. */
            treeLoader.on("beforeload", function(loader, node) {
                loader.baseParams.type = getUrlKey();
            });

			var tree = new Ext.tree.TreePanel({
				// el : 'tree-div',
				animate : true,
				autoScroll : true,
				enableDD : true,
				width : 300,
				height : 350,
				dropConfig : {
					appendOnly : true
				},
				containerScroll : true,
				rootVisible : true, // can't move folders to root otherwise
				loader : treeLoader,
				tbar : [{
					cls : 'x-btn-text-icon',
					handler : function() {
						// console.info("new folder");
						// console.log(this);
						// console.log(tree);
						var node = getSelectedNode();
						// console.log(node);

						// console.log(treeEditor);
						createNewFolder(node);
					},
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/folder_add.png',
					scope : this,
					text : TreeTranslations.createFolder
				}, {
					xtype : "tbseparator"
				}, {
					cls : 'x-btn-text-icon',
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/pencil.png',
					scope : this,
					text : TreeTranslations.rename,
					id : "tbarRenameButton",
					handler : function() {
						// console.info("rename");
						// console.log(this);
						// console.log(tree);
						var node = getSelectedNode();
						renameNode(node);
					}
				},

				{
					xtype : 'tbseparator'
				}, {
					cls : 'x-btn-text-icon',
					icon : 'http://static.pictosys.se/famfamfam/silk/icons/cross.png',
					scope : this,
					text : TreeTranslations.remove,
					disabled : true,
					id : "tbarRemoveButton",
					handler : function() {
						var node = getSelectedNode();
						deleteNode(node);
					}
				}],
				bbar : save ? saveBbar : loadBbar,
				listeners : {
					nodedrop : function(dropEvent) {
						var targetNode = dropEvent.target;
						var dropNode = dropEvent.dropNode;
						var parentNode = dropNode.parentNode;

						// console.log("parent node: ");
						// console.log(parentNode);
						// console.log("target node");
						// console.log(targetNode);

						// console.log("Dropped node %s on node %s", dropNode.text, targetNode.text);

						Ext.Ajax.request({
							url : "/document/tree/move",
							params : buildParams(dropNode)
						});

						return true;
					},
					dblclick : function(node, eventObject) {
						// console.log("doubleclicked %s", node.text);

						var sheetId = node.id;

						if (!save && node.isLeaf()) {
							loadWindow.hide();
							window.document.location.pathname = getLoadUrl(sheetId);
						}
					},
					beforeclick : function(node, eventObject) {

						/* prevent edit mode */
						return !node.isSelected();

						/*
						 * If edit on selection is to be enabled then you need
						 * to add a complete-listener on treeEditor.
						 */
					},
					click : function(node, eventObject) {

						// console.log(node);

						var renameButton = Ext.getCmp("tbarRenameButton");
						if (node.id !== "source") {
							renameButton.enable();
						} else {
							renameButton.disable();
						}

						var removeButton = Ext.getCmp("tbarRemoveButton");
						if (!node.hasChildNodes()) {
							removeButton.enable();
						} else {
							removeButton.disable();
						}

					}
				}
			});

			// add a tree sorter in folder mode
			var treeSorter = new Ext.tree.TreeSorter(tree, {
				folderSort : true
			});

			var treeEditor = new Ext.tree.TreeEditor(tree, {
				allowBlank : false,
				cancelOnEsc : true,
				completeOnEnter : true,
				ignoreNoChange : true,
				selectOnFocus : true

			});

			treeEditor.on({
                beforestartedit : function(editor, el, value) {
                    /* Don't allow renaming root node. */
                    return editor.editNode.id !== "source";
                },

                canceledit : function(editor, value, startValue) {
                	/* Remove temporary folder if cancelled */
                    if (editor.createFolder) {
                        editor.editNode.remove();
                    }
                },

                complete : {
                    fn : function(editor, value, startValue) {

                        /* XXX shouldn't the editor do this automatically? */
                        editor.editNode.setText(value);

                        if (editor.createFolder) {
                            onNewFolderComplete(editor, value, startValue);
                        } else {
                            onRenameNodeComplete(editor, value, startValue);
                        }

                        editor.createFolder = false;
                    }
                }

            });



			tree.setRootNode(save ? saveRoot : loadRoot);

			// render the tree
			// tree.render();

			var extWindow = new Ext.Window({
				title : 'Picto online',
				closable : true,
				id : save ? 'saveSheet' : "loadSheet",
				closeAction : 'hide', // allows re-opening window
				width : 370,
				// height : 360,
				autoHeight : true,
				border : true,
				plain : false,
				layout : 'fit',
				items : tree,
				modal : false,
				tools : [{
					id : "refresh",
					handler : function(event, toolEl, panel) {
						(save ? saveRoot : loadRoot).reload();
					}
				}]

			});

			if (save) {
				saveWindow = extWindow;
			} else {
				loadWindow = extWindow;
			}
		},

		save : function() {
			if (!saveWindow) {
				this.createWindow(true);
			}
			this.hideLoadWindow();
			saveWindow.show();

			// saveRoot.expand(false, false);
			saveRoot.reload();
			setTimeout(function() {
				Ext.getCmp("filename").focus();
			}, 0);

		},

		load : function() {
			if (!loadWindow) {
				this.createWindow(false);
			}

			this.hideSaveWindow();
			loadWindow.show();
			// loadRoot.expand(false, false);
			loadRoot.reload();

		},

		hideSaveWindow : function() {
			if (saveWindow) {
				saveWindow.hide();
			}
		},

		hideLoadWindow : function() {
			if (loadWindow) {
				loadWindow.hide();
			}
		}
	};
};


Ext.onReady(function() {
    P.SheetTreePanel = new Ext.app.SheetTreePanel();
});
Ext.namespace("P");

(function() {

    function Pinger() {
    }

    Pinger.prototype = {
        init : function() {
            var task = {
                run : P.Pinger.ping,
                interval : 20 * 60 * 1000,
                scope : P.Pinger
            };

            Ext.TaskMgr.start(task);
        },

        ping : function() {
            Ext.Ajax.request( {
                url : "/session/session",
                method : "POST",
                success : function(response, options) {

                    var json = Ext.decode(response.responseText);

                    if (!json.success) {
                        return;
                    }
                }
            });
        }

    };

    P.Pinger = new Pinger();

    Ext.onReady(P.Pinger.init, P.Pinger);

})();