"use strict";

var GitHubAPI = function(accessToken, org, repo) {

  var API_URL = 'https://api.github.com/repos/' + org + '/' + repo;

  return {
    callApi: function(method, endpoint, data) {
      return $.ajax({
        method: method,
        url: API_URL + endpoint,
        headers: {
          'Authorization': 'token ' + accessToken,
          'Content-Type': 'application/json'
        },
        data: JSON.stringify(data)
      });

    },

    get: function(endpoint) {
      return this.callApi('GET', endpoint);
    },

    put: function(endpoint, data) {
      return this.callApi('PUT', endpoint, data);
    },

    post: function(endpoint, data) {
      return this.callApi('POST', endpoint, data);
    },

    getBranch: function(branchName) {
      return this.get('/branches/' + branchName);
    },

    getTree: function(sha) {
      return this.get('/git/trees/' + sha + '?recursive=1');
    },

    getFileContents: function(path, ref) {
      return this.get('/contents/' + path + '?ref=' + ref);
    },

    updateFileContents: function(path, message, content, sha, branch) {
      return this.put(
        '/contents/' + path,
        {
          message: message,
          sha: sha,
          content: content,
          branch: branch
        }
      );
    },

    createBranch: function(branchName, sha) {
      return this.post(
        '/git/refs',
        {
          ref: 'refs/heads/' + branchName,
          sha: sha
        }
      );
    },

    createPullRequest: function(head, base, title, body) {
      return this.post(
        '/pulls',
        {
          head: head,
          base: base,
          title: title,
          body: body
        }
      );
    }
  };
}

// http://ecmanaut.blogspot.co.uk/2006/07/encoding-decoding-utf8-in-javascript.html
var decodeBase64ToText = function(base64) {
  return decodeURIComponent(escape(atob(base64.replace(/\s/g, ''))));
}

var encodeTextToBase64 = function(text) {
  return btoa(unescape(encodeURIComponent(text)));
}

var Vidius = function(github) {
  return {
    getBranch: function(name) {
      return github.getBranch(name);
    },

    getFileListing: function(branch) {
      return github.getTree(branch.commit.sha).then(function(data) {
        return data.tree;
      });
    },

    getMarkdownFiles: function(branch) {
      return this.getFileListing(branch).then(function(files) {
        return files.filter(function(file) {
          return file.path.endsWith('.md');
        });
      });
    },

    generatePreview: function(file, contents, branch) {

      function wait(ms) {
        // http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt2-practical-use#common-use-cases
        var deferred = $.Deferred();
        setTimeout(deferred.resolve, ms);

        return deferred.promise();
      }

      return $.post(
        '/preview',
        {
          git_ref: branch.commit.sha,
          file_path: file.path,
          file_contents: contents
        }).then(function(status_url) {

          var checkStatus = function(preview_url) {
            if (!! preview_url) {
              return preview_url;
            } else {

              console.log("Waiting for preview URL");
              return wait(1000).then(function() {
                return $.get(status_url).then(checkStatus);
              });
            }
          }

          return $.get(status_url).then(checkStatus);
        })
    },

    getTextFileContents: function(file, branch) {
      var deferred = $.Deferred();

      github.getFileContents(file.path, branch.commit.sha).then(
        function(contents) {
          // TODO check type is file and encoding is base64, otherwise fail
          deferred.resolve(decodeBase64ToText(contents.content));
        },
        function() {
          deferred.reject();
        }
      );

      return deferred.promise();
    },

    saveTextFileContents: function(file, contents, branch) {
      // TODO implement branch handling
      if (branch.name !== 'master') {
        throw 'editing branches not implemented';
      }

      var now = new Date(),
          timestamp = now.toISOString().replace(/:/g, '-').replace(/\..*$/, ''),
          // TODO: include user like `content/paulfurley/2016-01-28T18-34-56`
          branchName = 'content/' + timestamp,
          // TODO make a better commit message
          commitMessage = 'Updated file',
          base64Contents = encodeTextToBase64(contents);

      return github.createBranch(branchName, branch.commit.sha).then(function() {
        return github.updateFileContents(
          file.path,
          commitMessage,
          base64Contents,
          file.sha,
          branchName
        );
      }).then(function() {
        return github.createPullRequest(
          branchName,
          'master',
          commitMessage
        );
      }).then(function(pullRequestData) {
        return {
          link: pullRequestData.html_url,
          message: pullRequestData.html_url.replace(/https?:\/\//, '')
        };
      });
    }
  };
};

@@ -3643,39 +3643,49 @@
     
-// TODO check type is file and 
+if (contents.type === %22file%22 && contents.
 enco
@@ -3693,34 +3693,26 @@
 ing 
-is 
+=== %22
 base64
-, otherwise fail%0A
+%22) %7B%0A  
     
@@ -3773,16 +3773,88 @@
 tent));%0A
+          %7D%0A          else %7B%0A            deferred.reject();%0A          %7D%0A
         

Check type and encoding when getting file contents