#!/usr/bin/python2.5
# Turnin-NG, an assignment submitter and manager. --- Project script
# Copyright (C) 2009-2011  Ryan Kavanagh <ryanakca@kubuntu.org>
#
# 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import errno
from optparse import OptionParser, OptionGroup
import os
import os.path
import re
import sys

import turninng
from turninng.configparser import ProjectGlobal, ProjectCourse, ProjectProject
from turninng.coursemanage import create_course, delete_course, archive_course
from turninng.fileperms import chmod
from turninng.projectmanage import create_project, delete_project, verify_sig
from turninng.projectmanage import compress_project, extract_project
from turninng.projectmanage import strip_random_suffix
from turninng.submitter import list_projects

if __name__ == '__main__':
    usage = '%prog [options] [project name]'
    parser = OptionParser(version=turninng.__version__, usage=usage)
    parser.add_option('-d', '--disable', action='store_false', dest='enabled',
            help='Disable submissions for the current project.')
    parser.add_option('-D', '--perm-disable', action='store_true',
            dest='pdisable',
            help='Permanently disable submissions for the current project.')
    parser.add_option('-e', '--enable', action='store_true', dest='enabled',
            help='Enable submissions for the current project and make it ' +
            'the default project.')
    parser.add_option('-l', dest='enabled_nodefault', action='store_true',
            help="Enable submissions for the current project but don't make " +
            "it default.")
    parser.add_option('-r', '--remove', action='store_true', dest='remove',
            help='Remove the current project and all associated files.')
    parser.add_option('-i', '--init', action='store_true', dest='init',
            help='Initialize this project.')
    parser.add_option('-p', '--compress', action='store_true',
            help='Compress this project.')
    parser.add_option('-x', '--extract', action='store_true',
            help='Extract this project.')
    parser.add_option('-v', '--verify', action='store_true',
            help='Verify signatures on submitted projects.')
    parser.add_option('--list', help='Lists projects for the course. ' +
            'Also displays wether or not the project is enabled.',
            action='store_true')
    parser.add_option('-c', '--course', help='Course name')
