/*
  backbone-modelref.js 0.1.5
  (c) 2011, 2012 Kevin Malakoff - http://kmalakoff.github.com/backbone-modelref/
  License: MIT (http://www.opensource.org/licenses/mit-license.php)
  Dependencies: Backbone.js, and Underscore.js.
*/
(function() {
  return (function(factory) {
    // AMD
    if (typeof define === 'function' && define.amd) {
      return define('backbone-modelref', ['underscore', 'backbone'], factory);
    }
    // CommonJS/NodeJS or No Loader
    else {
      return factory.call(this);
    }
  })(function() {// Generated by CoffeeScript 1.3.3
/*
  backbone-modelref.js 0.1.5
  (c) 2011, 2012 Kevin Malakoff - http://kmalakoff.github.com/backbone-modelref/
  License: MIT (http://www.opensource.org/licenses/mit-license.php)
  Dependencies: Backbone.js, and Underscore.js.
*/

var Backbone, bind, isFunction,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

isFunction = function(obj) {
  return typeof obj === 'function';
};

bind = function(obj, fn_name) {
  var fn;
  fn = obj[fn_name];
  return obj[fn_name] = function() {
    return fn.apply(obj, arguments);
  };
};

Backbone = !this.Backbone && (typeof require !== 'undefined') ? require('backbone') : this.Backbone;

Backbone.ModelRef = (function() {

  ModelRef.VERSION = '0.1.5';

  __extends(ModelRef.prototype, Backbone.Events);

  ModelRef.MODEL_EVENTS_WHEN_LOADED = ['reset', 'remove'];

  ModelRef.MODEL_EVENTS_WHEN_UNLOADED = ['reset', 'add'];

  function ModelRef(collection, id, cached_model) {
    var event, _i, _j, _len, _len1, _ref, _ref1;
    this.collection = collection;
    this.id = id;
    this.cached_model = cached_model != null ? cached_model : null;
    this._checkForLoad = bind(this, '_checkForLoad');
    this._checkForUnload = bind(this, '_checkForUnload');
    if (!this.collection) {
      throw new Error("Backbone.ModelRef: collection is missing");
    }
    this.ref_count = 1;
    if (this.cached_model) {
      this.id = this.cached_model.id;
    }
    if (!this.cached_model && this.id) {
      this.cached_model = this.collection.get(this.id);
    }
    if (this.cached_model) {
      _ref = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        event = _ref[_i];
        this.collection.bind(event, this._checkForUnload);
      }
    } else {
      _ref1 = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        event = _ref1[_j];
        this.collection.bind(event, this._checkForLoad);
      }
    }
  }

  ModelRef.prototype.retain = function() {
    this.ref_count++;
    return this;
  };

  ModelRef.prototype.release = function() {
    var event, _i, _j, _len, _len1, _ref, _ref1;
    if (this.ref_count <= 0) {
      throw new Error("Backbone.ModelRef.release(): ref count is corrupt");
    }
    this.ref_count--;
    if (this.ref_count > 0) {
      return;
    }
    if (this.cached_model) {
      _ref = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        event = _ref[_i];
        this.collection.unbind(event, this._checkForUnload);
      }
    } else {
      _ref1 = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        event = _ref1[_j];
        this.collection.unbind(event, this._checkForLoad);
      }
    }
    this.collection = null;
    this.unbind(null);
    return this;
  };

  ModelRef.prototype.getModel = function() {
    if (this.cached_model && !this.cached_model.isNew()) {
      this.id = this.cached_model.id;
    }
    if (this.cached_model) {
      return this.cached_model;
    }
    if (this.id) {
      this.cached_model = this.collection.get(this.id);
    }
    return this.cached_model;
  };

  ModelRef.prototype._checkForLoad = function() {
    var event, model, _i, _j, _len, _len1, _ref, _ref1;
    if (this.cached_model || !this.id) {
      return;
    }
    model = this.collection.get(this.id);
    if (!model) {
      return;
    }
    _ref = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      event = _ref[_i];
      this.collection.unbind(event, this._checkForLoad);
    }
    _ref1 = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      event = _ref1[_j];
      this.collection.bind(event, this._checkForUnload);
    }
    this.cached_model = model;
    return this.trigger('loaded', this.cached_model);
  };

  ModelRef.prototype._checkForUnload = function() {
    var event, model, _i, _j, _len, _len1, _ref, _ref1;
    if (!this.cached_model || !this.id) {
      return;
    }
    model = this.collection.get(this.id);
    if (model) {
      return;
    }
    _ref = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      event = _ref[_i];
      this.collection.unbind(event, this._checkForUnload);
    }
    _ref1 = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      event = _ref1[_j];
      this.collection.bind(event, this._checkForLoad);
    }
    model = this.cached_model;
    this.cached_model = null;
    return this.trigger('unloaded', model);
  };

  return ModelRef;

})();

