	if(!com) var com = {};
	if(!com.qwidget) com.qwidget = {};
	
	com.qwidget.html = {};

	com.qwidget.QwidgetManager =
	{
		qwidgets: [],
		cqq: com.qwidget.qwids,
		onReady: function ()
		{
			var postAccountManagerInit = function ()
			{
				var cqqm = com.qwidget.QwidgetManager;
				jQuery(_qwid('container')).each( // TODO - cqq
					function ()
					{
						if (!com.qwidget.version)
							com.qwidget.version = jQuery(this).attr('qwidget_version');
						if (!com.qwidget.blogUrl)
							com.qwidget.blogUrl = jQuery(this).attr('blog_url') + "/";

						var id = cqqm.qwidgets.length;
						cqqm.qwidgets.push(new com.qwidget.Qwidget(this, id));
					}
				);
				// TODO - move initialization of version out of Qwidget.init. For now this can't go any higher...
				com.qwidget.debug('Qwidget version - ' + com.qwidget.version);

				var getHtml = function (filename)
				{
					var f = function (html) 
					{
						com.qwidget.html[filename] = html;
					}
					com.qwidget.getHtml(filename, f);
				}
				htmlList = [
					'qwidgetAccountCreate',
					'qwidgetAccountCreatePhoto',
					'qwidgetAccountLogIn',
					'qwidgetAccountLostPassword',
					'qwidgetAccountUpdate',
					'qwidgetMessages',
					'qwidgetLists',
					'qwidgetAbout',
					'qwidgetTOS'
				];
				for (var i = 0; i < htmlList.length; i++)
				{
					// TODO? - is this the correct place to load these html files?
					getHtml(htmlList[i]); // NOTE - if you want to move this earlier you'll have to coordinate with com.qwidget.blogUrl above...
				}
			}
			com.qwidget.AccountManager.init(postAccountManagerInit);
			com.qwidget.GuestAnswers.restore();
			com.qwidget.GuestResponseOpinions.restore();
		},
		memberLoggedIn: function (loggedIn)
		{
			for (var i = 0; i < this.qwidgets.length; i++)
			{
				this.qwidgets[i].memberLoggedIn(loggedIn);
			}
		},
		memberMessageCount: function (messageCount)
		{
			for (var i = 0; i < this.qwidgets.length; i++)
			{
				this.qwidgets[i].memberMessageCount(messageCount);
			}
		},
		getQwidget: function (node)
		{
			return com.qwidget.QwidgetManager.qwidgets[com.qwidget.QwidgetManager.getQwidgetId(node)];
		},
		getQwidgetId: function (node)
		{
			// TODO - single jQuery call?
			
			var attribute = this.cqq.qwidget_id;
			var container = this.cqq.container;
			
			// is this node the container?
			var q = jQuery(node);
			var id = q.attr(attribute);
			if (id !== undefined)
				return parseInt(id);
			// is it a child of the container?
			var parent = jQuery(node).parents(_qwid('container')); // TODO - cqq
			if (parent.length === 1)
			{
				id = parent.attr(attribute);
				if (id !== undefined)
					return parseInt(id);
			}
			// is it a parent of the container?
			var child = jQuery(node).find(_qwid('container')); // TODO - cqq
			if (child.length === 1)
			{
				id = child.attr(attribute);
				if (id !== undefined)
					return parseInt(id);
			}
			
			com.qwidget.error('QwidgetManager.getQwidgetId - no id found...');
			return -1;
		},
		qwidMap: function (qwidMap)
		{
		},
		toggle: function (refresh)
		{
			for (var i = 0; i < this.qwidgets.length; i++)
			{
				this.qwidgets[i].toggle(refresh);
			}
		},
		unreadMessageCount: function (unreadMessageCount)
		{
			for (var i = 0; i < this.qwidgets.length; i++)
			{
				this.qwidgets[i].unreadMessageCount(unreadMessageCount);
			}
		}
	};
	
	
	com.qwidget.Qwidget = Class.extend({
		qwidgetId: undefined,
		blog: undefined,
		permalink: undefined,
		cqq: undefined,
		init: function(node, id)
		{
			this.qwidgetId = id;
			var that = this;
			var q = jQuery(node);
			q.attr('qwidget_id', id);
			
			this.questionId = q.attr('question');
			this.blog = q.attr('blog_url');
			this.permalink = q.attr('permalink');
			this.post = q.attr('post');
			this.cqq = com.qwidget.qwids;
			
			com.qwidget.getHtml("qwidgetView", // TODO - viewer.html is pulled from the server once for each widget on the page. at some point, move the getHtml call to QwidgetManager...
				function (html)
				{
					//q.html(jQuery("#qwidget_open", html));
					q.html(jQuery(_qwid(that.cqq.qwidget), html).len(1));
					that.surveySection		= new com.qwidget.SurveySection(q, that, that.questionId);
					that.menuSection		= new com.qwidget.MenuSection(q, that, com.qwidget.AccountManager.isLoggedIn());
					that.resultsSection 	= new com.qwidget.ResultsSection(q, that, that.questionId);
					that.commentSection 	= new com.qwidget.CommentSection(q, that);
					that.responsesSection 	= new com.qwidget.ResponsesSection(q, that, that.questionId);
					that.footerSection 		= new com.qwidget.FooterSection(q, that);
					that.collapse();
					that.surveySection.refresh();
					com.qwidget.adjustStaticImageFilepaths(q);
				}
			);
		},
		submitAnswer: function ()
		{
			// TODO? - shouldn't we have a response model for this?
			
			//com.qwidget.debug('Qwidget.submitAnswer');
			var credentials = com.qwidget.AccountManager.credentials();

			var qwidMap = {};
			this.surveySection.qwidMap(qwidMap);
			this.commentSection.qwidMap(qwidMap);
			
			if (!qwidMap[this.cqq.survey_answerId])
			{
				alert('Please select an answer.');
				return;
			}
			
			var dataOut =
			{
				answerId:	qwidMap[this.cqq.survey_answerId],
				questionId:	this.questionId,
			 	blog:		this.blog,
			 	permalink:	this.permalink,
				post: 		this.post,
			 	comment: 	qwidMap[this.cqq.comment_text],
			 	memberId:	credentials.memberId,
			 	email:		credentials.memberEmail,
			 	password:	credentials.memberPassword
			};
			var dataPass = {
				notify: (dataOut.comment ? true : false)
			};
			
			if (credentials.memberId == com.qwidget.guestUserId)
			{
				if (com.qwidget.GuestAnswers.questionExists(dataOut.questionId))
				{
					com.qwidget.debug('Qwidget.submitAnswer - question exists');
					this.expand(true);
					return;
				}
				com.qwidget.GuestAnswers.store(dataOut.questionId, dataOut.answerId);
			}
			else
			{
				com.qwidget.GuestAnswers.remove(dataOut.questionId);
			}

   			var that = this;
			com.qwidget.ajax(com.qwidget.servicesUrl + '/response/create.jsp', dataOut, dataPass,
				function (dataIn, dataPass)
				{
					if (dataPass.notify)
						that.commentSection.submitSuccessful();
					that.expand(true);
				}
			);
		},
		sendReply: function (replyData, replySent)
		{
			if (com.qwidget.AccountManager.isLoggedIn())
			{
				if (!replyData.body || replyData.body.length == 0 || replyData.body == null)
				{
					alert("Please enter a reply.")
					return;
				}
				var f = function (dataIn, dataPass)
				{
					replySent();
				}
				com.qwidget.MessagesManager.replyToMessage(replyData.responseId, -1, replyData.toMemberId, this.surveySection.question(), replyData.body, -1, f);
			}
			// else
			// {
			// 	com.qwidget.AccountManager.showLogIn();
			// }
		},
		toggle: function (refresh)
		{
			var mode = this.menuSection.isHidden() ? 'expand' : 'collapse';
			this.expandCollapse(mode, refresh);
		},
		expand: function (refresh)
		{
			this.expandCollapse('expand', refresh)
			this.memberLoggedIn(com.qwidget.AccountManager.isLoggedIn());
		},
		collapse: function ()
		{
			this.expandCollapse('collapse', undefined);
		},
		expandCollapse: function (mode, refresh)
		{
			sections = [
				this.menuSection,
				this.resultsSection,
				this.commentSection,
				this.responsesSection,
				this.footerSection
			];
			for (var i = 0; i < sections.length; i++)
				mode === 'expand' ? sections[i].show(refresh) : sections[i].hide();
			this.surveySection.displayMode(mode, com.qwidget.AccountManager.unreadMessageCount() > 0);
		},
		memberLoggedIn: function (loggedIn)
		{
			if (this.menuSection)
			{
				this.menuSection.loggedIn(loggedIn);
				if (loggedIn && !this.menuSection.isHidden())
				{
					this.expandCollapse('expand', true);
					this.unreadMessageCount(com.qwidget.AccountManager.unreadMessageCount());
				}
			}
		},
		unreadMessageCount: function (unreadMessageCount)
		{
			this.menuSection.unreadMessageCount(unreadMessageCount);
		},
		openInbox: function ()
		{

			if (!com.qwidget.AccountManager.isLoggedIn())
			{
				com.qwidget.AccountManager.showLogIn(function () {
						com.qwidget.MessagesManager.showInbox();
					}
				);
			}
			else
				com.qwidget.MessagesManager.showInbox();
		}
	});

	if (com.qwidget.environment == 'wordpress')
		jQuery(document).ready(com.qwidget.QwidgetManager.onReady);
