"use strict";

var http = require("http");
var https = require("https");
var url = require("url");
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs"));
var path = require("path");
var exec = Promise.promisify(require("child_process").exec);

var destinationDir = "repos";

function httpsGet(options) {
	return new Promise(function(resolve, reject) {
		https.get(options, function(res) {
			if (res.statusCode >= 400) {
				promisifyReadableStream(res).then(function(data) {
					reject(res.statusCode + " " + http.STATUS_CODES[res.statusCode] + "\n" + data);
				}, function(err) {
					reject(err);
				});
				return;
			}
			resolve(res);
		}).on("error", function(err) {
			reject(err);
		});
	});
}
function promisifyReadableStream(stream) {
	return new Promise(function(resolve, reject) {
		var data = "";
		stream.on("data", function(d) {
			data += d;
		}).on("end", function() {
			resolve(data);
		}).on("error", function(err) {
			reject(err);
		});
	});
}

function get(path) {
	var options = url.parse("https://api.github.com" + path);
	options.headers = {
		"User-Agent": "github-backup",
		"Accept": "application/vnd.github.v3+json"
	};

	return httpsGet(options).then(promisifyReadableStream).then(JSON.parse);
}

function getPublicUserRepos(user) {
	var userRepos = get("/users/" + user + "/repos").all();
	var orgRepos = get("/users/" + user + "/orgs").map(getOrgRepos).all();
	return Promise.join(userRepos, orgRepos, function(userRepos, orgRepos) {
		return userRepos.concat.apply(userRepos, orgRepos);
	});
}

function getOrgRepos(org) {
	return get("/orgs/" + org.login + "/repos");
}

function backupRepo(repo) {
	var url = repo.clone_url;
	var re = new RegExp("https://github\.com/([^/]+)/([^/]+)");
	var matches = url.match(re);
	var user = matches[1];
	var repoName = matches[2];
	var repoPath = path.join(destinationDir, user, repoName);

	return fs.statAsync(user).error(function() {
		return fs.mkdirAsync(user);
	}).then(function() {
		return fs.statAsync(repoPath);
	}).then(function() {
		console.log("updating", url);
		return exec("git remote update", { cwd: repoPath });
	}, function(err) {
		console.log("cloning", url);
		return exec("git clone --mirror " + url + " " + repoPath);
	});
}

getPublicUserRepos("ericlathrop").then(function(repos) {
	var promise;
	for (var i = 0; i < repos.length; i++) {
		var repo = repos[i];
		if (promise) {
			promise = promise.then(function(stdout) {
				console.log("finished");
				console.log(stdout);
				return backupRepo(repo);
			}, function(err) {
				console.log("backupRepo err", err);
			});
		} else {
			promise = backupRepo(repo);
		}
	}
	return promise;
}, function(err) {
	console.error("Unhandled error:", err);
}).done();

@@ -2251,145 +2251,55 @@
 %0A%7D%0A%0A
-getPublicUserRepos(%22ericlathrop%22).then(function(repos) %7B%0A%09var promise;%0A%09for (var i = 0; i %3C repos.length; i++) %7B%0A%09%09var repo = repos%5Bi%5D;%0A%09
+function backupRepoSerialized(repo, promise) %7B%0A
 %09if 
@@ -2312,26 +2312,22 @@
 se) %7B%0A%09%09
-%09promise =
+return
  promise
@@ -2350,25 +2350,24 @@
 tdout) %7B%0A%09%09%09
-%09
 console.log(
@@ -2379,17 +2379,16 @@
 shed%22);%0A
-%09
 %09%09%09conso
@@ -2402,25 +2402,24 @@
 stdout);%0A%09%09%09
-%09
 return backu
@@ -2431,17 +2431,16 @@
 (repo);%0A
-%09
 %09%09%7D, fun
@@ -2455,17 +2455,16 @@
 r) %7B%0A%09%09%09
-%09
 console.
@@ -2493,22 +2493,20 @@
 err);%0A%09%09
-%09
 %7D);%0A
-%09
 %09%7D else 
@@ -2513,40 +2513,223 @@
 %7B%0A%09%09
-%09promise = backupRepo(repo);%0A%09%09%7D
+return backupRepo(repo);%0A%09%7D%0A%7D%0A%0AgetPublicUserRepos(%22ericlathrop%22).then(function(repos) %7B%0A%09var promise;%0A%09for (var i = 0; i %3C repos.length; i++) %7B%0A%09%09var repo = repos%5Bi%5D;%0A%09%09promise = backupRepoSerialized(repo, promise);
 %0A%09%7D%0A

Fix scoping bug that always operated on last repo.