
HTTPRequest; // (HTTPRequest.js is required.)
spackle; // (spackle.js is required.)

// The element should initially contain an image that will be displayed when
// loading, which can be nested within further elements for layout purposes.
function DFrame(element, url) {
	this.element = element;

	this.element.style.overflow = "auto";
	this.element.style.position = "relative";

	this.loading_image = this.element.getElementsByTagName("img")[0];
	if (this.loading_image) {
		spackle(this.loading_image);

		this.loading_image.style.position = "absolute";

		var clip = getComputedStyle(this.loading_image).clip;
		if (clip != "" && clip != null) {
			this.animate_loading_image = true;

			this.loading_image_original_clip = clip;
			this.loading_image_original_position = this.loading_image.absolute_position();
		} else
			this.animate_loading_image = false;

		this.loading_image.parentNode.removeChild(this.loading_image);
	}
	this.loading_animation_interval = 0;

	this.current_url = null;
	this.loading_url = null;
	this.pending_anchor = null;

	this.request = null;
	if (url)
		this.load(url);
}

DFrame.prototype.load = function(url) {
	var anchor = null;
	if (url.match(/^(.*)#(.+)$/)) {
		url = RegExp.$1;
		anchor = RegExp.$2;
	}

	if (!url && this.current_url ||
	    url == this.current_url) {
		if (anchor)
			this._anchor(anchor);
		return;
	}
	if (!url && this.loading_url ||
	    url == this.loading_url) {
		this.pending_anchor = anchor;
		return;
	}

	if (this.request)
		this.request = null;

	for (var i = this.element.firstChild, next; i; i = next) {
		next = i.nextSibling;

		if (i != this.loading_image)
			this.element.removeChild(i);
	}

	if (this.loading_image && !this.loading_image.parentNode)
		this.element.appendChild(this.loading_image);
	if (this.animate_loading_image)
		this.loading_animation_start();

	this.request = new HTTPRequest("GET", url);
	var that = this;
	this.request.onresponse = function(status, html) {
		if (status == 200)
			that._content_loaded(html);
	};
	this.request.send();

	this.current_url = null;
	this.loading_url = url;
	this.pending_anchor = anchor;
}

DFrame.prototype._content_loaded = function(html) {
	if (this.loading_image && this.loading_image.parentNode)
		this.element.removeChild(this.loading_image);
	if (this.animate_loading_image)
		this.loading_animation_stop();

	this.element.innerHTML = html;

	this.current_url = this.loading_url;
	this.loading_url = null;

	if (this.pending_anchor) {
		this._anchor(this.pending_anchor);
		this.pending_anchor = null;
	}
}

DFrame.prototype._anchor = function(name) {
	var anchor_elements = this.element.getElementsByTagName("a");
	var anchor_element = null;
	for (var i = 0; i < anchor_elements.length; ++i) {
		if (anchor_elements[i].name == name) {
			anchor_element = anchor_elements[i];
			break;
		}
	}
	if (!anchor_element)
		return;

	spackle(anchor_element);
	document.scroll_to(0, anchor_element.absolute_position().top);
}


DFrame.prototype.loading_animation_start = function() {
	if (!this.animate_loading_image)
		return;

	this.loading_image.style.clip = this.loading_image_original_clip;
	var p = this.loading_image_original_position;
	this.loading_image.move_to(p.left, p.top);

	var that = this;
	this.loading_animation_interval =
		setInterval(function() { that.loading_animation_advance(); },
		            60);
}
DFrame.prototype.loading_animation_stop = function() {
	if (!this.animate_loading_image)
		return;

	clearInterval(this.loading_animation_interval);
	this.loading_animation_interval = 0;
}

DFrame.prototype.loading_animation_advance = function() {
	var clip = getComputedStyle(this.loading_image).clip;
	if (!clip.match(/^\s*rect\s*\(\s*(0(?:pt)?|\d+px)\s*,\s*(0(?:pt)?|\d+px)\s*,\s*(0(?:pt)?|\d+px)\s*,\s*(0(?:pt)?|\d+px)\s*\)\s*$/)) {
		alert("!clip.match");
		return;
	}
	var clip_top    = parseInt(RegExp.$1),
	    clip_right  = parseInt(RegExp.$2),
	    clip_bottom = parseInt(RegExp.$3),
	    clip_left   = parseInt(RegExp.$4);
	var clip_height = clip_bottom - clip_top;

	clip_top += clip_height;
	if (clip_top >= this.loading_image.height)
		clip_top = 0;
	var new_clip = "rect(" + clip_top + "px, " + clip_right + "px, " +
	                         (clip_top + clip_height) + "px, " + clip_left + "px)";
//	this.loading_image.style.clip = new_clip;

	this.loading_image.move_to(this.loading_image_original_position.left,
	                           this.loading_image_original_position.top - clip_top);
}

