// Copyright 2007 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 Provides the namesspace for client-side communication
 * between pages originating from different domains (it works also
 * with pages from the same domain, but doing that is kinda
 * pointless).
 *
 * The only publicly visible class is goog.net.xpc.CrossPageChannel.
 *
 * Note: The preferred name for the main class would have been
 * CrossDomainChannel.  But as there already is a class named like
 * that (which serves a different purpose) in the maps codebase,
 * CrossPageChannel was chosen to avoid confusion.
 *
 * CrossPageChannel abstracts the underlying transport mechanism to
 * provide a common interface in all browsers.
 *
 *
 * @suppress {underscore}
 */

/*
TODO(user)
- resolve fastback issues in Safari (IframeRelayTransport)
 */


/**
 * Namespace for CrossPageChannel
 */
goog.provide('goog.net.xpc');
goog.provide('goog.net.xpc.CfgFields');
goog.provide('goog.net.xpc.ChannelStates');
goog.provide('goog.net.xpc.TransportNames');
goog.provide('goog.net.xpc.TransportTypes');
goog.provide('goog.net.xpc.UriCfgFields');
goog.require('goog.log');

goog.forwardDeclare('goog.net.xpc.CrossPageChannel');  // circular


/**
 * Enum used to identify transport types.
 * @enum {number}
 */
goog.net.xpc.TransportTypes = {
  UNDEFINED: 0,
  NATIVE_MESSAGING: 1,
  FRAME_ELEMENT_METHOD: 2,
  IFRAME_RELAY: 3,
  IFRAME_POLLING: 4,
  FLASH: 5,
  NIX: 6,
  DIRECT: 7
};


/**
 * Enum containing transport names. These need to correspond to the
 * transport class names for createTransport_() to work.
 * @const {!Object<string,string>}
 */
goog.net.xpc.TransportNames = {
  '1': 'NativeMessagingTransport',
  '2': 'FrameElementMethodTransport',
  '3': 'IframeRelayTransport',
  '4': 'IframePollingTransport',
  '5': 'FlashTransport',
  '6': 'NixTransport',
  '7': 'DirectTransport'
};


// TODO(user): Add auth token support to other methods.


/**
 * Field names used on configuration object.
 * @const
 */
goog.net.xpc.CfgFields = {
  /**
   * Channel name identifier.
   * Both peers have to be initialized with
   * the same channel name.  If not present, a channel name is
   * generated (which then has to transferred to the peer somehow).
   */
  CHANNEL_NAME: 'cn',
  /**
   * Authorization token. If set, NIX will use this authorization token
   * to validate the setup.
   */
  AUTH_TOKEN: 'at',
  /**
   * Remote party's authorization token. If set, NIX will validate this
   * authorization token against that sent by the other party.
   */
  REMOTE_AUTH_TOKEN: 'rat',
  /**
   * The URI of the peer page.
   */
  PEER_URI: 'pu',
  /**
   * Ifame-ID identifier.
   * The id of the iframe element the peer-document lives in.
   */
  IFRAME_ID: 'ifrid',
  /**
   * Transport type identifier.
   * The transport type to use. Possible values are entries from
   * goog.net.xpc.TransportTypes or a Transport constructor fuction. If not
   * present, the transport is determined automatically based on the useragent's
   * capabilities.
   */
  TRANSPORT: 'tp',
  /**
   * Local relay URI identifier (IframeRelayTransport-specific).
   * The URI (can't contain a fragment identifier) used by the peer to
   * relay data through.
   */
  LOCAL_RELAY_URI: 'lru',
  /**
   * Peer relay URI identifier (IframeRelayTransport-specific).
   * The URI (can't contain a fragment identifier) used to relay data
   * to the peer.
   */
  PEER_RELAY_URI: 'pru',
  /**
   * Local poll URI identifier (IframePollingTransport-specific).
   * The URI  (can't contain a fragment identifier)which is polled
   * to receive data from the peer.
   */
  LOCAL_POLL_URI: 'lpu',
  /**
   * Local poll URI identifier (IframePollingTransport-specific).
   * The URI (can't contain a fragment identifier) used to send data
   * to the peer.
   */
  PEER_POLL_URI: 'ppu',
  /**
   * The hostname of the peer window, including protocol, domain, and port
   * (if specified). Used for security sensitive applications that make
   * use of NativeMessagingTransport (i.e. most applications).
   */
  PEER_HOSTNAME: 'ph',
  /**
   * Usually both frames using a connection initially send a SETUP message to
   * each other, and each responds with a SETUP_ACK.  A frame marks itself
   * connected when it receives that SETUP_ACK.  If this parameter is true
   * however, the channel it is passed to will not send a SETUP, but rather will
   * wait for one from its peer and mark itself connected when that arrives.
   * Peer iframes created using such a channel will send SETUP however, and will
   * wait for SETUP_ACK before marking themselves connected.  The goal is to
   * cope with a situation where the availability of the URL for the peer frame
   * cannot be relied on, eg when the application is offline.  Without this
   * setting, the primary frame will attempt to send its SETUP message every
   * 100ms, forever.  This floods the javascript console with uncatchable
   * security warnings, and fruitlessly burns CPU.  There is one scenario this
   * mode will not support, and that is reconnection by the outer frame, ie the
   * creation of a new channel object to connect to a peer iframe which was
   * already communicating with a previous channel object of the same name.  If
   * that behavior is needed, this mode should not be used.  Reconnection by
   * inner frames is supported in this mode however.
   */
  ONE_SIDED_HANDSHAKE: 'osh',
  /**
   * The frame role (inner or outer). Used to explicitly indicate the role for
   * each peer whenever the role cannot be reliably determined (e.g. the two
   * peer windows are not parent/child frames). If unspecified, the role will
   * be dynamically determined, assuming a parent/child frame setup.
   */
  ROLE: 'role',
  /**
   * Which version of the native transport startup protocol should be used, the
   * default being '2'.  Version 1 had various timing vulnerabilities, which
   * had to be compensated for by introducing delays, and is deprecated.  V1
   * and V2 are broadly compatible, although the more robust timing and lack
   * of delays is not gained unless both sides are using V2.  The only
   * unsupported case of cross-protocol interoperation is where a connection
   * starts out with V2 at both ends, and one of the ends reconnects as a V1.
   * All other initial startup and reconnection scenarios are supported.
   */
  NATIVE_TRANSPORT_PROTOCOL_VERSION: 'nativeProtocolVersion',
  /**
   * Whether the direct transport runs in synchronous mode. The default is to
   * emulate the other transports and run asyncronously but there are some
   * circumstances where syncronous calls are required. If this property is
   * set to true, the transport will send the messages synchronously.
   */
  DIRECT_TRANSPORT_SYNC_MODE: 'directSyncMode'
};


