# src/PeerConnectionHandler.js

    import Context from './Context';
    import Health from './Health';
    import util from './Util';
    import RemonRecorder from './RemonRecorder';
    import Recorder from './Recorder';
    import l from './Logger';

    function bindPeerConnectionEvents({
      context,
      media,
    }) {
      function handleIceCandidateEvent(event) {
        l.i('PeerCon: HandleICECandidateEvent');
        l.d('Event:', event);
        l.d('-> Candidate:', event.candidate);

        const message = context.signalingConnection.createMessage({ command: 'ice', body: JSON.stringify(event.candidate) });

        if (event.candidate) {
          l.i('Message ->: ', message);
          if (context.channel.type==="BROADCAST"){
            message.channel.type="BROADCAST";
          }
          if (typeof message !=='undefined')context.signalingConnection.send(JSON.stringify(message));
        }
      }

      function handleIceGatheringStateChangeEvent() {
        l.i('PeerCon: Handle ice gathering state event');
        l.d(`Event: ${context.peerConnection.iceGatheringState}:`, event);
      }

      function handleSignalingStateChangeEvent(event) {
        l.i('PeerCon: Handle signaling state change event');
        l.d(`Event: ${context.peerConnection.signalingState}:`, event);
        switch (context.peerConnection.signalingState) {
          case 'stable': {
            context.endTime = new Date().getTime();
            if (context.eventManager.hasEventListener('onAddRemoteStream')) {
              context.eventManager.dispatchEvent('onAddRemoteStream', context.remoteStream);
            }
            break;
          }
          case 'have-local-offer': { break; }
          case 'have-remote-offer': { break; }
          case 'have-local-pranswer': { break; }
          case 'have-remote-pranswer': { break; }
          case 'closed': { break; }
          default: {
            l.e('Unknown signaling state event:', context.peerConnection.signalingState);
            break;
          }
        }
      }

      function handleNegotiationNeededEvent(event) {
        l.i('PeerCon: Handle negotiation needed event');
        l.d('Event:', event);
      }

      function handleIceConnectionStateChangeEvent(event) {
        l.i('PeerCon: Handle ICE state change event');
        l.v(`Event: ${context.peerConnection.iceConnectionState}:`, event);

        let message;
        switch (context.peerConnection.iceConnectionState) {
          case 'connected': {
            l.i('ice State:connected');
            if (context.eventManager.hasEventListener('onStateChange')) { context.eventManager.dispatchEvent('onStateChange', 'COMPLETE'); }
            if (context.eventManager.hasEventListener('onComplete')) { context.eventManager.dispatchEvent('onComplete'); }
            message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'COMPLETE' });
            var health = new Health(context);
            health.getStats(util.bind(function(stats){
              this.oldStats = stats;
            },health));
            health.start();
            context.health = health;
            if (context.channel.type==="BROADCAST" || context.channel.type ==="VIEWER")return;
            break;
          }
          case 'failed': {
            // 간혹 browser가 refresh될때 netty는 이것을 감지못하나 ice failed가 발생한다. 이것 역시 상대 peer로부터 발생한 close이벤트라고 판단해야할까?
            l.i('ice State:failed');
            if (context.eventManager.hasEventListener('onError')) { context.eventManager.dispatchEvent('onError', 'ICEFailedError'); }
            l.e('Ice connection state change failed');
            context.health.stop();
            if (context.useRecord) {
              context.remoteRecorder.stop();
              context.localRecorder.stop();
              context.useRecord=false;
            }
            context.peerConnection.close();
            //context.signalingConnection.close();
            // 상대편이 뭔가 문제가 있어서 그런듯 한데 굳이 보내야? 하긴 signal server는 모르고 있을 듯.
            message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'FAIL' });
            break;
          }
          case 'closed': {
            l.i('ice State:closed');
            return;
            //message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'CLOSE' });
            break;
          }
          case 'disconnected': {
            l.i('ice State:disconnected');
            message = context.signalingConnection.createMessage({ command: 'stateChange', body: 'CLOSE' });
            break;
          }
          case 'completed': { l.v('iceconState:completed');break; }
          case 'checking': { l.v('iceconState:checking');break; }
          default: {
            l.e('Unknown ice connection change event:', context.peerConnection.iceConnectionState);
            break;
          }
        }
        l.v('Message ->:', message);
        l.i('Sending ice state to other');
        if (typeof message !== 'undefined')
        context.signalingConnection.send(JSON.stringify(message));

      }

      function handleRemoveStreamEvent(event) {
        l.v('PeerCon: Handle remove stream event');
      }
      function handleRemoteStreamEvent(event) {
        l.g('PeerCon: Bind remote stream');
        l.v('bindRemoteStream:', event);

        let stream;
        // FIXME: Chrome, adapter does not support addTrack
        if (context.hasAddTrack) {
          l.v("PeerCon: context has track");
          stream = event.streams[0];
        } else {
          l.v("PeerCon: context has stream");
          stream = event.stream;
        }
        l.v('Stream:', stream);
        context.remoteVideo.srcObject = stream;
        context.remoteStream = stream;

        // window.AudioContext = window.AudioContext || window.webkitAudioContext;
        //   navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
        //   window.URL = window.URL || window.webkitURL;
        //context.remonRecorder = new Recorder((new window.AudioContext).createMediaStreamSource(stream));
        //context.remonRecorder.record();
        if (context.useRecord){
          context.remoteRecorder = new RemonRecorder(context, stream,"RR");
          context.remoteRecorder.start();
          context.localRecorder.start();
        }
        l.gEnd();
      }
      /* eslint-disable no-param-reassign */
      context.peerConnection.onicecandidate = handleIceCandidateEvent;
      context.peerConnection.onicegatheringstatechange = handleIceGatheringStateChangeEvent;
      context.peerConnection.onsignalingstatechange = handleSignalingStateChangeEvent;
      context.peerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
      context.peerConnection.oniceconnectionstatechange = handleIceConnectionStateChangeEvent;
      // FIXME: Chrome, adapter does not support addTrack
      // NOTE: ontrack called twice. Maybe for audio, video. Is it right?
      if (context.hasAddTrack) {
        l.v("PeerCon: context has addTrack");
        context.peerConnection.ontrack = handleRemoteStreamEvent;
      } else {
        l.v("PeerCon: context has onAddstream");
        context.peerConnection.onaddstream = handleRemoteStreamEvent;
      }
      context.peerConnection.onremovestream = handleRemoveStreamEvent;
      /* eslint-enable no-param-reassign */
    }

    export default bindPeerConnectionEvents;