function CodeGen(mediaId, args) {
	if (!args) args = {};
	var container = $(args.container || 'publish-' + mediaId);
	var activeTab = getElementsByClassName('active', container.getElementsByTagName('li'))[0];
	if (activeTab) activeTab = activeTab.firstChild;
	var previewSize = getElementsByClassName('size', container.getElementsByTagName('span'))[0];
	var hostname = args.hostname ? location.protocol + '//' + args.hostname : '';
	var minDelay = args.minDelay || 500;

	var cache = {};
	var script = null;
	var content = null;
	var startTime = 0;
	var me = this;


	function preview(e) {
		var input = $('blog-' + mediaId);
		var div = document.createElement('div');
		if (input) {
			div.innerHTML = input.value;
			var img = div.getElementsByTagName('img')[0];
			if (img) {
				var evt = 'setTimeout(function() { parent.CodeGen.popup.readjust = false }, 500)';
				img.setAttribute('onload', evt);
				img.setAttribute('onerror', evt);
			}
			div.innerHTML = img ? document.createElement('div').appendChild(img).parentNode.innerHTML : '';
		}
		var lists = container.getElementsByTagName('ul');
		div.appendChild(lists[lists.length - 1].cloneNode(true));
		for (var inputs = div.getElementsByTagName('input'), i = inputs.length; i--;) {
			input = inputs[i];
			input.defaultValue = input.value;
			input.parentNode.insertBefore(document.createElement('span'), input).appendChild(input).setAttribute('onclick', 'this.select()');
		}

		var info = new PopupInfo;
		info.html = '\
			<table cellpadding="0" cellspacing="0" border="0">\
				<tr><td class="tl"><div></div></td><td class="tm"><div></div></td><td class="tr"><div></div></td></tr>\
				<tr><td class="ml"><div></div></td><td class="mm">\
					<div id="header">\
						<h1>Inline Preview</h1>\
						<p>Post this photo to your blog, myspace, etc.</p>\
						<button type="button" onclick="parent.CodeGen.popup.destroy()">Close</button>\
					</div>\
					<div id="content">\
						<p>Preview at: ' + previewSize.innerHTML + ' pixels</p>'
						+ div.innerHTML + '\
					</div>\
				</td><td class="mr"><div></div></td></tr>\
				<tr><td class="bl"><div></div></td><td class="bm"><div></div></td><td class="br"><div></div></td></tr>\
			</table>';

		info.origin = 'viewport';
		info.position = 'center';
		info.hideDelay = -1;
		info.keepInView = true;
		CodeGen.popup.destroy();
		CodeGen.popup.create(document.body, e, info);
	}

	function init() {
		if (activeTab) {
			var codes = [];
			for (var inputs = container.getElementsByTagName('input'), i = inputs.length; i--;) {
				codes.push({id: inputs[i].id.slice(0, -(mediaId.length + 1)), data: inputs[i].value});
			}
			cache[activeTab.rel] = codes;
		}
		addEvent(container, 'click', handleUI);
	}

	function getCodes(tabId, size, fitType, quality) {
		if (!content) {
			content = container.appendChild(document.createElement('div'));
			content.className = 'content';
		}
		content.innerHTML = '<p>Generating codes for <span>' + size + '-pixel image</span></p>';

		startTime = new Date().getTime();

		if (cache[tabId]) {
			me.set({codes: cache[tabId]});
			return;
		}

		script = document.createElement('script');
		script.type = 'text/javascript';
		script.onerror = script.onload = fatalError;
		script.onreadystatechange = function() {
			if (this.readyState == 'loaded' || this.readyState == 'complete') {
				fatalError();
			}
		};
		script.src = hostname + '/inlinePhoto?tab=' + tabId + '&photoId=' + mediaId + '&maxX=' + size + '&maxY=' + size + '&fitType=' + fitType + '&quality=' + quality + '&' + Math.random();
		document.getElementsByTagName('head')[0].appendChild(script);
	}

	function setCodes(codes) {
		for (var i = codes.length, el; i--;) {
			el = $(codes[i].id + '-' + mediaId);
			if (el) el.value = codes[i].data;
		}
		cache[activeTab.rel] = codes;

		if (content) {
			content.parentNode.removeChild(content);
			content = null;
		}
	}

	function setErrors(errors) {
		addClass(container, 'inline-error');
		if (content) content.innerHTML = '\
			<p>Sorry, failed to generate codes: <em>' + errors.join(', ') + '</em></p>\
			<p><strong>Please try again later.</strong></p>';
	}

	function fatalError() {
		me.set({errors: ['resource temporarily unavailable']});
	}

	function cleanup() {
		if (script) {
			script.parentNode.removeChild(script);
			script = null;
		}
		delClass(container, 'inline-generating');
	}

	this.set = function(obj) {
		if (script) script.onerror = script.onload = script.onreadystatechange = null;

		var delta = minDelay - (new Date().getTime() - startTime);
		if (delta > 0) {
			setTimeout(function() { me.set(obj) }, delta);
			return;
		}

		if (!obj) {
			setErrors(['internal error']);
		} else if (obj.errors) {
			setErrors(obj.errors);
		} else {
			setCodes(obj.codes);
		}
		setTimeout(cleanup, 1);
	};

	function handleUI(e) {
		if (hasClass(container, 'inline-generating')) {
			haltEvent(e);
			return;
		}
		for (var el = e.srcElement || e.target; el; el = el.parentNode) {
			if (el.tagName == 'A') {
				if (el.rel == 'preview') {
					preview(e);
					haltEvent(e);
				} else if (/^\d+$/.test(el.rel)) {
					addClass(container, 'inline-generating');
					delClass(container, 'inline-error');
					delClass(activeTab.parentNode, 'active');
					activeTab = el;
					addClass(activeTab.parentNode, 'active');
					var size = el.rel;
					previewSize.innerHTML = size;
					getCodes(size, size, 'shrink', 85);
					haltEvent(e);
				}
			} else if (el.tagName == 'INPUT') {
				el.select();
			}
		}
	}

	init();
}
CodeGen.popup = new Popup(
	['http://p.webshots.net/css/preview.css?r=' + new Date().getTime()
/*@cc_on
@if (@_jscript)
	, 'http://p.webshots.net/css/previewIE.css?r=' + new Date().getTime()
@end @*/
	], '_parent'
);