Backbone.Model.prototype.model = function() {
  if (arguments.length === 0) {
    return this;
  }
  throw new Error('cannot set a Backbone.Model');
};

Backbone.Model.prototype.isLoaded = function() {
  return true;
};

Backbone.Model.prototype.bindLoadingStates = function(params) {
  if (isFunction(params)) {
    params(this);
  } else if (params.loaded) {
    params.loaded(this);
  }
  return this;
};

Backbone.Model.prototype.unbindLoadingStates = function(params) {
  return this;
};

Backbone.ModelRef.prototype.get = function(attribute_name) {
  if (attribute_name !== 'id') {
    throw new Error("Backbone.ModelRef.get(): only id is permitted");
  }
  if (this.cached_model && !this.cached_model.isNew()) {
    this.id = this.cached_model.id;
  }
  return this.id;
};

Backbone.ModelRef.prototype.model = function(model) {
  var changed, event, previous_model, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3;
  if (arguments.length === 0) {
    return this.getModel();
  }
  if (model && (model.collection !== this.collection)) {
    throw new Error("Backbone.ModelRef.model(): collections don't match");
  }
  changed = this.id ? !model || (this.id !== model.get('id')) : !!model;
  if (!changed) {
    return;
  }
  if (this.cached_model) {
    previous_model = this.cached_model;
    this.id = null;
    this.cached_model = null;
    _ref = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      event = _ref[_i];
      this.collection.unbind(event, this._checkForUnload);
    }
    _ref1 = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      event = _ref1[_j];
      this.collection.bind(event, this._checkForLoad);
    }
    this.trigger('unloaded', previous_model);
  }
  if (!model) {
    return;
  }
  this.id = model.get('id');
  this.cached_model = model.model();
  _ref2 = Backbone.ModelRef.MODEL_EVENTS_WHEN_UNLOADED;
  for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
    event = _ref2[_k];
    this.collection.unbind(event, this._checkForLoad);
  }
  _ref3 = Backbone.ModelRef.MODEL_EVENTS_WHEN_LOADED;
  for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
    event = _ref3[_l];
    this.collection.bind(event, this._checkForUnload);
  }
  return this.trigger('loaded', this.cached_model);
};

Backbone.ModelRef.prototype.isLoaded = function() {
  var model;
  model = this.getModel();
  if (!model) {
    return false;
  }
  if (model.isLoaded) {
    return model.isLoaded();
  } else {
    return true;
  }
};

Backbone.ModelRef.prototype.bindLoadingStates = function(params) {
  var model;
  if (isFunction(params)) {
    params = {
      loaded: params
    };
  }
  !params.loaded || this.bind('loaded', params.loaded);
  !params.unloaded || this.bind('unloaded', params.unloaded);
  model = this.model();
  if (!model) {
    return null;
  }
  return model.bindLoadingStates(params);
};

Backbone.ModelRef.prototype.unbindLoadingStates = function(params) {
  if (isFunction(params)) {
    params = {
      loaded: params
    };
  }
  !params.loaded || this.unbind('loaded', params.loaded);
  !params.unloaded || this.unbind('unloaded', params.unloaded);
  return this.model();
};

if (typeof exports !== 'undefined') {
  module.exports = Backbone.ModelRef;
}

if (this.Backbone) {
  this.Backbone.ModelRef = Backbone.ModelRef;
}

Backbone.ModelRef.VERSION = '0.1.5';
; return Backbone.ModelRef;});
}).call(this);