import { Tracker } from 'meteor/tracker';
require("webrtc-adapter");
class VideoCallServices {
    RTCConfiguration = {};
    constructor(){
        this.iceCandidates = [];
        Tracker.autorun(()=>{
            this.sub = Meteor.subscribe('VideoChatPublication');
        });
        let callLog;
        Meteor.connection._stream.on('message', (msg) => {

            msg = JSON.parse(msg);
            if( msg.collection === 'VideoChatCallLog'
            && msg.msg === 'removed'){
                this.onTerminateCall();
            }
            if( msg.collection === 'VideoChatCallLog'
                && msg.msg === 'added'
                && msg.fields.target === Meteor.userId()
            && msg.fields.status == "NEW"){
                callLog = msg.fields;
                this.stream = new Meteor.Streamer(msg.id);
                this.stream.on('video_message', (stream_data) => {
                    if( typeof stream_data == "string")
                        stream_data = JSON.parse(stream_data);
                    if( stream_data.offer ){
                        navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then( stream => {
                            if(this.localVideo){
                                this.localVideo.srcObject = stream;
                                this.localVideo.muted = true;
                                this.localVideo.play();
                                }
                            this.setupPeerConnection( stream, stream_data.offer );
                        }).catch( err => this.onError(err)
                        );
                    }
                    if( stream_data.candidate ){
                        if(this.peerConnection)
                            this.peerConnection.addIceCandidate( JSON.parse(stream_data.candidate) );
                        else this.iceCandidates.push(JSON.parse(stream_data.candidate));
                    }
                });
                this.onReceivePhoneCall(msg.id);
            }
            if( msg.collection === 'VideoChatCallLog'
                && msg.msg === 'added'
                && msg.fields.caller === Meteor.userId()
            && msg.fields.status === 'NEW'){
                callLog = msg.fields;
            }
            if (msg.msg == 'changed'
                && msg.collection == 'VideoChatCallLog'
                && msg.fields != undefined){
                const { fields } = msg;
                if ( fields.status == 'ACCEPTED' && callLog.caller == Meteor.userId() ){
                    this.onTargetAccept();
                    navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then( stream => {
                        if(this.localVideo){
                            this.localVideo.srcObject = stream;
                            this.localVideo.muted = true;
                            this.localVideo.play();
                        }
                        this.setupPeerConnection(stream);
                    }).catch( err => this.onError(err));
                }
            }
        });

    }
    /**
     * Set up the peer connection
     * @param stream {MediaStream}
     * @param remoteDescription {RTCPeerConnection}
     */
    setupPeerConnection( stream, remoteDescription ){
        this.peerConnection = new RTCPeerConnection(this.RTCConfiguration, {"optional": [ {'googIPv6': 'false'} ] } );
        this.onPeerConnectionCreated();
        this.setPeerConnectionCallbacks();
        this.peerConnection.addStream( stream );
        if( remoteDescription )
            this.createTargetSession( remoteDescription );
        else
            this.createCallSession();
    }
    /**
     * Set callback for RTCPeerConnection
     */
    setPeerConnectionCallbacks(){
        this.peerConnection.onicecandidate =  ( event ) => {
          if( event.candidate ){
              this.stream.emit( 'video_message', { candidate : JSON.stringify(event.candidate) });
          }
        };
        this.peerConnection.oniceconnectionstatechange =  ( event ) => {
          console.log(event);
        };
        this.peerConnection.onaddstream = function( stream ) {
            if(this.remoteVideo) {
                this.remoteVideo.srcObject = stream.stream;
                this.remoteVideo.play();
            }
        }.bind(this);
    }
    /**
     * Create the RTCPeerConnection for the person being called
     * @param remoteDescription {RemoteDescription}
     */
    createTargetSession( remoteDescription ){
        const { iceCandidates } = this;
        this.iceCandidates = [];
        let i ;
        for (i = 0; i< iceCandidates.length; i++)
            this.peerConnection.addIceCandidate(iceCandidates[i]);

        this.peerConnection.setRemoteDescription( remoteDescription ).then( () => {

            this.peerConnection.createAnswer().then( answer => {
                this.peerConnection.setLocalDescription( answer ).catch( err => this.onError(err));
                this.stream.emit( 'video_message', JSON.stringify({ answer }) );
            }).catch( err => this.onError(err));
        }).catch( err => this.onError(err));

    }
    createCallSession( ){
        this.peerConnection.createOffer().then( offer => {
            this.peerConnection.setLocalDescription( offer ).catch( err => this.onError(err));
            this.stream.emit( 'video_message', JSON.stringify({ offer }) );
        }).catch( err => this.onError(err));
    }
    /**
     * Call allows you to call a remote user using their userId
     * @param _id {string}
     */
    call(_id, local, remote) {
        if (local)
            this.localVideo = local;
        if (remote)
            this.remoteVideo = remote;
        Meteor.call('VideoCallServices/call', _id, ( err, _id )=>{

            if(err)
                this.onError(err);
            else {
            this.stream = new Meteor.Streamer(_id);
            this.stream.on('video_message', (stream_data) => {
                if(typeof stream_data == 'string')
                    stream_data = JSON.parse(stream_data);
                if( stream_data.answer ){
                    this.peerConnection.setRemoteDescription( stream_data.answer ).catch( err => this.onError(err));
                }
                if( stream_data.candidate ){
                    this.peerConnection.addIceCandidate( JSON.parse(stream_data.candidate) ).catch( err => this.onError(err));
                }
            });
            }
        });
    }
    /**
     * Answer the phone call
     * @param local {HTMLElement}
     * @param remote {HTMLElement}
     */
    answerPhoneCall(local, remote){
        if (local)
            this.localVideo = local;
        if (remote)
            this.remoteVideo = remote;
        Meteor.call('VideoCallServices/answer', err => {
            if(err)
                this.onError(err);
        });
    }
    /**
     * End the phone call
     */
    endPhoneCall(){
        Meteor.call("VideoCallServices/end", err => {
            if(err)
                this.onError(err);
        });
    }

    onTargetAccept(){

    }
    onReceivePhoneCall(fields){

    }
    onTerminateCall(){

    }
    onPeerConnectionCreated(){

    }
    onError(err){

    }
}


Meteor.VideoCallServices = new VideoCallServices();
@@ -1668,32 +1668,189 @@
 ta.candidate )%7B%0A
+                        if( typeof stream_data.candidate == %22string%22)%0A                            stream_data.candidate = JSON.parse(stream_data.candidate);%0A
                 
@@ -1941,36 +1941,24 @@
 ceCandidate(
- JSON.parse(
 stream_data.
@@ -1967,18 +1967,16 @@
 ndidate)
- )
 ;%0A      
@@ -2022,27 +2022,16 @@
 es.push(
-JSON.parse(
 stream_d
@@ -2044,17 +2044,16 @@
 ndidate)
-)
 ;%0A      
@@ -3222,32 +3222,33 @@
 ;%0A%0A    %7D%0A    /**
+5
 %0A     * Set up t
@@ -6435,32 +6435,183 @@
 ta.candidate )%7B%0A
+                    if( typeof stream_data.candidate == 'string' )%0A                        stream_data.candidate = JSON.parse(stream_data.candidate);%0A%0A
                 
@@ -6651,27 +6651,16 @@
 didate( 
-JSON.parse(
 stream_d
@@ -6672,17 +6672,16 @@
 andidate
-)
  ).catch

check candidate data type before JSON.parse