// Copyright 2016, University of Colorado Boulder

/**
 * IO type for Node
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var scenery = require( 'SCENERY/scenery' );

  // phet-io modules
  var assertInstanceOf = require( 'ifphetio!PHET_IO/assertInstanceOf' );
  var BooleanIO = require( 'ifphetio!PHET_IO/types/BooleanIO' );
  var FunctionIO = require( 'ifphetio!PHET_IO/types/FunctionIO' );
  var NullableIO = require( 'ifphetio!PHET_IO/types/NullableIO' );
  var NumberIO = require( 'ifphetio!PHET_IO/types/NumberIO' );
  var ObjectIO = require( 'ifphetio!PHET_IO/types/ObjectIO' );
  var phetioInherit = require( 'ifphetio!PHET_IO/phetioInherit' );
  var VoidIO = require( 'ifphetio!PHET_IO/types/VoidIO' );

  /**
   * IO type for phet/scenery's Node
   * @param {Node} node
   * @param {string} phetioID
   * @constructor
   */
  function NodeIO( node, phetioID ) {
    assert && assertInstanceOf( node, phet.scenery.Node );
    ObjectIO.call( this, node, phetioID );
  }

  phetioInherit( ObjectIO, 'NodeIO', NodeIO, {
    isVisible: {
      returnType: BooleanIO,
      parameterTypes: [],
      implementation: function() {
        return this.instance.visible;
      },
      documentation: 'Gets a Boolean value indicating whether the node can be seen and interacted with'
    },

    setVisible: {
      returnType: VoidIO,
      parameterTypes: [ BooleanIO ],
      implementation: function( visible ) {
        this.instance.visible = visible;
      },
      documentation: 'Set whether the node will be visible (and interactive)'
    },

    setPickable: {
      returnType: VoidIO,
      parameterTypes: [ NullableIO( BooleanIO ) ],
      implementation: function( pickable ) {
        this.instance.pickable = pickable;
      },
      documentation: 'Set whether the node will be pickable (and hence interactive). Pickable can take one of three values:<br><ul>' +
                     '<li>null: pass-through behavior. Nodes with input listeners are pickable, but nodes without input listeners won\'t block events for nodes behind it.</li>' +
                     '<li>false: The node cannot be interacted with, and it blocks events for nodes behind it.</li>' +
                     '<li>true: The node can be interacted with (if it has an input listener).</li></ul>' +
                     'For more about Scenery node pickability, please see <a href="http://phetsims.github.io/scenery/doc/implementation-notes#pickability">http://phetsims.github.io/scenery/doc/implementation-notes#pickability</a>.'
    },

    isPickable: {
      returnType: BooleanIO,
      parameterTypes: [],
      implementation: function() {
        return this.instance.pickable;
      },
      documentation: 'Gets whether the node is pickable (and hence interactive)'
    },

    addPickableListener: {
      returnType: VoidIO,
      parameterTypes: [ FunctionIO( VoidIO, [ BooleanIO ] ) ],
      implementation: function( callback ) {
        var inst = this.instance;
        this.instance.on( 'pickability', function() {
          callback( inst.isPickable() );
        } );
      },
      documentation: 'Adds a listener for when pickability of the node changes'
    },

    addVisibleListener: {
      returnType: VoidIO,
      parameterTypes: [ FunctionIO( VoidIO, [ BooleanIO ] ) ],
      implementation: function( callback ) {
        var inst = this.instance;
        this.instance.on( 'visibility', function() {
          callback( inst.isVisible() );
        } );
      },
      documentation: 'Adds a listener for when visibility of the node changes'
    },

    setOpacity: {
      returnType: VoidIO,
      parameterTypes: [ NumberIO ],
      implementation: function( opacity ) {
        this.instance.opacity = opacity;
      },
      documentation: 'Set opacity between 0-1 (inclusive)'
    },

    setRotation: {
      returnType: VoidIO,
      parameterTypes: [ NumberIO ],
      implementation: function( rotation ) {
        this.instance.rotation = rotation;
      },
      documentation: 'Set the rotation of the node, in radians'
    }
  }, {
    toStateObject: function( node ) {
      assert && assertInstanceOf( node, phet.scenery.Node );
      return {
        visible: node.isVisible(),
        pickable: node.isPickable(),
        opacity: node.opacity
      };
    },
    fromStateObject: function( stateObject ) {
      return stateObject;
    },
    setValue: function( node, fromStateObject ) {
      assert && assertInstanceOf( node, phet.scenery.Node );
      node.visible = fromStateObject.visible;
      node.pickable = fromStateObject.pickable;
      node.opacity = fromStateObject.opacity;
    },
    documentation: 'The base type for graphical and potentially interactive objects.'
  } );

  scenery.register( 'NodeIO', NodeIO );

  return NodeIO;
} );


@@ -237,24 +237,83 @@
  // modules%0A
+  var BooleanProperty = require( 'AXON/BooleanProperty' );%0A
   var scener
@@ -1158,74 +1158,69 @@
  );%0A
+%0A
   
-%7D%0A%0A  phetioInherit( ObjectIO, 'NodeIO', NodeIO, %7B%0A    isV
+  var visibleProperty = new BooleanProperty( node.v
 isible
-:
+,
  %7B%0A 
@@ -1228,192 +1228,115 @@
     
-returnType: BooleanIO,%0A      parameterTypes: %5B%5D,%0A      implementation: function() %7B%0A        return this.instance.visible;%0A      %7D,%0A      documentation: 'Gets a Boolean value indicating
+tandem: node.tandem.createTandem( 'visibleProperty' ),%0A      instanceDocumentation: 'Property that controls
  whe
@@ -1348,25 +1348,30 @@
 the 
-n
+N
 ode 
-can be seen 
+will be visible (
 and 
@@ -1382,127 +1382,50 @@
 ract
-ed with
+ive).
 '%0A    %7D
-,
+ );
 %0A%0A    
-setV
+v
 isible
-: %7B%0A      returnType: VoidIO,%0A      parameterTypes: %5B BooleanIO %5D,%0A      implementation:
+Property.link(
  fun
@@ -1449,30 +1449,19 @@
 %7B%0A      
-  this.instanc
+nod
 e.visibl
@@ -1481,98 +1481,158 @@
     
-  %7D,
+%7D );
 %0A    
-  documentation: 'Set whether the node will be visible (and interactive)'%0A    %7D,%0A
+node.on( 'visibility', function() %7B%0A      visibleProperty.value = node.visible;%0A    %7D );%0A%0A  %7D%0A%0A  phetioInherit( ObjectIO, 'NodeIO', NodeIO, %7B
 %0A   
@@ -3250,405 +3250,8 @@
  %7D,%0A
-%0A    addVisibleListener: %7B%0A      returnType: VoidIO,%0A      parameterTypes: %5B FunctionIO( VoidIO, %5B BooleanIO %5D ) %5D,%0A      implementation: function( callback ) %7B%0A        var inst = this.instance;%0A        this.instance.on( 'visibility', function() %7B%0A          callback( inst.isVisible() );%0A        %7D );%0A      %7D,%0A      documentation: 'Adds a listener for when visibility of the node changes'%0A    %7D,%0A%0A
     
@@ -3860,43 +3860,8 @@
 n %7B%0A
-        visible: node.isVisible(),%0A
     
@@ -4134,54 +4134,8 @@
  );%0A
-      node.visible = fromStateObject.visible;%0A
     

convert Node's visible PhET-iO interface to use Property, https://github.com/phetsims/phet-io/issues/1326