// ========================================================================== // Project: Greenhouse // Copyright: ©2010-2010 Mike Ball // ========================================================================== /*globals Greenhouse */

/**

This DataSource connects to the SproutCore sc-server to retrieve files

*/ Greenhouse.DataSource = SC.DataSource.extend({

/**
  Fetch a group of records from the data source.
*/
fetch: function(store, query) {
  var ret = NO, rt = query.get('recordType');
  if(rt === Greenhouse.File || rt === Greenhouse.Dir){
    ret = this.listFiles(store, query);
  }
  else if(rt === Greenhouse.Target){
    ret = this.fetchTargets(store, query);
  }
  else if(rt === Greenhouse.ViewConfig){
    ret = this.fetchViewConfigs(store,query);
  }
  return ret;
},

// ..........................................................
// Get file list
//
listFiles: function(store, query){
  SC.Request.create({type: 'GET', isJSON: YES, address: '/sproutcore/fs/apps%@/?action=list'.fmt(query.get('urlPath'))})
    .notify(this,this.listFilesDidComplete, {query: query, store: store})
    .send();
},

listFilesDidComplete: function(request, options){
  var response = request.get('response'),
      query    = options.query,
      store    = options.store,
      storeKeys, recordTypes;

  if (!SC.$ok(response)) {
    console.error("Couldn't request files");
  }
  else {
    recordTypes = response.map(function(item){
      return item.type === 'File' ? Greenhouse.File : Greenhouse.Dir;
    });
    storeKeys = store.loadRecords(recordTypes, response);
    store.loadQueryResults(query, storeKeys);
    Greenhouse.sendAction('fileListCallDidComplete');
  }
},

// ..........................................................
// FETCHING TARGETS
//

/**
  Fetch the actual targets.  Only understands how to handle a remote query.
*/
fetchTargets: function(store, query) {

  if (!query.get('isRemote')) return NO ;

  SC.Request.getUrl('/sc/targets.json')
    .set('isJSON', YES)
    .notify(this, 'fetchTargetsDidComplete', { query: query, store: store })
    .send();
  return YES ;
},

fetchTargetsDidComplete: function(request, opts) {
  var response = request.get('response'),
      query    = opts.query,
      store    = opts.store,
      storeKeys;

  if (!SC.$ok(response)) {
    console.error("TODO: Add handler when fetching targets fails");
  } else {
    storeKeys = store.loadRecords(Greenhouse.Target, response);
    store.loadQueryResults(query, storeKeys);
    Greenhouse.sendAction('fetchTargetsDidComplete');
  }
},

// ..........................................................
// FETCHING VIEW CONFIGS
//
fetchViewConfigs: function(store, query){
  if (!query.get('isRemote')) return NO ;

  SC.Request.getUrl('/sc/greenhouseconf.json?app=%@'.fmt(query.get('app')))
    .set('isJSON', YES)
    .notify(this, 'fetchViewConfigsDidComplete', { query: query, store: store })
    .send();
  return YES ;
},
fetchViewConfigsDidComplete: function(request, opts){
  var response = request.get('response'),
      query    = opts.query,
      store    = opts.store,
      storeKeys;
  if (!SC.$ok(response)) {
    console.error("TODO: Add handler when fetching view configs fails");
  } else {
    storeKeys = store.loadRecords(Greenhouse.ViewConfig, response);
    store.loadQueryResults(query, storeKeys);
  }
},

// ..........................................................
// Single File Actions
//
/**
  updates a single record

  @param {SC.Store} store the requesting store
  @param {Array} storeKey key to update
  @param {Hash} params to be passed down to data source. originated
    from the commitRecords() call on the store
  @returns {Boolean} YES if handled
*/
updateRecord: function(store, storeKey, params) {
  var file = store.materializeRecord(storeKey);
  var request = SC.Request.create({type: 'POST', address: "/sproutcore/fs/%@?action=overwrite".fmt(file.get('path')),
       body: file.get('body')})
      .notify(this,this.updateRecordDidComplete, {file: file, storeKey: storeKey, store: store})
      .send();
  return YES ;
},
updateRecordDidComplete: function(response, params){
  var file = params.file, results = response.get('body'), store = params.store;
  if(SC.ok(response)){
    //HACK: for some reason the records are always 514 ready dirty not refreshing dirty...
    status = store.readStatus(params.storeKey);
    store.writeStatus(params.storeKey, SC.Record.BUSY_COMMITTING);
    //end HACK
    params.store.dataSourceDidComplete(params.storeKey);
  }
  else{
    console.error("Couldn't update file!");
  }
},

/**
  Called from retrieveRecords() to retrieve a single record.

  @param {SC.Store} store the requesting store
  @param {Array} storeKey key to retrieve
  @param {String} id the id to retrieve
  @returns {Boolean} YES if handled
*/
retrieveRecord: function(store, storeKey, params) {
  var file = store.materializeRecord(storeKey), request;
  if(file.kindOf(Greenhouse.File)){
    request = SC.Request.create({type: 'GET', address: "/sproutcore/fs%@".fmt(file.get('path'))})
        .notify(this, this.retrieveRecordDidComplete, {file: file, storeKey: storeKey, store: store})
        .send();
    return YES;
  }
  return NO;
},
retrieveRecordDidComplete: function(response, params){
  var file = params.file, store = params.store, attributes, status;
  if(SC.ok(response)){
    attributes = file.get('attributes');//SC.clone(file.get('attributes'));
    attributes.body = response.get('body');
    //HACK: for some reason the records are always 514 ready dirty not refreshing dirty...
    status = store.readStatus(params.storeKey);
    store.writeStatus(params.storeKey, SC.Record.BUSY_REFRESH | (status & 0x03)) ;
    //end HACK
    store.dataSourceDidComplete(params.storeKey, attributes);
  }
  else{
    console.error("Couldn't request file");
  }
},
/**
  Called from createdRecords() to created a single record.  This is the
  most basic primitive to can implement to support creating a record.

  To support cascading data stores, be sure to return NO if you cannot
  handle the passed storeKey or YES if you can.

  @param {SC.Store} store the requesting store
  @param {Array} storeKey key to update
  @param {Hash} params to be passed down to data source. originated
    from the commitRecords() call on the store
  @returns {Boolean} YES if handled
*/
createRecord: function(store, storeKey, params) {
  var file = store.materializeRecord(storeKey);
  var request = SC.Request.create({type: 'POST', address: "/sproutcore/fs/%@?action=touch".fmt(file.get('path')),
       body: file.get('body')})
      .notify(this,this.createRecordDidComplete, {file: file, storeKey: storeKey, store: store})
      .send();
  return YES ;
},
createRecordDidComplete: function(response, params){
  var file = params.file, results = response.get('body'), store = params.store;
  if(SC.ok(response)){
    //HACK: for some reason the records are always 514 ready dirty not refreshing dirty...
    status = store.readStatus(params.storeKey);
    store.writeStatus(params.storeKey, SC.Record.BUSY_COMMITTING);
    //end HACK
    params.store.dataSourceDidComplete(params.storeKey);
  }
  else{
    console.error("Couldn't create file!");
  }
},

/**
  Called from destroyRecords() to destroy a single record.  This is the
  most basic primitive to can implement to support destroying a record.

  To support cascading data stores, be sure to return NO if you cannot
  handle the passed storeKey or YES if you can.

  @param {SC.Store} store the requesting store
  @param {Array} storeKey key to update
  @param {Hash} params to be passed down to data source. originated
    from the commitRecords() call on the store
  @returns {Boolean} YES if handled
*/
destroyRecord: function(store, storeKey, params) {
  var request = SC.Request.create({type: 'POST'}), file = store.materializeRecord(storeKey);

  request.set('address', "/sproutcore/fs/%@?action=remove".fmt(file.get('path')));

  request.notify(this,this.destroyRecordDidComplete,{file: file, storeKey: storeKey, store: store}).send();

  return YES;
},

destroyRecordDidComplete: function(response, params){
  var status, store = params.store;
  //HACK: for some reason the records are always 514 ready dirty not refreshing dirty...
  status = store.readStatus(params.storeKey);
  store.writeStatus(params.storeKey, SC.Record.BUSY_DESTROYING);
  //end HACK
  params.store.dataSourceDidDestroy(params.storeKey);
}

});