var express = require('express')
	,app = express.createServer()
	,fs = require('fs')
	,QRCode = require('../qrcode')
	,canvasutil = require('canvasutil')
	,Canvas = require('canvas')
	,Image = Canvas.Image;

var path = require('path')

app.configure(function(){
	app.use(express.methodOverride());
	app.use(express.bodyParser());
	app.use(app.router);
	app.use(express.static(path.resolve(__dirname,'..')));
});

app.get('/', function(req, res){
	fs.readFile(path.join(__dirname,'clientside.html'), function (err, data) {
		res.send(data?data.toString():err);
	});
});

var effectHandlers = {};

app.get('/generate', function(req, res){
	var q = req.query||{},imageSrc;
	
	QRCode.QRCodeDraw.color.light = q.lightColor||'#ffffff';
	QRCode.QRCodeDraw.color.dark = q.darkColor||'#000000';
	QRCode.QRCodeDraw.scale = +(q.scale);

	if(isNaN(QRCode.QRCodeDraw.scale)) QRCode.QRCodeDraw.scale = 4;
	//NOTE when i set scale to 500 something seg faulted
	if(QRCode.QRCodeDraw.scale > 50) QRCode.QRCodeDraw.scale = 50;

	var effect = q.effect||'plain';
	if(!effectHandlers[effect]){
		effect = 'plain';
	}
	
	effectHandlers[effect](q,function(error,canvas){
		if(!error){
			canvas.toBuffer(function(err, buf){
				res.header('Content-Type','image/png');
				res.send(buf);
			});
		} else {
			var msg = error.message+"\n"+error.stack;
			res.header('Content-Type','text/plain');
			res.send(msg);
			console.error(msg);
		}
	});
});

