// Generated by CoffeeScript 1.3.3 (function() {

var $, Controller, Events, Log, Model, Module, Spine, createObject, isArray, isBlank, makeArray, moduleKeywords,
  __slice = [].slice,
  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
  __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; },
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

Events = {
  bind: function(ev, callback) {
    var calls, evs, name, _i, _len;
    evs = ev.split(' ');
    calls = this.hasOwnProperty('_callbacks') && this._callbacks || (this._callbacks = {});
    for (_i = 0, _len = evs.length; _i < _len; _i++) {
      name = evs[_i];
      calls[name] || (calls[name] = []);
      calls[name].push(callback);
    }
    return this;
  },
  one: function(ev, callback) {
    return this.bind(ev, function() {
      this.unbind(ev, arguments.callee);
      return callback.apply(this, arguments);
    });
  },
  trigger: function() {
    var args, callback, ev, list, _i, _len, _ref;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    ev = args.shift();
    list = this.hasOwnProperty('_callbacks') && ((_ref = this._callbacks) != null ? _ref[ev] : void 0);
    if (!list) {
      return;
    }
    for (_i = 0, _len = list.length; _i < _len; _i++) {
      callback = list[_i];
      if (callback.apply(this, args) === false) {
        break;
      }
    }
    return true;
  },
  unbind: function(ev, callback) {
    var cb, i, list, _i, _len, _ref;
    if (!ev) {
      this._callbacks = {};
      return this;
    }
    list = (_ref = this._callbacks) != null ? _ref[ev] : void 0;
    if (!list) {
      return this;
    }
    if (!callback) {
      delete this._callbacks[ev];
      return this;
    }
    for (i = _i = 0, _len = list.length; _i < _len; i = ++_i) {
      cb = list[i];
      if (!(cb === callback)) {
        continue;
      }
      list = list.slice();
      list.splice(i, 1);
      this._callbacks[ev] = list;
      break;
    }
    return this;
  }
};

Log = {
  trace: true,
  logPrefix: '(App)',
  log: function() {
    var args;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    if (!this.trace) {
      return;
    }
    if (this.logPrefix) {
      args.unshift(this.logPrefix);
    }
    if (typeof console !== "undefined" && console !== null) {
      if (typeof console.log === "function") {
        console.log.apply(console, args);
      }
    }
    return this;
  }
};

moduleKeywords = ['included', 'extended'];

Module = (function() {

  Module.include = function(obj) {
    var key, value, _ref;
    if (!obj) {
      throw 'include(obj) requires obj';
    }
    for (key in obj) {
      value = obj[key];
      if (__indexOf.call(moduleKeywords, key) < 0) {
        this.prototype[key] = value;
      }
    }
    if ((_ref = obj.included) != null) {
      _ref.apply(this);
    }
    return this;
  };

  Module.extend = function(obj) {
    var key, value, _ref;
    if (!obj) {
      throw 'extend(obj) requires obj';
    }
    for (key in obj) {
      value = obj[key];
      if (__indexOf.call(moduleKeywords, key) < 0) {
        this[key] = value;
      }
    }
    if ((_ref = obj.extended) != null) {
      _ref.apply(this);
    }
    return this;
  };

  Module.proxy = function(func) {
    var _this = this;
    return function() {
      return func.apply(_this, arguments);
    };
  };

  Module.prototype.proxy = function(func) {
    var _this = this;
    return function() {
      return func.apply(_this, arguments);
    };
  };

  function Module() {
    if (typeof this.init === "function") {
      this.init.apply(this, arguments);
    }
  }

  return Module;

})();

