package me.eater.test.threedom.dom

import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.sequences.shouldHaveCount
import io.kotest.matchers.sequences.shouldHaveSingleElement
import io.kotest.matchers.shouldBe
import me.eater.threedom.dom.Document
import me.eater.threedom.dom.PlainNode
import me.eater.threedom.dom.createNode
import me.eater.threedom.dom.event.DOMTreeUpdate
import me.eater.threedom.dom.event.NodeIDUpdate

class DocumentTest : StringSpec({
    "test insert event" {
        val document = Document()
        var triggered = 0;
        document.on<DOMTreeUpdate.Insert> {
            triggered++
        }

        document.on<DOMTreeUpdate> {
            triggered++
        }

        val newNode = document.createNode<PlainNode>()
        document.addNode(newNode)

        triggered shouldBe 2
    }

    "test move event" {
        val document = Document()


        val newNode = document.createNode<PlainNode>()
        document.addNode(newNode)
        val secondNode = document.createNode<PlainNode>()
        document.addNode(secondNode)
        var triggered = 0

        document.on<DOMTreeUpdate.Move> { (data) ->
            data.newParent shouldBe secondNode
            data.oldParent shouldBe document.root
            data.child shouldBe newNode
            triggered++
        }


        secondNode.addNode(newNode)
        triggered shouldBe 1
    }

    "test remove event" {
        val document = Document()
        var triggered = 0
        document.on<DOMTreeUpdate.Remove> {
            triggered++
        }

        document.on<DOMTreeUpdate> {
            triggered++
        }

        val newNode = document.createNode<PlainNode>()
        document.addNode(newNode)
        document.removeNode(newNode)

        triggered shouldBe 3
    }

    "test byId" {
        val doc = Document()

        val newNode = doc.createNode<PlainNode>()
        val secondNewNode = doc.createNode<PlainNode>()
        val thirdNewNode = doc.createNode<PlainNode>()
        var triggered = 0
        doc.on<NodeIDUpdate> {
            triggered++
        }

        newNode.id = ":3"
        doc.addNode(secondNewNode)
        doc.addNode(thirdNewNode)

        doc.getNodeById(":3") shouldBe null
        thirdNewNode.addNode(newNode)
        doc.getNodeById(":3") shouldBe newNode
        secondNewNode.getNodeById(":3") shouldBe null
        thirdNewNode.getNodeById(":3") shouldBe newNode
        thirdNewNode.removeAll()
        thirdNewNode.getNodeById(":3") shouldBe null
        doc.getNodeById(":3") shouldBe null
        doc.addNode(newNode)
        doc.getNodeById(":3") shouldBe newNode
        newNode.id = ":/"
        doc.getNodeById(":3") shouldBe null
        doc.getNodeById(":/") shouldBe newNode
    }

    "test byClass" {
        val doc = Document()

        val newNode = doc.createNode<PlainNode>()
        val secondNewNode = doc.createNode<PlainNode>()
        val thirdNewNode = doc.createNode<PlainNode>()
        var triggered = 0
        doc.on<NodeIDUpdate> {
            triggered++
        }

        newNode.tagList.add(":3")
        doc.addNode(secondNewNode)
        doc.addNode(thirdNewNode)

        doc.getNodesByTag(":3") shouldHaveCount 0
        thirdNewNode.addNode(newNode)
        doc.getNodesByTag(":3") shouldHaveSingleElement newNode
        secondNewNode.getNodesByTag(":3") shouldHaveCount 0
        thirdNewNode.getNodesByTag(":3") shouldHaveSingleElement newNode
        thirdNewNode.removeAll()
        thirdNewNode.getNodesByTag(":3") shouldHaveCount 0
        doc.getNodesByTag(":3") shouldHaveCount 0
        newNode.tagList.clear()
        newNode.tagList.add(":/")
        doc.addNode(newNode)
        doc.getNodesByTag(":3") shouldHaveCount 0
        doc.getNodesByTag(":/") shouldHaveSingleElement newNode
        newNode.tagList.clear()
        newNode.tagList.add(":3")
        doc.getNodesByTag(":/") shouldHaveCount 0
        doc.getNodesByTag(":3") shouldHaveSingleElement newNode
    }
})
