import renderdoc as rd
import rdtest


# Not a direct test, re-used by API-specific tests
class Annotations(rdtest.TestCase):
    internal = True

    def check_resource_annotations(self):
        annot = lambda x: annots.FindChildByKeyPath(x)

        with rdtest.log.auto_section('Resource annotations'):
            res = self.get_resource_by_name('Annotated Image')

            annots = res.annotations
            self.check(annots is not None)

            self.check_eq(annot("basic.bool").type.basetype, rd.SDBasic.Boolean)
            self.check_eq(annot("basic.bool").AsBool(), True)
            
            self.check_eq(annot("basic.int32").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("basic.int32").type.byteSize, 4)
            self.check_eq(annot("basic.int32").AsInt(), -3)
            
            self.check_eq(annot("basic.int64").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("basic.int64").type.byteSize, 8)
            self.check_eq(annot("basic.int64").AsInt(), -3000000000000)
            
            self.check_eq(annot("basic.uint32").type.basetype, rd.SDBasic.UnsignedInteger)
            self.check_eq(annot("basic.uint32").type.byteSize, 4)
            self.check_eq(annot("basic.uint32").AsInt(), 3)
            
            self.check_eq(annot("basic.uint64").type.basetype, rd.SDBasic.UnsignedInteger)
            self.check_eq(annot("basic.uint64").type.byteSize, 8)
            self.check_eq(annot("basic.uint64").AsInt(), 3000000000000)

            self.check_eq(annot("basic.float").type.basetype, rd.SDBasic.Float)
            self.check_eq(annot("basic.float").type.byteSize, 4)
            self.check_eq(annot("basic.float").AsFloat(), 3.25)
            
            self.check_eq(annot("basic.double").type.basetype, rd.SDBasic.Float)
            self.check_eq(annot("basic.double").type.byteSize, 8)
            self.check(rdtest.value_compare(annot("basic.double").AsFloat(), 3.25000000001))

            self.check_eq(annot("basic.string").type.basetype, rd.SDBasic.String)
            self.check_eq(annot("basic.string").AsString(), "Hello, World!")

            self.check_eq(annot("basic.object").type.basetype, rd.SDBasic.Resource)
            obj = self.get_resource(annot("basic.object").AsResourceId())
            self.check_eq(obj.name, "Vertex Buffer")
            
            self.check_eq(annot("basic.object.__offset").AsInt(), 64)
            self.check_eq(annot("basic.object.__size").AsInt(), 32)
            
            self.check(rdtest.value_compare(annot("basic.vec3.1").AsFloat(), 1.1))
            self.check(rdtest.value_compare(annot("basic.vec3.2").AsFloat(), 2.2))
            self.check(rdtest.value_compare(annot("basic.vec3.3").AsFloat(), 3.3))
            
            self.check_eq(annot("deep.nested.path.to.annotation").AsInt(), -4)
            self.check_eq(annot("deep.nested.path.to.annotation2").AsInt(), -5)
            self.check_eq(annot("deep.alternate.path.to.annotation").AsInt(), -6)
            
            self.check(annot("deleteme") is None)
            
            self.check(annot("path.deleted.by.parent") is None)
            self.check(annot("path.deleted.by.parent2") is None)
            self.check(annot("path.deleted") is None)

    def check_command_annotations(self, cmd_buffers: bool):
        annot = lambda x: annots.FindChildByKeyPath(x)

        with rdtest.log.auto_section('Event annotations'):
            action = self.find_action("Start")
            rdtest.log.print(f"Checking {action.customName}")

            annots = action.events[-1].annotations
            self.check(annots is not None)

            # Should not have this annotation, it happened prior to the capture
            self.check(annot("queue.too_old") is None)

            # normal value set on the queue
            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            # this will later be overwritten by the commands, but for now has the queue value
            self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.overwritten").AsInt(), 9999)

            # this is inherited by the commands even as other siblings are modified
            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)

            # this will be deleted
            self.check_eq(annot("command.deleted").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.deleted").AsInt(), 50)

            action = self.find_action("Initial")
            rdtest.log.print(f"Checking {action.customName}")

            annots = action.events[-1].annotations
            self.check(annots is not None)

            # normal value set on the queue
            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            # this has the overwritten value now
            self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.overwritten").AsInt(), -3333)

            # this is inherited by the commands even as other siblings are modified
            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)
            
            # this has now been deleted
            self.check(annot("command.deleted") is None)

            # this is a new command-local value
            self.check_eq(annot("command.new").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.new").AsInt(), 3333)

            # this is a new command-local value
            self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("new.value").AsInt(), 2000)

            action = self.find_action("Pre-Draw")
            rdtest.log.print(f"Checking {action.customName}")

            annots = action.events[-1].annotations
            self.check(annots is not None)

            # normal value set on the queue
            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            # this has the overwritten value now
            self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.overwritten").AsInt(), -3333)

            # this is inherited by the commands even as other siblings are modified
            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)
            
            # this has now been deleted
            self.check(annot("command.deleted") is None)

            # this is a command-local value, which has changed type
            self.check_eq(annot("command.new").type.basetype, rd.SDBasic.Float)
            self.check_eq(annot("command.new").AsFloat(), 1.75)

            # this value has't changed
            self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("new.value").AsInt(), 2000)

            predraw_id = action.eventId

            action = self.find_action("Draw 1")
            rdtest.log.print(f"Checking {action.customName}")

            annots = action.events[-1].annotations
            self.check(annots is not None)

            # should be no events between these
            self.check_eq(predraw_id + 1, action.eventId)

            # this value was deleted and re-added, so it should be present as the new value
            self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("new.value").AsInt(), 4000)

            # normal value set on the queue
            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            # this has the overwritten value now
            self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.overwritten").AsInt(), -3333)

            # this is inherited by the commands even as other siblings are modified
            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)
            
            # this has now been deleted
            self.check(annot("command.deleted") is None)

            # this is a command-local value, which has changed type
            self.check_eq(annot("command.new").type.basetype, rd.SDBasic.Float)
            self.check_eq(annot("command.new").AsFloat(), 1.75)

            self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("new.value").AsInt(), 4000)

            action = self.find_action("Draw 2")
            rdtest.log.print(f"Checking {action.customName}")

            annots = action.events[-1].annotations
            self.check(annots is not None)

            # all of the values should still be present

            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.overwritten").AsInt(), -3333)

            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)
            
            self.check(annot("command.deleted") is None)

            self.check_eq(annot("command.new").type.basetype, rd.SDBasic.Float)
            self.check_eq(annot("command.new").AsFloat(), 1.75)
            
            self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("new.value").AsInt(), 4000)

            action = self.get_last_action()
            rdtest.log.print(f"Checking {action.customName}")
            
            annots = action.events[-1].annotations
            self.check(annots is not None)

            # normal value set on the queue
            self.check_eq(annot("queue.value").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("queue.value").AsInt(), 1000)

            self.check_eq(annot("command.inherited").type.basetype, rd.SDBasic.SignedInteger)
            self.check_eq(annot("command.inherited").AsInt(), 1234)

            # if we have real command buffers, the annotations revert back to where they were on queues
            if cmd_buffers:
                self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
                self.check_eq(annot("command.overwritten").AsInt(), 9999)

                self.check_eq(annot("command.deleted").type.basetype, rd.SDBasic.SignedInteger)
                self.check_eq(annot("command.deleted").AsInt(), 50)

                self.check(annot("command.new") is None)
                self.check(annot("new.value") is None)
            # otherwise they will be the same as on the command buffer
            else:
                self.check_eq(annot("command.overwritten").type.basetype, rd.SDBasic.SignedInteger)
                self.check_eq(annot("command.overwritten").AsInt(), -3333)
                
                self.check(annot("command.deleted") is None)
                
                self.check_eq(annot("command.new").type.basetype, rd.SDBasic.Float)
                self.check_eq(annot("command.new").AsFloat(), 1.75)
                
                self.check_eq(annot("new.value").type.basetype, rd.SDBasic.SignedInteger)
                self.check_eq(annot("new.value").AsInt(), 4000)
