// Generated by CoffeeScript 1.9.3
(function() {
  var Actor, Commit, Config, Diff, Head, Ref, Repo, Status, Tag, Tree, _, cmd, ref;

  _ = require('underscore');

  cmd = require('./git');

  Actor = require('./actor');

  Commit = require('./commit');

  Config = require('./config');

  Tree = require('./tree');

  Diff = require('./diff');

  Tag = require('./tag');

  Status = require('./status');

  ref = require('./ref'), Ref = ref.Ref, Head = ref.Head;

  module.exports = Repo = (function() {
    function Repo(path, bare, git_options) {
      this.path = path;
      this.bare = bare;
      this.git_options = git_options;
      if (this.bare) {
        this.dot_git = this.path;
      } else {
        this.dot_git = this.path + "/.git";
      }
      this.git = cmd(this.path, this.dot_git, this.git_options);
    }

    Repo.prototype.identity = function(callback) {
      return this.git("config", {}, ["user.email"], (function(_this) {
        return function(err, stdout) {
          var email;
          if (stdout == null) {
            stdout = '';
          }
          if (err) {
            return callback(err);
          }
          email = stdout != null ? stdout.trim() : void 0;
          return _this.git("config", {}, ["user.name"], function(err, stdout) {
            var name;
            if (stdout == null) {
              stdout = '';
            }
            if (err) {
              return callback(err);
            }
            name = stdout != null ? stdout.trim() : void 0;
            return callback(null, new Actor(name, email));
          });
        };
      })(this));
    };

    Repo.prototype.identify = function(actor, callback) {
      return this.git("config", {}, ["user.email", "\"" + actor.email + "\""], (function(_this) {
        return function(err) {
          if (err) {
            return callback(err);
          }
          return _this.git("config", {}, ["user.name", "\"" + actor.name + "\""], function(err) {
            if (err) {
              return callback(err);
            }
            return callback(null);
          });
        };
      })(this));
    };

    Repo.prototype.commits = function(start, limit, skip, callback) {
      var options, ref1, ref2, ref3;
      if (!callback) {
        ref1 = [callback, skip], skip = ref1[0], callback = ref1[1];
      }
      if (!callback) {
        ref2 = [callback, limit], limit = ref2[0], callback = ref2[1];
      }
      if (!callback) {
        ref3 = [callback, start], start = ref3[0], callback = ref3[1];
      }
      if (!callback) {
        throw new Error("a callback is required");
      }
      if (start == null) {
        start = "master";
      }
      if (limit == null) {
        limit = 10;
      }
      if (skip == null) {
        skip = 0;
      }
      options = {
        skip: skip
      };
      if (limit !== -1) {
        options["max-count"] = limit;
      }
      return Commit.find_all(this, start, options, callback);
    };

    Repo.prototype.current_commit_id = function(callback) {
      return this.git("rev-parse HEAD", {}, [], (function(_this) {
        return function(err, stdout, stderr) {
          if (err) {
            return callback(err);
          }
          return callback(null, _.first(stdout.split("\n")));
        };
      })(this));
    };

    Repo.prototype.current_commit = function(callback) {
      return this.current_commit_id((function(_this) {
        return function(err, commit_id) {
          if (err) {
            return callback(err);
          }
          return Commit.find(_this, commit_id, callback);
        };
      })(this));
    };

    Repo.prototype.tree = function(treeish) {
      if (treeish == null) {
        treeish = "master";
      }
      return new Tree(this, treeish);
    };

    Repo.prototype.diff = function(commitA, commitB) {
      var callback, options, paths, ref1, ref2;
      ref1 = [[], {}], paths = ref1[0], options = ref1[1];
      if (arguments.length === 3) {
        callback = arguments[2];
      } else if (arguments.length === 4) {
        callback = arguments[3];
        if (arguments[2] instanceof Array) {
          paths = arguments[2];
        } else if (arguments[2] instanceof Object) {
          options = arguments[2];
        }
      } else if (arguments.length === 5) {
        ref2 = Array.prototype.slice.call(arguments, 2), paths = ref2[0], options = ref2[1], callback = ref2[2];
      }
      if (_.isObject(commitA)) {
        commitA = commitA.id;
      }
      if (_.isObject(commitB)) {
        commitB = commitB.id;
      }
      return this.git("diff", options, _.flatten([commitA, commitB, "--", paths]), (function(_this) {
        return function(err, stdout, stderr) {
          if (err) {
            return callback(err);
          }
          if (_.has(options, 'raw')) {
            return callback(err, Diff.parse_raw(_this, stdout));
          } else {
            return callback(err, Diff.parse(_this, stdout));
          }
        };
      })(this), 'binary');
    };

    Repo.prototype.remotes = function(callback) {
      return Ref.find_all(this, "remote", Ref, callback);
    };

    Repo.prototype.remote_list = function(callback) {
      return this.git.list_remotes(callback);
    };

    Repo.prototype.remote_add = function(name, url, callback) {
      return this.git("remote", {}, ["add", name, url], function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_remove = function(name, callback) {
      return this.git("remote", {}, ["rm", name], function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_add_url = function(name, url, callback) {
      return this.git("remote set-url", {}, ["--add", name, url], function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_set_url = function(name, url, callback) {
      return this.git("remote set-url", {}, [name, url], function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_delete_url = function(name, url, callback) {
      return this.git("remote set-url", {}, ["--delete", name, url], function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_fetch = function(name, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      return this.git("fetch", options, name, function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.remote_push = function(name, branch, options, callback) {
      var args;
      if (!options && !callback) {
        callback = branch;
        args = name;
        options = {};
      } else {
        if (!callback) {
          callback = options;
          options = {};
        }
        args = [name, branch];
      }
      return this.git("push", options, args, function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.merge = function(name, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      return this.git("merge", options, name, function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.status = function(options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      return Status(this, options, callback);
    };

    Repo.prototype.ls_files = function(files, options, callback) {
      var ref1;
      if (arguments.length < 3) {
        ref1 = [files, options], options = ref1[0], callback = ref1[1];
        files = null;
      }
      if (callback == null) {
        callback = function() {};
      }
      if (options == null) {
        options = {};
      }
      if (files == null) {
        files = '';
      }
      if (_.isString(files)) {
        files = [files];
      }
      return this.git("ls-files", options, _.flatten(['--', files]), (function(_this) {
        return function(err, stdout, stderr) {
          if (err) {
            return callback(err);
          }
          return callback(null, _this.parse_lsFiles(stdout, options));
        };
      })(this));
    };

    Repo.prototype.config = function(callback) {
      return Config(this, callback);
    };

    Repo.prototype.tags = function(callback) {
      return Tag.find_all(this, callback);
    };

    Repo.prototype.create_tag = function(name, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      return this.git("tag", options, [name], callback);
    };

    Repo.prototype.delete_tag = function(name, callback) {
      return this.git("tag", {
        d: name
      }, callback);
    };

    Repo.prototype.branches = function(callback) {
      return Head.find_all(this, callback);
    };

    Repo.prototype.create_branch = function(name, callback) {
      return this.git("branch", {}, name, function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.delete_branch = function(name, callback) {
      return this.git("branch", {
        d: true
      }, name, function(err, stdout, stderr) {
        return callback(err);
      });
    };

    Repo.prototype.branch = function(name, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, name], name = ref1[0], callback = ref1[1];
      }
      if (!name) {
        return Head.current(this, callback);
      } else {
        return this.branches(function(err, heads) {
          var head, i, len;
          if (err) {
            return callback(err);
          }
          for (i = 0, len = heads.length; i < len; i++) {
            head = heads[i];
            if (head.name === name) {
              return callback(null, head);
            }
          }
          return callback(new Error("No branch named '" + name + "' found"));
        });
      }
    };

    Repo.prototype.checkout = function(treeish, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [{}, options], options = ref1[0], callback = ref1[1];
      }
      return this.git("checkout", options, treeish, callback);
    };

    Repo.prototype.clean = function(options, callback) {
      if (options == null) {
        options = {};
      }
      return this.git("clean", options, callback);
    };

    Repo.prototype.reset = function(treeish, options, callback) {
      var ref1, ref2, ref3;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      if (!callback) {
        ref2 = [callback, treeish], treeish = ref2[0], callback = ref2[1];
      }
      if (typeof treeish === 'object') {
        ref3 = [options, treeish], treeish = ref3[0], options = ref3[1];
      }
      if (treeish == null) {
        treeish = 'HEAD';
      }
      if (options == null) {
        options = {};
      }
      return this.git("reset", options, treeish, callback);
    };

    Repo.prototype.checkoutFile = function(files, options, callback) {
      var ref1, ref2, ref3;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      if (!callback) {
        ref2 = [callback, files], files = ref2[0], callback = ref2[1];
      }
      if (typeof files === 'object') {
        ref3 = [options, files], files = ref3[0], options = ref3[1];
      }
      if (options == null) {
        options = {};
      }
      if (files == null) {
        files = '.';
      }
      if (_.isString(files)) {
        files = [files];
      }
      return this.git("checkout", options, _.flatten(['--', files]), callback);
    };

    Repo.prototype.commit = function(message, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      if (options == null) {
        options = {};
      }
      options = _.extend(options, {
        m: "\"" + message + "\""
      });
      if (options.author != null) {
        options.author = "\"" + options.author + "\"";
      }
      return this.git("commit", options, callback);
    };

    Repo.prototype.add = function(files, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      if (options == null) {
        options = {};
      }
      if (_.isString(files)) {
        files = [files];
      }
      return this.git("add", options, files, callback);
    };

    Repo.prototype.remove = function(files, options, callback) {
      var ref1;
      if (!callback) {
        ref1 = [callback, options], options = ref1[0], callback = ref1[1];
      }
      if (options == null) {
        options = {};
      }
      if (_.isString(files)) {
        files = [files];
      }
      return this.git("rm", options, files, callback);
    };

    Repo.prototype.revert = function(sha, callback) {
      return this.git("revert", {}, sha, callback);
    };

    Repo.prototype.sync = function(remote_name, branch_name, callback) {
      var branch, ref1, ref2, ref3, remote;
      if (typeof callback === "function") {
        ref1 = [remote_name, branch_name], remote = ref1[0], branch = ref1[1];
      }
      if (typeof branch_name === "function") {
        ref2 = ["origin", remote_name, branch_name], remote = ref2[0], branch = ref2[1], callback = ref2[2];
      }
      if (typeof remote_name === "function") {
        ref3 = ["origin", "master", remote_name], remote = ref3[0], branch = ref3[1], callback = ref3[2];
      }
      return this.status((function(_this) {
        return function(err, status) {
          if (err) {
            return callback(err);
          }
          return _this.git("stash", {}, ["save", "-u"], function(err, stdout, stderr) {
            if (err) {
              return callback(stderr);
            }
            return _this.git("pull", {}, [remote, branch], function(err, stdout, stderr) {
              if (err) {
                return callback(stderr);
              }
              return _this.git("push", {}, [remote, branch], function(err, stdout, stderr) {
                if (err) {
                  return callback(stderr);
                }
                if (!(status != null ? status.clean : void 0)) {
                  return _this.git("stash", {}, ["pop"], function(err, stdout, stderr) {
                    if (err) {
                      return callback(stderr);
                    }
                    return callback(null);
                  });
                } else {
                  return callback(null);
                }
              });
            });
          });
        };
      })(this));
    };

    Repo.prototype.pull = function(remote_name, branch_name, callback) {
      var branch, ref1, ref2, ref3, remote;
      if (typeof callback === "function") {
        ref1 = [remote_name, branch_name], remote = ref1[0], branch = ref1[1];
      }
      if (typeof branch_name === "function") {
        ref2 = ["origin", remote_name, branch_name], remote = ref2[0], branch = ref2[1], callback = ref2[2];
      }
      if (typeof remote_name === "function") {
        ref3 = ["origin", "master", remote_name], remote = ref3[0], branch = ref3[1], callback = ref3[2];
      }
      return this.status((function(_this) {
        return function(err, status) {
          if (err) {
            return callback(err);
          }
          return _this.git("pull", {}, [remote, branch], function(err, stdout, stderr) {
            if (err) {
              return callback(stderr);
            }
            return callback(null);
          });
        };
      })(this));
    };

    Repo.prototype.parse_lsFiles = function(text, options) {
      var files, line, lines;
      files = [];
      if (_.has(options, 'z')) {
        lines = text.split("\0");
      } else {
        lines = text.split("\n");
      }
      while (lines.length) {
        line = lines.shift().split(" ");
        files.push(line);
        while ((lines[0] != null) && !lines[0].length) {
          lines.shift();
        }
      }
      return files;
    };

    return Repo;

  })();

}).call(this);
