User = {
  disable_samples: function() {
    new Ajax.Request("/user/update.json", {
      parameters: {
        "user[show_samples]": false
      },

      onComplete: function(resp) {
        var resp = resp.responseJSON

        if (resp.success) {
          $("resized_notice").hide();
          $("samples_disabled").show();
          Post.highres();
        } else {
          notice("Error: " + resp.reason)
        }
      }
    })
  },

  destroy: function(id) {
    notice("Deleting record #" + id)

    new Ajax.Request("/user_record/destroy.json", {
      parameters: {
        "id": id
      },
      onComplete: function(resp) {
        if (resp.status == 200) {
          notice("Record deleted")
        } else {
          notice("Access denied")
        }
      }
    })
  },

  current_check: null,
  cancel_check: function() {
    current_check = null;
  },

  /* If background is true, this is a request being made as an indirect result of other
   * input; these can be cancelled (rather, the result is ignord) and are automatically
   * cancelled if another is started while a previous one is still running.
   *
   * If background is false, this is an explicit user action (user submitted the form)
   * and the action must not be cancelled by unrelated background actions.
   */
  reset_password: function(username, email, func) {
    var new_check = new Ajax.Request("/user/reset_password.json", {
      parameters: {
        "user[name]": username,
        "user[email]": email
      },
      onComplete: function(resp) {
        var resp = resp.responseJSON;
        func(resp);
      }
    });
  },
  check: function(username, password, background, func) {
    var parameters = {
      "username": username
    }
    if(password)
      parameters.password = password;

    var new_check = new Ajax.Request("/user/check.json", {
      parameters: parameters,

      onSuccess: function(resp) {
        if(background && resp.request != current_check)
          return;
        current_check = null;

        var resp = resp.responseJSON;
        func(resp);

      }
    });
    if(background)
      current_check = new_check;
  },

  create: function(username, password, email, func) {
    var parameters = {
      "user[name]": username,
      "user[password]": password
    }
    if(email)
      parameters["user[email]"] = email;

    var new_check = new Ajax.Request("/user/create.json", {
      parameters: parameters,

      onComplete: function(resp) {
        var resp = resp.responseJSON;
        func(resp);
      }
    });
  },

  set_login: function(username, pass_hash, user_info)
  {
    Cookie.put("login", username)
    Cookie.put("pass_hash", pass_hash)
    Cookie.put("user_info", user_info)
  },

  check_name_timer: null,
  last_username_in_form: null,
  success_func: null,
  messages: [],

  init: function()
  {
    $("login-popup-notices").select("SPAN").each(function(e) {
      User.messages.push(e.id);
    });

    /*
     * IE makes us jump lots of hoops.  We have to watch submit events on every object
     * instead of just window because IE doesn't support event capturing.  We have to
     * override the submit method in every form to catch programmatic submits, because
     * IE doesn't seem to support initiating events by firing them.
     *
     * Also, since we can't capture events, we need to be sure our submit event is done
     * before other handlers, so if we cancel the event, we prevent other event handlers
     * from continuing.  However, we need to attach after forms have been created.  So,
     * this needs to be run as an early DOMLoaded event, and any other code that attaches
     * submit events to code needs to be run in a later DOMLoaded event (or later events).
     *
     */

    $$("FORM.need-signup").each(function(form) {
      form.observe("submit", User.run_login_onsubmit);
    });

    /* If you select an item from the history dropdown in IE7, change events never fire, so
     * use keyup instead.  This isn't a problem with password fields, since there's no history
     * dropdown. */
    $("login-popup").observe("submit", function(e) {
      e.stop();
      User.form_submitted();
    });

    $("login-popup-submit").observe("click", function(e) {
      e.stop();
      User.form_submitted();
    });

    $("login-popup-cancel").observe("click", function(e) { e.stop(); User.close(false); });
    $("login-popup-username").observe("blur", function(e) { User.form_username_blur(); });
    $("login-popup-username").observe("focus", function(e) { User.form_username_focus(); });
    $("login-popup-username").observe("keyup", function(e) { User.form_username_changed(true); });
    $("login-tabs").select("LI").each(function(a) { a.observe("mousedown", function(e) { e.stop(); }); });
    $("login-tabs").select("LI").each(function(a) { a.observe("click", function(e) { e.stop(); User.set_tab(a.id); }); });

    /* IE and FF are glitchy with form submission: they fail to submit forms unless
     * there's an <INPUT type="submit"> somewhere in the form.  IE is even worse:
     * even if there is one, if it's hidden on page load (including if it's a parent
     * element hidden), it'll never submit the form, even if it's shown later.  Don't
     * rely on this behavior; just catch enter presses and submit the form explicitly. */
    OnKey(13, {AllowInputFields: true, Element: $("login-popup")}, function(e)
    {
      e.stop();
      User.form_submitted();
    });

    /* Escape closes the login box. */
    OnKey(27, {AllowInputFields: true, AlwaysAllowOpera: true}, function(e)
    {
      if(!User.success_func)
        return false;

      User.close(false);
      return true;
    });
  },

  open: function(success)
  {
    if(User.success_func)
      User.close(false);
    User.success_func = success;

    $("login-background").show();
    $("login-container").show();

    User.set_tab("tab-login");
  },

  close: function(run_success_func)
  {
    if(!User.success_func)
      return;

    $("login-background").hide();
    $("login-container").hide();
    User.active_tab = null;
    User.check_name_timer = null;
    var func = User.success_func;
    User.success_func = null;

    success_func = null;
    if(run_success_func)
      window.setTimeout(func, 0);
  },

  /* Handle login from an onclick.  If login is not needed, return true.  Otherwise,
   * start the login, and return false; the object will receive another click when
   * the login is successful. */
  run_login_onclick: function(event)
  {
    event = Event.extend(event);

    /* event.target is not copied by clone_event. */
    var target = $(event.target);

    /* event is not available when we get to the callback in IE7. */
    var e = clone_event(event);

    if(User.run_login(true, function() {
        if(target.hasClassName("login-button"))
        {
          /* This is a login button, and not an action that happened to need login.  After
           * a successful login, don't click the button; that'll just go to the login page.
           * Instead, just reload the current page. */
          Cookie.put("notice", "You have been logged in.");
          document.location.reload();
          return;
        }
        target.simulate_anchor_click(e);
      }))
      return true;

    /* Login is running, so stop the event.  Don't just return false; call stop(), so
     * event.stopped is available to the caller if we've been sent this message via
     * Element.dispatchEvent. */
    event.stop();
    return false;
  },

  /* Handle login from an onsubmit.  If login is needed, stop the event and resubmit
   * it when the login completes.  If login is not needed, return and let the submit
   * complete normally. */
  run_login_onsubmit: function(event)
  {
    /* Set skip_complete_on_true, so if we don't need to login, we don't resubmit the
     * event; we just don't cancel it. */
    var target = $(event.target);
    if(!User.run_login(true, function() { target.simulate_submit(); }))
      event.stop();
  },

  /* Handle login.  If we're already logged in, run complete (unless only_complete_on_login
   * is true) and return true.  If we need to log in, start the login dialog; it'll call
   * complete() on successful login. */
  run_login: function(only_complete_on_login, complete)
  {
    if(Cookie.get("login") != "")
    {
      if(!only_complete_on_login)
        complete();
      return true;
    }

    User.open(complete);

    return false;
  },

  active_tab: null,
  set_tab: function(tab)
  {
    if(User.active_tab == tab)
      return;
    User.active_tab = tab;

    User.check_name_timer = null;
    User.last_username_in_form = null;

    $("login-tabs").select("LI").each(function(li) { li.removeClassName("selected"); });
    $("login-tabs").down("#" + tab).addClassName("selected");


    $$(".tab-header-text").each(function(li) { li.hide(); });
    $(tab + "-text").show();

    if(tab == "tab-login")
    {
      /* If the user's browser fills in a username but no password, focus the password.  Otherwise,
       * focus the username. */
      if($("login-popup-password").value == "" && $("login-popup-username").value != "")
        $("login-popup-password").focus();
      else
        $("login-popup-username").focus();

      User.set_state("login-blank");
    }
    else if(tab == "tab-reset")
    {
      User.set_state("reset-blank");
      $("login-popup-username").focus();
    }
    User.form_username_changed();
  },

  message: function(text)
  {
    for (var i = 0, l = User.messages.length; i < l; i++) {
      var elem = User.messages[i];
      $(elem).hide();
    }

    $("login-popup-message").update(text);
    $("login-popup-message").show();
  },

  set_state: function(state)
  {
    var show = {};
    if(state.match(/^login-/))
    {
      show["login-popup-password-box"] = true;
      if(state == "login-blank")
        $("login-popup-submit").update("Login");
      else if(state == "login-user-exists")
        $("login-popup-submit").update("Login");
      else if(state == "login-confirm-password")
      {
        show["login-popup-password-confirm-box"] = true;
        $("login-popup-submit").update("Create account");
      }
      else if(state == "login-confirm-password-mismatch")
        $("login-popup-submit").update("Create account");
      show["login-popup-" + state] = true;
    }
    else if(state.match(/^reset-/))
    {
      show["login-popup-email-box"] = true;
      $("login-popup-submit").update("Reset password");

      show["login-popup-" + state] = true;
    }

    var all = ["login-popup-email-box", "login-popup-password-box", "login-popup-password-confirm-box"].concat(User.messages);

    current_state = state;
    for (var i = 0, l = all.length; i < l; i++) {
      var elem = all[i];
      if(show[elem])
        $(elem).show();
      else
        $(elem).hide();
    }
  },

  pending_username: null,
  form_username_changed: function(keyup)
  {
    var username = $("login-popup-username").value;
    if(username == User.last_username_in_form)
      return;
    User.last_username_in_form = username;

    User.cancel_check();
    if(User.check_name_timer)
      window.clearTimeout(User.check_name_timer);
    User.pending_username = null;

    if(username == "")
    {
      if(User.active_tab == "tab-login")
        User.set_state("login-blank");
      else if(User.active_tab == "tab-reset")
        User.set_state("reset-blank");
      return;
    }

    /* Delay on keyup, so we don't send tons of requests.  Don't delay otherwise,
     * so we don't introduce lag when we don't have to. */
    var ms = 500;
    if(!keyup && User.check_name_timer)
      ms = 0;

    /*
     * Make sure the UI is still usable if this never finished.  This way, we don't
     * lag the interface if these JSON requests are taking longer than usual; you should
     * be able to click "login" immediately as soon as a username and password are entered.
     * Entering a username and password and clicking "login" should still behave properly
     * if the username doesn't exist and the check_name_timer JSON request hasn't come
     * back yet.
     *
     * If the state isn't "blank", the button is already enabled.
     */
    User.check_name_timer = window.setTimeout(function() {
      User.check_name_timer = null;
      User.check(username, null, true, function(resp)
      {
        if(resp.exists)
        {
          /* Update the username to match the actual user's case.  If the form contents have
           * changed since we started this check, don't do this.  (We cancel this event if we
           * see the contents change, but the contents can change without this event firing
           * at all.) */
          var current_username = $("login-popup-username").value;
          if(current_username == username)
          {
            /* If the element doesn't have focus, change the text to match.  If it does, wait
             * until it loses focus, so it doesn't interfere with the user editing it. */
            if(!$("login-popup").focused)
              $("login-popup-username").value = resp.name;
            else
              User.pending_username = resp.name;
          }
        }

        if(User.active_tab == "tab-login")
        {
          if(!resp.exists)
          {
            User.set_state("login-confirm-password");
            return;
          }
          else
            User.set_state("login-user-exists");
        }
        else if(User.active_tab == "tab-reset")
        {
          if(!resp.exists)
            User.set_state("reset-blank");
          else if(resp.no_email)
            User.set_state("reset-user-has-no-email");
          else
            User.set_state("reset-user-exists");
        }
      });
    }, ms);
  },

  form_username_focus: function()
  {
    $("login-popup").focused = true;
  },

  form_username_blur: function()
  {
    $("login-popup").focused = false;

    /* When the username field loses focus, update the username case to match the
     * result we got back from check(), if any. */
    if(User.pending_username)
    {
      $("login-popup").username.value = User.pending_username;
      User.pending_username = null;
    }

    /* We watch keyup on the username, because change events are unreliable in IE; update
     * when focus is lost, too, so we see changes made without using the keyboard. */
    User.form_username_changed(false);
  },

  form_submitted: function()
  {
    User.cancel_check();
    if(User.check_name_timer)
      window.clearTimeout(User.check_name_timer);

    var username = $("login-popup-username").value;
    var password = $("login-popup-password").value;
    var password_confirm = $("login-popup-password-confirm").value;
    var email = $("login-popup-email").value;

    if(username == "")
      return;

    if(User.active_tab == "tab-login")
    {
      if(password == "")
      {
        User.message("Please enter a password.");
        return;
      }

      if(current_state == "login-confirm-password")
      {
        if(password != password_confirm)
          User.message("The passwords you've entered don't match.");
        else
        {
          // create account
          User.create(username, password, null, function(resp) {
            if(resp.response == "success")
            {
              User.set_login(resp.name, resp.pass_hash, resp.user_info);
              User.close(true);
            }
            else if(resp.response == "error")
            {
              User.message(resp.errors.join("<br>"))
            }
          });
        }
        return;
      }

      User.check(username,  password, false, function(resp)
      {
        if(!resp.exists)
        {
          User.set_state("login-confirm-password");
          return;
        }

        /* We've authenticated successfully.  Our hash is in password_hash; insert the
         * login cookies manually. */
        if(resp.response == "wrong-password")
        {
          notice("Incorrect password");
          return;
        }
        User.set_login(resp.name, resp.pass_hash, resp.user_info);
        User.close(true);
      });
    }
    else if(User.active_tab == "tab-reset")
    {
      if(email == "")
        return;

      User.reset_password(username, email, function(resp)
      {
        if(resp.result == "success")
          User.set_state("reset-successful");
        else if(resp.result == "unknown-user")
          User.set_state("reset-unknown-user");
        else if(resp.result == "wrong-email")
          User.set_state("reset-user-email-incorrect");
        else if(resp.result == "no-email")
          User.set_state("reset-user-has-no-email");
        else if(resp.result == "invalid-email")
          User.set_state("reset-user-email-invalid");
      });
    }
  },

  modify_blacklist: function(add, remove, success)
  {
    new Ajax.Request("/user/modify_blacklist.json", {
      parameters: {
        "add[]": add,
        "remove[]": remove
      },
      onComplete: function(resp) {
        var resp = resp.responseJSON;

        if (resp.success)
        {
          if(success) success(resp);
        } else {
          notice("Error: " + resp.reason);
        }
      }
    });
  },

  set_pool_browse_mode: function(browse_mode) {
    new Ajax.Request("/user/update.json", {
      parameters: {
        "user[pool_browse_mode]": browse_mode
      },

      onComplete: function(resp) {
        var resp = resp.responseJSON;

        if (resp.success) {
          window.location.reload();
        } else {
          notice("Error: " + resp.reason);
        }
      }
    });
  },

  get_current_user_info: function()
  {
    var user_info = Cookie.get("user_info");
    if(!user_info)
      return null;
    return user_info.split(";");
  },
  get_current_user_info_field: function(idx, def)
  {
    var user_info = User.get_current_user_info();
    if(!user_info)
      return def;
    if(idx >= user_info.length)
      return def;
    return user_info[idx];
  },
  get_current_user_id: function()
  {
    return parseInt(User.get_current_user_info_field(0, 0));
  },

  get_current_user_level: function()
  {
    return parseInt(User.get_current_user_info_field(1, 0));
  },

  get_use_browser: function()
  {
    var setting = User.get_current_user_info_field(2, "0");
    return setting == "1";
  },

  is_member_or_higher: function()
  {
    return User.get_current_user_level() >= 20;
  },

  is_mod_or_higher: function()
  {
    return User.get_current_user_level() >= 40;
  }
}

