/*
Copyright (c) 2007 KUMAGAI Kentaro ku0522a*gmail.com
http://ido.nu/kuma

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/

var SCRIPT_VERSION = "0.0.1";
var DEBUG_TRACE = 0;

/**
 * (c) amachang
 * licence http://twitter.com/amachang/statuses/199049982
 * script available on http://usrb.in/svn/sbme/trunk/sbme@usrb.in/chrome/content/util.js
 * slightly modified by ku.
 **/ 
var SBME = {
	merge: function(dst) {
		for (var n in dst) this[n] = dst[n];
	},
	debug: function(text) {
		// TODO: DELETEME !! 超危険！！後で消す！
		window.content.wrappedJSObject.SBME = SBME;
	},
	getService: function(url, interface) {
		return Components.classes[url].getService(Components.interfaces[interface]);
	},
	createInstance: function(url, interface) {
		return Components.classes[url].createInstance(Components.interfaces[interface]);
	},
	QI: function(instance, interface) {
		return instance.QueryInterface(Components.interfaces[interface]);
	},
	newURI: function(uri) {
		const IO_SERVICE = Components.classes['@mozilla.org/network/io-service;1']
				.getService(Components.interfaces.nsIIOService);
		return IO_SERVICE.newURI(uri, null, null);
	},
	newChannel: function(uri) {
		const IO_SERVICE = Components.classes['@mozilla.org/network/io-service;1']
				.getService(Components.interfaces.nsIIOService);
		return IO_SERVICE.newChannelFromURI(SBME.newURI(uri, null, null));
	},
	setMethod: function(channel, method) {
		SBME.QI(channel, 'nsIHttpChannel').requestMethod = method.toUpperCase();
	},
	setPostData: function(channel, data) {
		var stream = SBME.createInstance('@mozilla.org/io/string-input-stream;1', 'nsIStringInputStream');
		stream.setData(data, data.length);
		SBME.QI(channel, 'nsIUploadChannel').setUploadStream(stream, 'application/x-www-form-urlencoded', -1);
		SBME.setMethod(channel, 'POST');
	},
	setHeaderData: function(channel, headers) {
		channel = SBME.QI(channel, 'nsIHttpChannel');
		for (var n in headers) {
			if (headers[n].constructor.name == 'Array') {
				headers[n].forEach(function(header) {
					channel.setRequestHeader(n, header, false);
				});
			}
			else {
				channel.setRequestHeader(n, headers[n], false);
			}
		}
	},
	setCookieData: function(channel, cookies) {
		SBME.setHeaderData(channel, { Cookie: cookies });
	},
	setReferrerData: function(channel, uri) {
		SBME.QI(channel, 'nsIHttpChannel').referrer = SBME.newURI(uri, null, null);
	},
	toBase64: function(data) {
		if (typeof data == 'string') return btoa(data);
		const toBase64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
		const base64Pad = '=';

		var result = '';
		var length = data.length;

		for (var i = 0; i < (length - 2); i += 3) {
			result += toBase64Table[data[i] >> 2];
			result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
			result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
			result += toBase64Table[data[i+2] & 0x3f];
		}

		if (length%3) {
			i = length - (length%3);
			result += toBase64Table[data[i] >> 2];
			if ((length%3) == 2) {
				result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
				result += toBase64Table[(data[i+1] & 0x0f) << 2];
				result += base64Pad;
			}
			else {
				result += toBase64Table[(data[i] & 0x03) << 4];
				result += base64Pad + base64Pad;
			}
		}
		return result;
	},
	getWsseData: function(username, password) {
		var created = SBME.iso8601Date(new Date());
		var nonce = (Math.random() + "").substr(2, 32);
		var data = nonce + created + (password || '');

		var converter = SBME.createInstance(
			'@mozilla.org/intl/scriptableunicodeconverter', 'nsIScriptableUnicodeConverter');
		converter.charset = 'UTF-8';
		data = converter.convertToByteArray(data, {});
		var ch = SBME.createInstance('@mozilla.org/security/hash;1', 'nsICryptoHash');
		ch.init(ch.SHA1);
		ch.update(data, data.length);
		var data = ch.finish(false);

		var passwordDigest = SBME.toBase64(data);
		nonce = SBME.toBase64(nonce);

		var wsse = 'UsernameToken Username="' + username + '", PasswordDigest="' + passwordDigest + '", Created="' + created + '", Nonce="' + nonce + '"';
		return wsse;
	},
	setWsseData: function(channel, username, password) {
		SBME.setHeaderData(channel, { 'Authorization': 'WSSE profile="UsernameToken"', 'X-WSSE': SBME.getWsseData(username, password) });
	},
	httpRequest: function(opts) {
		var uri          = opts.uri;
		var post         = opts.post;
		var cookies      = opts.cookies;
		var refer        = opts.refer;
		var callback     = opts.callback;
		var wsseUsername = opts.wsseUsername;
		var wssePassword = opts.wssePassword;
		var headers      = opts.headers;
		var method       = opts.method;
		var channel      = SBME.newChannel(uri);

		if (refer)        SBME.setReferrerData(channel, refer  );
		if (post)         SBME.setPostData    (channel, post   );
		if (cookies)      SBME.setCookieData  (channel, cookies);
		if (wsseUsername) SBME.setWsseData    (channel, wsseUsername, wssePassword);
		if (method)       SBME.setMethod      (channel, method );
		if (headers)      SBME.setHeaderData  (channel, headers);

		channel.asyncOpen({
			onStartRequest: function(request, context) {
				this.data = "";
			},
			onDataAvailable: function(request, context, stream, sourceOffset, length){
				var sStream = SBME.createInstance('@mozilla.org/scriptableinputstream;1', 'nsIScriptableInputStream');
				sStream.init(stream);
				this.data += sStream.read(length);
			},
			onStopRequest : function (request, context, status) {
				callback(this.data, request);
			}
		}, null);
	},
	newXmlRpc: function(uri, methodName) {

		function parseNumber(arg) {
			if (parseInt(arg) == arg) return <i4>{arg}</i4>;
			else                      return <double>{arg}</double>;
		}

		function parseBoolean(arg) {
			return <boolean>{arg ? 1 : 0}</boolean>;
		}

		function parseString(arg) {
			return <string>{arg}</string>;
		}

		function parseDate(arg) {
			return <dateTime.iso8601>{SBME.iso8601Date(arg)}</dateTime.iso8601>;
		}

		function parseArray(arg) {
			var array = <array />;
			arg.forEach(function(e) {
				array.appendChild(parse(e));
			});
			return array;
		}

		function parseObject(arg) {
			var struct = <struct />;
			for (var n in arg) {
				var member = <member />
				member.appendChild(<name>{n}</name>);
				member.appendChild(parse(arg[n]));
				struct.appendChild(member);
			}
			return struct;
		}

		function parse(arg) {

			var param;
			switch (typeof arg) {

				case 'number':  param = parseNumber(arg);  break;
				case 'boolean': param = parseBoolean(arg); break;
				case 'string':  param = parseString(arg);  break;

				default:
					switch(arg.constructor.name) {
						case 'Number':  param = parseNumber(arg);  break;
						case 'Boolean': param = parseBoolean(arg); break;
						case 'String':  param = parseString(arg);  break;
						case 'Date':    param = parseDate(arg);    break;
						case 'Array':   param = parseArray(arg);   break;
						default:        param = parseObject(arg);  break;
					}
					break;
			}

			var result = <value />;
			result.appendChild(param);
			return result;

		}

		function unparse(value) {
			var value = value.children()[0];
			switch(value.localName()) {
				case 'i4': case 'int': case 'double':
					value = +(value.text().toString());
					break;
				case 'string':
					value = value.text().toString();
					break;
				case 'dateTime.iso8601':
					value.text().toString().match(/^(\d{4})-?(\d{2})-?(\d{2})T(\d{2}):?(\d{2}):?(\d{2})/);
					new Date(Date.UTC(RegExp.$1, RegExp.$2-1, RegExp.$3, RegExp.$4, RegExp.$5, RegExp.$6));
					break;
				case 'array':
					var a = [];
					for (var n in value.value) {
						a.push(unparse(value.value));
					}
					value = a;
					break;
				case 'struct':
					var o = {};
					for (var n in value..member) {
						o[value..member[n].name.text().toString()] = unparse(value..member[n].value);
					}
					value = o;
					break;
				default:
					value = undefined;
					break;
			}
			return value;
		}

		return function(/* ..., opts */) {

			var methodXML = <methodCall>
					<methodName>{methodName}</methodName>
					<params></params>
				</methodCall>;

			var opts = Array.pop(arguments);

			switch(typeof opts) {
				case 'function':
					opts = { callback: opts };
					break;
				case 'string':
				case 'number':
				case 'boolean':
					Array.push(arguments, opts);
					opts = {};
					break;
			}

			Array.forEach(arguments, function(arg) {
				var param = <param />;
				param.appendChild(parse(arg));
				methodXML.params.appendChild(param);
			});

			opts.uri = uri;
			opts.post = methodXML.toString();
			opts.headers = {
				'Content-Type': 'text/xml'
			};
			if(opts.callback) {
				var callback = opts.callback;
				opts.callback = function(data, req) {
					if(data.match(/^<\?xml/)) {
						data = data.replace(/<\?xml.*?\?>/, '');
					}
					var data = new XML(data);
					var params = data.params.param;
					var args = [];

					for (var n in params) {
						args.push(unparse(params[n].value));
					}
					callback.apply(null, args);
				}
			}

			SBME.httpRequest(opts);
		};
	},
	newAtomAPI: function(opts) {
		var username         = opts.username;
		var password         = opts.password;
		var postUri          = opts.postUri;
		var editUri          = opts.editUri;
		var editFromEntryUri = opts.editFromEntryUri
		if (typeof editUri == 'function') {
			var editUriFactory = opts.editUri
		}
		else {
			var editUriFactory = function(id) { return editUri + id; }
		}
		if (typeof editFromEntryUri == 'function') {
			var editFromEntryUriFactory = opts.editFromEntryUri
		}
		else {
			var editFromEntryUriFactory = function(uri) { return editFromEntryUri + uri; }
		}

		return {
			_createEntryData: function(content) {
				var text = null;
				var tags = [ '<entry xmlns="http://purl.org/atom/ns#" >' ];
				for ( var tagname in content ) {
					var pairs = [];
					var attributes = content[tagname];
					var contentText = null;
					for ( var attr in attributes ) {
						if ( attr == 'TEXT' ) {
							contentText = attributes[attr];
						} else {
							pairs.push( attr + '=' + attributes[attr].qq() );
						}
					}
					pairs.unshift(tagname);
					tags.push( '<' + pairs.join(" ") + '>' + contentText +
								'</' + tagname + '>' );
				}

				tags.push('</entry>');
				var ret = tags.join("\n");
				return ret;
			},
			create: function(content, callback) {
				var uri = postUri;
				this._internal(uri, 'POST', this._createEntryData(content), callback);
			},
			read: function(id, callback) {
				var uri = editUriFactory(id);
				this._internal(uri, 'GET', undefined, callback);
			},
			update: function(id, opts, callback) {
				var uri = editUriFactory(id);
				this._internal(uri, 'PUT', this._createEntryData(opts), callback);
			},
			delete: function(id, callback) {
				var uri = editUriFactory(id);
				this._internal(uri, 'DELETE', undefined, callback);
			},
			readFromEntry: function(uri, callback) {
				var uri = editFromEntryUriFactory(uri);
				this._internal(uri, 'GET', undefined, callback);
			},
			_internal: function(uri, method, post, callback) {
				SBME.httpRequest({
					uri: uri,
					post: post,
					method: method,
					wsseUsername: username,
					wssePassword: password,
					callback: function(data, req) {
						if(data.match(/^<\?xml/)) {
							data = data.replace(/<\?xml.*?\?>/, '');
						}

						try {
							data = new XML(data);
						}
						catch(e) {
							data = '';
						}

						callback(data, req);
					}
				});
			}
		};

	},
	iso8601Date: function(date) {
		var datetime = date.getUTCFullYear() + "-";
		var month = String(date.getUTCMonth() + 1);
		datetime += (month.length == 1 ?  '0' + month : month);
		datetime += '-';
		var day = date.getUTCDate();
		datetime += (day < 10 ? '0' + day : day);
		datetime += 'T';
		var hour = date.getUTCHours();
		datetime += (hour < 10 ? '0' + hour : hour) + ':';
		var minutes = date.getUTCMinutes();
		datetime += (minutes < 10 ? '0' + minutes : minutes) + ':';
		var seconds = date.getUTCSeconds();
		datetime += (seconds < 10 ? '0' + seconds : seconds);
		return datetime + "Z";
	}
};


