#
# commit.py - DITrack 'commit' command
#
# Copyright (c) 2006-2007 The DITrack Project, www.ditrack.org.
#
# $Id: commit.py 2221 2007-10-19 21:36:00Z vss $
# $HeadURL: https://svn.xiolabs.com/ditrack/src/tags/0.8/DITrack/Command/commit.py $
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#  * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#

import string
import sys

# DITrack modules
import DITrack.Command.generic

class Handler(DITrack.Command.generic.Handler):
    canonical_name = "commit"
    description = """Commit local changes to the repository.
usage: %s [ID...]""" % canonical_name

    def _ids_from_cmdline(self, opts):

        assert len(opts.fixed) > 1

        # XXX: we should sort the entities to be committed
        ids = []

        for id in opts.fixed[1:]:

            try:
                parsed_id = DITrack.Common.Identifier(id)
            except ValueError:
                sys.stderr.write(
                    "Invalid entity name '%s', ignored\n" % id
                    )
                continue

            issue_id = parsed_id.issue.id

            if parsed_id.has_comment_part():

                comment_id = parsed_id.comment.id

                if comment_id.isdigit():
                    sys.stderr.write(
                        "Non-local comment id in '%s', ignored\n" % id
                        )
                    continue

            else:

                if issue_id.isdigit():
                    sys.stderr.write(
                        "Non-local issue id '%s', ignored\n" % id
                        )
                    continue

                comment_id = None


            ids.append((issue_id, comment_id))

        return ids

    def run(self, opts, globals):

        self.check_options(opts)

        db = DITrack.Util.common.open_db(globals, opts, "w")

        if len(opts.fixed) > 1:
            # We are told explicitly what to commit
            ids = self._ids_from_cmdline(opts)
        else:
            # Commit all local issues (not comments!)
            # See i#108: for now, let's just commit new issues since handling
            # comments is much more complex.
            ids = map(lambda x: (x[0], None), db.issues(from_wc=False))

        # Hash of issues that user wants to commit
        issues_to_commit = {}

        # Fill keys in the hash
        for issue_id, comment_id in ids:
            assert issue_id
            # Work only with comments
            if comment_id is not None:
                issues_to_commit[issue_id] = None;

        # Get the local comments for each issue (fill values)
        for issue_id in issues_to_commit.keys():
            issues_to_commit[issue_id] = db[issue_id].comments(firm=False);

        # Comments in each issues are sorted, so the first in the list
        # should be committed first.
        for issue_id, comment_id in ids:
            # work only with comments
            if comment_id is not None:
                if comment_id != issues_to_commit[issue_id][0][0]:
                    DITrack.Util.common.err(
                        "Can't commit %s.%s: %s.%s is in the way" % (
                            issue_id, comment_id, issue_id,
                            issues_to_commit[issue_id][0][0]
                        )
                    )

                # Keep the list in the state that the first comment in it
                # should be committed first.
                del(issues_to_commit[issue_id][0])

        for issue_id, comment_id in ids:

            if comment_id is None:
                firm_id = db.commit_issue(issue_id)

                id = "%s" % issue_id

            else:
                firm_id = db.commit_comment(issue_id, comment_id)

                firm_id = "%s.%s" % (issue_id, firm_id)
                id = "%s.%s" % (issue_id, comment_id)

            assert firm_id is not None

            # XXX: print 'Local i#ABC committed as i#123 in r234'.
            sys.stdout.write("Local i#%s committed as i#%s.\n" % (id, firm_id))
