// Connect to orders WebSocket
var ws = new ReconnectingWebSocket('ws://'+location.host+'/orders');

// Order arrays
var orders = [];
var ractiveOrders;
var announcedOrders = [];

// Speech Synthesis

var msg = new SpeechSynthesisUtterance();

window.speechSynthesis.onvoiceschanged = function() {
    var voices = window.speechSynthesis.getVoices();
	msg.voice = voices.filter(function(voice) { return voice.lang == 'en-GB'; })[3]; // british english

}

// 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;
  };
}

// Consec number finder
function findConsec(consec) {
	return orders.find( function (order) {
		return parseInt(order.consec) == parseInt(consec);
	});
}

function getOrders() {
    $.get('/orders', function(data) {
        orders.length = 0;  

        orders = data.orders;

        // Data bindings
        Ractive.DEBUG = false;
        ractiveOrders = new Ractive({
            template: '#order-template',
            data: { orders : orders },
            el: '#orders'
        });

        orders.forEach(function(order) {
            if (order.orderStatus === 'FINISHED')
            {
                announcedOrders.push(order.consec + '_' + order.finishedTimestamp);
            }
        });

        ractiveOrders.update();
    });
}

// Websocket connect 
ws.onopen = function () {
  console.log('Websocket open');
  getOrders();
}

// Incoming data on websocket
ws.onmessage = function (event) {
    // Parse the received data and apply the necessary changes to the orders array.
	var patches = JSON.parse(event.data);
    
    jsonpatch.apply(orders, patches);

    // Iterate through the orders and check if the received is one we're interested in.
    orders.forEach(function (order, i) {
        // Check if this order is FINISHED and if this order doesn't exist in our "announcedOrders" array.
        if (order.orderStatus === 'FINISHED' && announcedOrders.indexOf(order.consec + '_' + order.finishedTimestamp) === -1) 
        {
            // Order doesn't exist.
            // We're announcing the order, push this into our "announcedOrders" array.
            announcedOrders.push(order.consec + '_' + order.finishedTimestamp);
            
            // Prompt the please collect your order box.
            swal({
                title: 'Order ' + order.orderNumber2,
                text: 'Please collect your order',
                timer: 8000,
                width: 800,
                showConfirmButton: false,
                allowOutsideClick: true
            });

            // Create new "SpeechSynthesisUtterance" object and get the voices.
            var msg    = new SpeechSynthesisUtterance();
            var voices = window.speechSynthesis.getVoices();
            
            // Set a default just in case things don't work out.
            msg.voice = voices[3];
            msg.lang  = voices[3].lang;
            
            // Try and grab the locale from the CollectionPoint to assign the voice.
            for(var i = 0; i < voices.length; i++)
            {			
                // Does the local and lang exist?
                if(voices[i].lang == order.locale && voices[i].name == order.lang)
                {
                    // It does, assign the lang and voice to the message.
                    msg.voice = voices[i];
                    msg.lang = voices[i].lang;
                    break;
                }
            }
            
            // Assign the prefix if it exists.
            if(order.announcePrefix == undefined)
            {
                order.announcePrefix = "Your Order ";			
            }

            // Assign the suffix if it exists.
            if(order.announceSuffix == undefined)
            {
                order.announceSuffix = " is ready for collection";			
            }
            
            // Construct the message text and speak the order complete message "Your Order NUMBER is ready for collection".       
            msg.text = order.announcePrefix + ' ' + order.orderNumber2 + ' ' + order.announceSuffix;
            speechSynthesis.speak(msg);
        }
    });
  

    // Cycle through each of the orders in the "announcedOrders" array.
    announcedOrders.forEach(function(announced_order, index, object) {
        // Query the orders array for the current iteration's value.
        if(orders.find(function(order) { return order.consec + '_' + order.finishedTimestamp === announced_order; }) === undefined)
        {
            // Value not found. find returned "undefined".
            // Remove this order from the "announcedOrders" array.
            object.splice(index, 1);
        }
    });

    // Update the displayed orders.
    ractiveOrders.update();
}

setInterval(function() {
  $('#clock').text(moment().format('HH:mm'));
  $('#wait-time').text(moment.duration(averageWaitTime()).humanize());
}, 100);

// initial get orders
//getOrders();

function fakeTicket(howMany = 1) {
  function isEven(n) {n=Number(n);return n===0||!!(n&&!(n%2));}  
  for (n=0;n<howMany;n++) {
    var rndNumber = Math.floor(Math.random()*10000)+1;
    var tmpOrder = {
      "consec": rndNumber,
      "orderNumber2": rndNumber,
      "orderType": "ORDERNUMBER",
      "ticketNumber": 2,
      "orderStatus": isEven(rndNumber) ? "LIVE" : "FINISHED",
      "time": "14:36",
      "timeStamp": "1:22AM"
    };
    orders.push(tmpOrder);
  }
}

function averageWaitTime() {
  var mtw = minWaitTime * 1000 * 60;
  var duration = 0;
  var o = orders.slice(0);
  o = o.filter(function(order){return order.orderStatus!='FINISHED';});
  o = o.sort(function(a,b){ return a.timeStamp<b.timeStamp;});
  var oo = o.splice(0,5);
  oo.forEach(function(order){duration+=Date.now()-order.timeStamp2;});
  var r = isNaN(duration/oo.length)?0:duration/oo.length;
  if (r<mtw) r=mtw;
  //console.log(r);
  return r;
}