effectHandlers.node = function(args,cb){
	args.src = path.join(__dirname,'fixtures','node_logo.png');
	this.image(path.join(args,cb);
};

effectHandlers.npm = function(args,cb){
	args.src = path.join(__dirname,'fixtures','npm_logo.png');
	this.image(args,cb);
};

effectHandlers.bacon = function(args,cb){
	args.src = path.join(__dirname,'fixtures','bacon-love.png');
	this.image(args,cb);
};

effectHandlers.baconBikini = function(args,cb){
	args.src = path.join(__dirname,'fixtures','bacon-bikini.png');
	this.image(args,cb);
};

effectHandlers.rounded = function(args,cb){
	QRCode.draw(args.text||'',function(err,canvas){
		if(err) {
			cb(err,canvas);
			return;
		}

		var tpx = new canvasutil.PixelCore()
		,luma709Only = canvasutil.conversionLib.luma709Only
		,savedBuffer
		,up=[],down=[],left=[],right=[]
		,upPx,downPx,leftPx,rightPx,undefined,r,t,l,b,corner = 0;

		tpx.threshold = 100;
		
		tpx.iterate(canvas,function(px,i,len,pixels,w,h,pixelCore){
			corner = 0;

			//is dark
			if(luma709Only(px.r,px.g,px.b) < pixelCore.threshold) {

				if(i-w > 0){
					upPx = (i-w)*4;
					up[0] = pixels[upPx + 0];
					up[1] = pixels[upPx + 1];
					up[2] = pixels[upPx + 2];
					//console.log('up',up);
				}
				
				if(i+w <= len) {
					downPx = (i+w)*4;
					down[0] = pixels[downPx + 0];
					down[1] = pixels[downPx + 1];
					down[2] = pixels[downPx + 2];
					//console.log('down',down);
				}

				//have left pixel but no wrapping
				if(i%w != 0){
					leftPx = (i-1)*4;
					left[0] = pixels[leftPx + 0];
					left[1] = pixels[leftPx + 1];
					left[2] = pixels[leftPx + 2];
					//console.log('left',left);
				}
				
				if(i%w != w-1){
					rightPx = (i+1)*4;
					right[0] = pixels[rightPx + 0];
					right[1] = pixels[rightPx + 1];
					right[2] = pixels[rightPx + 2];
					//console.log('right',right);
				}

				r = rightPx?luma709Only(right[0],right[1],right[2]):0;
				t = upPx?luma709Only(up[0],up[1],up[2]):0;
				l = leftPx?luma709Only(left[0],left[1],left[2]):0;
				d = downPx?luma709Only(down[0],down[1],down[2]):0;

				if(l > pixelCore.threshold){//if left is light and i am dark
					if(t > pixelCore.threshold){//if top is light and i am dark
						corner = 1;
						pixels[rightPx + 4] = 100;
					} else if(d > pixelCore.threshold){//if bottom is light and i am dark
						pixels[rightPx + 4] = 100;
						corner = 1;
					}
				} else if(r > pixelCore.threshold){
					if(t > pixelCore.threshold){//if top is light and i am dark
						corner = 1;
					} else if(d > pixelCore.threshold){//if bottom is light and i am dark
						corner = 1;
					}
				}
				
				if(corner) {
					px.a = 50;
				}
			}
		});
		cb(false,canvas);
	});
};


effectHandlers.remoteImage = function(args,cb){
	
	var src = args.src,domain,uri;
	
	if(!src) {
		cb(new Error('src required'),null);
	} else {
		if(src.indexof('://') != -1){
			src = src.split('://').unshift();
			var parts = src.split('/');

			domain = parts.shift();
			uri = parts.join('/');
		}
	}

	if(!domain || !uri) {
		cb(new Error('missing domain or uri '+args.src));
		return;
	}

	var options = {
		host: domain,
		port: 80,
		path: uri,
		method: 'GET'
	}
	,req = http.request(options, function(res) {
		if(res.statusCode < 200 || res.statusCode > 299){
			cb(new Error('http '+res.statusCode+' response code'),null);
			return;
		}

		res.setEncoding('utf8');
		
		var data = '';
		res.on('data', function (chunk) {
			data += chunk;
			console.log('BODY: ' + chunk);
		});
		
		res.on('complete',function(){
			cb(false,data);
		});
		
		res.on('error',function(error){
			cb(error,null);
			cb = function(){};
		});
	});
	
	req.end();
};

effectHandlers.image = function(args,cb){
	src = args.src||'';
	
	var img = new Image(),convert = canvasutil.conversionLib;
	img.onload = function(){
		QRCode.draw(args.text||'',function(err,canvas){
			if(err) {
				cb(err,false);
				return;
			}
			
			var codeCtx = canvas.getContext('2d')
			, frame = codeCtx.getImageData(0,0,canvas.width,canvas.width)
			, tpx = new canvasutil.PixelCore()
			, baconCanvas = new Canvas(canvas.width,canvas.width)
			, ctx = baconCanvas.getContext('2d')
			,topThreshold = args.darkThreshold||25
			,bottomThreshold = args.lightThreshold||75;
			
			tpx.threshold = 50;
			
			//scale image
			var w = canvas.width;
			var h = canvas.height;
			
			if(img.width>img.height) {
				w = w*(canvas.height/h)
				h = canvas.height;
			} else {
				h = h*(canvas.height/w)
				w = canvas.width;
			}
			ctx.drawImage(img,0,0,w,h);
			
			try{
			tpx.iterate(baconCanvas,function(px,i,l,pixels,w,h,pixelCore){
				var luma = (0.2125*px.r + 0.7154*px.g + 0.0721*px.b)
				, codeLuma = convert.luma709Only(frame.data[i*4],frame.data[i*4+1],frame.data[i*4+2]);
				
				if(codeLuma > pixelCore.threshold){
					if(luma < bottomThreshold) {
						var yuv = convert.rgbToYuv(px.r,px.g,px.b),rgb;
						
						rgb = convert.yuvToRgb(bottomThreshold,yuv[1],yuv[2]);
						
						px.r = rgb[0];
						px.g = rgb[1];
						px.b = rgb[2];
						px.a = 255;
					}
				} else {
					if(luma > topThreshold) {
						var yuv = convert.rgbToYuv(px.r,px.g,px.b),rgb;
						
						rgb = convert.yuvToRgb(topThreshold,yuv[1],yuv[2]);
						
						px.r = rgb[0];
						px.g = rgb[1];
						px.b = rgb[2];
					}
				}
			});
			} catch(e){
				cb(err,false);
			}

			cb(false,baconCanvas);
		});
	};
	
	img.onerror = function(error){
		error.message += ' ('+src+')';
		cb(error,null);
	}
	
	img.src = src;
};

effectHandlers.plain = function(args,cb){
	var text = args.text||'';
	QRCode.draw(text||'',function(err,canvas){
		cb(err,canvas);
	});
};

app.listen(3031);
console.log('listening on 3031');