import {root} from './root';
import {isArray, isString, isUndef} from './types';
import {trim} from './string';

/**
 * DOM utilities
 */

const doc = root.document;

/**
 * Returns text + text of children of given node
 * @param  {NodeElement} node
 * @return {String}
 */
export const getText = (node) => {
    if (isUndef(node.textContent)) {
        return trim(node.innerText);
    }
    return trim(node.textContent);
};

/**
 * Returns the first text node contained in the supplied node
 * @param  {NodeElement} node node
 * @return {String}
 */
export const getFirstTextNode = (node) => {
    for (let i = 0; i < node.childNodes.length; i++) {
        let n = node.childNodes[i];
        if (n.nodeType === 3) {
            return n.data;
        }
    }
};

/**
 * Creates an html element with given collection of attributes
 * @param  {String} tag html tag name
 * @param  {Array} an undetermined number of arrays containing the with 2
 *                    items, the attribute name and its value ['id','myId']
 * @return {Object}     created element
 */
export const createElm = (...args) => {
    let tag = args[0];
    if (!isString(tag)) {
        return null;
    }

    let el = doc.createElement(tag);
    for (let i = 0; i < args.length; i++) {
        let arg = args[i];

        if (isArray(arg) && arg.length === 2) {
            el.setAttribute(arg[0], arg[1]);
        }
    }
    return el;
};

/**
 * Removes passed node from DOM
 * @param  {DOMElement} node
 * @return {DOMElement} old node reference
 */
export const removeElm = (node) => node.parentNode.removeChild(node);

/**
 * Returns a text node with given text
 * @param  {String} txt
 * @return {Object}
 */
export const createText = (txt) => doc.createTextNode(txt);

/**
 * Determine whether the passed elements is assigned the given class
 * @param {DOMElement} ele DOM element
 * @param {String} cls CSS class name
 * @returns {Boolean}
 */
export const hasClass = (ele, cls) => {
    if (isUndef(ele)) {
        return false;
    }

    if (supportsClassList()) {
        return ele.classList.contains(cls);
    }
    return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
};

/**
 * Adds the specified class to the passed element
 * @param {DOMElement} ele DOM element
 * @param {String} cls CSS class name
 */
export const addClass = (ele, cls) => {
    if (isUndef(ele)) {
        return;
    }

    if (supportsClassList()) {
        ele.classList.add(cls);
        return;
    }

    if (ele.className === '') {
        ele.className = cls;
    }
    else if (!hasClass(ele, cls)) {
        ele.className += ' ' + cls;
    }
};

/**
 * Removes the specified class to the passed element
 * @param {DOMElement} ele DOM element
 * @param {String} cls CSS class name
 */
export const removeClass = (ele, cls) => {
    if (isUndef(ele)) {
        return;
    }

    if (supportsClassList()) {
        ele.classList.remove(cls);
        return;
    }
    let reg = new RegExp('(\\s|^)' + cls + '(\\s|$)', 'g');
    ele.className = ele.className.replace(reg, '');
};

/**
 * Creates and returns an option element
 * @param  {String}  text  option text
 * @param  {String}  value option value
 * @param  {Boolean} isSel whether option is selected
 * @return {Object}        option element
 */
export const createOpt = (text, value, isSel) => {
    let isSelected = isSel ? true : false;
    let opt = isSelected ?
        createElm('option', ['value', value], ['selected', 'true']) :
        createElm('option', ['value', value]);
    opt.appendChild(createText(text));
    return opt;
};

/**
 * Creates and returns a checklist item
 * @param  {String} id  index of check item
 * @param  {String} chkValue  check item value
 * @param  {String} labelText check item label text
 * @param  {Array} extraAttr  array containing attribute name and its value
 * @return {Object}           li DOM element
 */
export const createCheckItem = (id, chkValue, labelText, extraAttr = []) => {
    let li = createElm('li');
    let label = createElm('label', ['for', id]);
    let check = createElm('input',
        ['id', id],
        ['name', id],
        ['type', 'checkbox'],
        ['value', chkValue],
        extraAttr
    );
    label.appendChild(check);
    label.appendChild(createText(labelText));
    li.appendChild(label);
    li.label = label;
    li.check = check;
    return li;
};

/**
 * Returns the element matching the supplied Id
 * @param  {String} id  Element identifier
 * @return {DOMElement}
 */
export const elm = (id) => doc.getElementById(id);

/**
 * Returns list of element matching the supplied tag name
 * @param  {String} tagname  Tag name
 * @return {NodeList}
 */
export const tag = (o, tagname) => o.getElementsByTagName(tagname);

// HTML5 classList API
function supportsClassList() {
    return doc.documentElement.classList;
}
