text: /* -------------------------------------------------------------------------- */
  /* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems                */
  /*                                                                            */
  /* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
  /* not use this file except in compliance with the License. You may obtain    */
  /* a copy of the License at                                                   */
  /*                                                                            */
  /* http://www.apache.org/licenses/LICENSE-2.0                                 */
  /*                                                                            */
  /* Unless required by applicable law or agreed to in writing, software        */
  /* distributed under the License is distributed on an "AS IS" BASIS,          */
  /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
  /* See the License for the specific language governing permissions and        */
  /* limitations under the License.                                             */
  /* -------------------------------------------------------------------------- */
  
  define(function(require) {
    var Config = require("sunstone-config");
    var Graphs = require("utils/graphs");
    var Humanize = require("utils/humanize");
    var Locale = require("utils/locale");
    var Notifier = require("utils/notifier");
    var OpenNebula = require("opennebula");
    var OpenNebulaVM = require("opennebula/vm");
    var ResourceSelect = require("utils/resource-select");
    var StateActions = require("tabs/vms-tab/utils/state-actions");
    var Sunstone = require("sunstone");
    var TemplateUtils = require("utils/template-utils");
    var VMsTableUtils = require('../../vms-tab/utils/datatable-common');
    var RemoteActions = require('utils/remote-actions');
  
    var TemplateConfirmPoweroff = require("hbs!./confirm_poweroff");
    var TemplateConfirmReboot = require("hbs!./confirm_reboot");
    var TemplateConfirmSaveAsTemplate = require("hbs!./confirm_save_as_template");
    var TemplateConfirmTerminate = require("hbs!./confirm_terminate");
    var TemplateConfirmUndeploy = require("hbs!./confirm_undeploy");
    var TemplateVmsList = require("hbs!./list");
  
    var TAB_ID = require("../tabId");
    var _accordionId = 0;
  
    return {
      "generate": generate_provision_vms_list,
      "show": show_provision_vm_list,
      "state": get_provision_vm_state
    };
  
    function show_provision_vm_list() {
      $(".section_content").hide();
      $(".provision_vms_list_section").fadeIn();
  
      $("dd:not(.active) .provision_back", $(".provision_vms_list_section")).trigger("click");
      $(".provision_vms_list_refresh_button", $(".provision_vms_list_section")).trigger("click");
    }
  
    function generate_provision_vms_list(context, opts) {
      context.off();
      context.html(html(opts));
  
      Foundation.reflow(context, "accordion");
  
      if (opts.data) {
        $(".provision_vms_table", context).data("opennebula", opts.data);
      }
  
      setup_provision_vms_list(context, opts);
      setup_info_vm(context);
    }
  
    function html(opts_arg) {
      opts = $.extend({
          title: Locale.tr("Virtual Machines"),
          refresh: true,
          create: true,
          filter: true
        }, opts_arg);
  
      _accordionId += 1;
      return TemplateVmsList({"accordionId": _accordionId, "opts": opts});
    }
  
    function fill_provision_vms_datatable(datatable, item_list) {
      datatable.fnClearTable(true);
      if (item_list.length == 0) {
        datatable.html("<div class=\"text-center\">" +
          "<span class=\"fa-stack fa-5x\">" +
            "<i class=\"fas fa-cloud fa-stack-2x\"></i>" +
            "<i class=\"fas fa-info-circle fa-stack-1x fa-inverse\"></i>" +
          "</span>" +
          "<br>" +
          "<br>" +
          "<span>" +
            Locale.tr("There are no Virtual Machines") +
          "</span>" +
          "<br>" +
          "<br>" +
          "</div>");
      } else {
        datatable.fnAddData(item_list);
      }
    }
  
    function update_provision_vms_datatable(datatable, timeout) {
      datatable.html("<div class=\"text-center\">" +
        "<span class=\"fa-stack fa-5x\">" +
          "<i class=\"fas fa-cloud fa-stack-2x\"></i>" +
          "<i class=\"fa  fa-spinner fa-spin fa-stack-1x fa-inverse\"></i>" +
        "</span>" +
        "<br>" +
        "<br>" +
        "<span>" +
        "</span>" +
        "</div>");
  
      var data = datatable.data("opennebula");
      if (data) {
        fill_provision_vms_datatable(datatable, data);
      } else {
        setTimeout(function() {
            OpenNebula.VM.list({
              timeout: true,
              success: function (request, item_list) {
                fill_provision_vms_datatable(datatable, item_list);
              },
              error: Notifier.onError
            });
          }, timeout);
      }
    }
  
    function setup_provision_vms_list(context, opts) {
      var provision_vms_datatable = $(".provision_vms_table", context).dataTable({
        "iDisplayLength": 6,
        "bAutoWidth": false,
        "sDom" : "<\"H\">t<\"F\"lp>",
        "aLengthMenu": Sunstone.getPaginate(),
        "aaSorting"  : [[0, "desc"]],
        "aoColumnDefs": [
            { "bVisible": false, "aTargets": ["all"]},
            { "sType": "num", "aTargets": [0]}
        ],
        "aoColumns": [
            { "mDataProp": "VM.ID" },
            { "mDataProp": "VM.NAME" },
            { "mDataProp": "VM.UID" }
        ],
        "fnPreDrawCallback": function (oSettings) {
          // create a thumbs container if it doesn't exist. put it in the dataTables_scrollbody div
          if (this.$("tr", {"filter": "applied"} ).length == 0) {
            this.html("<div class=\"text-center\">"+
              "<span class=\"fa-stack fa-5x\">"+
                "<i class=\"fas fa-cloud fa-stack-2x\"></i>"+
                "<i class=\"fas fa-info-circle fa-stack-1x fa-inverse\"></i>"+
              "</span>"+
              "<br>"+
              "<br>"+
              "<span>"+
                Locale.tr("There are no Virtual Machines")+
              "</span>"+
              "</div>");
          } else {
            $(".provision_vms_table", context).html("<div class=\"provision_vms_ul large-up-3 medium-up-3 small-up-1\"></div>");
          }
  
          return true;
        },
        "fnRowCallback": function( nRow, aData, _, iDisplayIndexFull ) {
          var data = aData.VM;
          if(data == undefined){
            return nRow;
          }
          var state = get_provision_vm_state(data);
          var monitoring = "";
          if(data.MONITORING.GUEST_IP){
            monitoring = "<li class=\"provision-bullet-item\"><span class=\"\"><i class=\"fas fa-fw fa-lg fa-server\"/>" + data.MONITORING.GUEST_IP + "</span></li>";
          }
          var charter = VMsTableUtils.leasesClock(data);
          var addStyle = charter && charter.length && 'style="padding-left:.5rem;"';
          $(".provision_vms_ul", context).append("<div class='column'>\
              <ul class='8 provision-pricing-table menu vertical' opennebula_id='"+data.ID+"' datatable_index='"+iDisplayIndexFull+"'>\
                <li class='provision-title'>\
                  <div style='display: inline-flex;justify-content:space-between;width:100%;align-items: baseline;'>\
                    <a class='provision_info_vm_button' style='flex-grow:1;'>\
                      <span class='"+ state.color +"-color right' title='"+state.str+"'>\
                        <i class='fas fa-square'/>\
                      </span>"+
                      data.NAME +
                    "</a>\
                    <div class='charter' "+addStyle+">"+charter+"</div> \
                  </div>\
                </li>\
                <li class='provision-bullet-item' >\
                  <i class='fas fa-fw fa-lg fa-laptop'/> "+"x"+data.TEMPLATE.CPU+" - "+
                  ((data.TEMPLATE.MEMORY > 1000) ?
                    (Math.floor(data.TEMPLATE.MEMORY/1024)+"GB") :
                    (TemplateUtils.htmlEncode(data.TEMPLATE.MEMORY)+"MB"))+
                  " - "+
                  get_provision_disk_image(data) +
                "</li>\
                <li class='provision-bullet-item' >\
                  <span class=''>"+
                    get_provision_ips(data) +
                  "</span>\
                </li>"+ monitoring +
                "<li class='provision-bullet-item-last' >\
                  <span class=''>\
                    <i class='fas fa-fw fa-lg fa-user'/> "+
                    data.UNAME+
                  "</span>"+
                  "<span class='right'>"+
                    Humanize.prettyTimeAgo(data.STIME)+
                  "</span>\
                </li>\
              </ul>\
            </div>"
          );
          VMsTableUtils.tooltipCharters();
          return nRow;
        }
      });
  
      $(".provision_list_vms_search", context).on("input",function(){
        provision_vms_datatable.fnFilter( $(this).val() );
      });
  
      context.on("click", ".provision_vms_list_refresh_button", function(){
        OpenNebula.Action.clear_cache("VM");
        update_provision_vms_datatable(provision_vms_datatable, 0);
        return false;
      });
  
      $(".provision_list_vms_filter", context).on("change", ".resource_list_select", function(){
        if ($(this).val() != "-2"){
          provision_vms_datatable.fnFilter("^" + $(this).val() + "$", 2, true, false);
        } else {
          provision_vms_datatable.fnFilter("", 2);
        }
      });
  
      ResourceSelect.insert({
          context: $(".provision_list_vms_filter", context),
          resourceName: "User",
          initValue: (opts.filter_expression ? opts.filter_expression : "-2"),
          extraOptions: "<option value=\"-2\">" + Locale.tr("ALL") + "</option>",
          triggerChange: true,
          onlyName: true
        });
  
      context.on("click", ".provision_vms_list_filter_button", function(){
        $(".provision_list_vms_filter", context).fadeIn();
        return false;
      });
  
      OpenNebula.Action.clear_cache("VM");
      update_provision_vms_datatable(provision_vms_datatable, 0);
  
      // $(document).foundation();
    }
  
    function setup_info_vm(context) {
      function update_provision_vm_info(vm_id, context) {
        //var tempScrollTop = $(window).scrollTop();
        $(".provision_info_vm_name", context).text("");
        $(".provision_info_vm_loading", context).show();
        $(".provision_info_vm", context).css("visibility", "hidden");
  
        OpenNebula.VM.show({
          data : {
            id: vm_id
          },
          error: Notifier.onError,
          success: function(_, response){
            Sunstone.insertPanels(TAB_ID, response, TAB_ID, $(".provision-sunstone-info", context));
  
            var data = response.VM;
            var state = get_provision_vm_state(data);
  
            // helper, cleaner code
            function enabled(action){
              return Config.isTabActionEnabled("provision-tab", action) &&
                     StateActions.enabledStateAction(action, data.STATE, data.LCM_STATE);
            }
  
            if (enabled("VM.reboot") || enabled("VM.reboot_hard")){
              $(".provision_reboot_confirm_button", context).show();
            } else {
              $(".provision_reboot_confirm_button", context).hide();
            }
  
            if (enabled("VM.poweroff") || enabled("VM.poweroff_hard")){
              $(".provision_poweroff_confirm_button", context).show();
            } else {
              $(".provision_poweroff_confirm_button", context).hide();
            }
  
            if (enabled("VM.undeploy") || enabled("VM.undeploy_hard")){
              $(".provision_undeploy_confirm_button", context).show();
            } else {
              $(".provision_undeploy_confirm_button", context).hide();
            }
  
            if (enabled("VM.resume")){
              $(".provision_resume_button", context).show();
            } else {
              $(".provision_resume_button", context).hide();
            }
  
            if (enabled("VM.terminate") || enabled("VM.terminate_hard")){
              $(".provision_terminate_confirm_button", context).show();
            } else {
              $(".provision_terminate_confirm_button", context).hide();
            }
  
            if(Config.isTabActionEnabled("provision-tab", "VM.save_as_template")){
              if (enabled("VM.save_as_template")){
                $(".provision_save_as_template_confirm_button", context).show();
                $(".provision_save_as_template_confirm_button_disabled", context).hide();
              } else {
                $(".provision_save_as_template_confirm_button", context).hide();
                $(".provision_save_as_template_confirm_button_disabled", context).show();
              }
            }else{
              $(".provision_save_as_template_confirm_button", context).hide();
              $(".provision_save_as_template_confirm_button_disabled", context).hide();
            }
  
            $(".provision_rdp_button", context).toggle(Boolean(OpenNebulaVM.isConnectionSupported(data, 'rdp')));
            $(".provision_wfile_button", context).toggle(Boolean(OpenNebulaVM.isWFileSupported(data)));
  
            if (OpenNebulaVM.isVNCSupported(data) ||
               OpenNebulaVM.isSPICESupported(data)) {
              $(".provision_vnc_button", context).show();
              $(".provision_vnc_button_disabled", context).hide();
            }else{
              $(".provision_vnc_button", context).hide();
              $(".provision_vnc_button_disabled", context).show();
            }
  
            $(".provision_info_vm", context).attr("vm_id", data.ID);
            $(".provision_info_vm", context).data("vm", data);
  
            $(".provision_info_vm_name", context).text(data.NAME);
  
            if (Config.isTabActionEnabled("provision-tab", "VM.rename")) {
              context.off("click", ".provision_info_vm_rename a");
              context.on("click", ".provision_info_vm_rename a", function() {
                var valueStr = $(".provision_info_vm_name", context).text();
                $(".provision_info_vm_name", context).html("<input class=\"input_edit_value_rename\" type=\"text\" value=\"" + valueStr + "\"/>");
              });
  
              context.off("change", ".input_edit_value_rename");
              context.on("change", ".input_edit_value_rename", function() {
                var valueStr = $(".input_edit_value_rename", context).val();
                if (valueStr != "") {
                  OpenNebula.VM.rename({
                    data : {
                      id: vm_id,
                      extra_param: {
                        "name" : valueStr
                      }
                    },
                    success: function() {
                      update_provision_vm_info(vm_id, context);
                    },
                    error: function(request, response){
                      Notifier.onError(request, response);
                    }
                  });
                }
              });
            }
  
            $(".provision-pricing-table_vm_info", context).html(
                "<li class=\"provision-title\">"+
                  "<span class=\"without-link "+ state.color +"-color\">"+
                    "<span class=\""+ state.color +"-color right\" title=\""+state.str+"\">"+
                      "<i class=\"fas fa-square\"/>"+
                    "</span>"+
                    state.str+
                  "</span>"+
                "</li>"+
                "<li class=\"provision-bullet-item\" >"+
                  "<span>"+
                    "<i class=\"fas fa-fw fa-lg fa-laptop\"/> "+
                    "x"+TemplateUtils.htmlEncode(data.TEMPLATE.CPU)+" - "+
                    ((data.TEMPLATE.MEMORY > 1000) ?
                      (Math.floor(data.TEMPLATE.MEMORY/1024)+"GB") :
                      (TemplateUtils.htmlEncode(data.TEMPLATE.MEMORY)+"MB"))+
                  "</span>"+
                  " - "+
                  "<span>"+
                    get_provision_disk_image(data) +
                  "</span>"+
                "</li>"+
                "<li class=\"provision-bullet-item\" >"+
                  "<span>"+
                    get_provision_ips(data) +
                  "</span>"+
                "</li>"+
                "<li class=\"provision-bullet-item-last text-right\">"+
                  "<span class=\"left\">"+
                    "<i class=\"fas fa-fw fa-lg fa-user\"/> "+
                    data.UNAME+
                  "</span>"+
                  "<span>"+
                    "<i class=\"fas fa-fw fa-lg fa-clock-o\"/> "+
                    Humanize.prettyTimeAgo(data.STIME)+
                    " - "+
                    "ID: "+
                    data.ID+
                  "</span>"+
                "</li>");
  
            if (Config.isFeatureEnabled("show_vcenter_info") && data.USER_TEMPLATE.HYPERVISOR === "vcenter"){
              var vcenter_info = "";
              if (Object.keys(data.MONITORING).length !== 0){
                vcenter_info = "<thead><tr><th>" + Locale.tr("vCenter information") + "</th></tr></thead>" +
                  "<tbody>" +
                    "<tr>" +
                      "<td>" + Locale.tr("GUEST STATE") + "</td>" +
                      "<td>" + ((data.MONITORING.VCENTER_GUEST_STATE) ? data.MONITORING.VCENTER_GUEST_STATE : "-") + "</td>" +
                      "<td>" + Locale.tr("VMWARETOOLS RUNNING STATUS") + "</td>" +
                      "<td>" + ((data.MONITORING.VCENTER_VMWARETOOLS_RUNNING_STATUS) ? data.MONITORING.VCENTER_VMWARETOOLS_RUNNING_STATUS : "-") + "</td>" +
                    "</tr>" +
                    "<tr>" +
                      "<td>" + Locale.tr("VMWARETOOLS VERSION") + "</td>" +
                      "<td>" + ((data.MONITORING.VCENTER_VMWARETOOLS_VERSION) ? data.MONITORING.VCENTER_VMWARETOOLS_VERSION : "-") + "</td>" +
                      "<td>" + Locale.tr("VMWARETOOLS VERSION STATUS") + "</td>" +
                      "<td>" + ((data.MONITORING.VCENTER_VMWARETOOLS_VERSION_STATUS) ? data.MONITORING.VCENTER_VMWARETOOLS_VERSION_STATUS : "-") + "</td>" +
                    "</tr>" +
                  "</tbody>";
              }
              $(".provision-sunstone-vcenter-list", context).html(vcenter_info);
            }
  
            $(".provision_confirm_action:first", context).html("");
  
            $(".provision_info_vm", context).css("visibility", "visible");
            $(".provision_info_vm_loading", context).hide();
  
            OpenNebula.VM.monitor({
              data : {
                timeout: true,
                id: data.ID,
                monitor: {
                  monitor_resources : "CPU,MEMORY,NETTX,NETRX"
                }
              },
              success: function(_, response){
                var vm_graphs = [
                    {
                        monitor_resources : "CPU",
                        labels : "Real CPU",
                        humanize_figures : false,
                        div_graph : $(".vm_cpu_provision_graph", context)
                    },
                    {
                        monitor_resources : "MEMORY",
                        labels : "Real MEM",
                        humanize_figures : true,
                        div_graph : $(".vm_memory_provision_graph", context)
                    },
                    {
                        labels : "Network reception",
                        monitor_resources : "NETRX",
                        humanize_figures : true,
                        convert_from_bytes : true,
                        div_graph : $(".vm_net_rx_provision_graph", context)
                    },
                    {
                        labels : "Network transmission",
                        monitor_resources : "NETTX",
                        humanize_figures : true,
                        convert_from_bytes : true,
                        div_graph : $(".vm_net_tx_provision_graph", context)
                    },
                    {
                        labels : "Network reception speed",
                        monitor_resources : "NETRX",
                        humanize_figures : true,
                        convert_from_bytes : true,
                        y_sufix : "B/s",
                        derivative : true,
                        div_graph : $(".vm_net_rx_speed_provision_graph", context)
                    },
                    {
                        labels : "Network transmission speed",
                        monitor_resources : "NETTX",
                        humanize_figures : true,
                        convert_from_bytes : true,
                        y_sufix : "B/s",
                        derivative : true,
                        div_graph : $(".vm_net_tx_speed_provision_graph", context)
                    }
                ];
  
                for(var i=0; i<vm_graphs.length; i++) {
                    Graphs.plot(
                        response,
                        vm_graphs[i]
                    );
                }
              }
            });
          }
        });
      }
  
      if (Config.isTabActionEnabled("provision-tab", "VM.save_as_template")) {
        context.on("click", ".provision_save_as_template_confirm_button", function(){
          $(".provision_confirm_action:first", context).html(
            TemplateConfirmSaveAsTemplate());
        });
  
        context.on("click", ".provision_save_as_template_button", function(){
          var button = $(this);
          button.attr("disabled", "disabled");
          var context = $(".provision_info_vm[vm_id]");
  
          var vm_id = context.attr("vm_id");
          var template_name = $(".provision_snapshot_name", context).val();
          var template_description = $(".provision_snapshot_description", context).val();
          var persistent =
            ($("input[name=provision_snapshot_radio]:checked").val() == "persistent");
  
          OpenNebula.VM.save_as_template({
            data : {
              id: vm_id,
              extra_param: {
                name : template_name,
                description: template_description,
                persistent : persistent
              }
            },
            timeout: false,
            success: function(request){
              OpenNebula.Action.clear_cache("VMTEMPLATE");
              Notifier.notifyMessage(Locale.tr("VM Template") + " " + request.request.data[1].name + " " + Locale.tr("saved successfully"));
              update_provision_vm_info(vm_id, context);
              button.removeAttr("disabled");
            },
            error: function(request, response){
              if(response.error.http_status == 0){   // Failed due to cloning template taking too long
                  OpenNebula.Action.clear_cache("VMTEMPLATE");
                  update_provision_vm_info(vm_id, context);
                  Notifier.notifyMessage(Locale.tr("VM cloning in the background. The Template will appear as soon as it is ready, and the VM unlocked."));
              } else {
                  Notifier.onError(request, response);
              }
              button.removeAttr("disabled");
            }
          });
  
          return false;
        });
      }
  
      context.on("click", ".provision_terminate_confirm_button", function(){
        var data = $(".provision_info_vm", context).data("vm");
  
        var hard = Config.isTabActionEnabled("provision-tab", "VM.terminate_hard") &&
               StateActions.enabledStateAction("VM.terminate_hard", data.STATE, data.LCM_STATE);
  
        var soft = Config.isTabActionEnabled("provision-tab", "VM.terminate") &&
               StateActions.enabledStateAction("VM.terminate", data.STATE, data.LCM_STATE);
  
        var opts = {};
  
        if(hard && soft){
          opts.both = true;
        } else if(hard){
          opts.hard = true;
        }
  
        $(".provision_confirm_action:first", context).html(TemplateConfirmTerminate({opts: opts}));
      });
  
      context.on("click", ".provision_poweroff_confirm_button", function(){
        var data = $(".provision_info_vm", context).data("vm");
  
        var hard = Config.isTabActionEnabled("provision-tab", "VM.poweroff_hard") &&
               StateActions.enabledStateAction("VM.poweroff_hard", data.STATE, data.LCM_STATE);
  
        var soft = Config.isTabActionEnabled("provision-tab", "VM.poweroff") &&
               StateActions.enabledStateAction("VM.poweroff", data.STATE, data.LCM_STATE);
  
        var opts = {};
  
        if(hard && soft){
          opts.both = true;
        } else if(hard){
          opts.hard = true;
        }
  
        $(".provision_confirm_action:first", context).html(TemplateConfirmPoweroff({opts: opts}));
      });
  
      context.on("click", ".provision_undeploy_confirm_button", function(){
        var data = $(".provision_info_vm", context).data("vm");
  
        var hard = Config.isTabActionEnabled("provision-tab", "VM.undeploy_hard") &&
               StateActions.enabledStateAction("VM.undeploy_hard", data.STATE, data.LCM_STATE);
  
        var soft = Config.isTabActionEnabled("provision-tab", "VM.undeploy") &&
               StateActions.enabledStateAction("VM.undeploy", data.STATE, data.LCM_STATE);
  
        var opts = {};
  
        if(hard && soft){
          opts.both = true;
        } else if(hard){
          opts.hard = true;
        }
  
        $(".provision_confirm_action:first", context).html(TemplateConfirmUndeploy({opts: opts}));
      });
  
      context.on("click", ".provision_reboot_confirm_button", function(){
        var data = $(".provision_info_vm", context).data("vm");
  
        var hard = Config.isTabActionEnabled("provision-tab", "VM.reboot_hard") &&
               StateActions.enabledStateAction("VM.reboot_hard", data.STATE, data.LCM_STATE);
  
        var soft = Config.isTabActionEnabled("provision-tab", "VM.reboot") &&
               StateActions.enabledStateAction("VM.reboot", data.STATE, data.LCM_STATE);
  
        var opts = {};
  
        if(hard && soft){
          opts.both = true;
        } else if(hard){
          opts.hard = true;
        }
  
        $(".provision_confirm_action:first", context).html(TemplateConfirmReboot({opts: opts}));
      });
  
      context.on("click", ".provision_terminate_button", function(){
        var button = $(this);
        button.attr("disabled", "disabled");
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        var terminate_action = $("input[name=provision_terminate_radio]:checked").val();
  
        OpenNebula.VM[terminate_action]({
          data : {
            id: vm_id
          },
          success: function() {
            update_provision_vm_info(vm_id, context);
            button.removeAttr("disabled");
          },
          error: function(request, response) {
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_poweroff_button", function(){
        var button = $(this);
        button.attr("disabled", "disabled");
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        var poweroff_action = $("input[name=provision_poweroff_radio]:checked").val();
  
        OpenNebula.VM[poweroff_action]({
          data : {
            id: vm_id
          },
          success: function(request, response){
            update_provision_vm_info(vm_id, context);
            button.removeAttr("disabled");
          },
          error: function(request, response){
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_undeploy_button", function(){
        var button = $(this);
        button.attr("disabled", "disabled");
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        var undeploy_action = $("input[name=provision_undeploy_radio]:checked").val();
  
        OpenNebula.VM[undeploy_action]({
          data : {
            id: vm_id
          },
          success: function() {
            update_provision_vm_info(vm_id, context);
            button.removeAttr("disabled");
          },
          error: function(request, response) {
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_reboot_button", function(){
        var button = $(this);
        button.attr("disabled", "disabled");
  
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        var reboot_action = $("input[name=provision_reboot_radio]:checked").val();
  
        OpenNebula.VM[reboot_action]({
          data : {
            id: vm_id
          },
          success: function() {
            update_provision_vm_info(vm_id, context);
            button.removeAttr("disabled");
          },
          error: function(request, response) {
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_resume_button", function() {
        var button = $(this);
        button.attr("disabled", "disabled");
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
  
        OpenNebula.VM.resume({
          data : {
            id: vm_id
          },
          success: function() {
            update_provision_vm_info(vm_id, context);
            button.removeAttr("disabled");
          },
          error: function(request, response) {
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_rdp_button", function() {
        var vm = $(".provision_info_vm", context).data("vm") || {};
        var rdpIp = OpenNebulaVM.isConnectionSupported(vm, 'rdp');
  
        var username, password;
        if (vm.TEMPLATE && vm.TEMPLATE.CONTEXT) {
          var context = vm.TEMPLATE.CONTEXT;
          for (var prop in context) {
            var propUpperCase = String(prop).toUpperCase();
            (propUpperCase === "USERNAME") && (username = context[prop]);
            (propUpperCase === "PASSWORD") && (password = context[prop]);
          }
        }
  
        Sunstone.runAction("VM.save_rdp", JSON.parse(JSON.stringify({
          name: vm.NAME,
          ip: rdpIp,
          username: username,
          password: password,
        })));
      });
  
      context.on("click", ".provision_wfile_button", function() {
        var vm_id = $(".provision_info_vm", context).attr("vm_id") || '';
        var vm = $(".provision_info_vm", context).data("vm") || {};
        var wFile = OpenNebulaVM.isWFileSupported(vm) || {};
  
        ("VM.save_virt_viewer_action", vm.ID, wFile);
        Sunstone.runAction("VM.save_virt_viewer_action", vm_id, wFile);
      });
  
      context.on("click", ".provision_vnc_button", function(){
        var button = $(this);
        button.attr("disabled", "disabled");
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        var vm_data = $(".provision_info_vm", context).data("vm");
  
        OpenNebulaVM.vnc({
          data : {
            id: vm_id
          },
          success: function(_, response){
            if (OpenNebulaVM.isVNCSupported(vm_data)) {
              var link = RemoteActions.getLink(response,{
                port: Config.vncProxyPort,
                connnection_type: 'vnc',
                extra_params: [
                  'port=' + Config.vncProxyPort,
                  'encrypt=' + Config.vncWSS,
                  !Config.requestVNCPassword && 'password=' + response.password
                ]
              });
              // Open in a new tab the noVNC connection
              window.open(link);
  
              button.removeAttr("disabled");
            } else if (OpenNebulaVM.isSPICESupported(vm_data)) {
              var link = RemoteActions.getLink(response, {
                port: Config.vncProxyPort, 
                connnection_type: 'spice',
                extra_params: [
                  'password=' + response.password,
                  'encrypt=' + config.user_config.vnc_wss,
                ]
              });
              // Open in a new tab the SPICE connection
              window.open(link);
            } else {
              Notifier.notifyError("The remote console is not enabled for this VM");
            }
          },
          error: function(request, response){
            Notifier.onError(request, response);
            button.removeAttr("disabled");
          }
        });
  
        return false;
      });
  
      context.on("click", ".provision_refresh_info", function(){
        var vm_id = $(".provision_info_vm", context).attr("vm_id");
        update_provision_vm_info(vm_id, context);
        return false;
      });
  
      //
      // Info VM
      //
  
      $(".provision_list_vms", context).on("click", ".provision_info_vm_button", function(){
        $("a.provision_show_vm_accordion", context).trigger("click");
        // TODO loading
  
        var vm_id = $(this).parents(".provision-pricing-table").attr("opennebula_id");
        update_provision_vm_info(vm_id, context);
        return false;
      });
    }
  
  
    // @params
    //    data: and VM object
    //      Example: data.ID
    // @returns and object containing the following properties
    //    color: css class for this state.
    //      color + '-color' font color class
    //      color + '-bg' background class
    //    str: user friendly state string
    function get_provision_vm_state(data) {
      var state = parseInt(data.STATE);
      var state_color;
      var state_str;
  
      switch (state) {
        case OpenNebulaVM.STATES.INIT:
        case OpenNebulaVM.STATES.PENDING:
        case OpenNebulaVM.STATES.HOLD:
          state_color = "deploying";
          state_str = Locale.tr("DEPLOYING") + " (2/4)";
          break;
        case OpenNebulaVM.STATES.ACTIVE:
          var lcm_state = parseInt(data.LCM_STATE);
  
          switch (lcm_state) {
            case OpenNebulaVM.LCM_STATES.LCM_INIT:
              state_color = "deploying";
              state_str = Locale.tr("DEPLOYING") + " (2/4)";
              break;
            case OpenNebulaVM.LCM_STATES.PROLOG:
            case OpenNebulaVM.LCM_STATES.PROLOG_RESUME:
            case OpenNebulaVM.LCM_STATES.PROLOG_UNDEPLOY:
              state_color = "deploying";
              state_str = Locale.tr("DEPLOYING") + " (3/4)";
              break;
            case OpenNebulaVM.LCM_STATES.BOOT:
            case OpenNebulaVM.LCM_STATES.BOOT_UNKNOWN:
            case OpenNebulaVM.LCM_STATES.BOOT_POWEROFF:
            case OpenNebulaVM.LCM_STATES.BOOT_SUSPENDED:
            case OpenNebulaVM.LCM_STATES.BOOT_STOPPED:
            case OpenNebulaVM.LCM_STATES.BOOT_UNDEPLOY:
              state_color = "deploying";
              state_str = Locale.tr("DEPLOYING") + " (4/4)";
              break;
            case OpenNebulaVM.LCM_STATES.RUNNING:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SNAPSHOT:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_POWEROFF:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_REVERT_POWEROFF:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_DELETE_POWEROFF:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_SUSPENDED:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_REVERT_SUSPENDED:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_DELETE_SUSPENDED:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_REVERT:
            case OpenNebulaVM.LCM_STATES.DISK_SNAPSHOT_DELETE:
            case OpenNebulaVM.LCM_STATES.MIGRATE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_POWEROFF:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_SUSPEND:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_UNKNOWN:
            case OpenNebulaVM.LCM_STATES.DISK_RESIZE:
            case OpenNebulaVM.LCM_STATES.DISK_RESIZE_POWEROFF:
            case OpenNebulaVM.LCM_STATES.DISK_RESIZE_UNDEPLOYED:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_RESIZE:
              state_color = "running";
              state_str = Locale.tr("RUNNING");
              break;
            case OpenNebulaVM.LCM_STATES.HOTPLUG:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_NIC:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_NIC_POWEROFF:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SAVEAS:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SAVEAS_POWEROFF:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SAVEAS_SUSPENDED:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SAVEAS_UNDEPLOYED:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_SAVEAS_STOPPED:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_PROLOG_POWEROFF:
            case OpenNebulaVM.LCM_STATES.HOTPLUG_EPILOG_POWEROFF:
              state_color = "deploying";
              state_str = Locale.tr("SAVING IMAGE");
              break;
            case OpenNebulaVM.LCM_STATES.FAILURE:
            case OpenNebulaVM.LCM_STATES.BOOT_FAILURE:
            case OpenNebulaVM.LCM_STATES.BOOT_MIGRATE_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_FAILURE:
            case OpenNebulaVM.LCM_STATES.EPILOG_FAILURE:
            case OpenNebulaVM.LCM_STATES.EPILOG_STOP_FAILURE:
            case OpenNebulaVM.LCM_STATES.EPILOG_UNDEPLOY_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_POWEROFF_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_SUSPEND_FAILURE:
            case OpenNebulaVM.LCM_STATES.BOOT_UNDEPLOY_FAILURE:
            case OpenNebulaVM.LCM_STATES.BOOT_STOPPED_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_RESUME_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_UNDEPLOY_FAILURE:
            case OpenNebulaVM.LCM_STATES.PROLOG_MIGRATE_UNKNOWN_FAILURE:
              state_color = "error";
              state_str = Locale.tr("ERROR");
              break;
            case OpenNebulaVM.LCM_STATES.SAVE_STOP:
            case OpenNebulaVM.LCM_STATES.SAVE_SUSPEND:
            case OpenNebulaVM.LCM_STATES.SAVE_MIGRATE:
            case OpenNebulaVM.LCM_STATES.EPILOG_STOP:
            case OpenNebulaVM.LCM_STATES.EPILOG:
            case OpenNebulaVM.LCM_STATES.EPILOG_UNDEPLOY:
            case OpenNebulaVM.LCM_STATES.SHUTDOWN:
            case OpenNebulaVM.LCM_STATES.CANCEL:
            case OpenNebulaVM.LCM_STATES.SHUTDOWN_POWEROFF:
            case OpenNebulaVM.LCM_STATES.SHUTDOWN_UNDEPLOY:
            case OpenNebulaVM.LCM_STATES.CLEANUP_RESUBMIT:
            case OpenNebulaVM.LCM_STATES.CLEANUP_DELETE:
              state_color = "powering_off";
              state_str = Locale.tr("POWERING OFF");
              break;
            case OpenNebulaVM.LCM_STATES.UNKNOWN:
              state_color = "powering_off";
              state_str = Locale.tr("UNKNOWN");
              break;
            default:
              state_color = "powering_off";
              state_str = Locale.tr("UNKNOWN");
              break;
          }
  
          break;
        case OpenNebulaVM.STATES.STOPPED:
        case OpenNebulaVM.STATES.SUSPENDED:
        case OpenNebulaVM.STATES.POWEROFF:
        case OpenNebulaVM.STATES.DONE:
          state_color = "off";
          state_str = Locale.tr("OFF");
  
          break;
        case OpenNebulaVM.STATES.UNDEPLOYED:
          state_color = "undeployed";
          state_str = Locale.tr("UNDEPLOYED");
  
          break;
  
        case OpenNebulaVM.STATES.CLONING:
          state_color = "deploying";
          state_str = Locale.tr("DEPLOYING") + " (1/4)";
          break;
  
        case OpenNebulaVM.STATES.CLONING_FAILURE:
          state_color = "error";
          state_str = Locale.tr("ERROR");
          break;
  
        default:
          state_color = "powering_off";
          state_str = Locale.tr("UNKNOWN");
          break;
      }
  
      return {
        color: state_color,
        str: state_str
      };
    }
  
    function get_provision_disk_image(data) {
      var disks = [];
      if (Array.isArray(data.TEMPLATE.DISK))
          disks = data.TEMPLATE.DISK;
      else if (!$.isEmptyObject(data.TEMPLATE.DISK))
          disks = [data.TEMPLATE.DISK];
  
      if (disks.length > 0) {
        return disks[0].IMAGE != undefined ? disks[0].IMAGE : "";
      } else {
        return "";
      }
    }
  
    function get_provision_ips(data) {
      return (
        "<div style=\"display: flex; gap: 5px;\">" +
          "<i class=\"fas fa-fw fa-lg fa-globe\"></i>" +
          "<div>" + OpenNebula.VM.ipsStr(data, { divider: ", " }) + "</div>" +
        "</div>"
      );
    }
  });
  