/** @class    TODO: Describe Class
  @extends SC.DataSource
  @since SproutCore 1.0
*/

// For testing
SC.DISABLE_REMOTE_REQUESTS = NO;

SC.RailsDataSource = SC.DataSource.extend( {

  _resourcePathFormat: '/sc/%@.json%@',

  getFullResourcePath: function(resourcePath, queryParams) {
    var params = '';

    if (queryParams) {
      var i = 0;

      for (var key in queryParams) {
        if (queryParams.hasOwnProperty(key)) {
          params += '%@%@=%@'.fmt(i === 0 ? '?' : '&', key, queryParams[key]);
          i++;
        }
      }
    }

    return this._resourcePathFormat.fmt(resourcePath, params);
  },


// STANDARD DATA SOURCE METHODS   //

  fetch: function(store, query) {
    var recordType = query.recordType || query.recordTypes[0];
    var url = this.getFullResourcePath(recordType.resourcePathFor('fetch'));

    var fetchParams = { query: query, store: store };

    if (!SC.DISABLE_REMOTE_REQUESTS) {
      return NO;
    } else {
      SC.Request.getUrl(url).set('isJSON', YES)
        .notify(this, this._didFetchRecords, fetchParams)
        .send();

      return YES; // Not necessary, but good form
    }
  },

  retrieveRecord: function(store, storeKey, id) {
    // map storeKey back to record type
    var recordType = SC.Store.recordTypeFor(storeKey);
    var url = this.getFullResourcePath(recordType.resourcePathFor('retrieve', storeKey));

    var retrieveParams = { store: store, storeKey: storeKey };

    if (SC.DISABLE_REMOTE_REQUESTS) {
      return NO;
    } else {
      SC.Request.getUrl(url).set('isJSON', YES)
        .notify(this, this._didRetrieveRecord, retrieveParams)
        .send();

      return YES;
    }
  },

  createRecord: function(store, storeKey, params) {
    var dataHash   = store.readDataHash(storeKey),
        recordType = SC.Store.recordTypeFor(storeKey),
        obj        = this._dataToParams(recordType, 'create', dataHash);

    var url = this.getFullResourcePath(recordType.resourcePathFor('create', storeKey, dataHash));

    var createParams = { store: store, storeKey: storeKey };

    if (SC.DISABLE_REMOTE_REQUESTS) {
      this._didCreateRecord(null, createParams);
    } else {
      SC.Request.postUrl(url).set('isJSON', YES)
        .header('X-Requested-With', 'XMLHttpRequest')
        .notify(this, this._didCreateRecord, createParams)
        .send(obj);
    }

    return YES ;
  },

  updateRecord: function(store, storeKey, params) {
    if(!params) params = {};

    var id         = store.idFor(storeKey),
        dataHash   = store.readDataHash(storeKey),
        recordType = SC.Store.recordTypeFor(storeKey),
        obj        = this._dataToParams(recordType, 'update', dataHash),
        request;

    var url = this.getFullResourcePath(recordType.resourcePathFor('update', storeKey));

    var updateParams = { store: store, storeKey: storeKey };

    if (!SC.DISABLE_REMOTE_REQUESTS) {
      // Send request unless disabled
      request = SC.Request.putUrl(url).set('isJSON', YES).header('X-Requested-With', 'XMLHttpRequest');
      // Don't notify if skipping response
      if (!params.skipResponse) request.notify(this, this._didUpdateRecord, updateParams);
      request.send(obj);
    }

    if (SC.DISABLE_REMOTE_REQUESTS || params.skipResponse) {
      // Don't wait for a server response
      this._didUpdateRecord(null, updateParams);
    }

    return YES ;
  },

  destroyRecord: function(store, storeKey, params) {
    if (!params) params = {};

    var status = store.readStatus(storeKey);

    if (status === SC.Record.DESTROYED_CLEAN) {

      // Already clean - probably from calling destroy on a new record
      // Is there a better place to handle this?
      store.removeDataHash(storeKey, status);
      store.dataHashDidChange(storeKey);

    } else {

      // Destroy normally
      var id         = store.idFor(storeKey),
          recordType = SC.Store.recordTypeFor(storeKey),
          notifyParams = { store: store, storeKey: storeKey };

      var url = this.getFullResourcePath(recordType.resourcePathFor('destroy', storeKey));

      if (params.noRequest || SC.DISABLE_REMOTE_REQUESTS) {
        this._didDestroyRecord(null, notifyParams);
      } else {
        SC.Request.deleteUrl(url)
          .header('X-Requested-With', 'XMLHttpRequest')
          .notify(this, this._didDestroyRecord, notifyParams).send();
      }
    }

    return YES ;
  },
      
  cancel: function(store, storeKeys) {
    return NO;
  },

  _didFetchRecords: function(response, params) {
    var store = params.store,
        query = params.query,
        results = response.get('response'),
        resultItem, cleanedResults= [], obj;

    if (SC.$ok(response)) {
      for(idx=0; idx < results.length; idx++) {
        resultItem = results[idx];

        // Hackish way to ignore key
        for (var k in resultItem) {
          obj = resultItem[k]; break;
        }

        cleanedResults.push(obj);
      }

      // load the contacts into the store...
      store.loadRecords(params.recordTypes, cleanedResults);

      // notify store that we handled the fetch
      store.dataSourceDidFetchQuery(query);
    } else {
      // handle error case
      store.dataSourceDidErrorQuery(query, response);
    }
  },

  _didRetrieveRecord: function(response, params) {
    var store = params.store,
        storeKey = params.storeKey,
        results = response.get('response'),
        cleanedResults;

    if (SC.$ok(response)) {
      // normal: load into store...response == dataHash

      // Get first item
      for (var k in results) {
        cleanedResults = results[k]; break;
      }
      store.dataSourceDidComplete(storeKey, cleanedResults, cleanedResults.id);
    } else {
      // error: indicate as such...response == error
      this._processError(storeKey, response);
    }
  },

  _didCreateRecord: function(response, params) {
    var results = response && response.get('response'), 
        storeKey = params.storeKey,
        store = params.store,
        resultsKeys= [], cleanedResults;

    if (!response) {
      // Request was skipped, pretend it succeeded
      store.dataSourceDidComplete(storeKey);
    } else if (SC.$ok(response)) {
      for(var k in results) resultsKeys.push(k);
      cleanedResults = results[resultsKeys[0]];

      store.dataSourceDidComplete(storeKey, cleanedResults, cleanedResults.id);
    } else this._processError(storeKey, response);
  },

  _didUpdateRecord: function(response, params){
    var storeKey = params.storeKey,
        store = params.store;

    if (SC.$ok(response)) {
      store.dataSourceDidComplete(storeKey);
    } else this._processError(storeKey, response);
  },

  _didDestroyRecord: function(response, params){
    var storeKey = params.storeKey,
        store = params.store;

    // Response will be null if no actual request made and SC.$ok will still evaluate true
    // This is fine since we want to pretend we succeeded anyway
    if (SC.$ok(response)) {
      store.dataSourceDidDestroy(storeKey);
    } else this._processError(storeKey, response);
  },

  _processError: function(storeKey, response) {
    var status = response.get('status');

    if (status === 401) { // Unauthorized
      SC.AlertPane.error("Not signed in", "You are not signed in. Please sign in again.");
    }

    store.dataSourceDidError(storeKey, response);
  },

  _dataToParams: function(recordType, action, data) {
    var resourceParams = recordType.resourceParamsFor(action),
        baseParam = recordType.resourceBaseParam,
        cleanedData = {}, item;

    cleanedData[baseParam] = {};

    for (v in data) {
      item = data[v];
      if(resourceParams.indexOf(v) != -1 && item != null) {
        if(item == true) item = 1;
        if(item == false) item = 0;
        cleanedData[baseParam][v] = item;
      }
    }

    return cleanedData;
  }

});