function xmlToString(xmlData, beautify) { 
    var xmlString;
    //IE
    if (window.ActiveXObject){
        xmlString = xmlData.xml;
    }
    // code for Mozilla, Firefox, Opera, etc.
    else {
        xmlString = new XMLSerializer().serializeToString(xmlData);
        xmlString = beautify ? vkbeautify.xml(xmlString) : xmlString;
    }
    return xmlString;
}  

function getXMLDoc(xmlString){
    return $.parseXML(xmlString);
}

function xmlToObject(xmlString){
    var xmlDoc = getXMLDoc(xmlString);
    return $(xmlDoc);
}

function getChildElement(parentObj, elementName) {
    if(!parentObj) {
       return null; 
    }
    
    var childNodes = parentObj.childNodes;
    if(!childNodes){
        return null;
    }
    
    for(var i=0; i<childNodes.length; i++){
        if(childNodes[i].nodeName == elementName){
            return childNodes[i];
        }
    }
    
    return null;
}

function getChildElements(parentObj, elementName) {
    if(!parentObj) {
       return []; 
    }
    
    var childNodes = parentObj.childNodes;
    var children = [];
    
    if(childNodes){
        for(var i=0; i<childNodes.length; i++){
            if(childNodes[i].nodeName == elementName){
                children.push(childNodes[i]);
            }
        }
    }
    
    return children;
}

function getNonTextChildren(parentObj){
    var array = [];

    if(parentObj.childNodes && parentObj.childNodes.length){
        for(var i=0; i<parentObj.childNodes.length; i++){
            var childNode = parentObj.childNodes[i];
            if(childNode.nodeName == '#text'){
                if(childNode.childNodes[0] && childNode.childNodes[0].nodeName != '#text'){
                    array.push(childNode.childNodes[0]);
                }
            }
            else {
                array.push(childNode);
            }
        }
    }

    return array;
}

function removeChild(parentObj, childName){
    if(parentObj){
        for(var i=0; i<parentObj.childNodes.length; i++){
            if(parentObj.childNodes[i].nodeName == childName){
                parentObj.removeChild(parentObj.childNodes[i]);
                return;
            }
        }
    }
}

function removeChildAtIndex(parentObj, childName, index){
    if(parentObj){
        var curIndex = 0;

        for(var i=0; i<parentObj.childNodes.length; i++) {
            if(parentObj.childNodes[i].nodeName == childName){
                if(curIndex == index){
                    parentObj.removeChild(parentObj.childNodes[i]);
                    return;
                }
                curIndex++;
            }
        }
    }
}

function createChild(parentObj, childName, xmlDoc, forceCreation){
    if(!forceCreation){
        var obj = getChildElement(parentObj, childName);
        if(obj) {
            return obj;    
        }
    }

    var newElem = xmlDoc.createElement(childName);
    return parentObj.appendChild(newElem);
}

function removeAllChildren(parentElement) {
    while (parentElement.firstChild) {
        parentElement.removeChild(parentElement.firstChild);
    }
}

function addNode(name, value, parentObj, xmlDoc, forceCreation){
    var obj = getChildElement(parentObj, name);
       
    if(!obj || forceCreation){
        obj = createChild(parentObj, name, xmlDoc, forceCreation)
    } else {
        removeAllChildren(obj);
    }
    
    obj.appendChild(xmlDoc.createTextNode(value));
    return obj;
}

function setNodeValue(element, value, xmlDoc){
    removeAllChildren(element);
    element.appendChild(xmlDoc.createTextNode(value));
}

/**
 * If node name not specified, it assumes that parentObj is the node object.
 */
function getNodeValue(parentObj, nodeName, defaultValue){
    var nodeObj = nodeName ? getChildElement(parentObj, nodeName) : parentObj;

    if(nodeObj && nodeObj.childNodes[0]){
        return nodeObj.childNodes[0].nodeValue;
    }
    
    return defaultValue;
}

function getNodeIntValue(parentObj, nodeName, defaultValue){
    return parseInt(getNodeValue(parentObj, nodeName, defaultValue));
}

function getNodeFloatValue(parentObj, nodeName, defaultValue){
    return parseFloat(getNodeValue(parentObj, nodeName, defaultValue));
}

function getNodeBooleanValue(parentObj, nodeName, defaultValue){
    var value = getNodeValue(parentObj, nodeName, defaultValue);
    
    return value === true || value === 'true';
}

function attributeExists(object, attributeName){
    return object.attributes[attributeName] ? true : false;
}

function getAttrValue(object, attributeName, convertBooleans) {
    if(!object) {
        return convertBooleans ? false : null;
    }
    
    var attribute = object.attributes[attributeName];
    
    if(!attribute || !valueFilled(attribute.value)){
        return null;
    } else if(convertBooleans){
        return attribute.value == 'true';
    }
    
   return attribute.value;
}

function getAttrStringValue(object, attributeName, defaultValue) {
    var value = getAttrValue(object, attributeName, false);
    
    if(value) {
        return value+"";
    }
    
    return defaultValue+"";
}

