export class XmlRpcHelper {

    _hasActiveX: boolean;

    constructor() {
        try {
            new ActiveXObject('MSXML2.DOMDocument');
            this._hasActiveX = true;
        } catch (e) {
            this._hasActiveX = false;
        }
    }

    /**
     *
     */
    get hasActiveX(): boolean {
        return this._hasActiveX;
    }
    
    /**
     *
     */
    cloneArray(object: any): Array<any> {
        var length = object.length;

        if (length > 0) {
            let result = new Array(length);

            for (let i = 0; i < length; i++) {
                result[i] = object[i];
            }

            return result;
        }

        return [];
    }

    /**
     *
     */
    createMsXmlDocument(): any {
        let doc: any = new ActiveXObject('MSXML2.DOMDocument');

        if (doc) {
            doc.resolveExternals = false;
            doc.validateOnParse = false;

            try {
                doc.setProperty('ProhibitDTD', true);
                doc.setProperty('MaxXMLSize', 2 * 1024);
                doc.setProperty('MaxElementDepth', 256);
            } catch (e) {
                console.log(e);
            }
        }

        return doc;
    }

    /**
     *
     */
    createDocument(rootTag: string, uriNamespace?: string): any {
        if (!rootTag && uriNamespace) {
            throw Error("Can't create document with namespace and no root tag");
        }

        if (this.hasActiveX) {
            var doc = this.createMsXmlDocument();

            if (doc) {
                if (rootTag) {
                      doc.appendChild(doc.createNode(1, rootTag, uriNamespace || ''));
                }

                return doc;
            }
        } else if (document.implementation && document.implementation.createDocument) {
            return document.implementation.createDocument(uriNamespace || '', rootTag || '', null);
        }

        throw Error('Your browser does not support creating new documents');
    }

    /**
     *
     */
    type(object): string {
        return Object.prototype.toString.call(object).slice(8, -1).toLowerCase();
    }

    /**
     *
     */
    createNode(doc: any, nodeName: any, ...children: any[]): any {
        let result = doc.createElement(nodeName);
        
        return result;
    }

    /**
     *
     */
    private appendChild(child: any): void {
        if (this.type(child) == 'object' && child.nodeType != 1) {
            for (let item in child) {
            }
        }
    }

    /**
     *
     */
    generateId(): string {
        return 'xmlrpc-' + (new Date().getTime()) + ' - ' + Math.floor(Math.random() * 1000);
    }

    /**
     *
     */
    loadXml(xml: any): Document {
        if (this.hasActiveX) {
            let doc = this.createMsXmlDocument();
            doc.loadXML(xml);

            return doc;
        } else if (typeof DOMParser != 'undefined') {
            return new DOMParser().parseFromString(xml, 'application/xml');
        }

        throw Error('Your browser does not support loading xml documents');
    }

    /**
     *
     */
    getOwnerDocument(node: any): any {
        return (node.nodeType == 9 ? node : node.ownerDocument || node.document);
    }

    /**
     *
     */
    selectSingleNode(node: any, path: any): any {
        let doc = this.getOwnerDocument(node);

        if (typeof node.selectSingleNode != 'undefined') {
            if (typeof doc.setProperty != 'undefined') {
                doc.setProperty('SelectionLanguage', 'XPath');
            }

            return node.selectSingleNode(path);
        } else if (document.implementation.hasFeature('XPath', '3.0')) {
            let resolver = doc.createNSResolver(doc.documentElement);
            let result = doc.evaluate(path, node, resolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
            
            return result.singleNodeValue;
        }

        return null;
    }

    /**
     *
     */
    getTextContent(node: any, buffer: Array<any>, normalizeWhitespace?: boolean): string {
        const PREDEFINED_TAG_VALUES = { 'IMG': '', 'BR': '\n' };
        
        if (node.nodeName in ['SCRIPT', 'STYLE', 'HEAD', 'IFRAME', 'OBJECT']) {
            // Ignored
        } else if (node.nodeType == 3) {
            if (normalizeWhitespace) {
                buffer.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
            } else {
                buffer.push(node.nodeValue);
            }
        } else if (node.nodeName in PREDEFINED_TAG_VALUES) {
            buffer.push(PREDEFINED_TAG_VALUES[node.nodeName]);
        } else {
            let child = node.firstChild;

            while (child) {
                this.getTextContent(child, buffer, normalizeWhitespace);
                child = child.nextSibling;
            }
        }

        return buffer.join('');
    }

    /**
     *
     */
    selectNodes(node: any, path: any): any {
        let doc = this.getOwnerDocument(node);

        if (typeof node.selectNodes != 'undefined') {
            if (typeof doc.setProperty != 'undefined') {
                doc.setProperty('SelectionLanguage', 'XPath');
            }
             
            return node.selectNodes(path); 
        } else if (document.implementation.hasFeature('XPath', '3.0')) {
            let resolver = doc.createNSResolver(doc.documentElement);
            let nodes = doc.evaluate(path, node, resolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            let results = [];
            let count = nodes.snapshotLength;
             
            for (let i = 0; i < count; i++) {
                results.push(nodes.snapshotItem(i));
            }
             
            return results;
        } else {
             
            return [];
        }
    }
}