function log() {

	if ( (typeof DEBUG_TRACE != 'undefined') && ! DEBUG_TRACE )
		return;

	var fn;
	if ( typeof Firebug == 'undefined' ) {
		fn = console;
	} else if ( Firebug && Firebug.Console && Firebug.Console.log  ) {
		fn = Firebug.Console;
	}

	if ( fn ) {
		if ( arguments.length == 1 ) {
			fn.log(arguments[0]);
		} else {
			var args = [];
			for (var i = 0; i < arguments.length; i++) {
				args.push(arguments[i]);
			}
			fn.log(args);
		}
	}
}

var ImageSaver = {
	VERSION: '0.0.1c',
	from: null,
	to: null,
	rect: null,
	onkeypress: null,
	onmousedown: null,
	onmousemove: null,
	status: null,
	style: null,
	encodeTo: 'image/jpeg',
	bind: function (fn, object) {
		object = object || this;
	  var __method = fn;
		return function() {
			__method.apply(object, arguments);
		}
	},
	dim: {
			x: {prop: 'width', origin: 'left'},
			y: {prop: 'height', origin: 'top'}
	},

	update_rect: function (e) {
		var to = {x: e.clientX, y: e.clientY};

		var x, y;
		for ( var n in this.dim ) {
			var v = this.dim[n];
			var t;
			if ( ( t = to[n] - this.from[n] ) < 0 ) {
				this.rect.style[v.origin] = (this.from[n] + t) + 'px';
			}
			this.rect.style[v.prop] = Math.abs(t) + 'px';
		}
			
		this.rect.style.height = (to.y - this.from.y ) + 'px';
	},

	cancel_capture: function (e) {
		this.stop_event_listening();

		this.show_text('');
		this.close_text_delayed('Canceled', 3 * 1000);
	},

	stop_event_listening: function () {
		document.removeEventListener( 'click', this.onclick, true );
		document.removeEventListener( 'keypress', this.onkeypress, true );
		document.removeEventListener( 'mousedown', this.onmousedown, true );
		if ( this.onmousemove ) { 
			document.removeEventListener( 'mousemove', this.onmousemove, true );
		}
		this.style.parentNode.removeChild( this.style );

		if ( this.rect ) {
			this.rect.parentNode.removeChild(this.rect);
		}
	},

	select_rect: function (e) {
		if ( this.from == null ) {
			this.from = {x: e.clientX, y: e.clientY};

			this.rect = document.createElement('div');
			this.rect.style.outlineWidth = '2px';
			this.rect.style.outlineStyle = 'dotted';
			this.rect.style.outlineColor = '#0063DC';
			this.rect.style.backgroundColor = '#0063DC';
			this.rect.style.opacity = '0.5';
			this.rect.style.position = 'fixed';
			this.rect.style.width = '0px';
			this.rect.style.height = '0px';
			this.rect.style.zIndex = 2100000000;
			this.rect.style.top = this.from.y + 'px',
			this.rect.style.left = this.from.x + 'px',
			document.body.appendChild(this.rect);

			document.addEventListener( 'mousemove', this.onmousemove, true );
		} else if ( this.to == null ) {
			this.to = {x: e.clientX, y: e.clientY};

			var rect = {};
			var self = this;
			["top", "left", "width", "height"].forEach( function(n) {
				rect[n] = parseInt( self.rect.style[n] );
			} );

			this.stop_event_listening();
			this.copy( rect );
		}
		return false;
	},
	onclick: function (e) {
		e.preventDefault();
		return false;
	},

	key_pressed: function(e) {
		if ( e.keyCode == e.DOM_VK_ESCAPE ) {
			this.cancel_capture();
			return false;
		}
		return true;
	},

	start_select: function () {
		this.onkeypress  = this.bind(this.key_pressed);
		this.onmousemove = this.bind(this.update_rect);
		this.onmousedown = this.bind(this.select_rect);
		document.addEventListener( 'click', this.onclick, true );
		document.addEventListener( 'keypress', this.onkeypress, true );
		document.addEventListener( 'mousedown', this.onmousedown, true );

		var s = document.createElement('style');
		s.innerHTML = '* {cursor: crosshair !important;}';
		document.body.appendChild(s);
		this.style = s;
	},

	show_text: function (text) {
		var d = document.createElement('div');
		d.innerHTML = text;
		d.className = 'capture_tumblr_statuscode';

		style = document.createElement('style');
		style.type = 'text/css';
		style.innerHTML = <><![CDATA[
			div.capture_tumblr_statuscode {
				position: fixed;
				font-size: x-large;
				font-family: sans-serif;
				font-weight: bold;
				margin: 0.3em;
				padding: 0.6em;
				top: 2px;
				right: 2px;
				color: white;
				background-color: #E72D89;
				z-index: 2100000000;
				-moz-border-radius: 0.3em;
				-moz-opacity: 0.95;
			}
			div.capture_tumblr_statuscode a {
				color: white;
			}
		]]></>;

		document.body.appendChild(d);
		document.body.appendChild(style);

		this.status = d;

	},
	close_text_delayed: function (html, duration) {
		duration = duration || 20 * 1000;

		this.status.innerHTML = html;
		this.status.style.backgroundColor = '#0063DC';
		var self = this;
		window.setTimeout( function () {
			self.status.parentNode.removeChild( self.status );
		}, duration );
	},

	post: function (title, bstream) {
		// override this method to save.
	},
	copy: function ( rect ) {
		var canvas = document.createElement('canvas');
		canvas.setAttribute("id", "svcanvas");
		canvas.style.display = "inline";
		canvas.width = rect.width;
		canvas.height = rect.height;

		var x = window.content.document.width;
		var y = window.content.document.height;

		var statusbar = ( top.document.getElementById('status-bar') );
		var body = ( document.getElementsByTagName('body') );

		var p = body[0];
		p.appendChild(canvas);

		var ctx = canvas.getContext("2d");
		ctx.clearRect(0, 0, rect.width, rect.height);
		//ctx.clearRect(0, 0, x, y);
		//trace( rect.width + " * " + rect.height);
		ctx.save();
		ctx.scale(1.0, 1.0);

		var x1 = rect.left + window.pageXOffset;
		var x2 = rect.left + rect.width + window.pageXOffset;
		var y1 = rect.top + window.pageYOffset;
		var y2 = rect.top + rect.height + window.pageYOffset;

		ctx.drawWindow(window.content, x1, y1, x2, y2, "rgb(255,255,255)");
		ctx.restore();

		try {
			var url = canvas.toDataURL( this.encodeTo );
		} catch(ex) {
			return trace("This feature requires Firefox 2.0.\n" + ex);
		}
		const ios = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces.nsIIOService);
		url = ios.newURI(url, null, null);

		var channel = ios.newChannelFromURI( url );
		var input = channel.open();
		var bstream = Components.classes["@mozilla.org/binaryinputstream;1"]
			.createInstance(Components.interfaces.nsIBinaryInputStream);
		bstream.setInputStream(input);
		
		var uc = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
						.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
		uc.charset = 'UTF-8';
		var title = uc.ConvertFromUnicode(window.content.document.title);

		this.show_text( 'Saving...' );

		this.post(title, bstream);
		canvas.style.display = "none";
		canvas.width = 1;
		canvas.height = 1;
	}
};

