##########################################################################
#
#  Copyright (c) 2013-2016, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import unittest
import subprocess
import os
import imath
import six

import IECore

import Gaffer
import GafferTest

class MetadataTest( GafferTest.TestCase ) :

	class DerivedAddNode( GafferTest.AddNode ) :

		def __init__( self, name="DerivedAddNode" ) :

			GafferTest.AddNode.__init__( self, name )

	IECore.registerRunTimeTyped( DerivedAddNode )

	def testPlugDescription( self ) :

		add = GafferTest.AddNode()

		self.assertEqual( Gaffer.Metadata.value( add["op1"], "description" ), None )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "description", "The first operand" )
		self.assertEqual( Gaffer.Metadata.value( add["op1"], "description" ), "The first operand" )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "description", lambda plug : plug.getName() + " description" )
		self.assertEqual( Gaffer.Metadata.value( add["op1"], "description" ), "op1 description" )

		derivedAdd = self.DerivedAddNode()
		self.assertEqual( Gaffer.Metadata.value( derivedAdd["op1"], "description" ), "op1 description" )

		Gaffer.Metadata.registerValue( self.DerivedAddNode, "op*", "description", "derived class description" )
		self.assertEqual( Gaffer.Metadata.value( derivedAdd["op1"], "description" ), "derived class description" )
		self.assertEqual( Gaffer.Metadata.value( derivedAdd["op2"], "description" ), "derived class description" )

		self.assertEqual( Gaffer.Metadata.value( add["op1"], "description" ), "op1 description" )
		self.assertEqual( Gaffer.Metadata.value( add["op2"], "description" ), None )

	def testArbitraryValues( self ) :

		add = GafferTest.AddNode()

		self.assertEqual( Gaffer.Metadata.value( add, "aKey" ), None )
		self.assertEqual( Gaffer.Metadata.value( add["op1"], "aKey" ), None )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "aKey", "something" )
		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op*", "aKey", "somethingElse" )

		self.assertEqual( Gaffer.Metadata.value( add, "aKey" ), "something" )
		self.assertEqual( Gaffer.Metadata.value( add["op1"], "aKey" ), "somethingElse" )

	def testInheritance( self ) :

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "iKey", "Base class value" )

		derivedAdd = self.DerivedAddNode()
		self.assertEqual( Gaffer.Metadata.value( derivedAdd, "iKey" ), "Base class value" )

		Gaffer.Metadata.registerValue( self.DerivedAddNode, "iKey", "Derived class value" )
		self.assertEqual( Gaffer.Metadata.value( derivedAdd, "iKey" ), "Derived class value" )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "iKey", "Base class plug value" )
		self.assertEqual( Gaffer.Metadata.value( derivedAdd["op1"], "iKey" ), "Base class plug value" )

		Gaffer.Metadata.registerValue( self.DerivedAddNode, "op1", "iKey", "Derived class plug value" )
		self.assertEqual( Gaffer.Metadata.value( derivedAdd["op1"], "iKey" ), "Derived class plug value" )

	def testNodeSignals( self ) :

		add = GafferTest.AddNode()
		multiply = GafferTest.MultiplyNode()

		addCS = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal( add ) )
		multiplyCS = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal( multiply ) )

		legacyNS = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal() )
		legacyPS = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal() )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "k", "something" )

		self.assertEqual( len( multiplyCS ), 0 )
		self.assertEqual( len( addCS ), 1 )
		self.assertEqual( addCS[0], ( add, "k", Gaffer.Metadata.ValueChangedReason.StaticRegistration ) )

		self.assertEqual( len( legacyPS ), 0 )
		self.assertEqual( len( legacyNS ), 1 )
		self.assertEqual( legacyNS[0], ( GafferTest.AddNode.staticTypeId(), "k", None ) )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "k", "somethingElse" )

		self.assertEqual( len( multiplyCS ), 0 )
		self.assertEqual( len( addCS ), 2 )
		self.assertEqual( addCS[1], ( add, "k", Gaffer.Metadata.ValueChangedReason.StaticRegistration ) )

		self.assertEqual( len( legacyPS ), 0 )
		self.assertEqual( len( legacyNS ), 2 )
		self.assertEqual( legacyNS[1], ( GafferTest.AddNode.staticTypeId(), "k", None ) )

	def testPlugSignals( self ) :

		add = GafferTest.AddNode()
		multiply = GafferTest.MultiplyNode()

		addCS = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal( add ) )
		multiplyCS = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal( multiply ) )

		legacyNS = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal() )
		legacyPS = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal() )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "k", "something" )

		self.assertEqual( len( addCS ), 1 )
		self.assertEqual( len( multiplyCS ), 0 )
		self.assertEqual( addCS[0], ( add["op1"], "k", Gaffer.Metadata.ValueChangedReason.StaticRegistration ) )

		self.assertEqual( len( legacyPS ), 1 )
		self.assertEqual( len( legacyNS ), 0 )
		self.assertEqual( legacyPS[0], ( GafferTest.AddNode.staticTypeId(), "op1", "k", None ) )

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "k", "somethingElse" )

		self.assertEqual( len( addCS ), 2 )
		self.assertEqual( len( multiplyCS ), 0 )
		self.assertEqual( addCS[1], ( add["op1"], "k", Gaffer.Metadata.ValueChangedReason.StaticRegistration ) )

		self.assertEqual( len( legacyPS ), 2 )
		self.assertEqual( len( legacyNS ), 0 )
		self.assertEqual( legacyPS[1], ( GafferTest.AddNode.staticTypeId(), "op1", "k", None ) )

	def testSignalsDontExposeInternedStrings( self ) :

		cs = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal() )
		Gaffer.Metadata.registerValue( GafferTest.AddNode, "k", "aaa" )
		self.assertTrue( type( cs[0][1] ) is str )

		cs = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal() )
		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "k", "bbb" )
		self.assertTrue( type( cs[0][1] ) is str )
		self.assertTrue( type( cs[0][2] ) is str )

	def testInstanceMetadata( self ) :

		Gaffer.Metadata.registerValue( GafferTest.AddNode, "imt", "globalNodeValue" )
		Gaffer.Metadata.registerValue( GafferTest.AddNode, "op1", "imt", "globalPlugValue" )

		n = GafferTest.AddNode()

		self.assertEqual( Gaffer.Metadata.value( n, "imt" ), "globalNodeValue" )
		self.assertEqual( Gaffer.Metadata.value( n["op1"], "imt" ), "globalPlugValue" )

		Gaffer.Metadata.registerValue( n, "imt", "instanceNodeValue" )
		Gaffer.Metadata.registerValue( n["op1"], "imt", "instancePlugValue" )

		self.assertEqual( Gaffer.Metadata.value( n, "imt" ), "instanceNodeValue" )
		self.assertEqual( Gaffer.Metadata.value( n["op1"], "imt" ), "instancePlugValue" )

		Gaffer.Metadata.registerValue( n, "imt", None )
		Gaffer.Metadata.registerValue( n["op1"], "imt", None )

		self.assertEqual( Gaffer.Metadata.value( n, "imt" ), None )
		self.assertEqual( Gaffer.Metadata.value( n["op1"], "imt" ), None )

	def testInstanceMetadataUndo( self ) :

		s = Gaffer.ScriptNode()
		s["n"] = GafferTest.AddNode()

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), None )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), None )

		with Gaffer.UndoScope( s ) :
			Gaffer.Metadata.registerValue( s["n"], "undoTest", "instanceNodeValue" )
			Gaffer.Metadata.registerValue( s["n"]["op1"], "undoTest", "instancePlugValue" )

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), "instanceNodeValue" )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), "instancePlugValue" )

		with Gaffer.UndoScope( s ) :
			Gaffer.Metadata.registerValue( s["n"], "undoTest", "instanceNodeValue2" )
			Gaffer.Metadata.registerValue( s["n"]["op1"], "undoTest", "instancePlugValue2" )

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), "instanceNodeValue2" )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), "instancePlugValue2" )

		s.undo()

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), "instanceNodeValue" )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), "instancePlugValue" )

		s.undo()

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), None )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), None )

		s.redo()

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), "instanceNodeValue" )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), "instancePlugValue" )

		s.redo()

		self.assertEqual( Gaffer.Metadata.value( s["n"], "undoTest" ), "instanceNodeValue2" )
		self.assertEqual( Gaffer.Metadata.value( s["n"]["op1"], "undoTest" ), "instancePlugValue2" )

	def testInstanceMetadataSignals( self ) :

		n = GafferTest.AddNode()

		ncs = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal( n ) )
		pcs = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal( n ) )

		legacyNCS = GafferTest.CapturingSlot( Gaffer.Metadata.nodeValueChangedSignal() )
		legacyPCS = GafferTest.CapturingSlot( Gaffer.Metadata.plugValueChangedSignal() )

		Gaffer.Metadata.registerValue( n, "signalTest", 1 )
		Gaffer.Metadata.registerValue( n["op1"], "signalTest", 1 )

		self.assertEqual( len( ncs ), 1 )
		self.assertEqual( len( pcs ), 1 )
		self.assertEqual( ncs[0], ( n, "signalTest", Gaffer.Metadata.ValueChangedReason.InstanceRegistration ) )
		self.assertEqual( pcs[0], ( n["op1"], "signalTest", Gaffer.Metadata.ValueChangedReason.InstanceRegistration ) )

		self.assertEqual( len( legacyNCS ), 1 )
		self.assertEqual( len( legacyPCS ), 1 )
		self.assertEqual( legacyNCS[0], ( GafferTest.AddNode.staticTypeId(), "signalTest", n ) )
		self.assertEqual( legacyPCS[0], ( GafferTest.AddNode.staticTypeId(), "op1", "signalTest", n["op1"] ) )

		Gaffer.Metadata.registerValue( n, "signalTest", 1 )
		Gaffer.Metadata.registerValue( n["op1"], "signalTest", 1 )

		self.assertEqual( len( ncs ), 1 )
		self.assertEqual( len( pcs ), 1 )
		self.assertEqual( len( legacyNCS ), 1 )
		self.assertEqual( len( legacyPCS ), 1 )

		Gaffer.Metadata.registerValue( n, "signalTest", 2 )
		Gaffer.Metadata.registerValue( n["op1"], "signalTest", 2 )

		self.assertEqual( len( ncs ), 2 )
		self.assertEqual( len( pcs ), 2 )
		self.assertEqual( ncs[1], ( n, "signalTest", Gaffer.Metadata.ValueChangedReason.InstanceRegistration ) )
		self.assertEqual( pcs[1], ( n["op1"], "signalTest", Gaffer.Metadata.ValueChangedReason.InstanceRegistration ) )

		self.assertEqual( len( legacyNCS ), 2 )
		self.assertEqual( len( legacyPCS ), 2 )
		self.assertEqual( legacyNCS[1], ( GafferTest.AddNode.staticTypeId(), "signalTest", n ) )