Model = (function(_super) {

  __extends(Model, _super);

  Model.extend(Events);

  Model.records = {};

  Model.crecords = {};

  Model.attributes = [];

  Model.configure = function() {
    var attributes, name;
    name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    this.className = name;
    this.records = {};
    this.crecords = {};
    if (attributes.length) {
      this.attributes = attributes;
    }
    this.attributes && (this.attributes = makeArray(this.attributes));
    this.attributes || (this.attributes = []);
    this.unbind();
    return this;
  };

  Model.toString = function() {
    return "" + this.className + "(" + (this.attributes.join(", ")) + ")";
  };

  Model.find = function(id) {
    var record;
    record = this.records[id];
    if (!record && ("" + id).match(/c-\d+/)) {
      return this.findCID(id);
    }
    if (!record) {
      throw 'Unknown record';
    }
    return record.clone();
  };

  Model.findCID = function(cid) {
    var record;
    record = this.crecords[cid];
    if (!record) {
      throw 'Unknown record';
    }
    return record.clone();
  };

  Model.exists = function(id) {
    try {
      return this.find(id);
    } catch (e) {
      return false;
    }
  };

  Model.refresh = function(values, options) {
    var record, records, _i, _len;
    if (options == null) {
      options = {};
    }
    if (options.clear) {
      this.records = {};
      this.crecords = {};
    }
    records = this.fromJSON(values);
    if (!isArray(records)) {
      records = [records];
    }
    for (_i = 0, _len = records.length; _i < _len; _i++) {
      record = records[_i];
      record.id || (record.id = record.cid);
      this.records[record.id] = record;
      this.crecords[record.cid] = record;
    }
    this.trigger('refresh', this.cloneArray(records));
    return this;
  };

  Model.select = function(callback) {
    var id, record, result;
    result = (function() {
      var _ref, _results;
      _ref = this.records;
      _results = [];
      for (id in _ref) {
        record = _ref[id];
        if (callback(record)) {
          _results.push(record);
        }
      }
      return _results;
    }).call(this);
    return this.cloneArray(result);
  };

  Model.findByAttribute = function(name, value) {
    var id, record, _ref;
    _ref = this.records;
    for (id in _ref) {
      record = _ref[id];
      if (record[name] === value) {
        return record.clone();
      }
    }
    return null;
  };

  Model.findAllByAttribute = function(name, value) {
    return this.select(function(item) {
      return item[name] === value;
    });
  };

  Model.each = function(callback) {
    var key, value, _ref, _results;
    _ref = this.records;
    _results = [];
    for (key in _ref) {
      value = _ref[key];
      _results.push(callback(value.clone()));
    }
    return _results;
  };

  Model.all = function() {
    return this.cloneArray(this.recordsValues());
  };

  Model.first = function() {
    var record;
    record = this.recordsValues()[0];
    return record != null ? record.clone() : void 0;
  };

  Model.last = function() {
    var record, values;
    values = this.recordsValues();
    record = values[values.length - 1];
    return record != null ? record.clone() : void 0;
  };

  Model.count = function() {
    return this.recordsValues().length;
  };

  Model.deleteAll = function() {
    var key, value, _ref, _results;
    _ref = this.records;
    _results = [];
    for (key in _ref) {
      value = _ref[key];
      _results.push(delete this.records[key]);
    }
    return _results;
  };

  Model.destroyAll = function() {
    var key, value, _ref, _results;
    _ref = this.records;
    _results = [];
    for (key in _ref) {
      value = _ref[key];
      _results.push(this.records[key].destroy());
    }
    return _results;
  };

  Model.update = function(id, atts, options) {
    return this.find(id).updateAttributes(atts, options);
  };

  Model.create = function(atts, options) {
    var record;
    record = new this(atts);
    return record.save(options);
  };

  Model.destroy = function(id, options) {
    return this.find(id).destroy(options);
  };

  Model.change = function(callbackOrParams) {
    if (typeof callbackOrParams === 'function') {
      return this.bind('change', callbackOrParams);
    } else {
      return this.trigger('change', callbackOrParams);
    }
  };

  Model.fetch = function(callbackOrParams) {
    if (typeof callbackOrParams === 'function') {
      return this.bind('fetch', callbackOrParams);
    } else {
      return this.trigger('fetch', callbackOrParams);
    }
  };

  Model.toJSON = function() {
    return this.recordsValues();
  };

  Model.fromJSON = function(objects) {
    var value, _i, _len, _results;
    if (!objects) {
      return;
    }
    if (typeof objects === 'string') {
      objects = JSON.parse(objects);
    }
    if (isArray(objects)) {
      _results = [];
      for (_i = 0, _len = objects.length; _i < _len; _i++) {
        value = objects[_i];
        _results.push(new this(value));
      }
      return _results;
    } else {
      return new this(objects);
    }
  };

  Model.fromForm = function() {
    var _ref;
    return (_ref = new this).fromForm.apply(_ref, arguments);
  };

  Model.recordsValues = function() {
    var key, result, value, _ref;
    result = [];
    _ref = this.records;
    for (key in _ref) {
      value = _ref[key];
      result.push(value);
    }
    return result;
  };

  Model.cloneArray = function(array) {
    var value, _i, _len, _results;
    _results = [];
    for (_i = 0, _len = array.length; _i < _len; _i++) {
      value = array[_i];
      _results.push(value.clone());
    }
    return _results;
  };

  Model.idCounter = 0;

  Model.uid = function(prefix) {
    if (prefix == null) {
      prefix = '';
    }
    return prefix + this.idCounter++;
  };

  function Model(atts) {
    Model.__super__.constructor.apply(this, arguments);
    if (atts) {
      this.load(atts);
    }
    this.cid = this.constructor.uid('c-');
  }

  Model.prototype.isNew = function() {
    return !this.exists();
  };

  Model.prototype.isValid = function() {
    return !this.validate();
  };

  Model.prototype.validate = function() {};

  Model.prototype.load = function(atts) {
    var key, value;
    for (key in atts) {
      value = atts[key];
      if (typeof this[key] === 'function') {
        this[key](value);
      } else {
        this[key] = value;
      }
    }
    return this;
  };

  Model.prototype.attributes = function() {
    var key, result, _i, _len, _ref;
    result = {};
    _ref = this.constructor.attributes;
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      key = _ref[_i];
      if (key in this) {
        if (typeof this[key] === 'function') {
          result[key] = this[key]();
        } else {
          result[key] = this[key];
        }
      }
    }
    if (this.id) {
      result.id = this.id;
    }
    return result;
  };

  Model.prototype.eql = function(rec) {
    return !!(rec && rec.constructor === this.constructor && (rec.cid === this.cid) || (rec.id && rec.id === this.id));
  };

  Model.prototype.save = function(options) {
    var error, record;
    if (options == null) {
      options = {};
    }
    if (options.validate !== false) {
      error = this.validate();
      if (error) {
        this.trigger('error', error);
        return false;
      }
    }
    this.trigger('beforeSave', options);
    record = this.isNew() ? this.create(options) : this.update(options);
    this.trigger('save', options);
    return record;
  };

  Model.prototype.updateAttribute = function(name, value, options) {
    this[name] = value;
    return this.save(options);
  };

  Model.prototype.updateAttributes = function(atts, options) {
    this.load(atts);
    return this.save(options);
  };

  Model.prototype.changeID = function(id) {
    var records;
    records = this.constructor.records;
    records[id] = records[this.id];
    delete records[this.id];
    this.id = id;
    return this.save();
  };

  Model.prototype.destroy = function(options) {
    if (options == null) {
      options = {};
    }
    this.trigger('beforeDestroy', options);
    delete this.constructor.records[this.id];
    delete this.constructor.crecords[this.cid];
    this.destroyed = true;
    this.trigger('destroy', options);
    this.trigger('change', 'destroy', options);
    this.unbind();
    return this;
  };

  Model.prototype.dup = function(newRecord) {
    var result;
    result = new this.constructor(this.attributes());
    if (newRecord === false) {
      result.cid = this.cid;
    } else {
      delete result.id;
    }
    return result;
  };

  Model.prototype.clone = function() {
    return createObject(this);
  };

  Model.prototype.reload = function() {
    var original;
    if (this.isNew()) {
      return this;
    }
    original = this.constructor.find(this.id);
    this.load(original.attributes());
    return original;
  };

  Model.prototype.toJSON = function() {
    return this.attributes();
  };

  Model.prototype.toString = function() {
    return "<" + this.constructor.className + " (" + (JSON.stringify(this)) + ")>";
  };

  Model.prototype.fromForm = function(form) {
    var key, result, _i, _len, _ref;
    result = {};
    _ref = $(form).serializeArray();
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      key = _ref[_i];
      result[key.name] = key.value;
    }
    return this.load(result);
  };

  Model.prototype.exists = function() {
    return this.id && this.id in this.constructor.records;
  };

  Model.prototype.update = function(options) {
    var clone, records;
    this.trigger('beforeUpdate', options);
    records = this.constructor.records;
    records[this.id].load(this.attributes());
    clone = records[this.id].clone();
    clone.trigger('update', options);
    clone.trigger('change', 'update', options);
    return clone;
  };

  Model.prototype.create = function(options) {
    var clone, record;
    this.trigger('beforeCreate', options);
    if (!this.id) {
      this.id = this.cid;
    }
    record = this.dup(false);
    this.constructor.records[this.id] = record;
    this.constructor.crecords[this.cid] = record;
    clone = record.clone();
    clone.trigger('create', options);
    clone.trigger('change', 'create', options);
    return clone;
  };

  Model.prototype.bind = function(events, callback) {
    var binder, unbinder,
      _this = this;
    this.constructor.bind(events, binder = function(record) {
      if (record && _this.eql(record)) {
        return callback.apply(_this, arguments);
      }
    });
    this.constructor.bind('unbind', unbinder = function(record) {
      if (record && _this.eql(record)) {
        _this.constructor.unbind(events, binder);
        return _this.constructor.unbind('unbind', unbinder);
      }
    });
    return binder;
  };

  Model.prototype.one = function(events, callback) {
    var binder,
      _this = this;
    return binder = this.bind(events, function() {
      _this.constructor.unbind(events, binder);
      return callback.apply(_this, arguments);
    });
  };

  Model.prototype.trigger = function() {
    var args, _ref;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    args.splice(1, 0, this);
    return (_ref = this.constructor).trigger.apply(_ref, args);
  };

  Model.prototype.unbind = function() {
    return this.trigger('unbind');
  };

  return Model;

})(Module);

