const express = require('express')
const app = express();
const expressWs = require('express-ws')(app);
const bodyParser = require('body-parser');
const objectAssign = require('object-assign');
const jsonpatch = require('fast-json-patch');


/*
 * Orders array
 *
 * Holds the KP tickets as JSON objects
 */
var orders = [];

observer = jsonpatch.observe(orders, function(patch) {
	wsBroadcast(JSON.stringify(patch));
});


/*
 * Array find Polyfill
 */
if (!Array.prototype.find) {
  Array.prototype.find = function(predicate) {
    if (this === null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return value;
      }
    }
    return undefined;
  };
}


function findConsec(consec) {
	return orders.find( function (order) {
		if (order) 
			return parseInt(order.consec) == parseInt(consec);
		return;
	});
}


/*
 * Broadcast message to websocket clients
 */
function wsBroadcast(message, ws) {
	// if no websocket argument parsed, presume 'expressWs'
	if (!ws) ws = expressWs;
	ws.getWss().clients.forEach( function (client) {
    	client.send(message);
	});	
}


/*
 * Create HTTP server
 *
 * HTTP server for order screen and websocket
 */
(function(){

	app.use(express.static('static'));
	app.use(bodyParser.urlencoded({ extended: true }));
	app.use(bodyParser.json());

	/**
	 * GET /orders 
	 */
	app.get('/orders', function(req, res) {

		res.json({orders: orders});

	});

	/**
	 * GET /order/:consec
	 */
	app.get('/order/:consec', function(req, res) {

		if (ticket = findConsec(req.params.consec)) {

			res.json({order: ticket});

		} else {

			res.sendStatus(404);

		}

	});

	/**
	 * POST /order
	 */
	app.post('/order', function(req, res) {

		var order = req.body;

		if (_order = findConsec(order.consec)) {

			// if finished flag, set finished timestamp
			if (order.orderStatus == 'FINISHED') {
				order.finishedTimestamp = Date.now();
			}

			objectAssign(_order, order);			

		} else {

			if (order.orderNumber2) {
		
				order.timeStamp2 = Date.now();
				orders.push(order);

			}

		}

		// Fire jsonpatch
		jsonpatch.generate(observer);

		res.status(200).send({orderNumber2: order.orderNumber2});

	});

	/**
	 * DELETE /order/:consec
	 */
	app.delete('/order/:consec', function(req, res) {

		if (order = findConsec(req.params.consec)) {

			// Splice this order out of the orders array
			orders.splice(orders.indexOf(order),1)
			//delete orders[orders.indexOf(order)];

			// Fire jsonpatch
			jsonpatch.generate(observer);
			
			res.sendStatus(202);

		} else {

			res.sendStatus(404);

		}
	});

	/**
	 * Websocket /orders
	 */
	app.ws('/orders', function (ws, req) {

		// Send orders to new connection
		//ws.send(JSON.stringify({orders: orders}));

		// Message from websocket
		ws.on('message', function (message) {		
			//onWsData(message);
		});

	});

	// HTTP listen
	app.listen(8080, '0.0.0.0', function () {

		console.log('HTTP server is listening on port 8080');

	});

})();


/*
 * Finished ticket timer
 *
 * Removes finished tickets after 3 mintues
 */
(function() {
	var minutes = 5;

	setInterval(function() {
		orders.forEach(function(order) {
			if (order.finishedTimestamp + (minutes * 60 * 1000) <= Date.now())
			{
				// Splice this order out of the orders array
				orders.splice(orders.indexOf(order), 1);

				// Fire jsonpatch
				jsonpatch.generate(observer);
			}
		});
	}, 1000); 
})();

//1474648485195
//1474648508435