'use strict';

// This file depends on `webrtc/RTCPeerConnection-helper.js`
// which should be loaded from the main HTML file.

// TODO: Replace with IETF link.
var kAbsCaptureTime =
    'http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time';

function addHeaderExtensionToSdp(sdp, uri) {
  // Find the highest used header extension id by sorting the extension ids
  // used, eliminating duplicates and adding one. This is not quite correct but
  // this code will go away with the header extension API.
  const usedIds =
      sdp.split('\n')
          .filter(line => line.startsWith('a=extmap:'))
          .map(line => parseInt(line.split(' ')[0].substring(9), 10))
          .sort((a, b) => a - b)
          .filter((item, index, array) => array.indexOf(item) === index);
  const nextId = usedIds[usedIds.length - 1] + 1;
  const extmapLine = 'a=extmap:' + nextId + ' ' + uri + '\r\n';

  const sections = sdp.split('\nm=').map((part, index) => {
    return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
  });
  const sessionPart = sections.shift();
  return sessionPart +
      sections.map(mediaSection => mediaSection + extmapLine).join('');
}

async function addAbsCaptureTimeAndExchangeOffer(caller, callee) {
  let offer = await caller.createOffer();

  // Absolute capture time header extension may not be offered by default,
  // in such case, munge the SDP.
  offer.sdp = addHeaderExtensionToSdp(offer.sdp, kAbsCaptureTime);

  await caller.setLocalDescription(offer);
  return callee.setRemoteDescription(offer);
}

async function checkAbsCaptureTimeAndExchangeAnswer(
    caller, callee, absCaptureTimeAnswered) {
  let answer = await callee.createAnswer();

  const extmap = new RegExp('a=extmap:\\d+ ' + kAbsCaptureTime + '\r\n', 'g');
  if (answer.sdp.match(extmap) == null) {
    // We expect that absolute capture time RTP header extension is answered.
    // But if not, there is no need to proceed with the test.
    assert_false(
        absCaptureTimeAnswered,
        'Absolute capture time RTP ' +
            'header extension is not answered');
  } else {
    if (!absCaptureTimeAnswered) {
      // We expect that absolute capture time RTP header extension is not
      // answered, but it is, then we munge the answer to remove it.
      answer.sdp = answer.sdp.replace(extmap, '');
    }
  }

  await callee.setLocalDescription(answer);
  return caller.setRemoteDescription(answer);
}

async function exchangeOfferAndListenToOntrack(
    t, caller, callee, absCaptureTimeOffered) {
  const ontrackPromise = addEventListenerPromise(t, callee, 'track');
  // Absolute capture time header extension is expected not offered by default,
  // and thus munging is needed to enable it.
  await absCaptureTimeOffered ?
      addAbsCaptureTimeAndExchangeOffer(caller, callee) :
      exchangeOffer(caller, callee);
  return ontrackPromise;
}

async function initiateCall(
    t, streamOptions, enableAbsCaptureTime, worker, enableSenderTransform,
    enableReceiverTransform) {
  const caller = new RTCPeerConnection();
  t.add_cleanup(() => caller.close());
  const callee = new RTCPeerConnection();
  t.add_cleanup(() => callee.close());
  const senderTransform = enableSenderTransform ?
      new RTCRtpScriptTransform(worker, {name: 'sender'}) :
      null;
  const receiverTransform = enableReceiverTransform ?
      new RTCRtpScriptTransform(worker, {name: 'receiver'}) :
      null;


  const stream = await getNoiseStream(streamOptions);
  stream.getTracks().forEach(track => {
    const sender = caller.addTrack(track, stream);
    if (enableSenderTransform) {
      sender.transform = senderTransform;
    }
    t.add_cleanup(() => track.stop());
  });

  callee.ontrack =
      e => {
        if (enableReceiverTransform) {
          e.receiver.transform = receiverTransform;
        }
      }

  exchangeIceCandidates(caller, callee);

  await exchangeOfferAndListenToOntrack(
      t, caller, callee, enableAbsCaptureTime);

  // Exchange answer and check whether the absolute capture time RTP header
  // extension is answered.
  await checkAbsCaptureTimeAndExchangeAnswer(
      caller, callee, enableAbsCaptureTime);
}