var Util = {
	getLoginInfomation: function (hostname, formSubmitURL, httprealm) {
		httprealm = httprealm || null;
		if ("@mozilla.org/passwordmanager;1" in Components.classes) {
			// fx2.
			//
			var pm  = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManager);
			var pmi = Cc["@mozilla.org/passwordmanager;1"].getService(Ci.nsIPasswordManagerInternal);

			var host = { value : "" }, user = { value : "" }, pass = { value : ""};
			pmi.findPasswordEntry("http://mixi.jp", null, null, host, user, pass);
			return {username: user.value, password: pass.value}
		} else if ("@mozilla.org/login-manager;1" in Components.classes) {
			// fx3.
			var lm = Components.classes["@mozilla.org/login-manager;1"]
									.getService(Components.interfaces.nsILoginManager);
			var logins = lm.findLogins({}, hostname, formSubmitURL, httprealm);
			if ( logins.length == 0 )
				throw {msg: "no login infomation."};
			return logins.shift();
		}
		return 1;
	}
	
}

var Mixi = {
	VERSION: '0.0.1',
	username: null,
	password: null,
	userid: null,
	nsAtom: null,
	init: function () {
		this.getLoginInfomation();
		this.getMixiID();
	},
	addPhoto: function (albumUri, title, bstream, contentType) {
		const CC = Components.classes;
		const CI = Components.interfaces;
		var ios = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);

log(albumUri)
		albumUri = ios.newURI(albumUri, 'UTF-8', null);

		var channel = ios.newChannelFromURI( albumUri );
		channel.QueryInterface( Components.interfaces.nsIUploadChannel);
		log(channel, albumUri);
		channel.setUploadStream(bstream, contentType, -1);
		channel.QueryInterface( Components.interfaces.nsIHttpChannel );
		var p = SBME.getWsseData(this.username, this.password);
		log(channel, p);
		channel.setRequestHeader("X-WSSE", p, false);
		channel.setRequestHeader("slug", encodeURIComponent(title), false );
		channel.requestMethod = "POST";
		var responseStream = channel.open();

		var response_body = "";
		var ss = Components.classes['@mozilla.org/scriptableinputstream;1'].
						createInstance(Components.interfaces.nsIScriptableInputStream);
		ss.init(responseStream);
		response_body += ss.read(ss.available());

		var xml = new XML(response_body.replace( /<\?.+?\?>/, '' ));
		log(xml, response_body, channel);
		var ns = new Namespace(xml.name().uri);
		return xml.ns::link.@href.toString();
	},
	getMixiID: function () {
		var xhr = this.invokeAPI("http://mixi.jp/atom/tracks/r=2/");

		var xml = new XML(xhr.responseText.replace( /<\?.+?\?>/, '' ));
		var trackURL = xml.workspace.collection.@href.toString();
		log(xhr,trackURL, xml);


		var ns = new Namespace(xml.name().uri);
		var trackURL = xml..ns::collection.@href.toString(); 

		// "http://mixi.jp/atom/tracks/r=2/member_id=26756"
		if ( trackURL.match( /member_id=(\d+)/ ) ) {
			return this.userid =  RegExp.$1;
		}
	},
	getLoginInfomation: function () {
		var hostname = 'http://mixi.jp';
		var formSubmitURL = 'http://mixi.jp';
		var httprealm = null;
		var login = Util.getLoginInfomation(hostname, formSubmitURL, httprealm);
		log(login);
		this.username = login.username;
		this.password = login.password;
	},
	invokeAPI: function (endpoint, dataToPost) {
		var p = SBME.getWsseData(this.username, this.password);
		var xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
		
		var method = (dataToPost) ? "POST" : "GET";
		xhr.open(method, endpoint, false);
		xhr.setRequestHeader("X-WSSE", p);
		if ( method == "POST" ) {
			xhr.setRequestHeader("Content-Type", "application/atom+xml;type=entry");
		}
		log(method, endpoint, dataToPost);
		xhr.send(dataToPost || null);

		log(xhr, xhr.responseText);

		return xhr;
		
	},
	invokeAtomAPI: function (r, dataToPost) {
		return this.invokeAPI( "http://photo.mixi.jp/atom/r=" + r, dataToPost );
	},
	getAlbumData: function () {
	}, 
	findOrCreateAlbum: function (albumname) {
		log("findOrCreateAlbum");
		var xhr = this.invokeAtomAPI(4);
		
		var xml = new XML(xhr.responseText.replace( /<\?.+?\?>/, '' ));
		var trackURL = xml.workspace.collection.@href.toString();

		var ns = new Namespace(xml.name().uri);
		var nsAtom = new Namespace("http://www.w3.org/2005/Atom");
		var candidates = xml..ns::collection.(nsAtom::title == albumname );
		if ( candidates.length() > 0 ) {
			return candidates[0].@href.toString();
		} else {
			return this.createAlbum(albumname);
		}
	},
	createAlbum: function (albumname) {
		var xml = <entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app#" xmlns:permit="http://mixi.jp/atom/ns#permit">
			<title />
			<id>urn:uuid:f2091734-f439-4c6d-a8b6-5af2ab9394f8</id>
			<author><name /></author>
			<content />
			<summary>capture.mixi.js screenshots</summary>
			<updated />
			<app:control>
				<permit:access>public</permit:access>
				<permit:token />
			</app:control>
		</entry>;

		var ns = new Namespace(xml.name().uri);
		xml.ns::updated = SBME.iso8601Date(new Date());
		xml.ns::title = albumname;

		// public.
		var xhr = this.invokeAtomAPI("4/member_id=" + this.userid, xml.toXMLString());
		var loc = xhr.getResponseHeader("location");
		return loc;
	}

}




	ImageSaver.post = function (title, bstream) {
		Mixi.init();
		var albumUri = Mixi.findOrCreateAlbum('screenshots');
		var title = window.content.document.location.href;
		var contentType = this.encodeTo;

		var u = Mixi.addPhoto(albumUri, title, bstream, contentType);

		ImageSaver.close_text_delayed('uploaded'.link(u), 8 * 1000);

	}

if ( typeof  JsActions == 'undefined' ) {
	
} else {
	ImageSaver.start_select();
}

/*
		this.addPhoto(albumUri, title, bstream, 'image/jpeg', -1);

		var localfile = '/home/kuma/images/glassed.jpg';

		const CC = Components.classes;
		const CI = Components.interfaces;
		var ios = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);

		var file = Components.classes["@mozilla.org/file/local;1"]
						.createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath( localfile );
		var uploadfile_uri = ios.newFileURI(file);
		var channel = ios.newChannelFromURI( uploadfile_uri );
		var bstream = channel.open();
*/


