// Requires
var Q = require('q');
var _ = require('underscore');
var inherits = require('util').inherits;

var Gift = require('gift/lib/repo');

var qPatchClass = require('./utils').qPatchClass;


function Gittle(path, bare) {
    bare = bare || false;
    Gittle.super_.call(this, path, bare);

    _.bindAll(this);
}
inherits(Gittle, qPatchClass(Gift, ['tree']));

// Normalize a diff
Gittle.prototype._normalizeDiff = function(d) {
    return {
        diff: d.diff,
        type: 'text',
        old: {
            path: d.a_path,
            mode: parseInt(d.a_mode || d.b_mode, 8),
            sha: d.a_blob.id
        },
        'new': {
            path: d.b_path,
            mode: parseInt(d.b_mode, 8),
            sha: d.b_blob.id
        }
    };
};

Gittle.prototype.diff = function() {
    var that = this;
    //console.log('DIFF FUNC =', Gittle.super_.prototype.diff);
    return Gittle.super_.prototype.diff.apply(this, _.toArray(arguments))
    .then(function(diffs) {
        return _.map(diffs, that._normalizeDiff);
    });
};

Gittle.prototype._git = function(command, options, files) {
    return Q.nfcall(this.git, command, options, files);
};

Gittle.prototype._track = function(files) {
    return this._git('add', {
        'N': true
    }, files).then(Q());
};

Gittle.prototype._untrack = function(files) {
    return this._git('rm', {
        'r': true,
        'cached': true,
    }, files).then(Q());
};

Gittle.prototype._untracked_files = function() {
    return this.status()
    .then(function(status) {
        return _.filter(_.keys(status.files), function(name) {
            return status.files[name].tracked === false;
        });
    }).then(Q());
};

// Add and remove files
Gittle.prototype._stage_files = function(files) {
    return this._git('add', {
        // -A option
        'A': true
    }, files).then(Q(files));
};

// Diff of the current working directory
// This pushes things to the index, we could avoid that maybe
Gittle.prototype.diff_working = function() {
    var that = this;
    return this._untracked_files()
    .then(function(files) {

        var _diff;
        var setDiff = function(d) {
            _diff = d;
        };
        var getDiff = function() {
            return _diff;
        };

        var diff = _.partial(that.diff, null, null);
        var track = _.partial(that._track, files);
        var untrack = _.partial(that._untrack, files);

        if(_.isEmpty(files)) {
            return diff();
        }

        return track()
        .then(diff)
        .then(setDiff)
        .then(untrack)
        .then(getDiff);
    });
};

Gittle.prototype.commit = function(name, email, msg, files) {
    files = files || [];

    var newIdentity = {
        name: name,
        email: email
    };

    var _author;
    var setAuthor = function(a) {
        _author = a;
    };
    var getAuthor = function() {
        return _author;
    };

    var setIdentity = function() {
        return this.identity(newIdentity);
    };

    var identity = this.identity;

    var commit = _.partial(Gittle.super_.prototype.commit, msg);

    return this._stage_files(files).then(Q())
    .then([
        // Get current identity and set it aside
        identity,
        setAuthor,

        // Set newIdentity from args
        setIdentity,

        // Do commit with new identity
        commit,

        // Restore previous identity
        getAuthor,
        identity

    ].reduce(Q.when, Q()));

};

Gittle.prototype.current_branch = function() {
    return this.branch().get('name');
};

Gittle.prototype.commits_pending = function() {
    var that = this;
    return this.current_branch()
    .then(function(branch) {
        return that.commits('origin/'+branch+'..');
    });
};

// Exports
exports.Gittle = Gittle;

@@ -2945,36 +2945,18 @@
 y = 
-function() %7B%0A        return 
+_.partial(
 this
@@ -2962,19 +2962,20 @@
 s.identi
-ty(
+fy, 
 newIdent
@@ -2980,23 +2980,50 @@
 ntity);%0A
+%0A
     
-%7D;%0A
+var identity = this.identity;
 %0A    var
@@ -3021,33 +3021,33 @@
 ;%0A    var identi
-t
+f
 y = this.identit
@@ -3045,17 +3045,17 @@
 s.identi
-t
+f
 y;%0A%0A    
@@ -3067,26 +3067,16 @@
 ommit = 
-_.partial(
 Gittle.s
@@ -3097,16 +3097,26 @@
 e.commit
+.bind(this
 , msg);%0A
@@ -3151,26 +3151,16 @@
 s(files)
-.then(Q())
 %0A    .th
@@ -3162,17 +3162,28 @@
   .then(
-%5B
+function() %7B
 %0A       
@@ -3232,24 +3232,31 @@
         
+return 
 identity
 ,%0A      
@@ -3251,29 +3251,111 @@
 tity
-,
+();
 %0A    
+%7D)%0A
     
-setAuthor,%0A
+.then(function(author) %7B%0A        return setAuthor(author);%0A    %7D)%0A    .then(function() %7B
 %0A   
@@ -3396,16 +3396,23 @@
         
+return 
 setIdent
@@ -3414,18 +3414,49 @@
 Identity
-,%0A
+();%0A    %7D)%0A    .then(function() %7B
 %0A       
@@ -3499,16 +3499,54 @@
     
-commit,%0A
+return commit();%0A    %7D)%0A    .then(function() %7B
 %0A   
@@ -3587,16 +3587,23 @@
         
+return 
 getAutho
@@ -3607,57 +3607,89 @@
 thor
-,
+();
 %0A    
+%7D)%0A
     
-identity%0A%0A    %5D.reduce(Q.when, Q())
+.then(function(author) %7B%0A        return identify(author);%0A    %7D
 );%0A
-%0A
 %7D;%0A%0A

Fix some issues in .commit