import {
    implementation,
    Element,
    DEFAULT_DOCUMENT_NAME,
    DEFAULT_NAMESPACE_PREFIX,
    DEFAULT_NAMESPACE_URI,
    NAMESPACE_SEPARATOR,
} from './core'
import { ElementAssembler } from './element'
import { DocumentTypeAssembler } from './doctype'
import { ParentNodeAssembler } from './parentnode'

const DEFAULT_DOCTYPE = null

/**
 * Document DOM node assembler
 */
export class DocumentAssembler extends ParentNodeAssembler {
    /**
     * Set the associated document type declaration node
     * @param {*} doctype node or assembler
     */
    set doctype(doctype) {
        const node = this.node
        const ref = this.doctype
        const child = doctype instanceof DocumentTypeAssembler?
            doctype.node :
            doctype
        if(ref) {
            node.replaceChild(child, ref.node)
        }
        else node.prepend(child)
    }

    /**
     * The associatied document type declaration node
     * @returns {DocumentType}
     */
    get doctype() {
        return this.getInstance(this.node.doctype)
    }

    /**
     * Set the root document element
     * @param {*} documentElement node or assembler or init dictionary
     */
    set documentElement(documentElement) {
        const node = this.node
        const element = this.documentElement
        if(documentElement instanceof ElementAssembler) {
            if(element) {
                node.replaceChild(documentElement.node, element.node)
            }
            else documentElement.parentNode = node
        }
        else if(documentElement instanceof Element) {
            if(element) {
                node.replaceChild(documentElement, element.node)
            }
            else node.appendChild(documentElement)
        }
        else {
            if(element) element.init(documentElement)
            else {
                const { documentElementClass } = this.constructor
                const init = { parentNode : node }
                new documentElementClass(documentElement, init)
            }
        }
    }

    /**
     * The root document element
     * @returns {Element} Element
     */
    get documentElement() {
        return this.getInstance(this.node.documentElement)
    }

    /**
     * Create the specified Document node
     * @param {*} [namespaceURI]
     * @param {*} [qualifiedName]
     * @param {*} [doctype]
     * @returns {Document}
     */
    static create({
        namespaceURI = this.namespaceURI,
        qualifiedName = this.qualifiedName,
        doctype = this.doctype
    } = this) {
        return implementation.createDocument(
            namespaceURI,
            qualifiedName,
            doctype instanceof DocumentTypeAssembler?
                doctype.node :
                doctype)
    }

    /**
     * The default namespace URI
     * @returns {String}
     */
    static get namespaceURI() {
        return DEFAULT_NAMESPACE_URI
    }

    /**
     * The qualified name of the document element node
     * @returns {String}
     */
    static get qualifiedName() {
        const { prefix, localName } = this
        return prefix?
            prefix + NAMESPACE_SEPARATOR + localName :
            localName
    }

    /**
     * The namespace prefix of the document element node
     * @returns {String}
     */
    static get prefix() {
        return DEFAULT_NAMESPACE_PREFIX
    }

    /**
     * The local name of the document element node
     * @returns {String}
     */
    static get localName() {
        return this === DocumentAssembler? DEFAULT_DOCUMENT_NAME : this.name
    }

    /**
     * Doctype redefenition facility
     * @returns {*|null}
     */
    static get doctype() {
        return DEFAULT_DOCTYPE
    }

    /**
     * @returns {Function}
     */
    static get documentElementClass() {
        return ElementAssembler
    }
}

@@ -2292,82 +2292,12 @@
 *%7D %5B
-namespaceURI%5D%0A     * @param %7B*%7D %5BqualifiedName%5D%0A     * @param %7B*%7D %5Bdoctype
+init
 %5D%0A  
@@ -2347,18 +2347,44 @@
  create(
+init) 
 %7B%0A
+        const %7B%0A    
         
@@ -2421,33 +2421,67 @@
 RI,%0A        
-qualified
+    prefix = this.prefix,%0A            local
 Name = this.
@@ -2480,31 +2480,31 @@
  = this.
-qualified
+local
 Name,%0A
+    
         
@@ -2534,19 +2534,243 @@
     
-%7D = this) %7B
+    %7D = init %7C%7C this%0A        let qualifiedName = init && init.qualifiedName%0A        if(!qualifiedName) %7B%0A            qualifiedName = prefix?%0A                prefix + NAMESPACE_SEPARATOR + localName :%0A                localName%0A        %7D
 %0A   

fix create static method