function isVarEmpty(value) {
  return (
    value == null ||
    (value.hasOwnProperty("length") && value.length === 0) ||
    (value.constructor === Object && Object.keys(value).length === 0)
  );
}

(function ($) {
  $.extend($.fn, {
    asyncExpandNodes: function (parent, data) {
      var isWas = $('li[name="' + data.name + '"]').length;
      if (isWas && !(data.children && data.children.length)) {
        return;
      }
      var add =
        '<div class="hitarea hasChildren-hitarea closed-hitarea expandable-hitarea"></div>';
      if (!data.hasChildren) {
        add = "";
      }

      var current = $("<li/>")
        .css("font-weight", "normal")
        .attr("id", data.id || "")
        .attr("name", data.name || "")
        .html(
          add +
            "<nobr><span><img src='" +
            data.icon + 
            "' class='navigation_image' /><A href=" +
            (isVarEmpty(data.src_guid)
              ? "'javascript:clickTree(\"" + data.name + "\");'"
              : "'javascript:clickTreeMessage(\"" +
                data.src_guid +
                '", "*");\'') +
            "class='' title='" +
            data.text.split("&frasr;").join("\\") +
            "'>" +
            data.text.split("&frasr;").join("\\") +
            "</a></span></nobr>"
        );

      if (!isWas) {
        current.appendTo(parent);
      } else {
        current = $('li[name="' + data.name + '"]')[0];
      }

      if (!isWas && data.classes) {
        current.children("span").addClass(data.classes);
      }

      if (!isWas && data.expanded) {
        current.addClass("open");
      }

      if (isWas && data.children && data.children.length > 0) {
        var sp = $(current).find("ul:first");
        if ($(sp).find("li:first").find("span:first").hasClass("placeholder")) {
          $(sp).find("li:first").remove();
        } else {
          $(sp).attr("style", "display: block");
        }

        if (
          $(current).hasClass("lastExpandable") ||
          $(current).hasClass("lastCollapsable")
        ) {
          $(current).removeClass("lastExpandable").addClass("lastCollapsable");
          $(current)
            .find("div:first")
            .removeClass("lastExpandable-hitarea")
            .addClass("lastCollapsable-hitarea");
        } else {
          $(current)
            .removeClass("hasChildren")
            .removeClass("expandable")
            .addClass("collapsable");
          $(current)
            .find("div:first")
            .removeClass("expandable-hitarea")
            .addClass("collapsable-hitarea");
        }
      }

      if (data.hasChildren || (data.children && data.children.length > 0)) {
        if (!isWas) {
          if (data.hasChildren) {
            var branch = $("<ul/>")
              .attr("style", "display: none")
              .appendTo(current);
            $("#mixed").treeview({ add: $(current) });
            $(current).removeClass().addClass("hasChildren");
            $(current)
              .find("div:first")
              .removeClass()
              .addClass("hitarea")
              .addClass("hasChildren-hitarea");

            var branch = $(current)
              .find("ul:first")
              .attr("style", "display: block;");

            if (data.children && data.children.length > 0) {
              $(current).addClass("collapsable");
              if (data.lastElement) {
                $(current).addClass("lastCollapsable");
                $(current)
                  .find("div:first")
                  .addClass("lastCollapsable-hitarea");
              } else {
                $(current).find("div:first").addClass("collapsable-hitarea");
              }

              for (var child in data.children) {
                $.fn.asyncExpandNodes(branch, data.children[child]);
              }
            } else {
              $(branch)
                .attr("style", "display: none;")
                .html(
                  '<li class="last"><span class="placeholder">&nbsp;</span></li>'
                );
              $(current).addClass("closed").addClass("expandable");
              if (data.lastElement) {
                $(current).addClass("lastExpandable");
                $(current).find("div:first").addClass("lastExpandable-hitarea");
              } else {
                $(current).find("div:first").addClass("expandable-hitarea");
              }
            }
          }
        } else {
          var branch = $(current).find("ul:first");
          $(branch).attr("style", "display: block");
          if (data.children && data.children.length) {
            for (var child in data.children) {
              $.fn.asyncExpandNodes(branch, data.children[child]);
            }
          }
        }
      } else if (data.lastElement) {
        $(current).addClass("last");
      }
    },
  });

  $.extend($.fn, {
    addComboBoxOptions: function (cmbx, data) {
      $(cmbx).append(
        $('<option value="' + data.guid + '">' + data.name + "</option>")
      );
    },
  });

  function load(settings, root, child, container) {
    function createNode(parent) {
      var isWas =
        $('li[name="' + this.name + '"]').length && this.name != "ph0";
      var add =
        '<div class="hitarea hasChildren-hitarea closed-hitarea expandable-hitarea"></div>';
      if (!this.hasChildren) add = "";
      var current = null;
      if (this.name == "ph0") {
        current = $("<li/>")
          .css("font-weight", "normal")
          .attr("id", this.id || "")
          .html('<span class="placeholder">&nbsp;</span>');
      } else {
        current = $("<li/>")
          .css("font-weight", "normal")
          .attr("id", this.id || "")
          .attr("name", this.name || "")
          .html(
            add +
              "<nobr><span><img src='" +
              this.icon + 
              "'class='navigation_image'/><a href=" +
              (isVarEmpty(this.src_guid)
                ? "'javascript:clickTree(\"" + this.name + "\");'"
                : "'javascript:clickTreeMessage(\"" +
                  this.src_guid +
                  '", "*");\'') +
              " title='" +
              this.text.split("&frasr;").join("\\") +
              "'>" +
              this.text.split("&frasr;").join("\\") +
              "</a></span></nobr>"
          );
      }

      if (!isWas) current.appendTo(parent);
      else current = $('li[name="' + this.name + '"]')[0];

      if (!isWas && this.name != "ph0" && this.classes) {
        current.children("span").addClass(this.classes);
      }

      if (!isWas && this.expanded) {
        current.addClass("open");
      }

      if (this.hasChildren || (this.children && this.children.length > 0)) {
        if (!isWas) {
          var branch = $("<ul/>")
            .attr("style", "display: none")
            .appendTo(current);
          if (this.hasChildren) {
            branch.html('<li><span class="placeholder">&nbsp;</span></li>');
            current.addClass("hasChildren");
            current.addClass("closed");
          }
          if (this.children && this.children.length > 0) {
            $.each(this.children, createNode, [branch]);
          }
        } else {
          var branch = current.children("ul");
          if (!branch) branch = $("<ul/>").appendTo(current);
          if (this.children && this.children.length) {
            $.each(this.children, createNode, [branch]);
          }
        }
      }
    }

    $.ajax(
      $.extend(
        true,
        {
          url: settings.url,
          dataType: "json",
          data: {
            root: root,
          },
          success: function (response) {
            child.empty();
            $.each(response, createNode, [child]);
            $(container).treeview({ add: child });
          },
        },
        settings.ajax
      )
    );
  }

  var proxied = $.fn.treeview;
  $.fn.treeview = function (settings) {
    if (!settings.url) {
      return proxied.apply(this, arguments);
    }
    var container = this;
    if (!container.children().size()) {
      load(settings, "source", this, container);
    }
    var userToggle = settings.toggle;
    return proxied.call(
      this,
      $.extend({}, settings, {
        collapsed: true,
        toggle: function () {
          var $this = $(this);
          if ($this.hasClass("hasChildren")) {
            var childList = $this.removeClass("hasChildren").find("ul");
            load(settings, this.id, childList, container);
          }
          if (userToggle) {
            userToggle.apply(this, arguments);
          }
        },
      })
    );
  };
})(jQuery);
