/* global JSEncrypt */
horizon.instances = {
  user_decided_length: false,
  user_volume_size: false,
  networks_selected: [],
  networks_available: [],

  getConsoleLog: function(via_user_submit) {
    var form_element = $("#tail_length"),
      data;

    if (!via_user_submit) {
      via_user_submit = false;
    }

    if(this.user_decided_length) {
      data = $(form_element).serialize();
    } else {
      data = "length=35";
    }

    $.ajax({
      url: $(form_element).attr('action'),
      data: data,
      method: 'get',
      success: function(response_body) {
        $('pre.logs').text(response_body);
      },
      error: function() {
        if(via_user_submit) {
          horizon.clearErrorMessages();
          horizon.alert('error', gettext('There was a problem communicating with the server, please try again.'));
        }
      }
    });
  },

  /*
   * Gets the html select element associated with a given
   * network id for network_id.
   **/
  get_network_element: function(network_id) {
    return $('label[for^="id_network_' + network_id + '"]');
  },

  /*
   * Initializes an associative array of lists of the current
   * networks.
   **/
  init_network_list: function () {
    horizon.instances.networks_selected = [];
    horizon.instances.networks_available = [];
    $(this.get_network_element("")).each(function () {
      var $this = $(this).parent();
      var $input = $this.children("input");
      var name = horizon.string.escapeHtml($this.text().replace(/^\s+/, ""));
      var network_property = {
        "name": name,
        "id": $input.attr("id"),
        "value": $input.attr("value")
      };
      if ($input.is(":checked")) {
        horizon.instances.networks_selected.push(network_property);
      } else {
        horizon.instances.networks_available.push(network_property);
      }
    });
  },

  /*
   * Generates the HTML structure for a network that will be displayed
   * as a list item in the network list.
   **/
  generate_network_element: function(name, id, value) {
    var $li = $('<li>');
    $li.attr('name', value).html(name + '<em class="network_id">(' + value + ')</em><a href="#" class="btn btn-primary"></a>');
    return $li;
  },

  /*
   * Generates the HTML structure for the Network List.
   **/
  generate_networklist_html: function() {
    var self = this;
    var available_network = $("#available_network");
    var selected_network = $("#selected_network");
    var updateForm = function() {
      var networkListId = $("#networkListId");
      var lists = networkListId.find("li").attr('data-index',100);
      var active_networks = $("#selected_network > li").map(function(){
        return $(this).attr("name");
      });
      networkListId.find("input:checkbox").removeAttr('checked');
      active_networks.each(function(index, value){
        networkListId.find("input:checkbox[value=" + value + "]")
          .prop('checked', true)
          .parents("li").attr('data-index',index);
      });
      networkListId.find("ul").html(
        lists.sort(function(a,b){
          if( $(a).data("index") < $(b).data("index")) { return -1; }
          if( $(a).data("index") > $(b).data("index")) { return 1; }
          return 0;
        })
      );
    };
    $("#networkListSortContainer").show();
    $("#networkListIdContainer").hide();
    self.init_network_list();
    // Make sure we don't duplicate the networks in the list
    available_network.empty();
    $.each(self.networks_available, function(index, value){
      available_network.append(self.generate_network_element(value.name, value.id, value.value));
    });
    // Make sure we don't duplicate the networks in the list
    selected_network.empty();
    $.each(self.networks_selected, function(index, value){
      selected_network.append(self.generate_network_element(value.name, value.id, value.value));
    });
    // $(".networklist > li").click(function(){
    //   $(this).toggleClass("ui-selected");
    // });
    $(".networklist > li > a.btn").click(function(e){
      var $this = $(this);
      e.preventDefault();
      e.stopPropagation();
      if($this.parents("ul#available_network").length > 0) {
        $this.parent().appendTo(selected_network);
      } else if ($this.parents("ul#selected_network").length > 0) {
        $this.parent().appendTo(available_network);
      }
      updateForm();
    });
    if ($("#networkListId > div.form-group.error").length > 0) {
      var errortext = $("#networkListId > div.form-group.error span.help-block").text();
      $("#selected_network_label").before($('<div class="dynamic-error">').html(errortext));
    }
    $(".networklist").sortable({
      connectWith: "ul.networklist",
      placeholder: "ui-state-highlight",
      distance: 5,
      start:function(){
        selected_network.addClass("dragging");
      },
      stop:function(){
        selected_network.removeClass("dragging");
        updateForm();
      }
    }).disableSelection();
  },

  workflow_init: function() {
    // Initialise the drag and drop network list
    horizon.instances.generate_networklist_html();
  }
};

