/*
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Initial Developer of the Original Code is
# KUMAGAI Kentaro <ku0522a*gmail.com> http://ido.nu/kuma/
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
*/

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

var conffile = 'capture.tumblr.conf';

function trace() {

	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);
		}
	}
}

{
function HTTP(){ }
/**	
 * opts
 *		async		returns async input stream.
 *		headers		additional http request headers.
 *		onStartRequest
 *		onDataAvailable
 *		onStopRequest
 *		notificationCallbacks
 */
HTTP.Request = function (uri, opts) {
	var VERSION = '0.0.1';

	this.uri = uri;
	this.opts = opts || {};
//	this.channel = null;
	const CC = Components.classes;
	const CI = Components.interfaces;
	this.ios = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);

	this.request_channel = null;
	this.response_body = null;

	this.create_string_input_stream = function ( ) {
		return CC["@mozilla.org/io/string-input-stream;1"].
				createInstance(CI.nsIStringInputStream);
	};
	
	var self = this;
	[ 'onStopRequest', 'onDataAvailable', 'onStartRequest' ].forEach( function (n) {
		if ( self.opts[n] )
			self[n] = self.opts[n];
	} );
}
HTTP.Request.boundary = 'DEADBEEF_DEADBEEF';
HTTP.Request.prototype.onDataAvailable = function (req, context, stream, offset, length) {
	var ss = Components.classes['@mozilla.org/scriptableinputstream;1'].
					createInstance(Components.interfaces.nsIScriptableInputStream);
	ss.init(stream);
	this.response_body += ss.read(length);
}
HTTP.Request.prototype.onStartRequest = function () {
	this.response_body = '';
}
HTTP.Request.prototype.onStopRequest = function (request, context, statusCode) {
}

HTTP.Request.prototype.urlencode = function () {
	var pairs = [];
	for (var n in this.params ) {
		pairs.push ( [ n, encodeURIComponent(this.params[n]) ].join('=') );
	}
	return pairs.join("&");
}
HTTP.Request.prototype.set_multipart_params = function () {
	var post_data_stream = Components.classes["@mozilla.org/io/multiplex-input-stream;1"].
	            createInstance(Components.interfaces.nsIMultiplexInputStream);

	var content_type = "multipart/form-data; boundary=" + HTTP.Request.boundary;

	var pairs = [];
	for (var name in this.params ) {
		var streams;
		var value = this.params[name];

		if ( value instanceof Components.interfaces.nsIFile ) {
			streams = this.create_stream_from_file(name, value);
		} else if ( value.stream ) {
			streams = this.create_stream(name, value.stream, value);
		} else {
			var stream = this.create_string_input_stream();
			var chunk = "--" + HTTP.Request.boundary + '\r\n';
			chunk += 'Content-Disposition: form-data; name="' + name + '"' + '\r\n';
			chunk += '\r\n' + value + '\r\n';
			stream.setData(chunk, chunk.length);
			streams = [ stream ];
		}	
		streams.forEach( function (s) {
			post_data_stream.appendStream(s);
		} );
	}

	var chunk = '\r\n--' + HTTP.Request.boundary + '--\r\n';
	var stream = this.create_string_input_stream();
	stream.setData(chunk, chunk.length);
	post_data_stream.appendStream(stream);
	
	var mime_stream = Components.classes["@mozilla.org/network/mime-input-stream;1"]
			.createInstance(Components.interfaces.nsIMIMEInputStream);

	mime_stream.addHeader("Content-Type", content_type);
	mime_stream.addContentLength = true;
	mime_stream.setData(post_data_stream);
	return mime_stream;
}

HTTP.Request.prototype.create_stream = function (param_name, input, stream_params) {
	var buffered_stream = Components.classes["@mozilla.org/network/buffered-input-stream;1"].
				createInstance(Components.interfaces.nsIBufferedInputStream);

	trace(input, stream_params);

	buffered_stream.init(input, 4096);

	var chunk =  "--" + HTTP.Request.boundary + '\r\n';
	chunk += 'Content-Disposition: form-data; name="';
	chunk += param_name + '";';
	if ( stream_params.filename ) {
		chunk += 'filename="' + stream_params.filename + '"' +  '\r\n';
	}
	if ( stream_params.contentType ) {
		chunk += "Content-Type: " + stream_params.contentType + '\r\n';
		chunk += '\r\n';
	}

	var sis = Components.classes["@mozilla.org/io/string-input-stream;1"].
	            createInstance(Components.interfaces.nsIStringInputStream);
	
	sis.setData(chunk, chunk.length);
	return [sis, buffered_stream];
}

HTTP.Request.prototype.create_stream_from_file = function (param_name, file) {
	var uploadfile_uri = this.ios.newFileURI(file);
	var channel = this.ios.newChannelFromURI( uploadfile_uri );
	var input = channel.open();
	return this.create_stream(param_name, input, {filename: file} );
}
HTTP.Request.prototype.setup_channel = function (uri) {
	var uri = this.ios.newURI(this.uri, 'UTF-8', null);
	this.request_channel = this.ios.newChannelFromURI(uri);
}

