dojo.provide("dirindex.Viewer");

dojo.require("dojo.fx");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

dirindex.BackgroundIframe = function(/* DomNode */node){
	//	summary:
	//		For IE z-index schenanigans. id attribute is required.
	// 		We use an iframe for all (though maybe its only FF, IE that really needs it)
	//
	//	description:
	//		new dirindex.BackgroundIframe(node)
	//			Makes a background iframe as a child of node, that fills
	//			area (and position) of node

	if(!node.id){ throw new Error("no id"); }
	var iframe = dijit._frames.pop();
	node.appendChild(iframe);
	if(dojo.isIE){
		iframe.style.setExpression("width", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetWidth");
		iframe.style.setExpression("height", dojo._scopeName + ".doc.getElementById('" + node.id + "').offsetHeight");
	}
	this.iframe = iframe;
};

dojo.extend(dirindex.BackgroundIframe, {
	destroy: function(){
		//	summary: destroy the iframe
		if(this.iframe){
			dijit._frames.push(this.iframe);
			delete this.iframe;
		}
	}
});

dojo.declare(
	"dirindex.DialogUnderlay",
	[dijit._Widget, dijit._Templated],
	{
		// summary: The component that grays out the screen behind the dialog
	
		// Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
		// Inner div has opacity specified in CSS file.
		templateString: "<div class='dijitDialogUnderlayWrapper' id='${id}_wrapper'><div class='dijitDialogUnderlay ${class}' id='${id}' dojoAttachPoint='node'></div></div>",

		attributeMap: {},

		postCreate: function(){
			// summary: Append the underlay to the body
			dojo.body().appendChild(this.domNode);
			this.bgIframe = new dirindex.BackgroundIframe(this.domNode);
		},

		layout: function(){
			// summary: Sets the background to the size of the viewport
			//
			// description:
			//	Sets the background to the size of the viewport (rather than the size
			//	of the document) since we need to cover the whole browser window, even
			//	if the document is only a few lines long.

			var viewport = dijit.getViewport();
			var is = this.node.style,
				os = this.domNode.style;

			os.top = viewport.t + "px";
			os.left = viewport.l + "px";
			is.width = viewport.w + "px";
			is.height = viewport.h + "px";

			// process twice since the scroll bar may have been removed
			// by the previous resizing
			var viewport2 = dijit.getViewport();
			if(viewport.w != viewport2.w){ is.width = viewport2.w + "px"; }
			if(viewport.h != viewport2.h){ is.height = viewport2.h + "px"; }
		},

		show: function(){
			// summary: Show the dialog underlay
			this.domNode.style.display = "block";
			this.layout();
			if(this.bgIframe.iframe){
				this.bgIframe.iframe.style.display = "block";
			}
		},

		hide: function(){
			// summary: hides the dialog underlay
			this.domNode.style.display = "none";
			if(this.bgIframe.iframe){
				this.bgIframe.iframe.style.display = "none";
			}
		},

		uninitialize: function(){
			if(this.bgIframe){
				this.bgIframe.destroy();
			}
		}
	}
);



dojo.declare(
	"dirindex.Viewer",
	[dijit._Widget, dijit._Templated],
	{
		// summary: A modal dialog Widget
		//
		// description:
		//	Pops up a modal dialog window, blocking access to the screen
		//	and also graying out the screen Dialog is extended from
		//
		// example:
		// |	<div dojoType="dirindex.Viewer" href="test.html"></div>
		//
		// example:
		// |	<div id="test">test content</div>
		// |	...
		// |	var foo = new dirindex.Viewer({ title: "test dialog" },dojo.byId("test"));
		// |	foo.startup();
		
		templateString: '<div class="dijitDialog" tabindex="-1" waiRole="dialog" waiState="labelledby-${id}_title">'
		+'	<div dojoAttachPoint="titleBar" class="dijitDialogTitleBar">'
		+'	<span dojoAttachPoint="titleNode" class="dijitDialogTitle" id="${id}_title">${title}</span>'
		+'	<span dojoAttachPoint="closeButtonNode" class="dijitDialogCloseIcon" dojoAttachEvent="onclick: onCancel">'
		+'		<span dojoAttachPoint="closeText" class="closeText">x</span>'
		+'	</span>'
		+'	</div>'
		+'		<div dojoAttachPoint="containerNode" class="dijitDialogPaneContent"></div>'
		+'</div>',

		// open: Boolean
		//		is True or False depending on state of dialog
		open: false,

		// duration: Integer
		//		The time in milliseconds it takes the dialog to fade in and out
		duration: dijit.defaultDuration,

		attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap),
			{title: "titleBar"}),

		postCreate: function(){
			dojo.body().appendChild(this.domNode);
			this.inherited(arguments);

			var s = this.domNode.style;
			s.visibility = "hidden";
			s.position = "absolute";
			s.display = "";
			s.top = "-9999px";

			this.connect(this, "onCancel", "hide");
			this._modalconnects = [];
		},
		setContent: function(node) {
			// summary: 
			// 	sets the content of the containerNode to be a single node (this.contentNode)
			this.containerNode.innerHTML = "";
			this.contentNode = this.containerNode.appendChild(node);
			return this.contentNode;
		},
		setTitle: function(title) {
			this.title = title;
			if(this.titleNode) {
				this.titleNode.innerHTML = title;
			}
		},
		onCancel: function() {},
		
		_setup: function(){
			// summary: 
			//		stuff we need to do before showing the Dialog for the first
			//		time (but we defer it until right beforehand, for
			//		performance reasons)

			var node = this.domNode;

			dojo.addClass(node,"dijitDialogFixed"); 
			
			this._underlay = new dirindex.DialogUnderlay({
				id: this.id+"_underlay",
				"class": dojo.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" ")
			});

			var underlay = this._underlay;
			
			this._showAnim = dojo.fadeIn({
				node: this.containerNode,
				duration: 200
			 });

			this._hideAnim = dojo.fadeOut({
				node: node,
				duration: this.duration,
				onEnd: function(){
					dojo.style(node, {
						visibility:"hidden",
						top: "-9999px",
						opacity: 1
					});
					underlay.hide();
				}
			 });
		},

		uninitialize: function(){
			if(this._showAnim && this._showAnim.status() == "playing"){
				this._showAnim.stop();
			}
			if(this._hideAnim && this._hideAnim.status() == "playing"){
				this._hideAnim.stop();
			}
			if(this._underlay){
				this._underlay.destroy();
			}
		},

		_position: function(){
			// summary: Position modal dialog as centered in the viewport. 
				var node = this.domNode;
				var viewport = this._viewport = dijit.getViewport();
				var mb = this._marginBox = dojo.marginBox(node);
				dojo.style(node,{
					left: Math.floor(viewport.l + (viewport.w - mb.w) / 2) + "px",
					top: Math.floor(viewport.t + (viewport.h - mb.h) / 2) + "px"
				});
		},

		_onKey: function(/*Event*/ evt){
			// summary: handles the keyboard events
			// 	simplified from Dialog to always and only handle escape 
			// (this listener is only active when the dialog is showing, 
			//	and we're not expecting any keyboard interactions with the content unlike Dialog)
			if(evt.keyCode){
				var dk = dojo.keys;
				if(evt.keyCode == dk.ESCAPE){
					this.hide(); 
				}else{
					return; // just let it go
				}
			}
		},
		showFromPoint: function(originBox) {
			this._originBox = originBox; 
			this.show();
		},
		show: function(){
			// summary: display the dialog

			if(this.open){ return; }
			
			// first time we show the dialog, there's some initialization stuff to do			
			if(!this._alreadyInitialized){
				this._setup();
				this._alreadyInitialized=true;
			}

			if(this._hideAnim.status() == "playing"){
				this._hideAnim.stop();
			}

			this._modalconnects.push(dojo.connect(window, "onscroll", this, "layout"));
			this._modalconnects.push(dojo.connect(window, "onresize", this, "layout"));
			this._modalconnects.push(dojo.connect(dojo.doc.documentElement, "onkeypress", this, "_onKey"));

			dojo.style(this.containerNode, {
				opacity:0,
				visibility:""
			});
			
			this.open = true;

			this._position();
			var viewport = this._viewport, 
				mb = this._marginBox,
				containerNode = this.containerNode,
				outerNode = this.domNode,
				underlay = this._underlay;
				
			var originBox = this._originBox || {
				t: viewport.t + viewport.h / 2,
				l: viewport.l + viewport.w / 2
			};
			var endStyle = this.domNode.style;
			var endPosn = {
				t: parseInt(endStyle.top, 10),
				l: parseInt(endStyle.left, 10),
				w: mb.w,
				h: mb.h
			};
			
			// explode a div to the dialogs posn/dimensions
			var explodeNode = dojo.doc.createElement("div");
			explodeNode.className = this.domNode.className;
			dojo.style(explodeNode, {
				height: "10px",
				width: "10px",
				position: "absolute",
				top: -5 + originBox.t + "px",
				left: -5 + originBox.l + "px"
			});
			this._explodeNode = dojo.body().appendChild(explodeNode);
			
			// animate by first growing in the box, then fading in the image
			// TODO: can reuse the animation? 
			var fadeIn = this._showAnim;
			var self = this;
			this._showAnim = dojo.fx.chain([
				dojo.animateProperty({
					node: explodeNode,
					duration: 350,
					properties: {
						width: { start: 10, end: endPosn.w },
						height: { start: 10, end: endPosn.h },
						top: { start: -5 + originBox.t, end: endPosn.t  }, 
						left: { start: -5 + originBox.l, end: endPosn.l }
					},
					onBegin: dojo.hitch(underlay, "show"),
					onEnd: function() {
						dojo.style(outerNode, "visibility", "");
						explodeNode.parentNode.removeChild(explodeNode);
						delete self.explodeNode;
					}
				}),
				fadeIn
			]); 

			this._showAnim.play();
		},

		hide: function(){
			// summary: Hide the dialog

			// if we haven't been initialized yet then we aren't showing and we can just return		
			if(!this._alreadyInitialized){
				return;
			}

			if(this._showAnim.status() == "playing"){
				this._showAnim.stop();
			}
			this._hideAnim.play();

			if (this._scrollConnected){
				this._scrollConnected = false;
			}
			dojo.forEach(this._modalconnects, dojo.disconnect);
			this._modalconnects = [];

			this.open = false;
		},

		layout: function() {
			// summary: Position the Dialog and the underlay
			if(this.domNode.style.visibility != "hidden"){
				this._underlay.layout();
				this._position(); 
			}
		},
		
		destroy: function(){
			dojo.forEach(this._modalconnects, dojo.disconnect);

			this.inherited(arguments);			
		}
	}
);

