/*

    Minimum Profit 5.x
    A Programmer's Text Editor

    Version Control System support

    Copyright (C) 1991-2012 Angel Ortega <angel@triptico.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    http://triptico.com

*/

/** default key bindings **/

mp_doc.keycodes['ctrl-p'] = 'vcs';

/** action descriptions **/

mp.actdesc['vcs'] = LL("Version Control...");

/** mp_doc commit subclass **/

global mp_doc_vcs = new(mp_doc, { name: '.COMMIT_MESSAGE' });


/** data **/

mp.vcs = {
    git: {
        id:     'Git',
        check:  [ '.git', '../.git', '../../.git', '../../../.git' ],
        opts:   {
            "git add '%s'"      => NULL,
            'git log'           => { unique_log: 1 },
            "git log '%s'"      => { unique_log: 1 },
            'git diff'          => { unique_log: 1 },
            "git diff '%s'"     => { unique_log: 1 },
            'git status'        => NULL,
            "git blame '%s'"    => { unique_log: 1 },
            "git checkout '%s'" => NULL,
            "git stash"         => NULL,
            "git stash apply"   => NULL,
            "git push"          => NULL,
            "git pull"          => NULL,
            "git commit -a"     => { commit_cmd: "git commit -a -F '%s'" }
        }
    },
    svn: {
        id:     'SVN',
        check:  [ '.svn', '../.svn', '../../.svn', '../../../.svn' ],
        opts:   {
            'svn diff'          => { unique_log: 1 },
            'svn status'        => NULL,
            'svn log'           => { unique_log: 1 },
            "svn diff '%s'"     => NULL,
            "svn log '%s'"      => { unique_log: 1 },
            "svn add '%s'"      => NULL,
            "svn annotate '%s'" => { unique_log: 1 },
            "svn update"        => NULL,
            "svn revert '%s'"   => NULL,
            "svn commit"        => { commit_cmd: "svn commit -F '%s'" }
        }
    },
    mercurial: {
        id:     'Mercurial',
        check:  [ '.hg', '../.hg', '../../.hg' ],
        opts:   {
            'hg diff'          => { unique_log: 1 },
            'hg status'        => NULL,
            'hg log'           => { unique_log: 1 },
            "hg diff '%s'"     => NULL,
            "hg log '%s'"      => { unique_log: 1 },
            "hg add '%s'"      => NULL,
            "hg push"          => NULL,
            "hg pull"          => NULL,
            "hg annotate '%s'" => { unique_log: 1 },
            "hg commit -A"     => { commit_cmd: "hg commit -A -l '%s'" }
        }
    }
};

/** editor actions **/

mp.actions['vcs'] = sub {
    local v = NULL;

    /* find which VCS apply to current directory */
    foreach (k, keys(mp.vcs)) {
        local n = mp.vcs[k];

        foreach (d, n.check) {
            if (stat(d) != NULL) {
                v = n;
                break;
            }
        }

        if (v != NULL)
            break;
    }

    if (v == NULL)
        mp.alert(L("This directory is not under a supported version control system"));
    else {
        local l = sort(keys(v.opts))->
            map(sub (e) { sprintf(e, regex(mp.active.name, '/[^\/\\]+$/')); });

        local t = mp.form(
            [
                {
                    label:  sprintf(L("Available %s commands"), v.id),
                    type:   'list',
                    list:   l,
                    value:  mp.vcs_target
                }
            ]
        );

        if (t != NULL) {
            mp.vcs_target = t[0];

            local opts  = v.opts[l[mp.vcs_target]];
            local cmd   = l[mp.vcs_target];

            if (opts.commit_cmd) {
                /* create a commit message editor document */
                local msg = new(mp_doc_vcs);

                msg.vcs = {
                    commit_cmd: opts.commit_cmd,
                    log_name:   sprintf(L("<%s output>"), v.id)
                };

                mp.add(msg);
            }
            else {
                local log;

                /* unique log for this command? */
                if (opts.unique_log) {
                    log = mp.open(sprintf(L("<%s output>"), cmd));
                    log.txt.lines   = [ '' ];
                    log.txt.y       = 0;
                }
                else {
                    /* common log */
                    log = mp.open(sprintf(L("<%s output>"), v.id));

                    log->move_eof();
                    log->insert(cmd ~ ":\n\n");
                }

                log->actions.exec_command(cmd);

                if (opts.unique_log) {
                    log->detect_syntax()->move_bof();
                }
                else
                    log->insert("\n");

                log.txt.mod     = 0;
                log.undo_q      = [];
                log.read_only   = 1;
            }
        }
    }
};

/** code **/

sub mp_doc_vcs.query_close(doc)
/* mp_doc.query_close overload for commit messages */
{
    local r;

    /* call superclass query close */
    if ((r = mp_doc.query_close(doc)) == 1) {
        /* has the commit message been saved? */
        if (stat(doc.name) != NULL) {
            local cmd = sprintf(doc.vcs.commit_cmd, doc.name);
            local log = mp.open(doc.vcs.log_name);

            log->move_eof();
            log->insert(cmd ~ ":\n\n");
            log->actions.exec_command(cmd);
            log->insert("\n");

            log.txt.mod     = 0;
            log.undo_q      = [];
            log.read_only   = 1;

            /* bring doc to active back */
            mp.open(doc.name);
        }

        unlink(doc.name);
    }

    return r;
}
