# src/SignalingConnection.js

    import Context from './Context';
    import l from './Logger';

    function SignalingConnection({ url, context }) {
      const connection = (function createConnection() {
        l.g('Signaling: Connect');
        const webSocket = new WebSocket(url);
        l.d('Signaling Connection: ', webSocket);
        l.gEnd();
        return webSocket;
      }());

      function send(...args) {
        return connection.send(...args);
      }
      function close(){
        if (connection.readyState<2){
          const message = createMessage({ command: 'disconnect' });
          l.v('disconnect Message ->:', message);
          send(JSON.stringify(message));
          connection.close();
        }
      }

      function onMessage(handler) {
        connection.onmessage = handler;
      }

      function handleOpenEvent(event) {
        l.i('Signaling: Success connect to the signaling server');
        l.v('OpenEvent:', event);
        if (context.eventManager.hasEventListener('onInit')){
          context.eventManager.dispatchEvent('onInit', context.token);
        }
        if (context.eventManager.hasEventListener('onStateChange')) {
          context.eventManager.dispatchEvent('onStateChange', 'INIT');
        }
      }

      function handleCloseEvent(event) {
        l.i('Signaling: Closed the signaling connection');
        l.v('Event:', event);
      }

      function handleErrorEvent(event) {
        l.i('Signaling: Error from the signaling connection.');
        l.v('Event', event);
        if (context.eventManager.hasEventListener('onError')) { context.eventManager.dispatchEvent('onError', 'WebSocketFailedError'); }
      }

      function createMessage({ command, body }) {
        l.i('Signaling: Create Message');

        const template = {
          command,
          token: context.token,
          serviceId: context.serviceId,
          channel: {
            id: context.channel.id,
          },
        };

        if (body) {
          template.body = body;
        }
        l.v("createMessage: "+ JSON.stringify(template));
        return template;
      }

      function connectChannel(channelId) {
        l.i('Signaling: Connect channel: As a caller');
        context.startTime = new Date().getTime();
        context.isCaller = true;
        context.channel.id = channelId;

        const message = createMessage({ command: 'connect' });
        l.v('ConnectCh Message ->:', message);

        send(JSON.stringify(message));
      }
      function createViewerChannel(channelId){
        l.i('Signaling: Create channel: As a viewer');
        context.startTime = new Date().getTime();
        context.isCaller = false;
        context.channel.id = channelId;

        const message = createMessage({ command: 'create' });
        message.channel.type="VIEWER";
        l.v('ConnectCh Message ->:', message);

        send(JSON.stringify(message));
      }
      function createBroadcastChannel(channelId) {
        l.i('Signaling: Create channel: As a presenter');
        context.startTime = new Date().getTime();
        context.isCaller = false;
        context.channel.id = channelId;

        const message = createMessage({ command: 'create' });
        message.channel.type="BROADCAST";
        l.v('ConnectCh Message ->:', message);

        send(JSON.stringify(message));
      }

      connection.onopen = handleOpenEvent;
      connection.onclose = handleCloseEvent;
      connection.onerror = handleErrorEvent;

      return Object.freeze({
        connectChannel,
        createMessage,
        createViewerChannel,
        createBroadcastChannel,
        send,
        close,
        onMessage,
        context,
      });
    }

    export default SignalingConnection;