#!/usr/bin/env python
#
# dt - DITrack command-line client
#
# Copyright (c) 2006-2007 The DITrack Project, www.ditrack.org.
#
# $Id: dt 2276 2007-10-24 00:31:06Z vss $
# $HeadURL: https://127.0.0.1/ditrack/src/tags/0.7/dt $
#
# 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 logging
import os.path
import sys

# DITrack modules
import DITrack.dt.globals
import DITrack.Command.act
import DITrack.Command.cat
import DITrack.Command.commit
import DITrack.Command.help
import DITrack.Command.list
import DITrack.Command.new
import DITrack.Command.remove
import DITrack.Command.status
import DITrack.Command.update
import DITrack.Util.cmdline

################################# GLOBALS ############################

globals = DITrack.dt.globals.Globals()

################################# CLASSES ############################

class CommandTable:
    def __init__(self, table):
        self.table = table

        keys = table.keys()
        cmds = {}

        for k in keys:
            item = table[k]
            if not cmds.has_key(item.canonical_name):
                cmds[item.canonical_name] = [ item.canonical_name ]

            if k != item.canonical_name:
                cmds[item.canonical_name].append(k)

        self.map = cmds

    def dispatch(self, opts):
        if self.table.has_key(opts.fixed[0]):
            self.table[opts.fixed[0]].run(opts, globals)
        else:
            usage()

############################### FUNCTIONS ###########################

def usage():
    print "Syntax error, type '%s help' for help." % globals.binname
    sys.exit(1)

############################## ENTRY POINT ##########################

#
# Options
#

opt_actions = DITrack.Util.cmdline.Option (
    name = "actions",
    descr = "specify actions to take",
    type = "string",
    arg = "ACTIONLIST",
    aliases = [ "-a" ]
)

opt_comment_file = DITrack.Util.cmdline.Option (
    name = "comment_file",
    descr = "specify a file containing the comment message",
    type = "string",
    arg = "FILE",
    aliases = [ "-F" ]
)

opt_comment_message = DITrack.Util.cmdline.Option (
    name = "comment_message",
    descr = "specify a comment message",
    type = "string",
    arg = "MESSAGE",
    aliases = [ "-m" ]
)

opt_database = DITrack.Util.cmdline.Option (
    name = "database",
    descr = "specify the path to an issue database",
    type = "string",
    arg = "PATH",
    aliases = [ "-d" ]
)

opt_listing_format = DITrack.Util.cmdline.Option (
    name = "listing_format",
    descr = "specify listing format",
    type = "string",
    arg = "FORMAT",
    aliases = [ "-f", "--format" ]
)

opt_listing_format_list = DITrack.Util.cmdline.Option (
    name = "listing_format_list",
    descr = "list available output formats",
    type = "boolean",
    arg = "",
    aliases = [ "--list-formats" ]
)

opt_headers_only = DITrack.Util.cmdline.Option (
    name = "headers_only",
    descr = "display only headers",
    type = "boolean",
    arg = "",
    aliases = [ "--headers-only" ],
)

opt_maxage = DITrack.Util.cmdline.Option (
    name = "maxage",
    descr = "tolerate the database to be out-of-date this much",
    type = "string",
    arg = "SECONDS",
    aliases = [ "--maxage" ]
)

opt_no_commits = DITrack.Util.cmdline.Option (
    name = "no_commits",
    descr = "do not perform commits",
    type = "boolean",
    arg = "",
    aliases = [ "-n", "--no-commits" ]
)

opt_path = DITrack.Util.cmdline.Option (
    name = "path",
    descr = "dump the path of the file, not its contents",
    type = "boolean",
    arg = "",
    aliases = [ "--path" ],
)

opt_user = DITrack.Util.cmdline.Option (
    name = "user",
    descr = "specify the user name",
    type = "string",
    arg = "NAME",
    aliases = [ "-u", "--user" ],
)

opt_version = DITrack.Util.cmdline.Option (
    name = "version",
    descr = "display version information",
    type = "boolean",
    arg = "",
    aliases = [ "--version" ],
)

opt_xml = DITrack.Util.cmdline.Option (
    name = "xml",
    descr = "output in XML",
    type = "boolean",
    arg = "",
    aliases = [ "--xml" ],
)

#
# Commands
#

cmd_act = DITrack.Command.act.Handler(
    opt_actions,
    opt_comment_file,
    opt_comment_message,
    opt_database,
    opt_no_commits,
    opt_user,
)

cmd_cat = DITrack.Command.cat.Handler(
    opt_database,
    opt_headers_only,
    opt_path,
    opt_xml,
)

cmd_commit = DITrack.Command.commit.Handler(
    opt_database,
    opt_user,
)

cmd_help = DITrack.Command.help.Handler(
)

cmd_list = DITrack.Command.list.Handler(
    opt_database,
    opt_user,
    opt_listing_format,
    opt_listing_format_list,
    opt_xml,
)

cmd_new = DITrack.Command.new.Handler(
    opt_database,
    opt_no_commits,
    opt_user,
)

cmd_remove = DITrack.Command.remove.Handler(
    opt_database,
    opt_user,
)

cmd_status = DITrack.Command.status.Handler(
    opt_database,
)

cmd_update = DITrack.Command.update.Handler(
    opt_database,
    opt_maxage,
    opt_user,
)

# Create command dispatching table.
globals.command_table = CommandTable({
    "act":          cmd_act,
    "cat":          cmd_cat,
    "ci":           cmd_commit,
    "commit":       cmd_commit,
    "help":         cmd_help,
    "list":         cmd_list,
    "ls":           cmd_list,
    "new":          cmd_new,
    "remove":       cmd_remove,
    "rm":           cmd_remove,
    "status":       cmd_status,
    "st":           cmd_status,
    "update":       cmd_update,
    "up":           cmd_update,
})

if "DITRACK_DEBUG" in os.environ:
    logging.getLogger().setLevel(logging.DEBUG)

try:
    opts = DITrack.Util.cmdline.ParseResults([
        opt_actions,
        opt_comment_file,
        opt_comment_message,
        opt_database,
        opt_headers_only,
        opt_listing_format,
        opt_listing_format_list,
        opt_maxage,
        opt_no_commits,
        opt_path,
        opt_user,
        opt_version,
        opt_xml,
        ])
except DITrack.Util.cmdline.DuplicateOptionError, e:
    print "Duplicate option:", e.option
    sys.exit(1)
except DITrack.Util.cmdline.InvalidValueTypeError, e:
    print "Invalid parameter type for: -" + e.option
    sys.exit(1)
except DITrack.Util.cmdline.MissingParameterError, e:
    print "Option requires a parameter:", e.option
    sys.exit(1)
except DITrack.Util.cmdline.UnknownOptionError, e:
    print "Unknown option:", e.option
    sys.exit(1)
        
if opts.var["version"]:
    print globals.dt_title
    sys.exit(0)

if len(opts.fixed) < 1:
    usage()

try:
    globals.command_table.dispatch(opts)
except DITrack.Command.generic.SyntaxError:
    usage()
