text: // Copyright 2015 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  /**
   * @fileoverview
   * 'settings-internet-detail' is the settings subpage containing details
   * for a network.
   */
  (function() {
  'use strict';
  
  /** @const */ var CARRIER_VERIZON = 'Verizon Wireless';
  
  Polymer({
    is: 'settings-internet-detail-page',
  
    behaviors:
        [CrPolicyNetworkBehavior, settings.RouteObserverBehavior, I18nBehavior],
  
    properties: {
      /** The network GUID to display details for. */
      guid: String,
  
      /**
       * The current properties for the network matching |guid|.
       * @type {!CrOnc.NetworkProperties|undefined}
       */
      networkProperties: {
        type: Object,
        observer: 'networkPropertiesChanged_',
      },
  
      /** Preferences state. */
      prefs: {
        type: Object,
        notify: true,
      },
  
      /**
       * Highest priority connected network or null.
       * @type {?CrOnc.NetworkStateProperties}
       */
      defaultNetwork: {
        type: Object,
        value: null,
      },
  
      /**
       * Interface for networkingPrivate calls, passed from internet_page.
       * @type {NetworkingPrivate}
       */
      networkingPrivate: Object,
  
      /**
       * The network AutoConnect state.
       * @private
       */
      autoConnect_: {
        type: Boolean,
        value: false,
        observer: 'autoConnectChanged_',
      },
  
      /**
       * The network preferred state.
       * @private
       */
      preferNetwork_: {
        type: Boolean,
        value: false,
        observer: 'preferNetworkChanged_',
      },
  
      /**
       * The network IP Address.
       * @private
       */
      IPAddress_: {
        type: String,
        value: '',
      },
  
      /** @private */
      advancedExpanded_: Boolean,
  
      /**
       * Object providing network type values for data binding.
       * @const
       * @private
       */
      NetworkType_: {
        type: Object,
        value: {
          CELLULAR: CrOnc.Type.CELLULAR,
          ETHERNET: CrOnc.Type.ETHERNET,
          VPN: CrOnc.Type.VPN,
          WIFI: CrOnc.Type.WI_FI,
          WIMAX: CrOnc.Type.WI_MAX,
        },
        readOnly: true
      },
    },
  
    /**
     * Listener function for chrome.networkingPrivate.onNetworksChanged event.
     * @type {?function(!Array<string>)}
     * @private
     */
    networksChangedListener_: null,
  
    /**
     * settings.RouteObserverBehavior
     * @param {!settings.Route} route
     * @protected
     */
    currentRouteChanged: function(route) {
      if (route != settings.Route.NETWORK_DETAIL) {
        if (this.networksChangedListener_) {
          this.networkingPrivate.onNetworksChanged.removeListener(
              this.networksChangedListener_);
          this.networksChangedListener_ = null;
        }
        return;
      }
      if (!this.networksChangedListener_) {
        this.networksChangedListener_ = this.onNetworksChangedEvent_.bind(this);
        this.networkingPrivate.onNetworksChanged.addListener(
            this.networksChangedListener_);
      }
      let queryParams = settings.getQueryParameters();
      this.guid = queryParams.get('guid') || '';
      if (!this.guid) {
        console.error('No guid specified for page:' + route);
        this.close_();
      }
      this.getNetworkDetails_();
    },
  
    /** @private */
    close_: function() {
      // Delay navigating until the next render frame to allow other subpages to
      // load first.
      setTimeout(function() {
        settings.navigateTo(settings.Route.INTERNET);
      });
    },
  
    /** @private */
    networkPropertiesChanged_: function() {
      if (!this.networkProperties)
        return;
  
      // Update autoConnect if it has changed. Default value is false.
      var autoConnect = CrOnc.getAutoConnect(this.networkProperties);
      if (autoConnect != this.autoConnect_)
        this.autoConnect_ = autoConnect;
  
      // Update preferNetwork if it has changed. Default value is false.
      var priority = /** @type {number} */ (
          CrOnc.getActiveValue(this.networkProperties.Priority) || 0);
      var preferNetwork = priority > 0;
      if (preferNetwork != this.preferNetwork_)
        this.preferNetwork_ = preferNetwork;
  
      // Set the IPAddress property to the IPV4 Address.
      var ipv4 =
          CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4);
      this.IPAddress_ = (ipv4 && ipv4.IPAddress) || '';
  
      // Update the detail page title.
      this.parentNode.pageTitle =
          CrOnc.getNetworkName(this.networkProperties, this);
    },
  
    /** @private */
    autoConnectChanged_: function() {
      if (!this.networkProperties || !this.guid)
        return;
      var onc = this.getEmptyNetworkProperties_();
      CrOnc.setTypeProperty(onc, 'AutoConnect', this.autoConnect_);
      this.setNetworkProperties_(onc);
    },
  
    /** @private */
    preferNetworkChanged_: function() {
      if (!this.networkProperties || !this.guid)
        return;
      var onc = this.getEmptyNetworkProperties_();
      onc.Priority = this.preferNetwork_ ? 1 : 0;
      this.setNetworkProperties_(onc);
    },
  
    /**
     * networkingPrivate.onNetworksChanged event callback.
     * @param {!Array<string>} networkIds The list of changed network GUIDs.
     * @private
     */
    onNetworksChangedEvent_: function(networkIds) {
      if (networkIds.indexOf(this.guid) != -1)
        this.getNetworkDetails_();
    },
  
    /**
     * Calls networkingPrivate.getProperties for this.guid.
     * @private
     */
    getNetworkDetails_: function() {
      assert(!!this.guid);
      this.networkingPrivate.getManagedProperties(
          this.guid, this.getPropertiesCallback_.bind(this));
    },
  
    /**
     * networkingPrivate.getProperties callback.
     * @param {CrOnc.NetworkProperties} properties The network properties.
     * @private
     */
    getPropertiesCallback_: function(properties) {
      this.networkProperties = properties;
      if (!properties) {
        // If |properties| becomes null (i.e. the network is no longer visible),
        // close the page.
        console.error('Network no longer exists: ' + this.guid);
        this.close_();
      }
    },
  
    /**
     * @param {!chrome.networkingPrivate.NetworkConfigProperties} onc The ONC
     *     network properties.
     * @private
     */
    setNetworkProperties_: function(onc) {
      assert(!!this.guid);
      this.networkingPrivate.setProperties(this.guid, onc, function() {
        if (chrome.runtime.lastError) {
          // An error typically indicates invalid input; request the properties
          // to update any invalid fields.
          this.getNetworkDetails_();
        }
      }.bind(this));
    },
  
    /**
     * @return {!chrome.networkingPrivate.NetworkConfigProperties} An ONC
     *     dictionary with just the Type property set. Used for passing properties
     *     to setNetworkProperties_.
     * @private
     */
    getEmptyNetworkProperties_: function() {
      return {Type: this.networkProperties.Type};
    },
  
    /**
     * @return {string} The text to display for the network connection state.
     * @private
     */
    getStateText_: function() {
      return this.i18n('Onc' + this.networkProperties.ConnectionState);
    },
  
    /**
     * @return {boolean} True if the network is connected.
     * @private
     */
    isConnectedState_: function() {
      return this.networkProperties.ConnectionState ==
          CrOnc.ConnectionState.CONNECTED;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    isRemembered_: function() {
      var source = this.networkProperties.Source;
      return !!source && source != CrOnc.Source.NONE;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    isRememberedOrConnected_: function() {
      return this.isRemembered_() || this.isConnectedState_();
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showConnect_: function() {
      return this.networkProperties.Type != CrOnc.Type.ETHERNET &&
          this.networkProperties.ConnectionState ==
          CrOnc.ConnectionState.NOT_CONNECTED;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showDisconnect_: function() {
      return this.networkProperties.Type != CrOnc.Type.ETHERNET &&
          this.networkProperties.ConnectionState !=
          CrOnc.ConnectionState.NOT_CONNECTED;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showForget_: function() {
      var type = this.networkProperties.Type;
      if (type != CrOnc.Type.WI_FI && type != CrOnc.Type.VPN)
        return false;
      return this.isRemembered_();
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showActivate_: function() {
      if (this.networkProperties.Type != CrOnc.Type.CELLULAR)
        return false;
      var activation = this.networkProperties.Cellular.ActivationState;
      return activation == CrOnc.ActivationState.NOT_ACTIVATED ||
          activation == CrOnc.ActivationState.PARTIALLY_ACTIVATED;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showConfigure_: function() {
      var type = this.networkProperties.Type;
      if (type == CrOnc.Type.CELLULAR || type == CrOnc.Type.WI_MAX)
        return false;
      if (type == CrOnc.Type.WI_FI &&
          this.networkProperties.ConnectionState !=
              CrOnc.ConnectionState.NOT_CONNECTED) {
        return false;
      }
      return this.isRemembered_();
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showViewAccount_: function() {
      // Show either the 'Activate' or the 'View Account' button.
      if (this.showActivate_())
        return false;
  
      if (this.networkProperties.Type != CrOnc.Type.CELLULAR ||
          !this.networkProperties.Cellular) {
        return false;
      }
  
      // Only show if online payment URL is provided or the carrier is Verizon.
      var carrier = CrOnc.getActiveValue(this.networkProperties.Cellular.Carrier);
      if (carrier != CARRIER_VERIZON) {
        var paymentPortal = this.networkProperties.Cellular.PaymentPortal;
        if (!paymentPortal || !paymentPortal.Url)
          return false;
      }
  
      // Only show for connected networks or LTE networks with a valid MDN.
      if (!this.isConnectedState_()) {
        var technology = this.networkProperties.Cellular.NetworkTechnology;
        if (technology != CrOnc.NetworkTechnology.LTE &&
            technology != CrOnc.NetworkTechnology.LTE_ADVANCED) {
          return false;
        }
        if (!this.networkProperties.Cellular.MDN)
          return false;
      }
  
      return true;
    },
  
    /**
     * @return {boolean} Whether or not to enable the network connect button.
     * @private
     */
    enableConnect_: function() {
      if (!this.showConnect_())
        return false;
      if (this.networkProperties.Type == CrOnc.Type.CELLULAR &&
          CrOnc.isSimLocked(this.networkProperties)) {
        return false;
      }
      if (this.networkProperties.Type == CrOnc.Type.VPN && !this.defaultNetwork)
        return false;
      return true;
    },
  
    /** @private */
    onConnectTap_: function() {
      this.networkingPrivate.startConnect(this.guid);
    },
  
    /** @private */
    onDisconnectTap_: function() {
      this.networkingPrivate.startDisconnect(this.guid);
    },
  
    /** @private */
    onForgetTap_: function() {
      this.networkingPrivate.forgetNetwork(this.guid);
      // A forgotten WiFi network can still be configured, but not other types.
      if (this.networkProperties.Type != CrOnc.Type.WI_FI)
        this.close_();
    },
  
    /** @private */
    onActivateTap_: function() {
      this.networkingPrivate.startActivate(this.guid);
    },
  
    /** @private */
    onConfigureTap_: function() {
      chrome.send('configureNetwork', [this.guid]);
    },
  
    /** @private */
    onViewAccountTap_: function() {
      // startActivate() will show the account page for activated networks.
      this.networkingPrivate.startActivate(this.guid);
    },
  
    /**
     * @param {Event} event
     * @private
     */
    toggleAdvancedExpanded_: function(event) {
      if (event.target.id == 'expandButton')
        return;  // Already handled.
      this.advancedExpanded_ = !this.advancedExpanded_;
    },
  
    /**
     * Event triggered for elements associated with network properties.
     * @param {!{detail: !{field: string, value: (string|!Object)}}} event
     * @private
     */
    onNetworkPropertyChange_: function(event) {
      if (!this.networkProperties)
        return;
      var field = event.detail.field;
      var value = event.detail.value;
      var onc = this.getEmptyNetworkProperties_();
      if (field == 'APN') {
        CrOnc.setTypeProperty(onc, 'APN', value);
      } else if (field == 'SIMLockStatus') {
        CrOnc.setTypeProperty(onc, 'SIMLockStatus', value);
      } else {
        console.error('Unexpected property change event: ' + field);
        return;
      }
      this.setNetworkProperties_(onc);
    },
  
    /**
     * Event triggered when the IP Config or NameServers element changes.
     * @param {!{detail: !{field: string,
     *                     value: (string|!CrOnc.IPConfigProperties|
     *                             !Array<string>)}}} event
     *     The network-ip-config or network-nameservers change event.
     * @private
     */
    onIPConfigChange_: function(event) {
      if (!this.networkProperties)
        return;
      var field = event.detail.field;
      var value = event.detail.value;
      // Get an empty ONC dictionary and set just the IP Config properties that
      // need to change.
      var onc = this.getEmptyNetworkProperties_();
      var ipConfigType =
          /** @type {chrome.networkingPrivate.IPConfigType|undefined} */ (
              CrOnc.getActiveValue(this.networkProperties.IPAddressConfigType));
      if (field == 'IPAddressConfigType') {
        var newIpConfigType =
            /** @type {chrome.networkingPrivate.IPConfigType} */ (value);
        if (newIpConfigType == ipConfigType)
          return;
        onc.IPAddressConfigType = newIpConfigType;
      } else if (field == 'NameServersConfigType') {
        var nsConfigType =
            /** @type {chrome.networkingPrivate.IPConfigType|undefined} */ (
                CrOnc.getActiveValue(
                    this.networkProperties.NameServersConfigType));
        var newNsConfigType =
            /** @type {chrome.networkingPrivate.IPConfigType} */ (value);
        if (newNsConfigType == nsConfigType)
          return;
        onc.NameServersConfigType = newNsConfigType;
      } else if (field == 'StaticIPConfig') {
        if (ipConfigType == CrOnc.IPConfigType.STATIC) {
          let staticIpConfig = this.networkProperties.StaticIPConfig;
          let ipConfigValue = /** @type {!Object} */ (value);
          if (staticIpConfig &&
              this.allPropertiesMatch_(staticIpConfig, ipConfigValue)) {
            return;
          }
        }
        onc.IPAddressConfigType = CrOnc.IPConfigType.STATIC;
        if (!onc.StaticIPConfig) {
          onc.StaticIPConfig =
              /** @type {!chrome.networkingPrivate.IPConfigProperties} */ ({});
        }
        for (let key in value)
          onc.StaticIPConfig[key] = value[key];
      } else if (field == 'NameServers') {
        // If a StaticIPConfig property is specified and its NameServers value
        // matches the new value, no need to set anything.
        let nameServers = /** @type {!Array<string>} */ (value);
        if (onc.NameServersConfigType == CrOnc.IPConfigType.STATIC &&
            onc.StaticIPConfig && onc.StaticIPConfig.NameServers == nameServers) {
          return;
        }
        onc.NameServersConfigType = CrOnc.IPConfigType.STATIC;
        if (!onc.StaticIPConfig) {
          onc.StaticIPConfig =
              /** @type {!chrome.networkingPrivate.IPConfigProperties} */ ({});
        }
        onc.StaticIPConfig.NameServers = nameServers;
      } else {
        console.error('Unexpected change field: ' + field);
        return;
      }
      // setValidStaticIPConfig will fill in any other properties from
      // networkProperties. This is necessary since we update IP Address and
      // NameServers independently.
      CrOnc.setValidStaticIPConfig(onc, this.networkProperties);
      this.setNetworkProperties_(onc);
    },
  
    /**
     * Event triggered when the Proxy configuration element changes.
     * @param {!{detail: {field: string, value: !CrOnc.ProxySettings}}} event
     *     The network-proxy change event.
     * @private
     */
    onProxyChange_: function(event) {
      if (!this.networkProperties)
        return;
      var field = event.detail.field;
      var value = event.detail.value;
      if (field != 'ProxySettings')
        return;
      var onc = this.getEmptyNetworkProperties_();
      CrOnc.setProperty(onc, 'ProxySettings', /** @type {!Object} */ (value));
      this.setNetworkProperties_(onc);
    },
  
    /**
     * @return {boolean} True if the shared message should be shown.
     * @private
     */
    showShared_: function() {
      return this.networkProperties.Source == 'Device' ||
          this.networkProperties.Source == 'DevicePolicy';
    },
  
    /**
     * @return {boolean} True if the AutoConnect checkbox should be shown.
     * @private
     */
    showAutoConnect_: function() {
      return this.networkProperties.Type != CrOnc.Type.ETHERNET &&
          this.isRemembered_();
    },
  
    /**
     * @return {!CrOnc.ManagedProperty|undefined} Managed AutoConnect property.
     * @private
     */
    getManagedAutoConnect_: function() {
      return CrOnc.getManagedAutoConnect(this.networkProperties);
    },
  
    /**
     * @return {boolean} True if the prefer network checkbox should be shown.
     * @private
     */
    showPreferNetwork_: function() {
      // TODO(stevenjb): Resolve whether or not we want to allow "preferred" for
      // networkProperties.Type == CrOnc.Type.ETHERNET.
      return this.isRemembered_();
    },
  
    /**
     * @param {!Array<string>} fields
     * @return {boolean}
     * @private
     */
    hasVisibleFields_: function(fields) {
      for (let key of fields) {
        let value = this.get(key, this.networkProperties);
        if (value !== undefined && value !== '')
          return true;
      }
      return false;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    hasInfoFields_: function() {
      return this.hasVisibleFields_(this.getInfoFields_());
    },
  
    /**
     * @return {!Array<string>} The fields to display in the info section.
     * @private
     */
    getInfoFields_: function() {
      /** @type {!Array<string>} */ var fields = [];
      if (this.networkProperties.Type == CrOnc.Type.CELLULAR) {
        fields.push(
            'Cellular.ActivationState', 'Cellular.RoamingState',
            'RestrictedConnectivity', 'Cellular.ServingOperator.Name');
      }
      if (this.networkProperties.Type == CrOnc.Type.VPN) {
        let vpnType = CrOnc.getActiveValue(this.networkProperties.VPN.Type);
        if (vpnType == 'ThirdPartyVPN') {
          fields.push('VPN.ThirdPartyVPN.ProviderName');
        } else {
          fields.push('VPN.Host', 'VPN.Type');
          if (vpnType == 'OpenVPN')
            fields.push('VPN.OpenVPN.Username');
          else if (vpnType == 'L2TP-IPsec')
            fields.push('VPN.L2TP.Username');
        }
      }
      if (this.networkProperties.Type == CrOnc.Type.WI_FI)
        fields.push('RestrictedConnectivity');
      if (this.networkProperties.Type == CrOnc.Type.WI_MAX) {
        fields.push('RestrictedConnectivity', 'WiMAX.EAP.Identity');
      }
      return fields;
    },
  
    /**
     * @return {!Array<string>} The fields to display in the Advanced section.
     * @private
     */
    getAdvancedFields_: function() {
      /** @type {!Array<string>} */ var fields = [];
      fields.push('MacAddress');
      if (this.networkProperties.Type == CrOnc.Type.CELLULAR) {
        fields.push(
            'Cellular.Carrier', 'Cellular.Family', 'Cellular.NetworkTechnology',
            'Cellular.ServingOperator.Code');
      }
      if (this.networkProperties.Type == CrOnc.Type.WI_FI) {
        fields.push(
            'WiFi.SSID', 'WiFi.BSSID', 'WiFi.Security', 'WiFi.SignalStrength',
            'WiFi.Frequency');
      }
      if (this.networkProperties.Type == CrOnc.Type.WI_MAX)
        fields.push('WiFi.SignalStrength');
      return fields;
    },
  
    /**
     * @return {!Array<string>} The fields to display in the device section.
     * @private
     */
    getDeviceFields_: function() {
      /** @type {!Array<string>} */ var fields = [];
      if (this.networkProperties.Type == CrOnc.Type.CELLULAR) {
        fields.push(
            'Cellular.HomeProvider.Name', 'Cellular.HomeProvider.Country',
            'Cellular.HomeProvider.Code', 'Cellular.Manufacturer',
            'Cellular.ModelID', 'Cellular.FirmwareRevision',
            'Cellular.HardwareRevision', 'Cellular.ESN', 'Cellular.ICCID',
            'Cellular.IMEI', 'Cellular.IMSI', 'Cellular.MDN', 'Cellular.MEID',
            'Cellular.MIN', 'Cellular.PRLVersion');
      }
      return fields;
    },
  
    /**
     * @return {boolean}
     * @private
     */
    showAdvanced_: function() {
      return this.hasAdvancedFields_() || this.hasDeviceFields_() ||
          this.isRememberedOrConnected_();
    },
  
    /**
     * @return {boolean}
     * @private
     */
    hasAdvancedFields_: function() {
      return this.hasVisibleFields_(this.getAdvancedFields_());
    },
  
    /**
     * @return {boolean}
     * @private
     */
    hasDeviceFields_: function() {
      return this.hasVisibleFields_(this.getDeviceFields_());
    },
  
    /**
     * @return {boolean}
     * @private
     */
    hasAdvancedOrDeviceFields_: function() {
      return this.hasAdvancedFields_() || this.hasDeviceFields_();
    },
  
    /**
     * @return {boolean} True if the network section should be shown.
     * @private
     */
    hasNetworkSection_: function() {
      if (this.networkProperties.Type == CrOnc.Type.VPN)
        return false;
      if (this.networkProperties.Type == CrOnc.Type.CELLULAR)
        return true;
      return this.isRememberedOrConnected_();
    },
  
    /**
     * @param {string} type The network type.
     * @return {boolean} True if the network type matches 'type'.
     * @private
     */
    isType_: function(type) {
      return this.networkProperties.Type == type;
    },
  
    /**
     * @return {boolean} True if the Cellular SIM section should be shown.
     * @private
     */
    showCellularSim_: function() {
      if (this.networkProperties.Type != 'Cellular' ||
          !this.networkProperties.Cellular) {
        return false;
      }
      return this.networkProperties.Cellular.Family == 'GSM';
    },
  
    /**
     * @param {!Object} curValue
     * @param {!Object} newValue
     * @return {boolean} True if all properties set in |newValue| are equal to
     *     the corresponding properties in |curValue|. Note: Not all properties
     *     of |curValue| need to be specified in |newValue| for this to return
     *     true.
     * @private
     */
    allPropertiesMatch_: function(curValue, newValue) {
      for (let key in newValue) {
        if (newValue[key] != curValue[key])
          return false;
      }
      return true;
    }
  });
  })();
  