// http://documentcloud.github.com/underscore/

(function(){
  function logger(m){
    var a = arguments;
    if(window.console){
      _.each(a, function(n, i){ window.console.log(n)});
    }
  }



  window.logger = logger;
})();

(function(){
  namespace("model", get_id);

  /*
    Returns a function for a kind (collection, image)
    The function returns the id for the given element,
    looking up its parent DOM tree until it finds one

    returns null for new images to use in posting the url
    ie : null -> collections/ not new -> collections/new
  */
  function get_id(kind){
    var re = new RegExp("(edit_|_|new_)?"+kind+"(_)?");

    var f = function(object){
      if(typeof object == "string"){
        var id = object.replace(re,"");
        return (id == "new") ? null : id;
      } else {
        return f(object.attr("id"))
      }
    }
    return f;
  }
})();

(function(){
  // Handles AJAX transmission
  namespace("request", post, get, put, edit, destroy)

  /* From: http://brandonaaron.net/blog/2009/02/24/jquery-rails-and-ajax */
  $(document).ajaxSend(function(event, request, settings){
    if(settings.type.match(/POST|PUT/img)){
      settings.data = (
              settings.data ? settings.data + "&" : "") +
              "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
      }
  });

  function request(object){
    $.ajax({
      cache: false,
      url:object.url,
      success: object.success,
      data: object.data,
      type: object.method,
      dataType: "json"
    })
  }

  function post(object, data){
    object.method = "POST"
    object.data = data;
    object.url = object.url.replace(/\/new$/,"");
    request(object);
  }

  function edit(object){
    object.url = object.url + "/edit";
    get(object);
  }

  function get(object){
    object.method = "GET"
    request(object)
  }

  function put(object){
    object.method = "PUT"
    request(object)
  }

  function destroy(object){
    object.method = "DELETE"
    object.data = ""
    request(object);
  }

})();
(function (){
  // Simple key value storage
  namespace("store", put, get);

  var store = {};

  // Stores HTML
  function put(id, v){
    store[id] = v;
  }

  function get(id){
    var n = store[id];
    delete store[id];
    return n;
  }
})();

(function(){
  namespace("view", render, render_flash, remove);

  function remove(el, callback){
    callback = callback || function(){};
    el.fadeOut(250, function(){el.remove(); callback()});
  }

  function render_flash(message, kind){
    if(message){
      var kind = kind || "notice";
      var t = $("<div class='"+kind+"'>"+message+"</div>");
      t.hide().fadeIn(250);
      $("#flash").show().append(t);
      _.delay(function(){t.fadeOut(250, function(){t.remove()})}, 5000)
    }
  }

  function render(target, data){
    var n = $(data.html),
        o = target.replaceWith(n);

    render_flash(data.flash);
    return n;
  }

})();

(function(){
  namespace("flash_messages");

  $(document).ready(function(){
    $("#flash.fade_in").slideDown();
    $("#flash.fade_in").click(function(){$(this).slideUp();});
  })

})();