/**
 * Config properties that need to be URL sanitized.
 * @type {Array<string>}
 */
goog.net.xpc.UriCfgFields = [
  goog.net.xpc.CfgFields.PEER_URI, goog.net.xpc.CfgFields.LOCAL_RELAY_URI,
  goog.net.xpc.CfgFields.PEER_RELAY_URI, goog.net.xpc.CfgFields.LOCAL_POLL_URI,
  goog.net.xpc.CfgFields.PEER_POLL_URI
];


/**
 * @enum {number}
 */
goog.net.xpc.ChannelStates = {
  NOT_CONNECTED: 1,
  CONNECTED: 2,
  CLOSED: 3
};


/**
 * The name of the transport service (used for internal signalling).
 * @type {string}
 * @suppress {underscore|visibility}
 */
goog.net.xpc.TRANSPORT_SERVICE_ = 'tp';


/**
 * Transport signaling message: setup.
 * @type {string}
 */
goog.net.xpc.SETUP = 'SETUP';


/**
 * Transport signaling message: setup for native transport protocol v2.
 * @type {string}
 */
goog.net.xpc.SETUP_NTPV2 = 'SETUP_NTPV2';


/**
 * Transport signaling message: setup acknowledgement.
 * @type {string}
 * @suppress {underscore|visibility}
 */
goog.net.xpc.SETUP_ACK_ = 'SETUP_ACK';


/**
 * Transport signaling message: setup acknowledgement.
 * @type {string}
 */
goog.net.xpc.SETUP_ACK_NTPV2 = 'SETUP_ACK_NTPV2';


/**
 * Object holding active channels.
 *
 * @package {Object<string, goog.net.xpc.CrossPageChannel>}
 */
goog.net.xpc.channels = {};


/**
 * Returns a random string.
 * @param {number} length How many characters the string shall contain.
 * @param {string=} opt_characters The characters used.
 * @return {string} The random string.
 */
goog.net.xpc.getRandomString = function(length, opt_characters) {
  var chars = opt_characters || goog.net.xpc.randomStringCharacters_;
  var charsLength = chars.length;
  var s = '';
  while (length-- > 0) {
    s += chars.charAt(Math.floor(Math.random() * charsLength));
  }
  return s;
};


/**
 * The default characters used for random string generation.
 * @type {string}
 * @private
 */
goog.net.xpc.randomStringCharacters_ =
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';


/**
 * The logger.
 * @type {goog.log.Logger}
 */
goog.net.xpc.logger = goog.log.getLogger('goog.net.xpc');
