import { NO_PARENT_INDEX } from './const'
import { NodeAssembler } from './node'

const { prototype : { indexOf } } = Array

/**
 * @see {@link https://www.w3.org/TR/dom/#interface-childnode}
 */
export class ChildNodeAssembler extends NodeAssembler {
    /**
     * @param {NodeAssembler|Node|String} items
     */
    after(...items) {
        this.node.after(...items.map(item => {
            return this.constructor.getNodeOf(item)
        }))
    }

    /**
     * @param {NodeAssembler|Node|String} items
     */
    before(...items) {
        this.node.before(...items.map(item => {
            return this.constructor.getNodeOf(item)
        }))
    }

    /**
     * @param {NodeAssembler|Node|String} items
     */
    replaceWith(...items) {
        this.node.replaceWith(...items.map(item => {
            return this.constructor.getNodeOf(item)
        }))
    }

    /**
     * Remove node from tree
     */
    remove() {
        // this.node.remove() // fixme?
        if(this.parentNode) {
            this.parentNode.removeChild(this.node)
        }
    }

    /**
     * Get the node index among its sibling nodes or -1 if it has no parent
     * @returns {Number}
     */
    get index() {
        const parentNode = this.node.parentNode
        return parentNode?
            indexOf.call(parentNode.childNodes, this.node) :
            NO_PARENT_INDEX
    }

    /**
     * Get a next sibling of the node
     * @returns {ChildNodeAssembler|null|*}
     */
    get nextSibling() {
        return this.getInstanceOf(this.node.nextSibling, ChildNodeAssembler)
    }

    /**
     * Get a previous sibling of the node
     * @returns {ChildNodeAssembler|null|*}
     */
    get previousSibling() {
        return this.getInstanceOf(this.node.previousSibling, ChildNodeAssembler)
    }

    /**
     * @param {ElementAssembler} parentElement
     */
    set parentElement(parentElement) {
        parentElement.appendChild(this.node)
    }

    /**
     * @returns {ElementAssembler}
     */
    get parentElement() {
        return this.getInstanceOf(this.node.parentElement)
    }

    /**
     * Append the node to the specified parent
     * @param {ParentNodeAssembler|*} parentNode
     */
    set parentNode(parentNode) {
        parentNode.appendChild(this.node)
    }

    /**
     * Get the parent node
     * @returns {ParentNodeAssembler|*}
     */
    get parentNode() {
        return this.getInstanceOf(this.node.parentNode)
    }
}

@@ -323,32 +323,77 @@
 ter(...items) %7B%0A
+        const constructor = this.constructor%0A
         this.nod
@@ -425,34 +425,8 @@
  =%3E 
-%7B%0A            return this.
 cons
@@ -444,34 +444,24 @@
 NodeOf(item)
-%0A        %7D
 ))%0A    %7D%0A%0A  
@@ -537,32 +537,77 @@
 ore(...items) %7B%0A
+        const constructor = this.constructor%0A
         this.nod
@@ -640,34 +640,8 @@
  =%3E 
-%7B%0A            return this.
 cons
@@ -659,35 +659,119 @@
 NodeOf(item)
+))
 %0A    
-    %7D)
+%7D%0A%0A    /**%0A     * Remove node from tree%0A     */%0A    remove() %7B%0A        this.node.remove(
 )%0A    %7D%0A%0A   
@@ -851,32 +851,77 @@
 ith(...items) %7B%0A
+        const constructor = this.constructor%0A
         this.nod
@@ -959,34 +959,8 @@
  =%3E 
-%7B%0A            return this.
 cons
@@ -986,218 +986,10 @@
 tem)
-%0A        %7D))%0A    %7D%0A%0A    /**%0A     * Remove node from tree%0A     */%0A    remove() %7B%0A        // this.node.remove() // fixme?%0A        if(this.parentNode) %7B%0A            this.parentNode.removeChild(this.node)%0A        %7D
+))
 %0A   
@@ -1475,36 +1475,16 @@
 tSibling
-, ChildNodeAssembler
 )%0A    %7D%0A
@@ -1677,28 +1677,8 @@
 ling
-, ChildNodeAssembler
 )%0A  
@@ -1970,16 +1970,51 @@
 tElement
+, this.constructor.elementAssembler
 )%0A    %7D%0A

use DOM ChildNode.remove method, refactoring