// (c) 2008 Aaron Isotton <aaron@isotton.com>

//---------------------------------------------------------------------------
// Format
//---------------------------------------------------------------------------
function Format(w, h) {
    this.w = w;
    this.h = h;
}

//---------------------------------------------------------------------------
// Angle
//---------------------------------------------------------------------------
function Angle(alpha, beta) {
    this.alpha = alpha;
    this.beta = beta;
}

//---------------------------------------------------------------------------
// Lens Canvas
//---------------------------------------------------------------------------
function LensCanvas() {
    // Parameters
    this.w = 240;
    this.h = 120;
    this.l = 120;
    this.ox = this.w / 2;
    this.oy = this.h;

    this.panoW = 400;
    this.panoH = 400;

    // Angle canvas
    var canvasDiv = document.getElementById('canvasDiv');
    var canvas = document.createElement('canvas');
    canvas.setAttribute('width', this.w);
    canvas.setAttribute('height', this.h);
    canvasDiv.appendChild(canvas);
    this.ctx = canvas.getContext('2d');
    
    // Panorama canvas
    var panoDiv = document.getElementById('panoDiv');
    var panoCanvas = document.createElement('canvas');
    panoCanvas.setAttribute('width', this.panoW);
    panoCanvas.setAttribute('height', this.panoH);
    panoDiv.appendChild(panoCanvas);
    this.panoCtx = panoCanvas.getContext('2d');
    this.panoImg = new Image();
    this.panoImg.onload = this.drawPano;
    this.panoImg.src = 'pano.jpeg';
    
    // More stuff
    this.focalLength = document.getElementById('focalLength');
    this.alpha = document.getElementById('alpha');
    this.format = document.getElementById('format');
    this.fullFrameFocalLength = document.getElementById('fullFrameFocalLength');
}

LensCanvas.prototype.drawPano = function() {
    if (this.panoCtx && this.panoImg)
	this.panoCtx.drawImage(this.panoImg, 0, 0);
}

LensCanvas.prototype.drawRect = function(angle) {
    var w = this.panoW * angle.alpha / Math.PI;
    var h = this.panoW * angle.beta / Math.PI;
    var l = (this.panoW - w) / 2;
    var r = (this.panoW + w) / 2;
    var t = (this.panoH - h) / 2;
    var b = (this.panoH + h) / 2;
    this.panoCtx.strokeStyle = "#00ffff";
    this.panoCtx.beginPath();
    this.panoCtx.moveTo(l, t);
    this.panoCtx.lineTo(l, b);
    this.panoCtx.lineTo(r, b);
    this.panoCtx.lineTo(r, t);
    this.panoCtx.closePath();
    this.panoCtx.stroke();
}

LensCanvas.prototype.splitRegexp = new RegExp('[,;-]');

LensCanvas.prototype.draw = function(angle) {
    dx = this.l * Math.sin(angle.alpha/2);
    dy = this.l * Math.cos(angle.alpha/2);

    this.ctx.beginPath();
    this.ctx.fillStyle = "rgba(0,0,255,0.2)";
    this.ctx.strokeStyle = "#000000";
    this.ctx.moveTo(this.ox, this.oy);
    this.ctx.lineTo(this.ox + dx, this.oy - dy);
    this.ctx.lineTo(this.ox - dx, this.oy - dy);
    this.ctx.closePath();
    this.ctx.stroke();
    this.ctx.fill();
}

LensCanvas.prototype.drawArc = function(angle) {
    this.ctx.beginPath();
    this.ctx.fillStyle = "rgba(255,255,0,0.5)";
    this.ctx.strokeStyle = "#000000";
    this.ctx.moveTo(this.ox, this.oy);
    this.ctx.arc(this.ox, this.oy, 40, 1.5*Math.PI - (angle.alpha/2), 
	    1.5*Math.PI + (angle.alpha/2), false);
    this.ctx.stroke();
    this.ctx.fill();
}

LensCanvas.prototype.clear = function() {
    this.ctx.clearRect(0, 0, this.w, this.h);
    this.panoCtx.clearRect(0, 0, this.panoW, this.panoH);
}

