/*
 * redmine-client
 * https://github.com/jthomerson/redmine-client
 *
 * Copyright (c) 2014 Jeremy Thomerson
 * Licensed under the MIT license.
 */

var request     = require('request'),
    Q           = require('q'),
    querystring = require('querystring');

function Redmine(config) {
   if (!config || !config.host || !config.apiKey) {
      throw new Error("ERROR: you must define both your host and your apiKey in the Redmine config");
   }
   this.config = config;
}

Redmine.prototype = {

   createURL: function(path, params) {
      if (path.slice(0, 1) !== '/') {
         path = '/' + path;
      }
      return (this.config.https ? 'https' : 'http') + '://' +
             this.config.host +
             path + '?' + querystring.stringify(params);
   },

   request: function(method, path, params) {
      var options = {
            url: this.createURL(path, params),
            method: method,
            headers: {
               'X-Redmine-API-Key': this.config.apiKey
            }
         },
         deferred = Q.defer();

      if (this.config.user && this.config.pass) {
         options.auth = { user: this.config.user, pass: this.config.pass };
      }

      request(options, function(err, res, body) {
         if (err) {
            deferred.fail(err);
         }
         deferred.resolve(JSON.parse(body));
      });

      return deferred.promise;
   },

   getGroup: function(gid, params) {
      params = !params ? { include: 'users' } : params;
      return this.request('GET', '/groups/' + gid + '.json', params);
   },

   getGroups: function(params) {
      return this.request('GET', '/groups.json', params);
   },

   getIssues: function(params) {
      return this.request('GET', '/issues.json', params);
   }

};


module.exports = Redmine;

@@ -257,16 +257,811 @@
 ing');%0A%0A
+function chainTogether(method, params, fieldName, deferred, all, offset) %7B%0A   params.limit = 100;%0A   params.offset = offset;%0A%0A   method(params).then(function(resp) %7B%0A      var these = resp%5BfieldName%5D,%0A          combined = all.concat(these);%0A%0A      // console.log('received: ' + these.length + '; combined len: ' + combined.length + '; total: ' + resp.total_count);%0A      if (combined.length %3C resp.total_count) %7B%0A         chainTogether(method, params, fieldName, deferred, combined, offset + these.length);%0A      %7D else %7B%0A         resp%5BfieldName%5D = combined;%0A         resp.offset = 0;%0A         resp.limit = combined.length;%0A         // console.log('chainTogether found ' + combined.length + ' total ' + fieldName);%0A         deferred.resolve(resp);%0A      %7D%0A   %7D);%0A%0A   return deferred.promise;%0A%7D%0A%0A
 function
@@ -1079,16 +1079,16 @@
 nfig) %7B%0A
-
    if (!
@@ -1516,16 +1516,27 @@
  path + 
+(params ? (
 '?' + qu
@@ -1558,24 +1558,31 @@
 gify(params)
+) : '')
 ;%0A   %7D,%0A%0A   
@@ -2190,32 +2190,126 @@
 promise;%0A   %7D,%0A%0A
+   getIssueURL: function(issueID) %7B%0A      return this.createURL('/issues/' + issueID);%0A   %7D,%0A%0A
    getGroup: fun
@@ -2487,32 +2487,32 @@
 ction(params) %7B%0A
-
       return thi
@@ -2552,32 +2552,405 @@
 params);%0A   %7D,%0A%0A
+   getIssue: function(issueID, params) %7B%0A      return this.request('GET', '/issues/' + issueID + '.json', params);%0A   %7D,%0A%0A   getAllIssues: function(params) %7B%0A      var deferred = Q.defer(),%0A          self = this,%0A          all = %5B%5D;%0A%0A      return chainTogether(function(params) %7B%0A         return self.getIssues(params);%0A      %7D, params, 'issues', deferred, all, 0);%0A   %7D,%0A%0A
    getIssues: fu

add helper functions for getting all or single issues