horizon.addInitFunction(horizon.instances.init = function () {
  var $document = $(document);

  $document.on('submit', '#tail_length', function (evt) {
    horizon.instances.user_decided_length = true;
    horizon.instances.getConsoleLog(true);
    evt.preventDefault();
  });

  /* Launch instance workflow */

  // Handle field toggles for the Launch Instance source type field
  function update_launch_source_displayed_fields (field) {
    var $this = $(field);
    var base_type = $this.val();
    var elements_list;

    $this.closest(".form-group").nextAll().hide();

    switch(base_type) {
      case "image_id":
        elements_list = "#id_image_id";
        break;
      case "instance_snapshot_id":
        elements_list = "#id_instance_snapshot_id";
        break;
      case "volume_id":
        elements_list = "#id_volume_id, #id_device_name, #id_vol_delete_on_instance_delete";
        break;
      case "volume_image_id":
        elements_list = "#id_image_id, #id_volume_size, #id_device_name, #id_vol_delete_on_instance_delete";
        break;
      case "volume_snapshot_id":
        elements_list = "#id_volume_snapshot_id, #id_device_name, #id_vol_delete_on_instance_delete";
        break;
    }
    var elements_list_group = $(elements_list).closest(".form-group");
    elements_list_group.addClass("required");
    // marking all the fields in 'elements_list' as mandatory except '#id_device_name'
    $("#id_device_name").closest(".form-group").removeClass("required");
    // showing all the fields in 'elements_list'
    elements_list_group.show();
  }

  $document.on('change', '.workflow #id_source_type', function () {
    update_launch_source_displayed_fields(this);
  });

  $('.workflow #id_source_type').change();
  horizon.modals.addModalInitFunction(function (modal) {
    $(modal).find("#id_source_type").change();
  });

  /*
   Update the device size value to reflect minimum allowed
   for selected image and flavor
   */
  function update_device_size(source_type) {
    var volume_size = horizon.Quota.getSelectedFlavor().disk;
    var size_field = $("#id_volume_size");

    if (source_type === 'image') {
      var image = horizon.Quota.getSelectedImageOrSnapshot(source_type);
      if (image !== undefined && image.min_disk > volume_size) {
        volume_size = image.min_disk;
      }
      if (image !== undefined && image.size > volume_size) {
        volume_size = image.size;
      }
    }

    // If the user has manually changed the volume size, do not override
    // unless user-defined value is too small.
    if (horizon.instances.user_volume_size) {
      var user_value = size_field.val();
      if (user_value > volume_size) {
        volume_size = user_value;
      }
    }

    // Make sure the new value is >= the minimum allowed (1GB)
    if (volume_size < 1) {
      volume_size = 1;
    }

    size_field.val(volume_size);
  }

  $document.on('change', '.workflow #id_flavor', function () {
    update_device_size();
  });

  $document.on('change', '.workflow #id_image_id', function () {
    update_device_size('image');
  });

  $document.on('input', '.workflow #id_volume_size', function () {
    horizon.instances.user_volume_size = true;
    // We only need to listen for the first user input to this field,
    // so remove the listener after the first time it gets called.
    $document.off('input', '.workflow #id_volume_size');
  });

  horizon.instances.decrypt_password = function(encrypted_password, private_key) {
    var crypt = new JSEncrypt();
    crypt.setKey(private_key);
    return crypt.decrypt(encrypted_password);
  };

  $document.on('change', '#id_private_key_file', function (evt) {
    var file = evt.target.files[0];
    var reader = new FileReader();
    if (file) {
      reader.onloadend = function(event) {
        $("#id_private_key").val(event.target.result);
      };
      reader.onerror = function() {
        horizon.clearErrorMessages();
        horizon.alert('error', gettext('Could not read the file'));
      };
      reader.readAsText(file);
    }
    else {
      horizon.clearErrorMessages();
      horizon.alert('error', gettext('Could not decrypt the password'));
    }
  });
  /*
    The font-family is changed because with the default policy the major I
    and minor the l cannot be distinguished.
  */
  $document.on('show.bs.modal', '#password_instance_modal', function () {
    $("#id_decrypted_password").css({
      "font-family": "monospace",
      "cursor": "text"
    });
    $("#id_encrypted_password").css("cursor","text");
    $("#id_keypair_name").css("cursor","text");
  });

  $document.on('click', '#decryptpassword_button', function (evt) {
    var encrypted_password = $("#id_encrypted_password").val();
    var private_key = $('#id_private_key').val();
    if (!private_key) {
      evt.preventDefault();
      $(this).closest('.modal').modal('hide');
    }
    else {
      if (private_key.length > 0) {
        evt.preventDefault();
        var decrypted_password = horizon.instances.decrypt_password(encrypted_password, private_key);
        if (decrypted_password === false || decrypted_password === null) {
          horizon.clearErrorMessages();
          horizon.alert('error', gettext('Could not decrypt the password'));
        }
        else {
          $("#id_decrypted_password").val(decrypted_password);
          $("#decryptpassword_button").hide();
        }
      }
    }
  });
});
