<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
    <head>
        <script src="../../resources/js-test-pre.js"></script>
        <script src="resources/promise-utils.js"></script>
    </head>
    <body>
        <script>
            if (window.internals)
                internals.useMockRTCPeerConnectionFactory("");

            var stream;
            var remotePcAudioTrack;
            var remotePcVideoTrack;
            var remotePcAudioTransceiver;
            var remotePcVideoTransceiver;

            var remoteOffer1;
            var remoteOffer2;

            var trackEvent;
            var mediaTypes = ["Audio", "Video"];

            description("Test RTCPeerConnection.setRemoteDescription called with an RTCSessionDescription of type 'offer'");

            if (window.testRunner)
                testRunner.setUserMediaPermission(true);
            else {
                debug("This test can not be run without the testRunner");
                finishJSTest();
            }

            var pc = new RTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});
            var remotePc = new RTCPeerConnection({iceServers:[{urls:'stun:foo.com'}]});

            function testRemoteTrack(evt, mediaType) {
                trackEvent = evt;
                var remotePcTrackName = `remotePc${mediaType}Track`;

                debug("*** 'track' event must fire before setRemoteDescription promise is fulfilled");

                debug("*** Check track event properties");
                shouldBeTrue("pc.getReceivers().includes(trackEvent.receiver)");
                shouldBeTrue("pc.getTransceivers().includes(trackEvent.transceiver)");

                debug("*** Remote track should be muted initially");
                shouldBeTrue("trackEvent.track.muted");

                debug("*** Remote track properties should match track added at remote side (remotePc)");
                shouldBe("trackEvent.track.kind", `${remotePcTrackName}.kind`);
                shouldBe("trackEvent.track.id", `${remotePcTrackName}.id`);
                shouldBe("trackEvent.track.label", `'remote ${mediaType.toLocaleLowerCase()}'`);

                debug("*** Check local and remote transceivers");
                shouldBe("trackEvent.transceiver.mid", `remotePc${mediaType}Transceiver.mid`);
                debug("");
            }

            pc.ontrack = function (evt) {
                testRemoteTrack(evt, mediaTypes.shift());
            };

            navigator.mediaDevices.getUserMedia({ "audio": true, "video": true })
            .then(function (s) {
                stream = s;

                remotePcAudioTrack = stream.getAudioTracks()[0];
                remotePcVideoTrack = stream.getVideoTracks()[0];

                debug("*** Create (remote) offer with audio (remoteOffer1)");
                remotePc.addTrack(remotePcAudioTrack, stream);
                remotePcAudioTransceiver = remotePc.getTransceivers()[0];

                return remotePc.createOffer();
            })
            .then(function (remoteOfferArg) {
                remoteOffer1 = remoteOfferArg;

                return remotePc.setLocalDescription(remoteOffer1);
            })
            .then(function () {

                debug("*** Done, start testing with remoteOffer1");
                shouldBe("pc.signalingState", "'stable'");

                shouldBeNull("pc.remoteDescription");
                shouldBeNull("pc.pendingRemoteDescription");
                shouldBeNull("pc.currentRemoteDescription");
                debug("");

                return pc.setRemoteDescription(remoteOffer1);
            })
            .then(function () {
                testPassed("remoteOffer1 set as remote description");

                shouldBe("pc.signalingState", "'have-remote-offer'");

                shouldBe("pc.remoteDescription", "remoteOffer1");
                shouldBe("pc.pendingRemoteDescription", "remoteOffer1");
                shouldBeNull("pc.currentRemoteDescription");
                debug("");

                return pc.setRemoteDescription(remoteOffer1);
            })
            .then(function () {
                testPassed("remoteOffer1 set as remote description (again)");

                shouldBe("pc.signalingState", "'have-remote-offer'");
                debug("");

                debug("*** Try setting local descriptions with bad types for the current state");
                return promiseShouldReject("pc.setRemoteDescription({type:'answer', sdp:remoteOffer1.sdp});");
            })
            .then(function () {
                return promiseShouldReject("pc.setRemoteDescription({type:'pranswer', sdp:remoteOffer1.sdp});");
            })
            .then(function () {
                debug("");

                debug("*** Create (remote) offer with video (remoteOffer2)");
                var sender = remotePc.addTrack(remotePcVideoTrack, stream);
                // Order of transceivers is undefined so we need to match it with the sender.
                var transceivers = remotePc.getTransceivers();
                remotePcVideoTransceiver = transceivers[1].sender == sender ? transceivers[1] : transceivers[0];

                return remotePc.createOffer();
            })
            .then(function (remoteOfferArg) {
                remoteOffer2 = remoteOfferArg;

                return remotePc.setLocalDescription(remoteOffer2);
            })
            .then(function () {
                debug("*** Done, start testing with remoteOffer2");
                shouldBe("pc.signalingState", "'have-remote-offer'");
                debug("");

                return pc.setRemoteDescription(remoteOffer2);
            })
            .then(function () {
                testPassed("remoteOffer2 set as remote description");

                shouldBe("pc.signalingState", "'have-remote-offer'");

                shouldBe("pc.remoteDescription", "remoteOffer2");
                shouldBe("pc.pendingRemoteDescription", "remoteOffer2");
                shouldBeNull("pc.currentRemoteDescription");
                debug("");

                finishJSTest();
            })
            .catch(function (error) {
                testFailed("Error in promise chain: " + error);
                finishJSTest();
            });

            window.jsTestIsAsync = true;
            window.successfullyParsed = true;

        </script>
        <script src="../../resources/js-test-post.js"></script>
    </body>
</html>
