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

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

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 json
import markdown

# Globals
FORMATS = {}
ARGS = None
PLATFORM_PATH = os.environ["PLATFORM_PATH"]
GENERATED_PATH = os.environ["GENERATED_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 generate_exercise(type):

    format_path = ARGS['formats'] + type

    template_path = GENERATED_PATH + "/templates/generated_exercises/" + type
    static_path = GENERATED_PATH + "/static/generated_exercises/" + type
    print(template_path)
    print(static_path)

    try:
        os.makedirs(static_path)
    except:
        e = sys.exc_info()[0]
        print(e)
        print("WARNING: Make dirs static failed.", type)

    try:
        os.makedirs(template_path)
    except:
        e = sys.exc_info()[0]
        print(e)
        print("WARNING: Make dirs template failed.", type)

    # copy scripts.js
    src = format_path + '/script.js'
    dst = static_path + '/script.js'
    print(src)
    print(dst)
    try:
        shutil.copy(src, dst)
    except:
        e = sys.exc_info()[0]
        print(e)
        print("WARNING: script.js missing!", type, src)

    # copy styles.css
    src = format_path + '/styles.css'
    dst = static_path + '/styles.css'
    print(src)
    print(dst)
    try:
        shutil.copy(src, dst)
    except:
        e = sys.exc_info()[0]
        print(e)
        print("WARNING: styles.js missing!", type, src)

    # copy template.html
    src = format_path + '/template.html'
    dst = template_path + '/template.html'
    print(src)
    print(dst)
    try:
        shutil.copy(src, dst)
    except:
        e = sys.exc_info()[0]
        print(e)
        print("WARNING: template.html missing!", type, src)

    print()


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 'ExerciseHandler.py' in files:
            name = root.replace(path, '')
            loader = importlib.machinery.SourceFileLoader(name, root + '/ExerciseHandler.py')
            mod = loader.load_module()

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

            generate_exercise(name)


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

        # Perform essential sanitization
        self.get_type()
        if not self.type:
            print('Skipped.')
            return


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

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

        # add a database entry
        item, created = Slide.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.title_short = self.meta['title']
        item.slide_type = self.type
        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

        # Add section to course if ARG['course'] is provided
        try:
            parent = Section.objects.get(source_path=ARGS['section'])
            print("Found specified section:", parent)
            parent.slides.add(item)
            print('Added slide "%s" to section "%s".' % (item, parent))
        except Section.DoesNotExist:
            print("WARNING: Could find specified section!")


        if self.type in FORMATS:
            FORMATS[self.type]['mod'].ExerciseHandler(self)

            # generate directory structure for format
            self.generate_exercise()
        else:
            print('WARNING: No ExerciseHandler for type: "%s".' % self.type)
            print('Skipped.')





        pass


    def generate_exercise(self):



        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('Exercise-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()
                print('raw_json', raw_json)

                meta = json.loads(raw_json)
                print('meta', meta)

                if len(meta.keys()) == 0:
                    print('WARNING: No keys extracted from meta file.')
                self.meta = meta
        except:
            print('WARNING: Error parsing exercise meta file.')
            self.meta = None

    def get_file_content(self, filename):
        try:
            with open(self.path + '/' + filename, 'r') as f:
                content = f.read().strip()
                return content
        except:
            print('WARNING: Error parsing exercise meta file.')
            return ""


    def get_exercise_content(self, filename=None):

        content = ''

        # get html
        try:
            content = self.get_file_content('content.html')
        except:
            content = ''

        if content == '':
            try:
                md = self.get_file_content('content.md')
                content = markdown.markdown(md)
            except:
                content = ''

        return content




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 + '/exercises')
        parser.add_argument('--destination', nargs='?', action=writeable_dir, default=GENERATED_PATH)
        parser.add_argument('--formats', nargs='?', action=readable_dir, default=OER_SRC_DIR + '/exercise-formats/')
        parser.add_argument('--section', nargs='?', default=None)
        parser.add_argument('--course', nargs='?', default=None)


    def handle(self, *args, **options):
        """ Do your work here """
        start = time.clock()

        global ARGS
        global FORMAT

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


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

        discover_formats(ARGS['formats'])
        print('SUPPORTED FORMATS:')
        pprint.pprint(FORMATS)

        print('')
        print('PARSING EXERCISES:')

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

            print('-------------------------------------------------------------------------------')

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

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