(function(){
  namespace("positions", init, empty)

  function get_url(list_element, url_or_func){
    if(typeof url_or_func == "function"){
      return url_or_func(list_element);
    } else {
      return url_or_func;
    }
  }

  function serialize(list_element, kind){
    var regEx     = new RegExp(kind+"_"),
        elements  = list_element.find("."+kind);

    return $.map(
        _.compact($.map(elements, function(e, i, l){ return e.id})),
        function(e, n){
          var i = e.replace(regEx,"");
          return kind+"["+i+"]="+n}).join("&")

  }

  function empty(el){
    if(el.find("> li").length > 0){
      el.find("> .empty").hide();
    } else {
      el.find("> .empty").show();
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  function update(options, el){
    var url       = get_url(options.element, options.url),
        data      = serialize(options.element, options.kind)

    if(data.length > 0){
      $.post(url+"/positions", data);
    }
    empty($(el));
  }

  function init(options){
    var defaults = {
      placeholder: 'sortable-placeholder',
      distance: 20,
      items: 'li',
      update:function(){
        var el = this;
        update(options, this);
      },
      remove:function(){
        empty($(this));
        //var el = this;
        //update(options, this);
      }
    }
    return options.element.sortable(_.extend(defaults, options.options))
  };

})();

(function(){
  namespace("forms", save, monitor, autosize_textarea, unsaved_changes,
            show_errors, clear_errors,
            nice_inputs, autogrow_textarea, prevent_double_submit)

  function prevent_double_submit(form){
    form.submit(function(){
      if(form.data("submitted")){ return false}
      form.data("submitted", true);
      form.find(".rbutton").attr("disabled", "true");
      return true
    })
  }

  function autosize_textarea(target){

    function resize(){
      var t = target.hide(),
          th = $(window).height();
          bg = $(document.body).height();
          ih = Math.max(th-bg-140, 400);
      t.css("height", ih+"px").show();
    }
    _.delay(resize, 50);
    $(window).resize(resize)
  }

  // TODO improve the calculation for the textarea height
  function autogrow_textarea(target, max){
    var max_height = max || 40;
    target.keyup(function(){
      target.css("height", "0px");
      var lh = Math.max(this.scrollHeight, max_height);

      target.css("height", (lh)+"px");
    });

    target.keyup();
  };

  /* Accepts a text area or input field and monitors for changes */
  function monitor(context){
    if(context === undefined){
      $(document).trigger("save_occured");
      return false;
    }
    context_setup(context);

    // FIXME there is a bug if there is more than one form on a page being monitored.
    // window.onbeforeunload = function (e) {
    //   // Do not halt for new records
    //   var f = context.parents().filter("form").attr("id");
    //
    //   if(f != null && f.match(/^new_/) != null){
    //     return undefined;
    //   } else {
    //     if(!context_did_change(context)) { return undefined; }
    //
    //     var e = e || window.event,
    //         s = "You have unsaved changed.";
    //
    //     // For IE and Firefox
    //     if (e) { e.returnValue = "You have unsaved changed."; }
    //
    //     // For Safari
    //     return s;
    //   }
    // };

    context.data("orginal_value", context.val());
    context.keyup(function(){unsaved_changes(context)});

    $(document).bind("save_occured", function(){
      context_setup(context);
      unsaved_changes(context)
    })
  }

  function context_setup(context){
    var field;
    for (var i=0; i < context.length; i++) {
      field = $(context[i]);
      field.data("original_value", field.val());
    };
  }

  function context_did_change(context){
    var field,
        unsaved = false;
    for (var i=0; i < context.length; i++) {
      field = $(context[i]);
      if(field.val() != field.data("original_value")){
        unsaved = true;
      }
    };

    return unsaved;
  }

  function unsaved_changes(context){
    if(context_did_change(context)){
      $(".unsaved_changes").stop(true, true).fadeIn();
      $("body").addClass("warn_user")
      return true;
    } else {
      $(".unsaved_changes").stop(true, true).fadeOut();
      $("body").removeClass("warn_user")
      return false;
    }
  }

  function save(){
    $(this).parents().filter("form").submit();
  }

  function clear_errors(class_name){
    $("."+class_name+" *").removeClass("fieldWithErrors").find(".errorNote").remove()
  }

  function show_errors(errors, class_name){
    var el;
    clear_errors(class_name)
    for (var i=0; i < errors.length; i++) {
      el = $("#"+class_name+"_"+errors[i][0]);
      el.parent().addClass("fieldWithErrors")
      el.parent().append($("<b class='errorNote'>"+errors[i][1]+"</b>"));
    };
  }

  // Monitors for changes
  // Creates tabby text areas
  //and binds C+S to save for all text inputs
  function nice_inputs(parent, save_func){
    $(parent+" input[type='text']").bind("keydown", "Ctrl+s", save_func);
    $(parent+" textarea").tabby().bind("keydown", "Ctrl+s", save_func);
    $(parent+" .save_button").live("click", save_func);

  }

})();

(function(){
  // Code taken from
  // http://technology.hostei.com/?p=3
  $.fn.insertAtCaret = function (tagName) {
    return this.each(function(){
      if (document.selection) {
        //IE support
        this.focus();
        sel = document.selection.createRange();
        sel.text = tagName;
        this.focus();
      }else if (this.selectionStart || this.selectionStart == '0') {
        //MOZILLA/NETSCAPE support
        startPos = this.selectionStart;
        endPos = this.selectionEnd;
        scrollTop = this.scrollTop;
        this.value = this.value.substring(0, startPos) + tagName + this.value.substring(endPos,this.value.length);
        this.focus();
        this.selectionStart = startPos + tagName.length;
        this.selectionEnd = startPos + tagName.length;
        this.scrollTop = scrollTop;
      } else {
        this.value += tagName;
        this.focus();
      }
    });
  };
})();

(function(){
  namespace("form.examples");

  function remove_example(example, original){
    example.hide();
    original.show().focus();
    original.blur(function(){check_example(example, original)});
  }

  function check_example(example, original){
    if(original.val().length < 1){
      example.show();
      original.hide();
    }
  }

  function clone(el){
    if(el.attr("type") == 'password'){
      var new_el = $("<input type='text'/>"),
          attrs = ["id", "name", "class", "style", "size"];

      for(var n = 0; n < attrs.length; n++){
        new_el.attr(attrs[n], el.attr(attrs[n]))
      }
      return new_el;
    } else {
      return el.clone();
    }
  }

  ready(function(){
    _.defer(function(){
    $("input, textarea").each(function(i,e){
      e = $(e);
      if( e.attr("example") &&
          e.val().length < 1 &&
          !e.parent().hasClass("fieldWithErrors")
      ){
        var example = clone(e);
        example.insertAfter(e);
        example.attr("name","")
        e.hide();
        example.val(e.attr("example"));
        example.addClass("example");
        var remove = function(){remove_example(example, e)}
        example.focus(remove);
      }
    });
    });
  })
})();
