'use strict';

var CASE_SENSITIVE_TAGS = require('./constants').CASE_SENSITIVE_TAGS
var CASE_SENSITIVE_TAGS_LOWERCASE = CASE_SENSITIVE_TAGS.map(function(tag) {
    return tag.toLowerCase();
});

/**
 * Format DOM attributes to an associative array.
 *
 * @param  {NamedNodeMap} - The list of attributes.
 * @return {Object}       - The object of attributes.
 */
function formatAttributes(attributes) {
    var result = {};
    var attribute;

    // NamedNodeMap is array-like
    for (var i = 0, len = attributes.length; i < len; i++) {
        attribute = attributes[i];
        result[attribute.name] = attribute.value;
    }

    return result;
}

/**
 * Format the browser DOM nodes to mimic the output of `htmlparser2.parseDOM()`.
 *
 * @param  {NodeList} nodes        - The DOM nodes.
 * @param  {Object}   [parentObj]  - The formatted parent node.
 * @param  {String}   [directive]  - The directive.
 * @return {Object}                - The formatted DOM object.
 */
function formatDOM(nodes, parentObj, directive) {
    parentObj = parentObj || null;

    var result = [];
    var node;
    var prevNode;
    var nodeObj;

    // NodeList is array-like
    for (var i = 0, len = nodes.length; i < len; i++) {
        node = nodes[i];
        // reset
        nodeObj = {
            next: null,
            prev: result[i - 1] || null,
            parent: parentObj
        };

        // set the next node for the previous node (if applicable)
        prevNode = result[i - 1];
        if (prevNode) {
            prevNode.next = nodeObj;
        }

        // set the node name if it's not "#text" or "#comment"
        // e.g., "div"
        if (node.nodeName.indexOf('#') !== 0) {
            var nodeName = node.nodeName.toLowerCase();
            var caseSensitiveTagIndex = CASE_SENSITIVE_TAGS_LOWERCASE.indexOf(nodeName);
            // fix case if element is case-sensitive SVG
            if (caseSensitiveTagIndex !== -1) {
                nodeName = CASE_SENSITIVE_TAGS[caseSensitiveTagIndex];
            }
            nodeObj.name = nodeName;

            // also, nodes of type "tag" have "attribs"
            nodeObj.attribs = {}; // default
            if (node.attributes && node.attributes.length) {
                nodeObj.attribs = formatAttributes(node.attributes);
            }
        }

        // set the node type
        // e.g., "tag"
        switch (node.nodeType) {
            // 1 = element
            case 1:
                if (nodeObj.name === 'script' || nodeObj.name === 'style') {
                    nodeObj.type = nodeObj.name;
                } else {
                    nodeObj.type = 'tag';
                }
                // recursively format the children
                nodeObj.children = formatDOM(node.childNodes, nodeObj);
                break;
                // 2 = attribute
                // 3 = text
            case 3:
                nodeObj.type = 'text';
                nodeObj.data = node.nodeValue;
                break;
                // 8 = comment
            case 8:
                nodeObj.type = 'comment';
                nodeObj.data = node.nodeValue;
                break;
            default:
                break;
        }

        result.push(nodeObj);
    }

    if (directive) {
        result.unshift({
            name: directive.substring(0, directive.indexOf(' ')).toLowerCase(),
            data: directive,
            type: 'directive',
            next: result[0] ? result[0] : null,
            prev: null,
            parent: parentObj
        });

        if (result[1]) {
            result[1].prev = result[0];
        }
    }

    return result;
}

/**
 * Detect IE with or without version.
 *
 * @param  {Number} [version] - The IE version to detect.
 * @return {Boolean}          - Whether IE or the version has been detected.
 */
function isIE(version) {
    if (version) {
        return document.documentMode === version;
    }
    return /(MSIE |Trident\/|Edge\/)/.test(navigator.userAgent);
}

/**
 * Export utilities.
 */
module.exports = {
    formatAttributes: formatAttributes,
    formatDOM: formatDOM,
    isIE: isIE
};

@@ -641,24 +641,642 @@
  result;%0A%7D%0A%0A
+/**%0A * Correct the case of tag names. For case-sensitive SVG tags, return the proper%0A * tag name; for all other tags, return the lowercased name.%0A *%0A * @param  %7BString%7D tagName - The tag name to correct.%0A * @return %7BString%7D         - The corrected tag name.%0A */%0Afunction fixTagCase(tagName) %7B%0A    var correctedName = tagName.toLowerCase();%0A    var caseSensitiveTagIndex = CASE_SENSITIVE_TAGS_LOWERCASE.indexOf(correctedName);%0A    // fix case if element is case-sensitive SVG%0A    if (caseSensitiveTagIndex !== -1) %7B%0A        correctedName = CASE_SENSITIVE_TAGS%5BcaseSensitiveTagIndex%5D;%0A    %7D%0A    return correctedName;%0A%7D%0A%0A
 /**%0A * Forma
@@ -2321,366 +2321,47 @@
     
-var nodeName = node.nodeName.toLowerCase();%0A            var caseSensitiveTagIndex = CASE_SENSITIVE_TAGS_LOWERCASE.indexOf(nodeName);%0A            // fix case if element is case-sensitive SVG%0A            if (caseSensitiveTagIndex !== -1) %7B%0A                nodeName = CASE_SENSITIVE_TAGS%5BcaseSensitiveTagIndex%5D;%0A            %7D%0A            nodeObj.name = 
+nodeObj.name = fixTagCase(node.
 nodeName
 ;%0A%0A 
@@ -2356,18 +2356,18 @@
 nodeName
+)
 ;
-%0A
 %0A       

Extract case correction code into a function