function getAttrIntValue(object, attributeName, defaultValue) {
    var value = getAttrValue(object, attributeName, false);
    
    if(value) {
        return parseInt(value);
    }
    
    return parseInt(defaultValue);
}

function getAttrFloatValue(object, attributeName, defaultValue) {
    var value = getAttrValue(object, attributeName, false);
    
    if(value) {
        return parseFloat(value);
    }
    
    return parseFloat(defaultValue);
}

function getAttrBooleanValue(object, attributeName, defaultValue) {
    var value = getAttrValue(object, attributeName, false);
    
    if(value) {
        return value == 'true';
    }
    
    return defaultValue;
}

function correctAttrValue(value, convertBooleans){
    var newValue;

    if(!value || value.value == 'not set'){
        newValue = null;
    }
    else {
        newValue = value.value;
    }

    if(convertBooleans){
        return newValue == 'true';
    }

    return newValue;
}

function parseSettingsMethods(methodsObjs) {
    var methods = [];

    if(!methodsObjs) {
        return methods;
    }   
    
    var methodObjs = getChildElements(methodsObjs, "Method");
    if(!methodObjs) {
        console.error("No methods found.");
        return methods;
    }

    for(var i=0; i<methodObjs.length; i++) {
        var methodElem = methodObjs[i]; 
        methods.push(parseMethodSettings(methodElem));
    }

    return methods;
}

function parseMethodSettings(methodElem){
    if(!methodElem) return { method: 'None', params: [] };
    else return {
        method: correctAttrValue(methodElem.attributes["type"]),
        params: parseParameters(methodElem),
        use: getAttrBooleanValue(methodElem, 'use', false)
    };
}

function parseParameters(methodElem) {
    var params = [];
    
    if(methodElem) {
        var paramsElem = getChildElement(methodElem, 'Params');
        var paramElems = getChildElements(paramsElem, 'Param');

        for(var p=0; p<paramElems.length; p++){
            var paramElem = paramElems[p];
            var key = correctAttrValue(paramElem.attributes["key"]);
            var value = paramElem.childNodes[0] ? paramElem.childNodes[0].nodeValue : '';

            params.push({
                key: key,
                value: value
            });
        }
    }
    
    return params;
}

function elementIs(elementObj, attributeName, attributeValue){
    var attrValue = getAttrValue(elementObj, attributeName, false);
    if(attrValue == attributeValue) return true;
}

function getChildByAttribute(parentObj, childName, attrName, attrValue){
    if(!parentObj) return null;

    var children = getChildElements(parentObj, childName);

    for(var i=0; i<children.length; i++){
        if(elementIs(children[i], attrName, attrValue)) return children[i];
    }

    return null;
}

function getTasks(projectObj) {
    if(!projectObj) {
        return [];
    }

    var tasksObj = getChildElement(projectObj, 'Tasks');
    return getChildElements(tasksObj, 'Task');
}

function getTask(projectObj, task) {
    if(!projectObj) {
        return null;
    }

    var tasksObj = getChildElement(projectObj, 'Tasks');
    var taskObjs = getChildElements(tasksObj, 'Task');

    for(var i=0; i<taskObjs.length; i++) {
        var taskObj = taskObjs[i]; 

        var type2 = getAttrValue(taskObj, 'type', false);
        var name2 = getAttrValue(taskObj, 'name', false);

        if(type2 && name2 && (task.type==type2 || task.typeOrig==type2) && task.name==name2) {
            return taskObj;
        }
    }

    return null;
}

function getTaskTemplate(AppService, SQConstants, taskType, taskName){
    var config = xmlToString(getTask(AppService.getProjectConfig(), {
        type: taskType,
        name: taskName
    }));

    let elTaskCloned = xmlToObject(config).find("Task")[0];
    let elSettings = SQConstants.getTaskConfig(AppService.getProject(), getAttrStringValue(elTaskCloned, "taskXMLFile"), true);
    elTaskCloned.appendChild(elSettings);

    return elTaskCloned;
}

function getTaskByXMLFile(projectObj, taskXMLFile){
    var elTasks = getChildElement(projectObj, 'Tasks');
    var taskObjs = getChildElements(elTasks, "Task");

    for(var i=0; i<taskObjs.length; i++) {
        var taskObj = taskObjs[i]; 

        var xmlFileName = getAttrValue(taskObj, 'taskXMLFile', null);

        if(xmlFileName && xmlFileName === taskXMLFile) {
            return taskObj;
        }
    }

    return null;
}

function findParentElement(currentObj, parentName){
    var node = currentObj.parentNode;
    while(node && node.nodeName != parentName){
        node = currentObj.parentNode;
    }

    if(node.nodeName == parentName){
        return $(node);
    }
    return null;
}

function getHTMLContent(htmlString){
    var element = xmlToObject(htmlString);
    return element[0].firstChild.innerHTML;
}