var uint8ToCString = require('../utils/string.js').uint8ToCString;

var getUint64 = require('../utils/numbers.js').getUint64;
/**
 * Based on: ISO/IEC 23009 Section: 5.10.3.3
 * References:
 * https://dashif-documents.azurewebsites.net/Events/master/event.html#emsg-format
 * https://aomediacodec.github.io/id3-emsg/
 * 
 * Takes emsg box data as a uint8 array and returns a emsg box object
 * @param {UInt8Array} boxData data from emsg box
 * @returns A parsed emsg box object
 */


var parseEmsgBox = function parseEmsgBox(boxData) {
  // version + flags
  var offset = 4;
  var version = boxData[0];
  var scheme_id_uri, value, timescale, presentation_time, presentation_time_delta, event_duration, id, message_data;

  if (version === 0) {
    scheme_id_uri = uint8ToCString(boxData.subarray(offset));
    offset += scheme_id_uri.length;
    value = uint8ToCString(boxData.subarray(offset));
    offset += value.length;
    var dv = new DataView(boxData.buffer);
    timescale = dv.getUint32(offset);
    offset += 4;
    presentation_time_delta = dv.getUint32(offset);
    offset += 4;
    event_duration = dv.getUint32(offset);
    offset += 4;
    id = dv.getUint32(offset);
    offset += 4;
  } else if (version === 1) {
    var dv = new DataView(boxData.buffer);
    timescale = dv.getUint32(offset);
    offset += 4;
    presentation_time = getUint64(boxData.subarray(offset));
    offset += 8;
    event_duration = dv.getUint32(offset);
    offset += 4;
    id = dv.getUint32(offset);
    offset += 4;
    scheme_id_uri = uint8ToCString(boxData.subarray(offset));
    offset += scheme_id_uri.length;
    value = uint8ToCString(boxData.subarray(offset));
    offset += value.length;
  }

  message_data = new Uint8Array(boxData.subarray(offset, boxData.byteLength));
  var emsgBox = {
    scheme_id_uri: scheme_id_uri,
    value: value,
    // if timescale is undefined or 0 set to 1 
    timescale: timescale ? timescale : 1,
    presentation_time: presentation_time,
    presentation_time_delta: presentation_time_delta,
    event_duration: event_duration,
    id: id,
    message_data: message_data
  };
  return isValidEmsgBox(version, emsgBox) ? emsgBox : undefined;
};
/**
 * Scales a presentation time or time delta with an offset with a provided timescale
 * @param {number} presentationTime 
 * @param {number} timescale 
 * @param {number} timeDelta 
 * @param {number} offset 
 * @returns the scaled time as a number
 */


var scaleTime = function scaleTime(presentationTime, timescale, timeDelta, offset) {
  return presentationTime || presentationTime === 0 ? presentationTime / timescale : offset + timeDelta / timescale;
};
/**
 * Checks the emsg box data for validity based on the version
 * @param {number} version of the emsg box to validate
 * @param {Object} emsg the emsg data to validate
 * @returns if the box is valid as a boolean
 */


var isValidEmsgBox = function isValidEmsgBox(version, emsg) {
  var hasScheme = emsg.scheme_id_uri !== '\0';
  var isValidV0Box = version === 0 && isDefined(emsg.presentation_time_delta) && hasScheme;
  var isValidV1Box = version === 1 && isDefined(emsg.presentation_time) && hasScheme; // Only valid versions of emsg are 0 and 1

  return !(version > 1) && isValidV0Box || isValidV1Box;
}; // Utility function to check if an object is defined


var isDefined = function isDefined(data) {
  return data !== undefined || data !== null;
};

module.exports = {
  parseEmsgBox: parseEmsgBox,
  scaleTime: scaleTime
};