Node.prototype.setData = function(key, value){
	this.__userdata = this.__userdata || {};
	this.__userdata[key] = value;
};
Node.prototype.getData = function(key){
	try {
		return this.__userdata[key];
	} catch (e) {
		return null;
	}
};
HTMLHeadingElement.prototype.__defineGetter__("level",
	function(){
		return this.__level || (this.__level = Number(this.tagName.charAt(1)));
	}
);
Element.prototype.__defineGetter__("klass",
	function(){
		return this.__klass || (this.__klass = this.className.split(/\s/))
	}
);
Element.prototype.__defineSetter__("klass",
	function(ary){
		this.__klass = ary;
		try {
			this.className = ary.length && ary.join(" ") || "";
		} catch(e) {
			throw new TypeError("TypeError. Element.klass property must be an array.");
		}
	}
);
Element.prototype.isClassOf = function(name){
	return this.klass.indexOf(name) != -1;
};
Element.prototype.changeClass = function(newClass, oldClass){
	var klass = this.klass;
	if (!newClass && !oldClass)
		klass = [];
	else if (!oldClass)
		this.isClassOf(newClass) || klass.push(newClass);
	else if (!newClass)
		this.isClassOf(oldClass) && klass.splice(klass.indexOf(oldClass), 1);
	else
		klass.splice(klass.indexOf(oldClass), 1, newClass);
	this.klass = klass;
};

function _XPathNSResolver(nsmap, nodeResolver){
  this._nsmap = nsmap;
  this._resolver = nodeResolver?
    nodeResolver.ownerDocument.createNSResolver(nodeResolver) : null;
}

_XPathNSResolver.prototype.lookupNamespaceURI = function(prefix){
  var v;
  if (v = this._nsmap[prefix])
    return v;
  if (v = this._resolver)
    return v.lookupNamespaceURI(prefix);
  return v;
};

/* Tipical usage of _XPathNSResolver
var de = document.documentElement;
var type = XPathResult.FIRST_ORDERED_NODE_TYPE;
var nsresolver = new _XPathNSResolver(
	{xht: "http://www.w3.org/1999/xhtml"}, de);
var result = document.evaluate(
	'descendant::xht:*', de, nsresolver, type, null);
*/

(function(__proto__/* Node.prototype */){

var resolver = (
	Document.prototype.xpathNSResolver = new _XPathNSResolver({}, null)
);

__proto__.selectNodes = function(expression){
	var doc = this.nodeType == Node.DOCUMENT_NODE ? this : this.ownerDocument;
	var result = doc.evaluate(
			expression, // XPath expression
			this, // Context node
			resolver, // Name space resolver
			XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, // Result type
			null // XPathResult if reuse
		);
	if (result.snapshotLength == 0) return null;
	var nl = new _NodeList(result);
	return nl;
};

__proto__.selectSingleNode = function(expression){
	var doc = this.nodeType == Node.DOCUMENT_NODE ? this : this.ownerDocument;
	var result = doc.evaluate(
			expression,
			this,
			resolver,
			XPathResult.FIRST_ORDERED_NODE_TYPE,
			null
		);
	return result.singleNodeValue;
};

function _NodeList(result){ // 「死」んでいる点に注意する
	this.__index = 0;
	this.__result = result;
	this.length = result.snapshotLength;
}

(function(__proto__){
	__proto__.__iterator__ = function(){
		return this;
	};
	__proto__.item = function(index){
		return this.__result.snapshotItem(index);
	};
	__proto__.next = function(){
		var item = this.item(this.__index++);
		if (!item) {
			this.__index = 0;
			throw StopIteration;
		} else {
			return item;
		}
	};
})(_NodeList.prototype);

})(Node.prototype);

document.__defineGetter__("fontSize", function(){
	return document.defaultView.getComputedStyle(document.body, "").fontSize.slice(0, -2);
});




function structure(){
	var div = document.createElement("DIV"),
		rng = document.createRange(),
		address = document.selectSingleNode("descendant::div[@class='navi']") || document.getElementsByTagName("ADDRESS").item(0),
		links;
	
	rng.setStartAfter(document.getElementsByTagName("H1").item(0));
	rng.setEndBefore(address);
		div.id = "BODY";
		rng.surroundContents(div);
	if (links = document.getElementById("LINKS")) {
		rng.setStartBefore(div.firstChild);
		rng.setEndBefore(links);
			div = document.createElement("DIV");
			div.id = "MAIN";
		rng.surroundContents(div);
	}
	optimizeLayout();
}

function optimizeLayout(){
    var w = document.documentElement.clientWidth;
    var h = document.documentElement.clientHeight;
    var body = document.getElementById("BODY");
    var main = document.getElementById("MAIN");
    var links = document.getElementById("LINKS");
    if (main && links) {
        if (w > (50 + 17) * document.fontSize) {
            body.className = "table";
            main.className = "main";
            links.className = "sidebar";
            document.body.className = "double-column";
        } else {
            body.className = "";
            main.className = "";
            links.className = "";
            document.body.className = "single-column";
        }
    } else if (document.selectNodes("descendant::table[@class='object']")) {
        body.className = "";
        document.body.className = "wide";
    } else {
        var rect = body.clientWidth * body.clientHeight;
        var limit = w*h;
        if (rect < limit*0.4) {
            body.className = "";
            document.body.className = "wide";
        } else if (rect < limit*1.2) {
            body.className = "longdesc";
            document.body.className = "variable-column";
        } else if (rect < limit*2) {
            body.className = "";
            document.body.className = "wide";
        } else {
            body.className = "";
            document.body.className = "single-column";
        }
    }
	// make thin tables floating element
/*
	for each(let e in document.selectNodes("descendant::table"))
		if (e.parentNode.clientWidth - e.clientWidth > document.fontSize * 15)
			e.changeClass("float");
		else
			e.changeClass(null, "float");
*/
}

window.addEventListener("load", structure, true);
window.addEventListener("resize", optimizeLayout, true);
window.addEventListener("load", function(){
	for each(let e in document.selectNodes("descendant::ul | descendant::ol"))
		e.selectNodes("child::li").length < 4 && (e.className = "short");
}, true);

window.addEventListener("scroll", function(){}, true);