HTTP.Request.prototype.set_params = {
	GET: function () {
		var query = this.urlencode();
		if ( query != '' ) {
			this.uri += ( ( this.uri.indexOf('?') >= 0) ? '&' : '?' ) + query; 
		}
		this.setup_channel();
	},
	POST: function () {
		var content_type = 'application/x-www-form-urlencoded';
		var post_data_stream;
		if ( this.opts.multipart ) {
			content_type = null;
			post_data_stream = this.set_multipart_params();
		} else {
			var query = this.urlencode();
			post_data_stream = this.create_string_input_stream();
			post_data_stream.setData(query, query.length);
			//post_data_stream = sis;
		}
		this.setup_channel();
		this.request_channel.QueryInterface(Components.interfaces.nsIUploadChannel);
		this.request_channel.setUploadStream(post_data_stream, content_type, -1);
	},
}

HTTP.Request.prototype.send_request = function (method, params) {
	this.params = params;
	var fn = this.set_params[method];
	fn.apply(this);

	this.request_channel.QueryInterface( Components.interfaces.nsIHttpChannel);
	this.request_channel.requestMethod = method;
	this.request_channel.notificationCallbacks = this.opts.notificationCallbacks;
	
	var response_input_stream = ( this.opts.async ) ?
			this.request_channel.asyncOpen(this, this) :
			this.request_channel.open() ;

	if ( ! this.opts.async ) {
		var ss = Components.classes['@mozilla.org/scriptableinputstream;1'].
						createInstance(Components.interfaces.nsIScriptableInputStream);
		ss.init(response_input_stream);
		this.response_body = '';
		var n;
		while ( n = ss.available() ) {
			this.response_body += ss.read(n);
		}
		return this.response_body;
	}
}

HTTP.Request.prototype.get = function (params) {
	return this.send_request('GET', params);
}
HTTP.Request.prototype.post = function (params) {
	return this.send_request('POST', params);
}

HTTP.Request.Util = {
	open_file: function (filename) {
		var file = Components.classes["@mozilla.org/file/local;1"]
							.createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath(filename);
		return file;
	}
}

}

{
var Tumblr = {
	endpoint: 'http://www.tumblr.com/api/',
	post: function (params, opts) {
		var uri = this.endpoint + 'write';

		opts.multipart = ( params.type.match(/^(audio|video|photo)$/) );
		return new HTTP.Request(uri, opts).post(params);
	},
}

}
/*
*/

String.prototype.qq = function ( ) {
	return '"' + this.toString() + '"';
}

var capture_phase = true;

var ImageSaver = {
	VERSION: "0.0.1c",
	from: null,
	to: null,
	rect: null,
	onkeypress: null,
	onmousedown: null,
	onmousemove: null,
	status: null,
	style: null,
	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, capture_phase );
		document.removeEventListener( 'keypress', this.onkeypress, capture_phase );
		document.removeEventListener( 'mousedown', this.onmousedown, capture_phase );
		if ( this.onmousemove ) { 
			document.removeEventListener( 'mousemove', this.onmousemove, capture_phase );
		}
		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, capture_phase );
		} 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, capture_phase );
		document.addEventListener( 'keypress', this.onkeypress, capture_phase );
		document.addEventListener( 'mousedown', this.onmousedown, capture_phase );

		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) {
try {
		var uri = window.content.document.location.href;
		Tumblr.post( {
			email: this.conf.email,
			password: this.conf.password,
			type: 'photo',
			caption: title.link(uri),
			generator: 'capture.tumblr.js/' + SCRIPT_VERSION + ' (http://ido.nu/kuma/)',
//			source: uri,
			data: {contentType: 'image/png', stream: bstream},
		}, {
			async: true,
			onStopRequest: function (request, context, statusCode) {
				request.QueryInterface(Components.interfaces.nsIHttpChannel);
				var text = request.responseStatusText;
				trace(this.response_body);
				if ( ImageSaver.conf.id ) {
					text = text.fontcolor("white").link(
						'http://' + ImageSaver.conf.id + '.tumblr.com/post/' +
						this.response_body
					);
				}
				ImageSaver.close_text_delayed(text);
			}
		} );

} catch (e) {
		Firebug.Console.log(e);
}
	},
	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("image/png");
		} 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;
	}
};


new function () {
	var file = Components.classes["@mozilla.org/file/local;1"]
					.createInstance(Components.interfaces.nsILocalFile);

	var script_loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
									 .createInstance(Components.interfaces.mozIJSSubScriptLoader);

	const IO_SERVICE = Components.classes['@mozilla.org/network/io-service;1']
					.getService(Components.interfaces.nsIIOService);

	if ( typeof  JsActions == 'undefined' ) {
	} else {
		var folder = JsActions.scriptFolderPath || JsActions.getScriptFolder();
		file.initWithPath( folder );
		file.append( conffile );
		var entryURI = IO_SERVICE.newFileURI(file).spec;
		var conf = script_loader.loadSubScript( entryURI, window );
		ImageSaver.conf = conf;
	}

	try {
		ImageSaver.start_select();
	} catch (e) {
		trace(e);
	}								     

};


