/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * This file implements the /api/csv route. This route accepts csv data for 
 * meter and readings data.
 *
 */

const escapeHtml = require('core-js/fn/string/escape-html');
const express = require('express');
const fs = require('fs').promises;
const { getConnection } = require('../db');
const { loadCsvInput } = require('../services/pipeline-in-progress/loadCsvInput');
const { log } = require('../log');
const multer = require('multer');
const streamBuffers = require('stream-buffers');
const zlib = require('zlib');

// The upload here ensures that the file is saved to server RAM rather than disk; TODO: Think about large uploads
const upload = multer({ storage: multer.memoryStorage() });
const router = express.Router();

/**
 * Inform the client of a failure (406 Not Acceptable), and log it.
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} reason The reason for the failure.
 *
 */
function failure(req, res, reason = '') {
	const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
	log.error(`Obvius protocol request from ${ip} failed due to ${reason}`);

	res.status(406) // 406 Not Acceptable error, as required by Obvius
		.send(`<pre>\n${escapeHtml(reason)}\n</pre>\n`);
}

/**
 * Inform the client of a success (200 OK).
 *
 * @param {express.Request} req The Express request object
 * @param {express.Response} res The Express response object
 * @param {string} comment Any additional data to be returned to the client.
 *
 */
function success(req, res, comment = '') {
	res.status(200) // 200 OK
		.send(`<pre>\nSUCCESS\n${escapeHtml(comment)}</pre>\n`);
}

function streamToWriteBuffer(stream) {
	const writableStreamBuffer = new streamBuffers.WritableStreamBuffer({
		frequency: 10,
		chunkSize: 2048
	});
	writableStreamBuffer.put(stream);
	writableStreamBuffer.stop(); // stop() indicates we are done putting the data in our readable stream.
	return writableStreamBuffer;
}

router.post('/', upload.single('csvFile'), async (req, res) => {
	// We do readings for meters first then meter data later
	// since the pipeline only supports readings atm.

	const { createmeter, cumulative, cumulativereset, duplications, length, meter, mode, password,
		timeSort, update } = req.query; // extract query parameters

	switch (mode) {
		case 'readings':
			// create buffer to save into file; will need to gunzip file 
			const myWritableStreamBuffer = streamToWriteBuffer(req.file.buffer);
			// save this buffer into a file
			const filePath = './readings.txt'; // TODO: use a unique name and use that name in the new meter creation
			await fs.writeFile(filePath, myWritableStreamBuffer)
				.then(() => log.info(`The file ${filePath} was created to upload csv data`))
				.catch(reason => log.error(`Failed to write the file: ${filePath}`, reason));

			const mapRowToModel = (row) => (row); // stub func to satisfy param
			const conn = getConnection();
			loadCsvInput(filePath, meter, mapRowToModel, false, cumulative, cumulativereset,
				duplications, undefined, conn); // load csv data
			return;
		case 'meter':
			failure(req, res, `Mode meter has not been implemented`);
			return;
		default:
			failure(req, res, `Mode ${mode} is invalid. Mode can either be 'readings' or 'meter'.`)
			return;
	}
});

module.exports = router;

@@ -2405,16 +2405,29 @@
 atemeter
+: createMeter
 , cumula
@@ -2447,16 +2447,33 @@
 ivereset
+: cumulativeReset
 , duplic
@@ -2513,16 +2513,26 @@
 word,%0A%09%09
+timesort: 
 timeSort
@@ -2584,16 +2584,506 @@
 meters%0A%0A
+%09if (!req.file) %7B%0A%09%09failure(req, res, 'No file uploaded.');%0A%09%09return;%0A%09%7D// TODO: Validate file upload%0A%0A%09// Invalidate improper mode, meter pair.%0A%09if (mode === 'readings' && !meter) %7B%0A%09%09failure(req, res, %60Readings are provided, but no meter is provided. Meter '$%7Bmeter%7D' is invalid.%60)%0A%09%09return;%0A%09%7D%0A%0A%09// Invalidate unimplemented time sort.%0A%09if (timeSort !== 'increasing') %7B%0A%09%09failure(req, res, %60Time sort '$%7BtimeSort%7D' is invalid. Only 'increasing' is currently implemented.%60);%0A%09%09return;%0A%09%7D%0A%0A
 %09switch 
@@ -3788,25 +3788,25 @@
 , cumulative
-r
+R
 eset,%0A%09%09%09%09du

Add some query validation