
const NavHeaderError = require('./error');

/**
 * Detect if a LABO header is present in `buffer`.
 */
function detect (buffer) {
	const s = buffer.indexOf("$1");
	return (s != -1 &&
		buffer.subarray(s+6, s+10).toString('ascii') == "0003") ? s : false;
};

function parse (buffer) {

	const s = buffer.indexOf("$1");

	if (s == -1) {
		return; // undefined
	}

	let offset = 0;

	function ascii (length) {
		const start = offset;
		const end = offset+length;
		offset += length;
// 		const v = buffer.subarray(start, end).toString('ascii');
// 		console.log("v = ", v);
// 		return v;
		return buffer.subarray(start, end).toString('ascii');
	}

	const parser = [
		// LABO marker
		(buf, ctx) => {
			if (! /\$[12]/.test(ascii(2))) {
				throw new NavHeaderError("Expected LABO marker not found at position "+s, buf);
			}
		},

		// Message length
		// NOTE isn't this fixed?
		(buf, ctx) => {
			ctx.messageLength = Number(ascii(4));
		},

	   // Revision
	   (buf, ctx) => {
		   const rev = Number(ascii(4));
		   if (rev != 3) {
			   throw new NavHeaderError("Unsupported LABO header version: "+rev, buf);
		   }
	   },

	   // Line status
	   (buf, ctx) => {
		   const status = Number(ascii(2));
		   switch (status) {
			   case 1:
				   ctx.lineStatus = "offline";
				   break;
			   case 2:
				   ctx.lineStatus = "approach";
				   break;
			   case 3:
				   ctx.lineStatus = "online";
				   break;
			   case 4:
				   ctx.lineStatus = "runout";
				   break;
			   default:
				   throw new NavHeaderError("Unrecognised line status: "+status, buf);
		   }
	   },

	   // Timestamp
	   // We process a number of fields in one go
	   (buf, ctx) => {
		   const t = ascii(6);
		   const ms = ascii(7);
		   const d = ascii(8);
		   const tref = ascii(3);

		   if (tref != "UTC" && tref != "GPS") {
			   throw new NavHeaderError("Unrecognised time reference: "+tref, buf);
		   }

		   const tstr =
			d.replace(/^(.{4})(.{2})(.{2})$/, "$1-$2-$3") + "T" +
			t.replace(/^(.{2})(.{2})(.{2})$/, "$1:$2:$3") +
			ms + "Z";

			const tstamp = new Date(tstr);

			if (isNaN(tstamp)) {
				throw new NavHeaderError("Invalid timestamp: "+tstr, buf);
			}
			ctx.tstamp = tstamp;
	   },

	   // Shotpoint
	   (buf, ctx) => {
		   ctx.shotPoint = Number(ascii(6));
	   },

	   // Line name
	   (buf, ctx) => {
		   ctx.lineName = ascii(16);
	   },

	   // Master latitude
	   (buf, ctx) => {
		   ctx.latitudeMaster = Number(ascii(11));
	   },

	   // Master longitude
	   (buf, ctx) => {
		   ctx.longitudeMaster = Number(ascii(11));
	   },

	   // Master depth
	   // in metres
	   (buf, ctx) => {
		   ctx.waterDepth = Number(ascii(6));
	   },

	   // Source latitude
	   (buf, ctx) => {
		   ctx.latitude = Number(ascii(11));
	   },

	   // Source longitude
	   (buf, ctx) => {
		   ctx.longitude = Number(ascii(11));
	   },

	   // Source gyro
	   // NOTE is this the same as Hydronav bearing?
	   (buf, ctx) => {
		   ctx.heading = Number(ascii(5));
	   },

	   // Master CMG
	   (buf, ctx) => {
		   ctx.cmg = Number(ascii(5));
	   },

	   // Master speed
	   // FIXME Probably knots?
	   // We convert to m/s
	   (buf, ctx) => {
		   ctx.speed = Number(ascii(4)) * 1.852 / 3.6;
	   },

	   // Vessel ID
	   (buf, ctx) => {
		   ctx.vesselId = ascii(3);
	   },

	   // Master easting
	   (buf, ctx) => {
		   ctx.eastingMaster = Number(ascii(11));
	   },

	   // Master northing
	   (buf, ctx) => {
		   ctx.northingMaster = Number(ascii(11));
	   },

	   // Source delta easting
	   // NOTE This is the vessel's easting in Triggerfish
	   (buf, ctx) => {
		   ctx.deltaEasting = Number(ascii(7));
	   },

	   // Source delta northing
	   // NOTE This is the vessel's northing in Triggerfish
	   (buf, ctx) => {
		   ctx.deltaNorthing = Number(ascii(7));
	   },

	   // Line bearing
	   (buf, ctx) => {
		   ctx.lineBearing = Number(5);
	   }

	   // Julian day
	   // NOTE We don't care about this, ignored

	   // -rstdiff option
	   // NOTE We don't even know what this is, ignored
	];

	const labo = {};
	labo._type = "labov3";
	labo._received = new Date();
	for (const fn of parser) {
		fn(buffer, labo);
	}

	return labo;
}


module.exports = {
	name: "Labo v3",
	detect,
	parse
};