Controller = (function(_super) {

  __extends(Controller, _super);

  Controller.include(Events);

  Controller.include(Log);

  Controller.prototype.eventSplitter = /^(\S+)\s*(.*)$/;

  Controller.prototype.tag = 'div';

  function Controller(options) {
    this.release = __bind(this.release, this);

    var key, value, _ref;
    this.options = options;
    _ref = this.options;
    for (key in _ref) {
      value = _ref[key];
      this[key] = value;
    }
    if (!this.el) {
      this.el = document.createElement(this.tag);
    }
    this.el = $(this.el);
    if (this.className) {
      this.el.addClass(this.className);
    }
    if (this.attributes) {
      this.el.attr(this.attributes);
    }
    if (!this.events) {
      this.events = this.constructor.events;
    }
    if (!this.elements) {
      this.elements = this.constructor.elements;
    }
    if (this.events) {
      this.delegateEvents(this.events);
    }
    if (this.elements) {
      this.refreshElements();
    }
    Controller.__super__.constructor.apply(this, arguments);
  }

  Controller.prototype.release = function() {
    this.trigger('release');
    this.el.remove();
    return this.unbind();
  };

  Controller.prototype.$ = function(selector) {
    return $(selector, this.el);
  };

  Controller.prototype.delegateEvents = function(events) {
    var eventName, key, match, method, selector, _results,
      _this = this;
    _results = [];
    for (key in events) {
      method = events[key];
      if (typeof method === 'function') {
        method = (function(method) {
          return function() {
            method.apply(_this, arguments);
            return true;
          };
        })(method);
      } else {
        method = (function(method) {
          return function() {
            _this[method].apply(_this, arguments);
            return true;
          };
        })(method);
      }
      match = key.match(this.eventSplitter);
      eventName = match[1];
      selector = match[2];
      if (selector === '') {
        _results.push(this.el.bind(eventName, method));
      } else {
        _results.push(this.el.delegate(selector, eventName, method));
      }
    }
    return _results;
  };

  Controller.prototype.refreshElements = function() {
    var key, value, _ref, _results;
    _ref = this.elements;
    _results = [];
    for (key in _ref) {
      value = _ref[key];
      _results.push(this[value] = this.$(key));
    }
    return _results;
  };

  Controller.prototype.delay = function(func, timeout) {
    return setTimeout(this.proxy(func), timeout || 0);
  };

  Controller.prototype.html = function(element) {
    this.el.html(element.el || element);
    this.refreshElements();
    return this.el;
  };

  Controller.prototype.append = function() {
    var e, elements, _ref;
    elements = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    elements = (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = elements.length; _i < _len; _i++) {
        e = elements[_i];
        _results.push(e.el || e);
      }
      return _results;
    })();
    (_ref = this.el).append.apply(_ref, elements);
    this.refreshElements();
    return this.el;
  };

  Controller.prototype.appendTo = function(element) {
    this.el.appendTo(element.el || element);
    this.refreshElements();
    return this.el;
  };

  Controller.prototype.prepend = function() {
    var e, elements, _ref;
    elements = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    elements = (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = elements.length; _i < _len; _i++) {
        e = elements[_i];
        _results.push(e.el || e);
      }
      return _results;
    })();
    (_ref = this.el).prepend.apply(_ref, elements);
    this.refreshElements();
    return this.el;
  };

  Controller.prototype.replace = function(element) {
    var previous, _ref;
    _ref = [this.el, $(element.el || element)], previous = _ref[0], this.el = _ref[1];
    previous.replaceWith(this.el);
    this.delegateEvents(this.events);
    this.refreshElements();
    return this.el;
  };

  return Controller;

})(Module);

