var ActiveResource = function(model, params) {
    this.model = model;
    this.table = model.pluralize();
    this.params = params || {};
    this.cache = true;
};

ActiveResource.save = function(model, changes, onsuccess, onfail){
  var resource = new ActiveResource(model);
  if (changes.id){
    return resource.update(changes.id, changes, onsuccess, onfail);
  }
  else{
    return resource.create(changes, onsuccess, onfail);
  }
};
ActiveResource.destroy = function(model, id, onsuccess, onfail){
  var resource = new ActiveResource(model);
  return resource.destroy(id, onsuccess, onfail);
}

ActiveResource.prototype = {
    request: function(id, onsuccess, onfail) {
        var request = this._getRequestObject(onsuccess, onfail);
        request.open("GET", this._getResourceUrl(id), true);
        request.send(null);
        return request;
    },
    requestThrough: function(parent_model, parent_id, id, onsuccess, onfail) {
        var request = this._getRequestObject(onsuccess, onfail);
        request.open("GET", '/' + parent_model.pluralize() + '/' + parent_id + '/' + this.table + '/' + id + '.json' + this._getQuery(), true);
        request.send(null);
        return request;
    },
    index: function(onsuccess, onfail){
      var request = this._getRequestObject(onsuccess, onfail);
      request.open("GET", '/' + this.table + '.json' + this._getQuery(), true);
      request.send(null);
      return request;
    },
    create: function(obj, onsuccess, onfail) {
        var request = this._getRequestObject(onsuccess, onfail);
        request.open("POST", this._getResourceUrl(), true);
        request.setRequestHeader("Content-Type", "application/json;");    
        request.send(this.getSubmission(obj));
        return request;
    },
    createThrough: function(parent_model, parent_id, obj, onsuccess, onfail){
      var request = this._getRequestObject(onsuccess, onfail);
      request.open("POST", '/' + parent_model.tableize() + '/' + parent_id + this._getResourceUrl(), true);
      request.setRequestHeader("Content-Type", "application/json;");    
      request.send(this.getSubmission(obj));
      return request;
    },
    action: function(id, action, onsuccess, onfail){
      var request = this._getRequestObject(onsuccess, onfail);
      request.open("POST", this._getResourceUrl(id + '/' + action), true);
      request.setRequestHeader("Content-Type", "application/json;");    
      request.send(null);
      return request;
    },
    update: function(id, obj, onsuccess, onfail) {
        var request = this._getRequestObject(onsuccess, onfail);
        request.open("PUT", this._getResourceUrl(id), true);
        request.setRequestHeader("Content-Type", "application/json;");    
        request.send(this.getSubmission(obj));
        return request;
    },
    destroy: function(id, onsuccess, onfail){
      if (!id) throw "ID not specified.";
      var request = this._getRequestObject(onsuccess, onfail);
      request.open("DELETE", this._getResourceUrl(id), true);
      request.setRequestHeader("Content-Type", "application/json;");    
      request.send(null);
      return request;    
    },
    getSubmission: function(obj) {
      if (obj.toLowerCase){
        return obj;
      }
      else{
        var submission = {};
        submission[this.model] = obj;
        return JSON.stringify(submission)
      }
    },
    setParam: function(key, value) {
        this.params[key] = value;
    },
    _getRequestObject: function(onsuccess, onfail) {
        var obj;
        var context = this;
        try {
             obj = new XMLHttpRequest();
        }
        catch (e) {
            obj = new ActiveXObject("Msxml2.XMLHTTP");
        }
        obj.onreadystatechange = function() {
            if (obj.readyState==4) {
                if (obj.status >= 200 && obj.status < 300) {
                    var responseObject = null;
                    if ($.trim(obj.responseText)) {
                      responseObject = eval('(' + obj.responseText + ')');
                      if (responseObject[context.model]) responseObject = responseObject[context.model]
                      else if (responseObject[context.table]) responseObject = responseObject[context.table]
                    }  //JSON.parse(this.httpRequest.responseText);
                    if (onsuccess) {
                        onsuccess(responseObject, context);
                    }
                }
                else {
                    if (onfail) {
                        var responseObject = null;
                        try {
                          responseObject = eval('(' + obj.responseText + ')')[context.model]; 
                        }
                        catch (e) {
                          responseObject = {};
                        }
                        responseObject.statusCode = this.status;
                        responseObject.statusText = this.statusText;
                        onfail(responseObject, context);
                        
                    }
                }                
            }
        };
        return obj;
    },
    _getQuery: function(){
      result = '';
      for (var p in this.params) {
          if (this.params.hasOwnProperty(p)) {
              result += ((result.indexOf('?') >= 0) ? '&' : '?') + p + '=' + encodeURIComponent(this.params[p]);
          }
      }
      if (!this.cache) {
          result += ((result.indexOf('?') >= 0) ? '&' : '?') + 'nocache=' + encodeURIComponent(Math.random() * 1000);
      }
      return result;
    },
    _getResourceUrl: function(action) {

        var result = '/' + this.table;
        if (action) result += '/' + action;
        
        result += '.json';

        for (var p in this.params) {
            if (this.params.hasOwnProperty(p)) {
                result += ((result.indexOf('?') >= 0) ? '&' : '?') + p + '=' + encodeURIComponent(this.params[p]);
            }
        }
        if (!this.cache) {
            result += ((result.indexOf('?') >= 0) ? '&' : '?') + 'nocache=' + encodeURIComponent(Math.random() * 1000);
        }
        return result;
    }
};