',{class:"red-ui-search-result-node-id"}).html(node.id).appendTo(contentDiv);
        //             }
        //
        //         });
        //
        //         var statsInfo = '
':'');
        //         stats.html(statsInfo);
        //
        //
        //
        //         //
        //         //
        //         //
        //         // var node = object.node;
        //         // var realNode = RED.nodes.node(node.id);
        //         // var def = RED.nodes.getType(object.node.type)||{};
        //         // var l = "";
        //         // if (def && def.label && realNode) {
        //         //     l = def.label;
        //         //     try {
        //         //         l = (typeof l === "function" ? l.call(realNode) : l);
        //         //     } catch(err) {
        //         //         console.log("Definition error: "+node.type+".label",err);
        //         //     }
        //         // }
        //         // l = l||node.label||node.name||node.id||"";
        //         // console.log(node);
        //         // var div = $('
').appendTo(container);
        //         // div.html(l);
        //     }
        // });
    }
    function formatNodeProperty(prop) {
        var formattedProperty = prop;
        if (formattedProperty === null) {
            formattedProperty = 'null';
        } else if (formattedProperty === undefined) {
            formattedProperty = 'undefined';
        } else if (typeof formattedProperty === 'object') {
            formattedProperty = JSON.stringify(formattedProperty);
        }
        if (/\n/.test(formattedProperty)) {
            formattedProperty = "
"+formattedProperty+"
"
        }
        return formattedProperty;
    }
    function getNodeInfo(node) {
        var tabLabel = "";
        if (node.z) {
            var tab = RED.nodes.workspace(node.z);
            if (!tab) {
                tab = RED.nodes.subflow(node.z);
                tabLabel = tab.name;
            } else {
                tabLabel = tab.label;
            }
        }
        var label = "";
        if (typeof node._def.label == "function") {
            try {
                label = node._def.label.call(node);
            } catch(err) {
                console.log("Definition error: "+node_def.type+".label",err);
                label = node_def.type;
            }
        } else {
            label = node._def.label;
        }
        label = label || node.id;
        return {tab:tabLabel,type:node.type,label:label};
    }
    function sortNodeInfo(A,B) {
        if (A.tab < B.tab) { return -1;}
        if (A.tab > B.tab) { return 1;}
        if (A.type < B.type) { return -1;}
        if (A.type > B.type) { return 1;}
        if (A.name < B.name) { return -1;}
        if (A.name > B.name) { return 1;}
        return 0;
    }
    function resolveConflict(currentNodes) {
        $( "#node-dialog-confirm-deploy-config" ).hide();
        $( "#node-dialog-confirm-deploy-unknown" ).hide();
        $( "#node-dialog-confirm-deploy-unused" ).hide();
        $( "#node-dialog-confirm-deploy-conflict" ).show();
        $( "#node-dialog-confirm-deploy-type" ).val("conflict");
        $( "#node-dialog-confirm-deploy" ).dialog( "open" );
        // $("#node-dialog-confirm-deploy-review").append($('

'));
        // $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",0.4);
        // $("#node-dialog-confirm-deploy-review").attr("disabled",true).addClass("disabled");
        // $.ajax({
        //     headers: {
        //         "Accept":"application/json",
        //     },
        //     cache: false,
        //     url: 'flows',
        //     success: function(nodes) {
        //         var newNodes = nodes.flows;
        //         var newRevision = nodes.rev;
        //         generateDiff(currentNodes,newNodes);
        //         $("#node-dialog-confirm-deploy-review").attr("disabled",false).removeClass("disabled");
        //         $("#node-dialog-confirm-deploy-review img").remove();
        //         $("#node-dialog-confirm-deploy-review .ui-button-text").css("opacity",1);
        //     }
        // });
    }
    // function parseNodes(nodeList) {
    //     var tabOrder = [];
    //     var tabs = {};
    //     var subflows = {};
    //     var globals = [];
    //     var all = {};
    //
    //     nodeList.forEach(function(node) {
    //         all[node.id] = node;
    //         if (node.type === 'tab') {
    //             tabOrder.push(node.id);
    //             tabs[node.id] = {n:node,nodes:[]};
    //         } else if (node.type === 'subflow') {
    //             subflows[node.id] = {n:node,nodes:[]};
    //         }
    //     });
    //
    //     nodeList.forEach(function(node) {
    //         if (node.type !== 'tab' && node.type !== 'subflow') {
    //             if (tabs[node.z]) {
    //                 tabs[node.z].nodes.push(node);
    //             } else if (subflows[node.z]) {
    //                 subflows[node.z].nodes.push(node);
    //             } else {
    //                 globals.push(node);
    //             }
    //         }
    //     });
    //
    //     return {
    //         all: all,
    //         tabOrder: tabOrder,
    //         tabs: tabs,
    //         subflows: subflows,
    //         globals: globals
    //     }
    // }
    // function generateDiff(currentNodes,newNodes) {
    //     var currentConfig = parseNodes(currentNodes);
    //     var newConfig = parseNodes(newNodes);
    //     var pending = RED.nodes.pending();
    //     var added = {};
    //     var deleted = {};
    //     var changed = {};
    //     var conflicted = {};
    //
    //
    //     Object.keys(currentConfig.all).forEach(function(id) {
    //         var node = RED.nodes.workspace(id)||RED.nodes.subflow(id)||RED.nodes.node(id);
    //         if (!newConfig.all.hasOwnProperty(id)) {
    //             if (!pending.added.hasOwnProperty(id)) {
    //                 deleted[id] = true;
    //                 conflicted[id] = node.changed;
    //             }
    //         } else if (JSON.stringify(currentConfig.all[id]) !== JSON.stringify(newConfig.all[id])) {
    //             changed[id] = true;
    //             conflicted[id] = node.changed;
    //         }
    //     });
    //     Object.keys(newConfig.all).forEach(function(id) {
    //         if (!currentConfig.all.hasOwnProperty(id) && !pending.deleted.hasOwnProperty(id)) {
    //             added[id] = true;
    //         }
    //     });
    //
    //     // console.log("Added",added);
    //     // console.log("Deleted",deleted);
    //     // console.log("Changed",changed);
    //     // console.log("Conflicted",conflicted);
    //
    //     var formatString = function(id) {
    //         return conflicted[id]?"!":(added[id]?"+":(deleted[id]?"-":(changed[id]?"~":" ")));
    //     }
    //     newConfig.tabOrder.forEach(function(tabId) {
    //         var tab = newConfig.tabs[tabId];
    //         console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
    //         tab.nodes.forEach(function(node) {
    //             console.log(" ",formatString(node.id),node.type,node.name || node.id);
    //         })
    //         if (currentConfig.tabs[tabId]) {
    //             currentConfig.tabs[tabId].nodes.forEach(function(node) {
    //                 if (deleted[node.id]) {
    //                     console.log(" ",formatString(node.id),node.type,node.name || node.id);
    //                 }
    //             })
    //         }
    //     });
    //     currentConfig.tabOrder.forEach(function(tabId) {
    //         if (deleted[tabId]) {
    //             console.log(formatString(tabId),"Flow:",tab.n.label, "("+tab.n.id+")");
    //         }
    //     });
    //
    //     currentDiff = {
    //         currentConfig: currentConfig,
    //         newConfig: newConfig,
    //         added: added,
    //         deleted: deleted,
    //         changed: changed,
    //         conflicted: conflicted
    //     }
    // }
    // function showDiff() {
    //     if (currentDiff) {
    //         var list = $("#node-dialog-view-diff-diff");
    //         list.editableList('empty');
    //         var currentConfig = currentDiff.currentConfig;
    //         currentConfig.tabOrder.forEach(function(tabId) {
    //             var tab = currentConfig.tabs[tabId];
    //             list.editableList('addItem',{tab:tab})
    //         });
    //     }
    //     $("#node-dialog-view-diff").dialog("open");
    // }
    function save(skipValidation,force) {
        if (!$("#btn-deploy").hasClass("disabled")) {
            if (!skipValidation) {
                var hasUnknown = false;
                var hasInvalid = false;
                var hasUnusedConfig = false;
                var unknownNodes = [];
                var invalidNodes = [];
                RED.nodes.eachNode(function(node) {
                    hasInvalid = hasInvalid || !node.valid;
                    if (!node.valid) {
                        invalidNodes.push(getNodeInfo(node));
                    }
                    if (node.type === "unknown") {
                        if (unknownNodes.indexOf(node.name) == -1) {
                            unknownNodes.push(node.name);
                        }
                    }
                });
                hasUnknown = unknownNodes.length > 0;
                var unusedConfigNodes = [];
                RED.nodes.eachConfig(function(node) {
                    if (node.users.length === 0 && (node._def.hasUsers !== false)) {
                        unusedConfigNodes.push(getNodeInfo(node));
                        hasUnusedConfig = true;
                    }
                });
                $( "#node-dialog-confirm-deploy-config" ).hide();
                $( "#node-dialog-confirm-deploy-unknown" ).hide();
                $( "#node-dialog-confirm-deploy-unused" ).hide();
                $( "#node-dialog-confirm-deploy-conflict" ).hide();
                var showWarning = false;
                if (hasUnknown && !ignoreDeployWarnings.unknown) {
                    showWarning = true;
                    $( "#node-dialog-confirm-deploy-type" ).val("unknown");
                    $( "#node-dialog-confirm-deploy-unknown" ).show();
                    $( "#node-dialog-confirm-deploy-unknown-list" )
                        .html("
"+unknownNodes.join("")+"");
                } else if (hasInvalid && !ignoreDeployWarnings.invalid) {
                    showWarning = true;
                    $( "#node-dialog-confirm-deploy-type" ).val("invalid");
                    $( "#node-dialog-confirm-deploy-config" ).show();
                    invalidNodes.sort(sortNodeInfo);
                    $( "#node-dialog-confirm-deploy-invalid-list" )
                        .html("
"+invalidNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("")+"");
                } else if (hasUnusedConfig && !ignoreDeployWarnings.unusedConfig) {
                    // showWarning = true;
                    // $( "#node-dialog-confirm-deploy-type" ).val("unusedConfig");
                    // $( "#node-dialog-confirm-deploy-unused" ).show();
                    //
                    // unusedConfigNodes.sort(sortNodeInfo);
                    // $( "#node-dialog-confirm-deploy-unused-list" )
                    //     .html("
"+unusedConfigNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("")+"");
                }
                if (showWarning) {
                    $( "#node-dialog-confirm-deploy-hide" ).prop("checked",false);
                    $( "#node-dialog-confirm-deploy" ).dialog( "open" );
                    return;
                }
            }
            var nns = RED.nodes.createCompleteNodeSet();
            var startTime = Date.now();
            $(".deploy-button-content").css('opacity',0);
            $(".deploy-button-spinner").show();
            $("#btn-deploy").addClass("disabled");
            var data = {flows:nns};
            if (!force) {
                data.rev = RED.nodes.version();
            }
            $.ajax({
                url:"flows",
                type: "POST",
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf-8",
                headers: {
                    "Node-RED-Deployment-Type":deploymentType
                }
            }).done(function(data,textStatus,xhr) {
                RED.nodes.dirty(false);
                RED.nodes.version(data.rev);
                if (hasUnusedConfig) {
                    RED.notify(
                    '
'+RED._("deploy.successfulDeploy")+'
'+
                    '
'+RED._("deploy.unusedConfigNodes")+' '+RED._("deploy.unusedConfigNodesLink")+'
',"success",false,6000);
                } else {
                    RED.notify(RED._("deploy.successfulDeploy"),"success");
                }
                RED.nodes.eachNode(function(node) {
                    if (node.changed) {
                        node.dirty = true;
                        node.changed = false;
                    }
                    if(node.credentials) {
                        delete node.credentials;
                    }
                });
                RED.nodes.eachConfig(function (confNode) {
                    confNode.changed = false;
                    if (confNode.credentials) {
                        delete confNode.credentials;
                    }
                });
                RED.nodes.eachWorkspace(function(ws) {
                    ws.changed = false;
                })
                // Once deployed, cannot undo back to a clean state
                RED.history.markAllDirty();
                RED.view.redraw();
                RED.events.emit("deploy");
            }).fail(function(xhr,textStatus,err) {
                RED.nodes.dirty(true);
                $("#btn-deploy").removeClass("disabled");
                if (xhr.status === 401) {
                    RED.notify(RED._("deploy.deployFailed",{message:RED._("user.notAuthorized")}),"error");
                } else if (xhr.status === 409) {
                    resolveConflict(nns);
                } else if (xhr.responseText) {
                    RED.notify(RED._("deploy.deployFailed",{message:xhr.responseText}),"error");
                } else {
                    RED.notify(RED._("deploy.deployFailed",{message:RED._("deploy.errors.noResponse")}),"error");
                }
            }).always(function() {
                var delta = Math.max(0,300-(Date.now()-startTime));
                setTimeout(function() {
                    $(".deploy-button-content").css('opacity',1);
                    $(".deploy-button-spinner").hide();
                },delta);
            });
        }
    }
    return {
        init: init
    }
})();