$ = (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) || (typeof window !== "undefined" && window !== null ? window.Zepto : void 0) || function(element) {
  return element;
};

createObject = Object.create || function(o) {
  var Func;
  Func = function() {};
  Func.prototype = o;
  return new Func();
};

isArray = function(value) {
  return Object.prototype.toString.call(value) === '[object Array]';
};

isBlank = function(value) {
  var key;
  if (!value) {
    return true;
  }
  for (key in value) {
    return false;
  }
  return true;
};

makeArray = function(args) {
  return Array.prototype.slice.call(args, 0);
};

Spine = this.Spine = {};

if (typeof module !== "undefined" && module !== null) {
  module.exports = Spine;
}

Spine.version = '1.0.6';

Spine.isArray = isArray;

Spine.isBlank = isBlank;

Spine.$ = $;

Spine.Events = Events;

Spine.Log = Log;

Spine.Module = Module;

Spine.Controller = Controller;

Spine.Model = Model;

Module.extend.call(Spine, Events);

Module.create = Module.sub = Controller.create = Controller.sub = Model.sub = function(instances, statics) {
  var result;
  result = (function(_super) {

    __extends(result, _super);

    function result() {
      return result.__super__.constructor.apply(this, arguments);
    }

    return result;

  })(this);
  if (instances) {
    result.include(instances);
  }
  if (statics) {
    result.extend(statics);
  }
  if (typeof result.unbind === "function") {
    result.unbind();
  }
  return result;
};

Model.setup = function(name, attributes) {
  var Instance;
  if (attributes == null) {
    attributes = [];
  }
  Instance = (function(_super) {

    __extends(Instance, _super);

    function Instance() {
      return Instance.__super__.constructor.apply(this, arguments);
    }

    return Instance;

  })(this);
  Instance.configure.apply(Instance, [name].concat(__slice.call(attributes)));
  return Instance;
};

Spine.Class = Module;

}).call(this);