(function () {
	if (typeof mcd === 'undefined') {
		throw "mcd.dom and mcd.event are required libraries.";
	}

	/**
	 * The MCD Obtrusive Overlay Library
	 *
	 * Forces user interaction with a dialog box by darkening the page and
	 * displaying a standard overlay on top.
	 *
	 * @namespace   mcd
	 * @class       mcd.ObtrusiveOverlay
	 * @author      Michael Girouard (mgirouard@mcdpartners.com)
	 * @author      Michael T. Smith (msmith@mcdpartners.com)
	 * @constructor
	 */
	mcd.ObtrusiveOverlay = function (id) {

		this.iframe = document.createElement('iframe');
		this.iframe.setAttribute('id',id + '-shim');
		this.iframe.setAttribute('src', 'javascript:false');
		this.iframe.setAttribute('class', 'overlay-shim');
		this.iframe.frameBorder = '0';
		this.iframe.style.position = 'relative';
		this.iframe.style.zIndex = '1';
		this.iframe.style.display = 'none';

		this.terminators = {};

		this.parent = document.getElementById(id);

		mcd.event.add(id, 'click', function (event) {
			var target = mcd.event.getTarget(event);

			if (this.terminators[id]) {
				while (target !== null) {
					if (target.id in this.terminators[this.parent.id]) {

						mcd.event.preventDefault(event);

						if (this.terminators[this.parent.id][target.id](event)) {
							this.hide();

							mcd.ObtrusiveOverlay.manager.hideBackdrop();
						}

						break;
					}
					target = target.parentNode;
				}
			} else {
                // This branch is for overlays that do not have on-page triggers, and do not use the manager
                if (target.nodeName == "IMG") target = target.parentNode;
                if (this.terminators[target.id]) {
					if (this.terminators[target.id](event)) {
						this.hide();

					    mcd.ObtrusiveOverlay.manager.hideBackdrop();
				    }

                }
            }
		}, this);
	};

	/**
	 * Shows an obtrusive overlay
	 */
	mcd.ObtrusiveOverlay.prototype.show = function () {
		mcd.dom.removeClass(this.parent, 'hide');
		if (this.iframe){
			this.iframe.style.display = '';
		}
	};

	/**
	 * Hides an obtrusive overlay
	 */
	mcd.ObtrusiveOverlay.prototype.hide = function () {
		mcd.dom.addClass(this.parent, 'hide');
		if (this.iframe){
			this.iframe.style.display = 'none';
		}
	};

	/**
	 * Toggles the visibility of an obtrusive overlay
	 */
	mcd.ObtrusiveOverlay.prototype.toggle = function () {
		mcd.dom.toggleClass(this.parent, 'hide');
		if (this.iframe){
			this.iframe.style.display = this.iframe.style.display == '' ? 'none' : '';
		}
	};

	/**
	 * @deprecated
	 */
	mcd.ObtrusiveOverlay.prototype.attachOverlay = function (parent,yx) {
		var div = mcd.dom.getElement(parent);
		div.appendChild(this.parent);
		if (this.iframe){
			div.appendChild(this.iframe);
		}
	};

	/**
	 * @deprecated
	 */
	mcd.ObtrusiveOverlay.prototype.removeOverlay = function (parent) {
		var div = mcd.dom.getElement(parent);
		div.removeChild(this.parent)
		if (this.iframe){
			div.removeChild(this.iframe)
		}
	};

	/**
	 * Registers a terminator to an overlay instace
	 *
	 * @param {String} id
	 * @param {Function} callback
	 */
	mcd.ObtrusiveOverlay.prototype.registerTerminator = function (id, callback) {
		this.terminators[id] = callback;
	};

	/**
	 * The MCD Obtrusive Overlay Manager
	 *
	 * @namespace   mcd.ObtrusiveOverlay
	 * @class       mcd.ObtrusiveOverlay.manager
	 * @author      Michael Girouar (mgirouard@mcdpartners.com)
	 * @author      Michael T. Smith (msmith@mcdpartners.com)
	 * @constructor
	 */
	mcd.ObtrusiveOverlay.manager = {
		overlays : {},

		init : function (terminators) {
			var triggerList = mcd.dom.getElementsByAttribute('class', 'obtrusive-trigger', document.body, 'a', true);


			for (var i = 0; i < triggerList.length; i++) {
				var id = triggerList[i].getAttribute('rel');
				var nodeName = triggerList[i].nodeName.toLowerCase();

				if (id) {
					if (!(id in this.overlays)) {
						this.overlays[id] = new mcd.ObtrusiveOverlay(id);

						var terminatorName;
						for (terminatorName in terminators) {
							this.overlays[id].registerTerminator(terminatorName, terminators[terminatorName]);
						}
					}

						if (nodeName === 'a') {
							mcd.event.add(triggerList[i], 'click', function (event) {

								var rel = this.getAttribute('rel');
								var overlayParent = mcd.dom.getElement(rel).parentNode;
								var xy  = mcd.dom.getPosition(this);


								if (rel) {

									mcd.ObtrusiveOverlay.manager.getOverlay(rel).activator = this;

									mcd.event.preventDefault(event);

									if (!mcd.dom.getElement('backdrop')) {
										mcd.ObtrusiveOverlay.manager.createBackdrop();
									}
									else {
										mcd.ObtrusiveOverlay.manager.showBackdrop();
									}

									mcd.ObtrusiveOverlay.manager.getOverlay(rel).toggle();
									mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe.style.display = 'block';
									mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe.style.top    = mcd.ObtrusiveOverlay.manager.getOverlay(rel).parent.offsetTop + 'px';
									mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe.style.left   = mcd.ObtrusiveOverlay.manager.getOverlay(rel).parent.offsetLeft + 'px';
									mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe.style.width  = mcd.ObtrusiveOverlay.manager.getOverlay(rel).parent.offsetWidth + 'px';
									mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe.style.height = mcd.ObtrusiveOverlay.manager.getOverlay(rel).parent.offsetHeight + 'px';
									overlayParent.appendChild(mcd.ObtrusiveOverlay.manager.getOverlay(rel).iframe);
								};
							});
						}
				}
			}

			return this;
		},

		/**
		 * Creates the backdrop element
		 */
		createBackdrop : function () {
			mcd.dom.addClass(document.getElementsByTagName('html')[0], 'in-obtrusive');
			mcd.dom.addClass(document.body, 'in-obtrusive');
			this.backdrop = document.createElement('div');
			this.backdrop.className = 'show';
			window.scrollTo(0,0);
			this.backdrop.setAttribute('id', 'backdrop');
			document.body.appendChild(this.backdrop);
		},

		/**
		 * Shows the backdrop element
		 */
		showBackdrop : function () {
			mcd.dom.addClass(document.getElementsByTagName('html')[0], 'in-obtrusive');
			mcd.dom.addClass(document.body, 'in-obtrusive');
			window.scrollTo(0,0);
			var backdrop = mcd.dom.getElement('backdrop');
			mcd.dom.toggleClass(backdrop, 'show');
		},

		/**
		 * Toggles the backdrop element and creates it if necessary
		 */
		displayBackdrop : function () {
			mcd.dom.addClass(document.getElementsByTagName('html')[0], 'in-obtrusive');
			mcd.dom.addClass(document.body, 'in-obtrusive');
			if (!document.getElementById('backdrop')){
				// No backdrop exists; create it.
				this.backdrop = document.createElement('div');
				this.backdrop.className = 'show';
				this.backdrop.setAttribute('id', 'backdrop');
				document.body.appendChild(this.backdrop);
			}
			else {
				this.backdrop = mcd.dom.getElement('backdrop');
				mcd.dom.addClass(this.backdrop, 'show');
			}
			window.scrollTo(0,0);

		},

		/**
		 * Hide the backdrop element
		 */
		hideBackdrop : function () {
			mcd.dom.removeClass(document.getElementsByTagName('html')[0], 'in-obtrusive');
			mcd.dom.removeClass(document.body, 'in-obtrusive');
			var backdrop = mcd.dom.getElement('backdrop');
            if (backdrop) mcd.dom.removeClass(backdrop, 'show');
		},

		/**
		 * Gets an overlay instance
		 */
		getOverlay : function (id) {
			if (id in this.overlays) {
				return this.overlays[id];
			}
		},

		/**
		 * Exits from an obtrusive state
		 */
		exitObtrusive : function () {
			for (var overlay in this.overlays) {
				mcd.ObtrusiveOverlay.manager.getOverlay(overlay).hide();
				mcd.ObtrusiveOverlay.manager.hideBackdrop();
			}
		},

		/**
		 * Enters into an obtrusive state
		 *
		 * @param {String} id [, id...]
		 */
		enterObtrusive : function () {
			for (var i = 0; i < arguments.length; i++) {
				var overlay = arguments[i];

				if(overlay in mcd.ObtrusiveOverlay.manager.overlays) {
					mcd.ObtrusiveOverlay.manager.getOverlay(overlay).show();
					mcd.ObtrusiveOverlay.manager.displayBackdrop();
				}
			}
		}
	};
})()