define(['./util', './baseClient', './getputdelete', './store'], function(util, BaseClient, getputdelete, store) {

  var logger = util.getLogger('foreignClient');

  var knownClients = {};

  store.on('foreign-change', function(event) {
    var userAddress = event.path.split(':')[0];
    var client = knownClients[userAddress];
    if(client) {
      client.events.emit('change', event);
    }
  });

  /*
    Class: ForeignClient
    
    A modified <BaseClient>, to query other people's storage.
   */

  // Constructor: ForeignClient
  //
  // Parameters:
  //   userAddress - A userAddress string in the form user@host.
  //
  // The userAddress must be known to wireClient.
  //
  var ForeignClient = function(userAddress) {
    this.userAddress = userAddress;
    this.pathPrefix = userAddress + ':';

    this.moduleName = 'root', this.isPublic = true;
    this.events = util.getEventEmitter('change', 'error');
    knownClients[userAddress] = this;
    util.bindAll(this);
  };
  
  ForeignClient.prototype = {

    // Method: getPublished
    //
    // Get the 'publishedItems' object for the given module.
    //
    // publishedItems is an object of the form { path : timestamp, ... }.
    //
    // Parameters:
    //   moduleName - (optional) module name to get the publishedItems object for
    //   callback   - callback to call with the result
    //
    // Example:
    //   (start code)
    //   remoteStorage.getForeignClient('user@host', function(client) {
    //     client.getPublished(object, function(publishedItems) {
    //       for(var key in publishedItems) {
    //         console.log("Item: ", key, " published at: ", publishedItems[key]);
    //       }
    //     });
    //   });
    //   (end code)
    getPublished: function(moduleName, callback) {
      var fullPath;
      if(typeof(moduleName) == 'function') {
        callback = moduleName;
        fullPath = '/publishedItems';
      } else {
        fullPath = '/' + moduleName + '/publishedItems';
      }
      this.getObject(fullPath, function(data) {
        if(data) { delete data['@context']; }
        callback(data || {});
      });
    },

    getPublishedObjects: function(moduleName, callback) {
      this.getPublished(moduleName, util.bind(function(list) {
        var paths = Object.keys(list);
        var i = 0;
        var objects = {};
        function loadOne() {
          if(i < paths.length) {
            var key = paths[i++];
            var path = '/' + moduleName + '/' + key;
            this.getObject(path, util.bind(function(object) {
              objects[path] = object;
                
              loadOne.call(this);
            }, this));
          } else {
            callback(objects);
          }
        }

        loadOne.call(this);
      }, this));
    },

    makePath: function(path) {
      return this.pathPrefix + BaseClient.prototype.makePath.call(this, path);
    },

    nodeGivesAccess: function(path, mode) {
      return mode == 'r';
    },

    on: function(eventName, handler) {
      this.events.on(eventName, handler);
    }

  };

  var methodBlacklist = {
    makePath: true,
    getListing: true,
    getAll: true,
    storeDocument: true,
    storeObject: true,
    remove: true,
    nodeGivesAccess: true,
    fetchNow: true,
    syncNow: true,
    on: true
  };

  // inherit some stuff from BaseClient

  for(var key in BaseClient.prototype) {
    if(! methodBlacklist[key]) {
      ForeignClient.prototype[key] = BaseClient.prototype[key];
    }
  }

  return {
    getClient: function(userAddress) {
      var client = knownClients[userAddress];
      return client || new ForeignClient(userAddress);
    }
  };

});
