# Source: flash-worker.js

    /**
     * @file flash-worker.js
     */

    /**
     * videojs-contrib-media-sources
     *
     * Copyright (c) 2015 Brightcove
     * All rights reserved.
     *
     * Handles communication between the browser-world and the mux.js
     * transmuxer running inside of a WebWorker by exposing a simple
     * message-based interface to a Transmuxer object.
     */
    import window from 'global/window';
    import flv from 'mux.js/lib/flv';

    const orderTags = function(tags) {
      let videoTags = tags.videoTags;
      let audioTags = tags.audioTags;
      let ordered = [];
      let tag;

      while (videoTags.length || audioTags.length) {
        if (!videoTags.length) {
          // only audio tags remain
          tag = audioTags.shift();
        } else if (!audioTags.length) {
          // only video tags remain
          tag = videoTags.shift();
        } else if (audioTags[0].dts < videoTags[0].dts) {
          // audio should be decoded next
          tag = audioTags.shift();
        } else {
          // video should be decoded next
          tag = videoTags.shift();
        }

        ordered.push(tag);
      }

      return ordered;
    }

    /**
     * Re-emits tranmsuxer events by converting them into messages to the
     * world outside the worker.
     *
     * @param {Object} transmuxer the transmuxer to wire events on
     * @private
     */
    const wireTransmuxerEvents = function(transmuxer) {
      transmuxer.on('data', function(segment) {

        segment.tags = orderTags(segment.tags);

        window.postMessage({
          action: 'data',
          segment
        });
      });

      transmuxer.on('done', function(data) {
        window.postMessage({ action: 'done' });
      });
    };

    /**
     * All incoming messages route through this hash. If no function exists
     * to handle an incoming message, then we ignore the message.
     *
     * @class MessageHandlers
     * @param {Object} options the options to initialize with
     */
    class MessageHandlers {
      constructor(options) {
        this.options = options || {};
        this.init();
      }

      /**
       * initialize our web worker and wire all the events.
       */
      init() {
        if (this.transmuxer) {
          this.transmuxer.dispose();
        }
        this.transmuxer = new flv.Transmuxer(this.options);
        wireTransmuxerEvents(this.transmuxer);
      }

      /**
       * Adds data (a ts segment) to the start of the transmuxer pipeline for
       * processing.
       *
       * @param {ArrayBuffer} data data to push into the muxer
       */
      push(data) {
        // Cast array buffer to correct type for transmuxer
        let segment = new Uint8Array(data.data, data.byteOffset, data.byteLength);

        this.transmuxer.push(segment);
      }

      /**
       * Recreate the transmuxer so that the next segment added via `push`
       * start with a fresh transmuxer.
       */
      reset() {
        this.init();
      }

      /**
       * Forces the pipeline to finish processing the last segment and emit it's
       * results.
       *
       * @param {Object} data event data, not really used
       */
      flush(data) {
        this.transmuxer.flush();
      }
    }

    /**
     * Our web wroker interface so that things can talk to mux.js
     * that will be running in a web worker. the scope is passed to this by
     * webworkify.
     *
     * @param {Object} self the scope for the web worker
     */
    const Worker = function(self) {
      self.onmessage = function(event) {
        if (event.data.action === 'init' && event.data.options) {
          this.messageHandlers = new MessageHandlers(event.data.options);
          return;
        }

        if (!this.messageHandlers) {
          this.messageHandlers = new MessageHandlers();
        }

        if (event.data && event.data.action && event.data.action !== 'init') {
          if (this.messageHandlers[event.data.action]) {
            this.messageHandlers[event.data.action](event.data);
          }
        }
      };
    };

    export default (self) => {
      return new Worker(self);
    };