LensCanvas.prototype.focalLengths2angles = function(focalLengths, format) {
    var angles = new Array;
    for (i = 0; i < focalLengths.length; i++) {
	angles[i] = new Angle(2 * Math.atan(format.w/(2*focalLengths[i])),
		          2 * Math.atan(format.h/(2*focalLengths[i])));
    }
    return angles;
}

LensCanvas.prototype.angles2focalLengths = function(angles, format) {
    var focalLengths = new Array;
    for (var i = 0; i < angles.length; i++) {
	focalLengths[i] = format.w/Math.tan(angles[i].alpha/2)/2;
    }
    return focalLengths;
}

LensCanvas.prototype.getFocalLengths = function() {
    var s = this.focalLength.value.split(this.splitRegexp);
    var focalLengths = new Array;
    for (i = 0; i < s.length; ++i)
	focalLengths[i] = parseFloat(s[i]);
    return focalLengths;
}

LensCanvas.prototype.setFocalLengths = function(focalLengths) {
    var s = new Array;
    for (var i = 0; i < focalLengths.length; i++)
	s[i] = focalLengths[i].toFixed(1);
    this.focalLength.value = s.join(',');
}

LensCanvas.prototype.setFullFocalLengths = function(focalLengths) {
    var s = new Array;
    for (var i = 0; i < focalLengths.length; i++)
	s[i] = focalLengths[i].toFixed(1);
    this.fullFrameFocalLength.value = s.join(',');
}

LensCanvas.prototype.getAngles = function() {
    var s = this.alpha.value.split(this.splitRegexp);
    var format = this.getFormat();
    var angles = new Array;
    for (i = 0; i < s.length; ++i) {
	alpha = parseFloat(s[i]) / 180. * Math.PI;
	beta = 2 * Math.atan(format.h/(format.w/Math.tan(alpha/2)));
	angles[i] = new Angle(alpha, beta);
    }
    return angles;
}

LensCanvas.prototype.setAngles = function(angles) {
    var s = new Array;
    for (var i = 0; i < angles.length; i++)
	s[i] = (angles[i].alpha * 180. / Math.PI).toFixed(1);
    this.alpha.value = s.join(',');
}

LensCanvas.prototype.getFormat = function() {
    var f = this.format.value.split('x');
    return new Format(parseFloat(f[0]), parseFloat(f[1]));
}

LensCanvas.prototype.update = function(source) {
    var angles;
    if (source == 'alpha') {
	angles = this.getAngles();
	var focalLengths = this.angles2focalLengths(angles, this.getFormat());
	this.setFocalLengths(focalLengths);
    }
    else if (source == 'focalLength') {
	var focalLengths = this.getFocalLengths();
	angles = this.focalLengths2angles(focalLengths, this.getFormat());
	this.setAngles(angles);
    }
    else if (source == 'format') {
	var focalLengths = this.getFocalLengths();
	angles = this.focalLengths2angles(focalLengths, this.getFormat());
	this.setFocalLengths(focalLengths);
	this.setAngles(angles);
    }
    else {
	angles = this.getAngles();
    }

    this.setFullFocalLengths(this.angles2focalLengths(angles, 
		new Format(36, 24)));

    this.clear();
    this.drawPano();

    var maxAngle = new Angle(0, 0);
    for (i = 0; i < angles.length; ++i) {
        if (maxAngle.alpha < angles[i].alpha) maxAngle = angles[i];
	this.draw(angles[i]);
	this.drawRect(angles[i]);
    }
    this.drawArc(maxAngle);
    this.storeCookies();
}

LensCanvas.prototype.setCookie = function(name, value) {
    var date = new Date();
    date.setTime(date.getTime() + 365 * 86400 * 1000);
    document.cookie = name + "=" + escape(value) + ";expires=" 
	+ date.toGMTString() + ";path=/";
}

LensCanvas.prototype.getCookie = function(name, defaultValue) {
    var m = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
    if (m) return unescape(m[2]);
    return defaultValue;
}

LensCanvas.prototype.restoreCookies = function() {
    this.focalLength.value = this.getCookie('f', '18-200');
    this.format.value = this.getCookie('format', '36x24');
    this.update('format');
}

LensCanvas.prototype.storeCookies = function() {
    this.setCookie('f', this.focalLength.value);
    this.setCookie('format', this.format.value);
}

LensCanvas.prototype.startup = function() {
    this.restoreCookies();
}

