// dabbler.js
//
// Functions for loading and saving state to dabbler.org.
//
// Usage:
//
// <script src="http://dabbler.org/dabbler.js"></script>
// <script>
//   dabbler.load('/guest/datafile', function(data) {
//     alert('loaded data ' + data);
//   });
//   dabbler.save('/guest/datafile', 'new-data-here', function() {
//     alert('done saving new data');
//   });
//   dabbler.directory('/guest/', function(list) {
//     for (var j = 0; j < list.length; ++j) {
//       console.log(list[j].name);
//     }
//   });
//   dabbler.tail('/guest/datafile', 3, function(lastlines) {
//     alert('loaded last 3 lines:\n' + lastlines);
//   });
//   dabbler.append('/guest/datafile', 'new-line\n', function() {
//     alert('appended a line');
//   });
// </script>

(function() {

var counter = 0, head, window = this, domain = 'http://dabbler.org/';

function loadscript(url) {
  var script = document.createElement('script'),
  done = false;
  script.src = url;
  script.async = true;
  script.onload = script.onreadystatechange = function() {
    if (!done && (!this.readyState || this.readyState === "loaded" ||
        this.readyState === "complete")) {
      done = true;
      script.onload = script.onreadystatechange = null;
      if (script && script.parentNode) {
        script.parentNode.removeChild(script);
      }
    }
  };
  if (!head) {
    head = document.getElementsByTagName('head')[0];
  }
  head.appendChild(script);
}

function invoke(url, params, callback) {
  var query = "?";
  params = params || {};
  for (key in params) {
    if ( params.hasOwnProperty(key) ) {
      query += encodeURIComponent(key) + "=" +
               encodeURIComponent(params[key]) + "&";
    }
  }
  var jsonp = "dabbler_json_" + (++counter);
  window[jsonp] = function(data){
    callback(data);
    window[jsonp] = null;
    try {
      delete window[jsonp];
    } catch (e) {}
  };
  loadscript(url + query + "callback=" + jsonp);
  return jsonp;
}

function normalize(path) {
  if (path.length == 0 || path.charAt(0) != '/')
    path = '/' + path;
  return path;
}

function load(path, ondone) {
  path = normalize(path);
  invoke(domain + 'load' + path, { }, function(msg) {
    if (ondone !== undefined) {
      ondone(msg.data);
    }
  });
}

function save(path, data, ondone) {
  path = normalize(path);
  invoke(domain + 'save' + path, { data : data }, function(msg) {
    if (ondone !== undefined) {
      ondone();
    }
  });
}

function directory(path, ondone) {
  path = normalize(path);
  invoke(domain + 'load' + path, { }, function(msg) {
    if (ondone !== undefined) {
      ondone(msg.list);
    }
  });
}

function tail(path, num, ondone) {
  path = normalize(path);
  invoke(domain + 'load' + path, { tail: num }, function(msg) {
    if (ondone !== undefined) {
      ondone(msg.data);
    }
  });
}

function append(path, data, ondone) {
  path = normalize(path);
  invoke(domain + 'save' + path, { data : data, mode: 'a' }, function(msg) {
    if (ondone !== undefined) {
      ondone();
    }
  });
}

function copy(srcpath, destpath, ondone) {
  load(srcpath, function(data) {
    save(destpath, data, ondone);
  });
}

function remove(path, ondone) {
  path = normalize(path);
  invoke(domain + 'save' + path, { }, function(msg) {
    if (ondone !== undefined) {
      ondone();
    }
  });
}


window['dabbler'] = {
  load: load,
  save: save,
  directory: directory,
  tail: tail,
  append: append,
  copy: copy ,
  remove: remove
};

}());

