// Copyright 2014-2020, University of Colorado Boulder

/**
 * ABSwitch is a control for switching between 2 choices, referred to as 'A' & 'B'.
 * Choice 'A' is to the left of the switch, choice 'B' is to the right.
 * This decorates ToggleSwitch with labels.
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */

import InstanceRegistry from '../../phet-core/js/documentation/InstanceRegistry.js';
import merge from '../../phet-core/js/merge.js';
import PressListener from '../../scenery/js/listeners/PressListener.js';
import Line from '../../scenery/js/nodes/Line.js';
import Node from '../../scenery/js/nodes/Node.js';
import PhetioObject from '../../tandem/js/PhetioObject.js';
import Tandem from '../../tandem/js/Tandem.js';
import sun from './sun.js';
import SunConstants from './SunConstants.js';
import ToggleSwitch from './ToggleSwitch.js';

// constants

// Uses opacity as the default method of indicating whether a {Node} label is {boolean} enabled.
const DEFAULT_SET_ENABLED = ( label, enabled ) => {
  label.opacity = enabled ? 1.0 : SunConstants.DISABLED_OPACITY;
};

class ABSwitch extends Node {

  /**
   * @param {Property.<*>} property stores the value of the current choice
   * @param {*} valueA value for choice 'A'
   * @param {Node} labelA label for choice 'A'
   * @param {*} valueB value for choice 'B'
   * @param {Node} labelB label for choice 'B'
   * @param {Object} [options]
   */
  constructor( property, valueA, labelA, valueB, labelB, options ) {

    // PhET-iO requirements
    assert && assert( labelA.tandem, 'labelA must have a tandem' );
    assert && assert( labelB.tandem, 'labelB must have a tandem' );

    // default option values
    options = merge( {

      // options passed to ToggleSwitch
      toggleSwitchOptions: null,

      // {number} space between labels and switch
      xSpacing: 8,

      // if true, centerX will be at the centerX of the ToggleSwitch
      centerOnButton: false,

      // {function( Node, boolean )} method of making the labels look disabled
      setEnabled: DEFAULT_SET_ENABLED,

      // phet-io
      tandem: Tandem.REQUIRED
    }, options );

    super();

    PhetioObject.mergePhetioComponentOptions( { visibleProperty: { phetioFeatured: true } }, options );

    const toggleSwitch = new ToggleSwitch( property, valueA, valueB, merge( {
      tandem: options.tandem.createTandem( 'toggleSwitch' )
    }, options.toggleSwitchOptions ) );

    // rendering order
    this.addChild( toggleSwitch );
    this.addChild( labelA );
    this.addChild( labelB );

    // layout: 'A' on the left, 'B' on the right
    labelA.right = toggleSwitch.left - options.xSpacing;
    labelA.centerY = toggleSwitch.centerY;
    labelB.left = toggleSwitch.right + options.xSpacing;
    labelB.centerY = toggleSwitch.centerY;

    // add a horizontal strut that will cause the 'centerX' of this node to be at the center of the button
    if ( options.centerOnButton ) {
      const additionalWidth = Math.abs( labelA.width - labelB.width );
      const strut = new Line( 0, 0, this.width + additionalWidth, 0 );
      this.addChild( strut );
      strut.moveToBack();
      if ( labelA.width < labelB.width ) {
        strut.left = labelA.left - ( additionalWidth / 2 );
      }
      else {
        strut.left = labelA.left;
      }
    }

    const propertyListener = value => {
      if ( options.setEnabled ) {
        options.setEnabled( labelA, value === valueA );
        options.setEnabled( labelB, value === valueB );
      }
    };
    property.link( propertyListener ); // unlink on dispose

    // No need to dispose because we own the toggleSwitch
    toggleSwitch.enabledProperty.link( enabled => {
      if ( options.setEnabled ) {

        // When disabled, make both look disabled
        if ( !enabled ) {
          options.setEnabled( labelA, false );
          options.setEnabled( labelB, false );
        }
        else {
          options.setEnabled( labelA, property.value === valueA );
          options.setEnabled( labelB, property.value === valueB );
        }
      }
      this.pickable = enabled;
    } );

    // click on labels to select
    const pressListenerA = new PressListener( {
      release: () => { property.value = valueA; },
      tandem: labelA.tandem.createTandem( 'pressListener' )
    } );
    labelA.addInputListener( pressListenerA ); // removeInputListener on dispose

    const pressListenerB = new PressListener( {
      release: () => { property.value = valueB; },
      tandem: labelB.tandem.createTandem( 'pressListener' )
    } );
    labelB.addInputListener( pressListenerB ); // removeInputListener on dispose

    // @private - for dispose
    this.disposeABSwitch = () => {
      property.unlink( propertyListener );
      toggleSwitch.dispose();
      labelA.removeInputListener( pressListenerA );
      labelB.removeInputListener( pressListenerB );
      pressListenerA.dispose();
      pressListenerB.dispose();
    };

    this.mutate( options );

    // support for binder documentation, stripped out in builds and only runs when ?binder is specified
    assert && phet.chipper.queryParameters.binder && InstanceRegistry.registerDataURL( 'sun', 'ABSwitch', this );
  }

  /**
   * Make eligible for garbage collection.
   * @public
   * @override
   */
  dispose() {
    this.disposeABSwitch();
    super.dispose();
  }
}

sun.register( 'ABSwitch', ABSwitch );
export default ABSwitch;
@@ -839,16 +839,60 @@
 tch.js';
+%0Aimport UIComponent from './UIComponent.js';
 %0A%0A// con
@@ -1117,16 +1117,48 @@
 TY;%0A%7D;%0A%0A
+/**%0A * @mixes %7BUIComponent%7D%0A */%0A
 class AB
@@ -1839,12 +1839,169 @@
 ns: 
-null
+%7B%0A        enabledPropertyOptions: %7B%0A          phetioFeatured: false // ABSwitch has an enabledProperty that is preferred to the sub-component's%0A        %7D%0A      %7D
 ,%0A%0A 
@@ -2468,24 +2468,68 @@
 options );%0A%0A
+    this.initializeUIComponent( options );%0A%0A
     const to
@@ -3842,541 +3842,8 @@
 se%0A%0A
-    // No need to dispose because we own the toggleSwitch%0A    toggleSwitch.enabledProperty.link( enabled =%3E %7B%0A      if ( options.setEnabled ) %7B%0A%0A        // When disabled, make both look disabled%0A        if ( !enabled ) %7B%0A          options.setEnabled( labelA, false );%0A          options.setEnabled( labelB, false );%0A        %7D%0A        else %7B%0A          options.setEnabled( labelA, property.value === valueA );%0A          options.setEnabled( labelB, property.value === valueB );%0A        %7D%0A      %7D%0A      this.pickable = enabled;%0A    %7D );%0A%0A
     
@@ -5087,19 +5087,53 @@
 ();%0A  %7D%0A
-
 %7D%0A%0A
+UIComponent.mixInto( ABSwitch );%0A%0A
 sun.regi

add enabledProperty to ABSwitch instead of using the toggleSwitch, https://github.com/phetsims/sun/issues/571