app.service('$entity', function($http, $q, blockUI, $auth, inform, entityMap) {
  var svc = this;

  this.map = entityMap;

  this.getByKey = function(collection, keyValuePair, callback) {
    if (typeof callback === 'undefined') {
      return $http.get('api/' + collection + '/fetch', {params: keyValuePair});
    }

    $http.get('api/' + collection, {params: keyValuePair})
    .then(function(response) {
      callback(null, response);
    })
    .catch(function(response) {
      callback(response);
    });
  };

  this.get = function(entity, id) {
    if (id) {
      return $http.get('./api/' + entity + '/list/' + id);
    }
    else {
      return $http.get('./api/' + entity + '/list');
    }
  };

  this.setFormFiles = function(fd, item, parent) {
    //ignore if current object has nothing or is a string
    if (!item || typeof item === 'string') {
      return;
    }

    //array
    if (item.length) {
      for (var i = 0; i < item.length; i++) {
        svc.setFormFiles(fd, item[i], parent + '[' + i + ']');
      }
    }
    //not array
    else {
      //for each nested object
      for (var property in item) {
        if (typeof item[property] !== 'object') {
          continue;
        }

        //file object
        if (property === 'newFile') {
          for (var file in item[property]) {
            var filePath = parent ? parent + '.' + file : file;
            fd.append(filePath, item[property][file]);
          }
        }
        //non file object
        else {
          svc.setFormFiles(fd, item[property], parent ? parent + '.' + property : property);
        }
      }
    }
  };

  this.add = function(entity, item) {
    var url = './api/' + entity + '/add/';
    if (item._id) {
      url += item._id;
    }

    var fd = new FormData();
    if (entity !== 'message') {
      svc.setFormFiles(fd, item);
    }
    fd.append('item', angular.toJson(item));

    return $http.post(url, fd, {transformRequest: angular.identity, headers: {'Content-Type': undefined}});
  };

  this.getLookups = function(entity, callback) {
    if (!svc.map[entity].lookup) {
      callback();
      return;
    }

    if (svc.map[entity].lookup.length === 0) {
      callback();
      return;
    }

    var lookups = [];
    for (var i = 0; i < svc.map[entity].lookup.length; i++) {
      var lookup = svc.map[entity].lookup[i];
      lookups.push(svc.get(lookup));
    }

    $q.all(lookups).then(function(response) {
      var data = {};
      for (var i = 0; i < response.length; i++) {
        data[svc.map[entity].lookup[i]] = response[i].data;
      }

      callback(null, data);
    }, function(response) {
      callback(response);
    });
  };

  this.getMany = function(entities, callback) {
    var lookups = entities, promises = [];
    lookups.forEach(function(lookup) {
      promises.push(svc.get(lookup));
    });

    var response = {};
    $q.all(promises).then(function(results) {
      var data = {};
      results.forEach(function(result, i) {
        response[lookups[i]] = result.data;
      });

      callback(null, response);
    }, function(err) {
      callback(err);
    });
  };

  this.validate = function(entity, object, dataset) {
    if (!svc.map[entity].service.validate) {
      return false;
    }

    return svc.map[entity].service.validate(object, dataset);
  };

  this.remove = function(entity, item) {
    var url = './api/' + entity + '/remove/' + item._id;
    return $http.get(url);
  };

  this.blank = function(entity) {
    if (svc.map[entity].service.blank) {
      return svc.map[entity].service.blank();
    }
    else {
      return {};
    }
  };
});
