#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone

from courses.models import Slide
from courses.models import Section
from courses.models import Course


import argparse
import atexit
import csv
import datetime
import os
import re
import shutil
import sys
import tempfile
import time
import pprint
import importlib.machinery
import subprocess
import json


# Globals
FORMATS = {}
ARGS = None
PLATFORM_PATH = os.environ["PLATFORM_PATH"]
OER_SRC_DIR = os.environ["OER_SRC_DIR"]


# Sanitize in and output parameters for argparse
class readable_dir(argparse.Action):
    def __call__(self,parser, namespace, values, option_string=None):
        prospective_dir=values
        if not os.path.isdir(prospective_dir):
            print('readable_dir:{0} is not a valid path'.format(prospective_dir))
            exit(1)
            #raise argparse.ArgumentTypeError("readable_dir:{0} is not a valid path".format(prospective_dir))
        if os.access(prospective_dir, os.R_OK):
            setattr(namespace,self.dest,prospective_dir)
        else:
            print('readable_dir:{0} is not a readable dir'.format(prospective_dir))
            exit(1)
            #raise argparse.ArgumentTypeError("readable_dir:{0} is not a readable dir".format(prospective_dir))

class writeable_dir(argparse.Action):
    def __call__(self,parser, namespace, values, option_string=None):
        prospective_dir=values
        if not os.path.isdir(prospective_dir):
            print('writeable_dir:{0} is not a valid path'.format(prospective_dir))
            exit(1)
            #raise argparse.ArgumentTypeError("readable_dir:{0} is not a valid path".format(prospective_dir))
        if os.access(prospective_dir, os.W_OK):
            setattr(namespace,self.dest,prospective_dir)
        else:
            print('writeableable_dir:{0} is not a writeable dir'.format(prospective_dir))
            exit(1)
            #raise argparse.ArgumentTypeError("readable_dir:{0} is not a readable dir".format(prospective_dir))


def discover_formats(path):
    """ Traverse directory and find available handlers for types. As a exercise
    type may have additional attachments and template code, type handlers are
    supposed to create a folder with a type file in it. This approach allows
    arbitrary nesting of subtypes
    """
    global formats
    for root, dirs, files in os.walk(path):
        #print(root)
        #print(dirs)
        #print(files)
        if 'CourseHandler.py' in files:
            name = root.replace(path, '')
            loader = importlib.machinery.SourceFileLoader(name, root + '/CourseHandler.py')
            mod = loader.load_module()

            FORMATS[name] = {
                'path': root,
                'loader': loader,
                'mod': mod
            }


class CourseParser(object):
    """ The CourseParser only handles the very basic operations required
    for all course types. It determines the type of an course and then
    passes further processing to the correct CourseHandler.
    """
    def __init__(self, path):
        self.path = path
        self.type = None
        self.meta = None
        print('Check course:', self.path)

        self.get_meta()

        if self.meta == None:
            print('Skipped. Invalid meta information.')
            return

        if not 'title' in self.meta:
            print('Skipped. No title provided.')
            return

        item, created = Course.objects.get_or_create(source_path=self.path)
        if created:
            print('INFO: Creating item "%s".' % self.meta['title'])
        else:
            print('INFO: Updating existing item "%s".' % self.meta['title'])

        item.title = self.meta['title']
        item.description = self.meta['description']

        item.sections.clear()
        item.save()

        # assume a database item to be existing by now
        # make item member of the parser to be accessable by handlers
        self.item = item

        if 'sections' in os.listdir(self.path):
            print("Course organized in sections!")
            args = [PLATFORM_PATH + "/manage.py",
                    "import-sections",
                    "--sources", (self.path + '/sections'),
                    "--course", (self.path),
                    ]
            print(args)
            subprocess.call(args, shell=False)

        else:
            if 'exercises' in os.listdir(self.path):
                args = [PLATFORM_PATH + "/manage.py",
                        "import-exercises",
                        "--sources", (self.path + '/exercises'),
                        "--course", (self.path),
                        ]
                print(args)
                subprocess.call(args, shell=False)
            else:
                print('WARNING: No exercises directory found.')
                print('Skipped.')
                return

        pass


    def get_type(self):
        try:
            with open(self.path + '/type', 'r') as f:
                type = f.readline().strip()
                if len(type) == 0:
                    print('WARNING: Empty type declaration.')
                    return False
                print('Course-Type:', type)
                self.type = type
        except:
            print('WARNING: Could not find type declaration file.')
            self.type = False


    def get_meta(self):
        try:
            with open(self.path + '/meta', 'r') as f:
                raw_json = f.read().strip()
                meta = json.loads(raw_json)
                if len(meta.keys()) == 0:
                    print('WARNING: No keys extracted from meta file.')
                self.meta = meta
        except:
            print('WARNING: Error parsing course meta file.')
            self.meta = None




class Command(BaseCommand):
    help = 'Does some magical work'


    def add_arguments(self, parser):
        parser.add_argument('--sources', nargs='?', action=readable_dir, default=OER_SRC_DIR + '/courses')
        # courses are fed to the database ;)
        #parser.add_argument('--destination', nargs='?', action=writeable_dir, default='~/git/HOOU/oer/generated/')
        parser.add_argument('--formats', nargs='?', action=readable_dir, default=OER_SRC_DIR +  '/course-formats/')


    def handle(self, *args, **options):
        """ Do your work here """

        start = time.clock()


        global ARGS
        global FORMATS

        # maybe some environment variables?
        # print(os.environ['MY_ENV_VARNAME'])


        ARGS = options
        ARGS['sources'] = os.path.expanduser(ARGS['sources'])
        ARGS['formats'] = os.path.expanduser(ARGS['formats'])
        print(ARGS)
        print()




        # For sections, the discover formats mechanism is currently not needed
        # but as we wish to transition to more adaptive course formats it might
        # become relevant again and is therefore kept here.
        discover_formats(ARGS['sources'])
        print('SUPPORTED FORMATS:')
        pprint.pprint(FORMATS)

        print('')
        print('PARSING COURSES:')

        print('===============================================================================', end="")
        print('===============================================================================')
        for elem in sorted(filter(lambda x: os.path.isdir(os.path.join(ARGS['sources'], x)), os.listdir(ARGS['sources']))):
            el = CourseParser(ARGS['sources'] + '/' + elem)


            print('===============================================================================', end="")
            print('===============================================================================')



        end = time.clock()
        elapsed = end - start

        print('\nProcess time:', elapsed, 'seconds')