#    parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
#            help='Verbose. Print shell commands as they are executed.')
    parser.add_option('-C', '--config', help='Use an alternate config file.')
    parser.add_option('-w', '--legal', action='store_true',
            help='Print warranty and license information.')
    admin = OptionGroup(parser, "Administrative options",
            "These options can add or remove courses, etc.")
    admin.add_option('--create-course', help='Creates a course.')
    admin.add_option('--delete-course', help='Deletes a course.')
    admin.add_option('--archive-course', help='Archive a course.')
    parser.add_option_group(admin)
    parser.set_defaults(config=os.path.join('/etc', 'turnin-ng.cf'))
    (options, args) = parser.parse_args()

    config = options.config

    # We're moving away from the Uber-generic "project" command
    if re.match('.*project', sys.argv[0]):
        print (
"""    *****************************************************************
    * WARNING: The 'project' command is now deprecated, this legacy *
    * link to the new executable, turnincfg, may disappear in any   *
    * future release.                                               *
    *****************************************************************""")

    if options.legal:
        sys.exit(turninng.__license__)

    # Administrative functions :
    if options.create_course:
        try:
            create_course(config, options.create_course)
            sys.exit("Successfully created the course %s." % options.create_course)
        except ValueError, e:
            sys.exit(e)
    if options.delete_course:
        try:
            delete_course(config, options.delete_course)
            sys.exit("Successfully deleted the course %s." % options.delete_course)
        except ValueError, e:
            sys.exit(e)
    if options.archive_course:
        try:
            path = archive_course(config, options.archive_course, ret_path=True)
            sys.exit("Successfully archived the course %s to %s." %
                    (options.archive_course, path))
        except ValueError, e:
            sys.exit(e)
        except OSError, e:
            if e.errno == errno.ENOENT:
                print "Has someone already moved the submission directory?"
                sys.exit(e)


    # End user functions :
    if options.course:
        if ProjectGlobal(config).config.has_key(options.course):
            # From now on we want to use the projlist as the config file
            config = ProjectCourse(config, options.course).course['projlist']
            default_course = options.course
        else:
            sys.exit("The course %s does not exist." % options.course)
    else:
        parser.print_help()
        sys.exit("Please specify your course using the '-c course' or " +
            "'--course=COURSE' options.")

    # List projects
    if options.list:
        try:
            projects = list_projects(config, default_course)
            for i in projects:
                print i
            sys.exit()
        except ValueError, e:
            sys.exit(e)

    # Let's set the project_name variable
    if len(args) > 1:
        raise ValueError("Error, please pass one project name at a time.")
    elif len(args) == 1:
        project_name = args[0]
    elif ProjectCourse(config, default_course).course['default']:
        project_name = ProjectCourse(config, default_course).course['default']
    else:
        print "Please specify the project or set a default project."
        sys.exit(parser.print_help())

    # Create, delete or (un)compress the project if needed before creating an
    # object
    if options.init:
        create_project(config, default_course, project_name)
        sys.exit("Successfully created the project %s in the course %s." %
                (project_name, default_course))
    elif options.remove:
        try:
            delete_project(config, default_course, project_name)
            sys.exit("Successfully deleted the project %s." % project_name)
        except ValueError, e:
            sys.exit(e)
    # Compress or decompress
    try:
        if options.compress:
            compress_project(config, default_course, project_name)
            sys.exit("Successfully compressed the project %s." % project_name)
        elif options.extract:
            extract_project(config, default_course, project_name)
            sys.exit("Successfully extracted the project %s." % project_name)
    except ValueError, e:
        sys.exit(e)


    # Enable submissions for a project
    if options.enabled:
        if ProjectCourse(config, default_course).course.has_key(project_name):
            project = ProjectProject(config, default_course, project_name)
        else:
            sys.exit(ValueError('Course %s does not have the project %s.' %
                (default_course, project_name)))
        if project.project.has_key('tarball') and project.project['tarball']:
            extract_project(config, default_course, project_name)
            print "Extracted the project %s." % project_name
        if project.course['group_managed']:
            # Set the directory writable by everybody
            chmod(project.project['directory'], 0773)
        else:
            # Set the directory writable by the student group.
            chmod(project.project['directory'], 0730)
        project.write(True, default=True)
        sys.exit("Successfully enabled and set default the project %s." % project_name)
    elif options.enabled == False: # Disable it. I know, using '== False' is
        # bad according to PEP 8. However, using 'elif not options.enabled' will
        # return true even if the user didn't pass the option since
        # options.enabled will be None. We could check for != None, but I'd
        # rather be explicit than implicit ;)
        #       This chmod line is to prevent students from manually uploading
        # assignments to a project once it's disabled.
        if ProjectCourse(config, default_course).course.has_key(project_name):
            project = ProjectProject(config, default_course, project_name)
        else:
            sys.exit(ValueError('Course %s does not have the project %s.' %
                (default_course, project_name)))
        if project.course['group_managed']:
            chmod(project.project['directory'], 0770)
        else:
            chmod(project.project['directory'], 0700)
        project.write(False)
        sys.exit("Successfully disabled the project %s." % project_name)
    elif options.enabled_nodefault:
        if ProjectCourse(config, default_course).course.has_key(project_name):
            project = ProjectProject(config, default_course, project_name)
        else:
            sys.exit(ValueError('Course %s does not have the project %s.' %
                (default_course, project_name)))
        if project.project.has_key('tarball') and project.project['tarball']:
            extract_project(config, default_course, project_name)
            print "Extracted the project %s." % project_name
        project.write(True)
        sys.exit("Successfully enabled the project %s." % project_name)
    elif options.verify:
        if ProjectCourse(config, default_course).course.has_key(project_name):
            project = ProjectProject(config, default_course, project_name)
        else:
            sys.exit(ValueError('Course %s does not have the project %s.' %
                (default_course, project_name)))
        try:
            unsigned = verify_sig(project)
            sys.exit("\n".join(unsigned))
        except ValueError, e:
            sys.exit(e)
    elif options.pdisable:
        if ProjectCourse(config, default_course).course.has_key(project_name):
            project = ProjectProject(config, default_course, project_name)
        else:
            sys.exit(ValueError('Course %s does not have the project %s.' %
                (default_course, project_name)))
        if project.course['group_managed']:
           chmod(project.project['directory'], 0770)
        else:
            chmod(project.project['directory'], 0700)
        project.write(False)
        try:
            strip_random_suffix(project)
        except ValueError, e:
            sys.exit(e)
        sys.exit("Successfully disabled the project %s and " % project_name +
            "stripped random suffixes.")
    elif args and default_course:
        create_project(config, default_course, project_name)
        sys.exit("Successfully created the project %s in the course %s." %
                (project_name, default_course))
    else:
        # We didn't get anything.
        parser.print_help()
