text: // Copyright 2013 The Closure Library Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //      http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS-IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  /**
   * @fileoverview Implementation of a WebChannel transport using WebChannelBase.
   *
   * When WebChannelBase is used as the underlying transport, the capabilities
   * of the WebChannel are limited to what's supported by the implementation.
   * Particularly, multiplexing is not possible, and only strings are
   * supported as message types.
   *
   */
  
  goog.provide('goog.labs.net.webChannel.WebChannelBaseTransport');
  
  goog.require('goog.asserts');
  goog.require('goog.events.EventTarget');
  goog.require('goog.labs.net.webChannel.WebChannelBase');
  goog.require('goog.log');
  goog.require('goog.net.WebChannel');
  goog.require('goog.net.WebChannelTransport');
  goog.require('goog.string.path');
  
  
  
  /**
   * Implementation of {@link goog.net.WebChannelTransport} with
   * {@link goog.labs.net.webChannel.WebChannelBase} as the underlying channel
   * implementation.
   *
   * @constructor
   * @struct
   * @implements {goog.net.WebChannelTransport}
   * @final
   */
  goog.labs.net.webChannel.WebChannelBaseTransport = function() {};
  
  
  goog.scope(function() {
  var WebChannelBaseTransport = goog.labs.net.webChannel.WebChannelBaseTransport;
  var WebChannelBase = goog.labs.net.webChannel.WebChannelBase;
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.prototype.createWebChannel = function(
      url, opt_options) {
    return new WebChannelBaseTransport.Channel(url, opt_options);
  };
  
  
  
  /**
   * Implementation of the {@link goog.net.WebChannel} interface.
   *
   * @param {string} url The URL path for the new WebChannel instance.
   * @param {!goog.net.WebChannel.Options=} opt_options Configuration for the
   *     new WebChannel instance.
   *
   * @constructor
   * @implements {goog.net.WebChannel}
   * @extends {goog.events.EventTarget}
   * @final
   */
  WebChannelBaseTransport.Channel = function(url, opt_options) {
    WebChannelBaseTransport.Channel.base(this, 'constructor');
  
    /**
     * The underlying channel object.
     *
     * @private {!WebChannelBase}
     */
    this.channel_ = new WebChannelBase(opt_options);
  
    /**
     * The URL of the target server end-point.
     *
     * @private {string}
     */
    this.url_ = url;
  
    /**
     * The test URL of the target server end-point. This value defaults to
     * this.url_ + '/test'.
     *
     * @private {string}
     */
    this.testUrl_ = (opt_options && opt_options.testUrl) ? opt_options.testUrl :
        goog.string.path.join(this.url_, 'test');
  
    /**
     * The logger for this class.
     * @private {goog.log.Logger}
     */
    this.logger_ = goog.log.getLogger(
        'goog.labs.net.webChannel.WebChannelBaseTransport');
  
  
    /**
     * @private {Object.<string, string>} messageUrlParams_ Extra URL parameters
     * to be added to each HTTP request.
     */
    this.messageUrlParams_ =
        (opt_options && opt_options.messageUrlParams) || null;
  
    var messageHeaders = (opt_options && opt_options.messageHeaders) || null;
    if (messageHeaders) {
      this.channel_.setExtraHeaders(messageHeaders);
    }
  
    /**
     * @private {boolean} supportsCrossDomainXhr_ Whether to enable CORS.
     */
    this.supportsCrossDomainXhr_ =
        (opt_options && opt_options.supportsCrossDomainXhr) || false;
  };
  goog.inherits(WebChannelBaseTransport.Channel, goog.events.EventTarget);
  
  
  /**
   * The channel handler.
   *
   * @type {WebChannelBase.Handler}
   * @private
   */
  WebChannelBaseTransport.Channel.prototype.channelHandler_ = null;
  
  
  /**
   * Test path is always set to "/url/test".
   *
   * @override
   */
  WebChannelBaseTransport.Channel.prototype.open = function() {
    this.channel_.connect(this.testUrl_, this.url_,
                          (this.messageUrlParams_ || undefined));
  
    this.channelHandler_ = new WebChannelBaseTransport.Channel.Handler_(this);
    this.channel_.setHandler(this.channelHandler_);
    if (this.supportsCrossDomainXhr_) {
      this.channel_.setSupportsCrossDomainXhrs(true);
    }
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.prototype.close = function() {
    this.channel_.disconnect();
  };
  
  
  /**
   * The WebChannelBase only supports object types.
   *
   * @param {!goog.net.WebChannel.MessageData} message The message to send.
   * @override
   */
  WebChannelBaseTransport.Channel.prototype.send = function(message) {
    goog.asserts.assert(goog.isObject(message), 'only object type expected');
    this.channel_.sendMap(message);
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.prototype.disposeInternal = function() {
    this.channel_.setHandler(null);
    delete this.channelHandler_;
    this.channel_.disconnect();
    delete this.channel_;
  
    WebChannelBaseTransport.Channel.base(this, 'disposeInternal');
  };
  
  
  
  /**
   * The message event.
   *
   * @param {!Array} array The data array from the underlying channel.
   * @constructor
   * @extends {goog.net.WebChannel.MessageEvent}
   * @final
   */
  WebChannelBaseTransport.Channel.MessageEvent = function(array) {
    WebChannelBaseTransport.Channel.MessageEvent.base(this, 'constructor');
  
    this.data = array;
  };
  goog.inherits(WebChannelBaseTransport.Channel.MessageEvent,
                goog.net.WebChannel.MessageEvent);
  
  
  
  /**
   * The error event.
   *
   * @param {WebChannelBase.Error} error The error code.
   * @constructor
   * @extends {goog.net.WebChannel.ErrorEvent}
   * @final
   */
  WebChannelBaseTransport.Channel.ErrorEvent = function(error) {
    WebChannelBaseTransport.Channel.ErrorEvent.base(this, 'constructor');
  
    /**
     * Transport specific error code is not to be propagated with the event.
     */
    this.status = goog.net.WebChannel.ErrorStatus.NETWORK_ERROR;
  };
  goog.inherits(WebChannelBaseTransport.Channel.ErrorEvent,
                goog.net.WebChannel.ErrorEvent);
  
  
  
  /**
   * Implementation of {@link WebChannelBase.Handler} interface.
   *
   * @param {!WebChannelBaseTransport.Channel} channel The enclosing WebChannel.
   *
   * @constructor
   * @extends {WebChannelBase.Handler}
   * @private
   */
  WebChannelBaseTransport.Channel.Handler_ = function(channel) {
    WebChannelBaseTransport.Channel.Handler_.base(this, 'constructor');
  
    /**
     * @type {!WebChannelBaseTransport.Channel}
     * @private
     */
    this.channel_ = channel;
  };
  goog.inherits(WebChannelBaseTransport.Channel.Handler_, WebChannelBase.Handler);
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.Handler_.prototype.channelOpened = function(
      channel) {
    goog.log.info(this.channel_.logger_,
        'WebChannel opened on ' + this.channel_.url_);
    this.channel_.dispatchEvent(goog.net.WebChannel.EventType.OPEN);
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.Handler_.prototype.channelHandleArray =
      function(channel, array) {
    goog.asserts.assert(array, 'array expected to be defined');
    this.channel_.dispatchEvent(
        new WebChannelBaseTransport.Channel.MessageEvent(array));
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.Handler_.prototype.channelError = function(
      channel, error) {
    goog.log.info(this.channel_.logger_,
        'WebChannel aborted on ' + this.channel_.url_ +
        ' due to channel error: ' + error);
    this.channel_.dispatchEvent(
        new WebChannelBaseTransport.Channel.ErrorEvent(error));
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.Handler_.prototype.channelClosed = function(
      channel, opt_pendingMaps, opt_undeliveredMaps) {
    goog.log.info(this.channel_.logger_,
        'WebChannel closed on ' + this.channel_.url_);
    this.channel_.dispatchEvent(goog.net.WebChannel.EventType.CLOSE);
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.Channel.prototype.getRuntimeProperties = function() {
    return new WebChannelBaseTransport.ChannelProperties(this.channel_);
  };
  
  
  
  /**
   * Implementation of the {@link goog.net.WebChannel.RuntimeProperties}.
   *
   * @param {!WebChannelBase} channel The underlying channel object.
   *
   * @constructor
   * @implements {goog.net.WebChannel.RuntimeProperties}
   * @final
   */
  WebChannelBaseTransport.ChannelProperties = function(channel) {
    /**
     * The underlying channel object.
     *
     * @private {!WebChannelBase}
     */
    this.channel_ = channel;
  
    /**
     * The flag to turn on/off server-side flow control.
     *
     * @private {boolean}
     */
    this.serverFlowControlEnabled_ = false;
  
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.ChannelProperties.prototype.getSpdyRequestLimit =
      function() {
    return this.channel_.getForwardChannelRequestPool().getMaxSize();
  };
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.ChannelProperties.prototype.setServerFlowControl =
      goog.abstractMethod;
  
  
  /**
   * @override
   */
  WebChannelBaseTransport.ChannelProperties.prototype.getNonAckedMessageCount =
      goog.abstractMethod;
  });  // goog.scope
  