text: /* jshint node: true */
  'use strict';
  
  var nub = require('whisk/nub');
  var pluck = require('whisk/pluck');
  var flatten = require('whisk/flatten');
  var reLineBreak = /\r?\n/;
  var reTrailingNewlines = /\r?\n$/;
  
  // list sdp line types that are not "significant"
  var nonHeaderLines = [ 'a', 'c', 'b', 'k' ];
  var parsers = require('./parsers');
  
  /**
    # rtc-sdp
  
    This is a utility module for intepreting and patching sdp.
  
    ## Usage
  
    The `rtc-sdp` main module exposes a single function that is capable of
    parsing lines of SDP, and providing an object allowing you to perform
    operations on those parsed lines:
  
    ```js
    var sdp = require('rtc-sdp')(lines);
    ```
  
    The currently supported operations are listed below:
  
  **/
  module.exports = function(sdp) {
    var ops = {};
    var parsed = [];
    var activeCollector;
  
    // initialise the lines
    var lines = sdp.split(reLineBreak).filter(Boolean).map(function(line) {
      return line.split('=');
    });
  
    var inputOrder = nub(lines.filter(function(line) {
      return line[0] && nonHeaderLines.indexOf(line[0]) < 0;
    }).map(pluck(0)));
  
    var findLine = ops.findLine = function(type, index) {
      var lineData = parsed.filter(function(line) {
        return line[0] === type;
      })[index || 0];
  
      return lineData && lineData[1];
    };
  
    // push into parsed sections
    lines.forEach(function(line) {
      var customParser = parsers[line[0]];
  
      if (customParser) {
        activeCollector = customParser(parsed, line);
      }
      else if (activeCollector) {
        activeCollector = activeCollector(line);
      }
      else {
        parsed.push(line);
      }
    });
  
    /**
      ### `sdp.addIceCandidate(data)`
  
      Modify the sdp to include candidates as denoted by the data.
  
  **/
    ops.addIceCandidate = function(data) {
      var lineIndex = (data || {}).lineIndex || (data || {}).sdpMLineIndex;
      var mLine = typeof lineIndex != 'undefined' && findLine('m', lineIndex);
      var candidate = (data || {}).candidate;
  
      // if we have the mLine add the new candidate
      if (mLine && candidate) {
        mLine.childlines.push(candidate.replace(reTrailingNewlines, '').split('='));
      }
    };
  
    /**
      ### `sdp.getMediaTypes() => []`
  
      Retrieve the list of media types that have been defined in the sdp via
      `m=` lines.
    **/
    ops.getMediaTypes = function() {
      function getMediaType(data) {
        return data[1].def.split(/\s/)[0];
      }
  
      return parsed.filter(function(parts) {
        return parts[0] === 'm' && parts[1] && parts[1].def;
      }).map(getMediaType);
    };
  
    /**
      ### `sdp.getMediaIDs() => []`
  
      Returns the list of unique media line IDs that have been defined in the sdp
      via `a=mid:` lines.
     **/
    ops.getMediaIDs = function() {
      return parsed.filter(function(parts) {
        return parts[0] === 'm' && parts[1] && parts[1].childlines && parts[1].childlines.length > 0;
      }).map(function(mediaLine) {
        var lines = mediaLine[1].childlines;
        // Default ID to the media type
        var mediaId = mediaLine[1].def.split(/\s/)[0];
  
        // Look for the media ID
        for (var i = 0; i < lines.length; i++) {
          var tokens = lines[i][1].split(':');
          if (tokens.length > 0 && tokens[0] === 'mid') {
            mediaId = tokens[1];
            break;
          }
        }
        return mediaId;
      });
    };
  
    /**
      ### `sdp.toString()`
  
      Convert the SDP structure that is currently retained in memory, into a string
      that can be provided to a `setLocalDescription` (or `setRemoteDescription`)
      WebRTC call.
  
    **/
    ops.toString = function() {
      return parsed.map(function(line) {
        return typeof line[1].toArray == 'function' ? line[1].toArray() : [ line ];
      }).reduce(flatten).map(function(line) {
        return line.join('=');
      }).join('\r\n') + '\r\n';
    };
  
    /**
      ## SDP Filtering / Munging Functions
  
      There are additional functions included in the module to assign with
      performing "single-shot" SDP filtering (or munging) operations:
  
    **/
  
    return ops;
  };
  