
import yaml
import sys, os
from os import getpid
import psutil
import shutil
from subprocess import call,check_call,Popen, PIPE
import time
import functools
import logging
import types
import traceback
from importlib import import_module

def initConf():
    cwd = os.getcwd()
    if cwd.find('luigi')>-1 and  not cwd.endswith('dakd'):
        return yaml.load(open('../conf/conf.yml','r'))
    elif cwd.find('luigi')>-1 and  cwd.endswith('dakd'):
        return yaml.load(open('../../conf/conf.yml','r'))


conf = initConf()

def load_plugin(name=conf["plugin"], pkg=conf["plugin_pkg"]):
    mod = import_module(name,pkg)
    myplugin = mod.dakd_plugin()
    return myplugin

def shellexec(command, logfile="", cwd="."):

    my_env = os.environ.copy()
    if my_env["PATH"].find("/usr/sbin:/sbin:") < 0 :
        my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
    p = Popen([command], cwd=cwd, shell=True, env=my_env, stdout=PIPE,stderr=PIPE)
    (out,err) = p.communicate()
    print(logfile)
    print(type(logfile))
    if isinstance(logfile,str):
        if logfile != "" and os.path.exists(logfile):
            logfile.write(out.decode("utf-8"))
            logfile.write("\n")
            logfile.write(err.decode("utf-8"))
            logfile.write("\n")

def cleanVagrant():

    conf = initConf()

    # kill any vagrant process running
    mypid = getpid()
    for process in psutil.process_iter():
        if process.pid != mypid:
            for path in process.cmdline():
                if "vagrant" in path:
                    process.terminate()
                    
    # vagrant destroy
    shellexec(
        command="vagrant destroy -f",  
        cwd=conf["vagrantpath2"])

def cleanFinished():
    try:
        os.remove(os.path.join(conf["plannerpath"],'finish.txt'))
    except:
        return

def cleanFolder():
  

    conf = initConf()
    # create all needed folders!

    # remove exe files from folders
    # remove txt files from folders
    # remove xml files from folders
    # remove df files from folder

    clean_folders = [
        conf["lvl1path"],
        conf["lvl2path"],
        conf["lvl3path"],
        conf["lvl4path"],
        conf["vagrantpath"],
        conf["plannerpath"]
        ]


    for folder in clean_folders: 
        print("cleaninig: "+folder)
        for root, dirs, files in os.walk(folder):
            if conf["clean_exclude"] in dirs:
                dirs.remove(conf["clean_exclude"])
            for name in files:
                try:
                    os.remove(os.path.join(root,name))
                except OSError:
                    pass

    try:
        os.remove(os.path.join(conf["vagrantpath2"],conf["procmonlog"]))
    except OSError:
        pass

def cleanEnvironment():

    conf = initConf()


    # clean logs!!!
    logfolder = os.path.dirname(conf["basic_log_file"])
    #print(" cleaning logs from "+logfolder)
    # walk folder cleaning logs
    for root, dirs, files in os.walk(logfolder):
        for log in files:
            #print("cleaning:")
            #print(os.path.join(root,log))
            f = open(os.path.join(root,log), 'w')
            f.truncate()
            f.close()

    if not os.path.exists(conf["doneFilesList"]):
        f = open(conf["doneFilesList"],'a')
        f.close()


    shortRun = conf["shortRun"]
    if shortRun:
        cleanFolders()

    cleanFinished()

    cleanVagrant()

    return

def prepareTestEnvironment():

    conf = initConf()

    # clean environment
    cleanEnvironment()

    # put a mock exe file to ../samples/legit
    a=False
    if a:
        filepath = os.path.join(conf["mock_exe_dir"],conf["mock_exe1"])
        destination = os.path.join(conf["mock_fetchDir"],conf["mock_exe1"])
        if os.path.exists( filepath):
            #filename = os.path.basename(filepath)
            shutil.copy(filepath,destination)
            
        else:
            raise Exception('mock exe file does not exist')


        filepath = os.path.join(conf["mock_exe_dir"],conf["mock_exe2"])
        destination = os.path.join(conf["mock_fetchDir"],conf["mock_exe2"])
        if os.path.exists( filepath):
            #filename = os.path.basename(filepath)
            shutil.copy(filepath,destination)

        else:
            raise Exception('mock exe file does not exist')

    return


def create_logger(name):
    """
    Creates a logging object and returns it
    """

    conf = initConf()

    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
 
    # create the logging file handler
    fh = logging.FileHandler(conf["basic_log_file"])
 
    fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    formatter = logging.Formatter(fmt)
    fh.setFormatter(formatter)
 
    # add handler to logger object
    logger.addHandler(fh)
    return logger

conf = initConf()
basicLogger = create_logger(conf["logger_basic"])

def basicLoggerDecorator(logger):


    """
    A decorator that wraps the passed in function and logs 
    exceptions should one occur

    @param logger: The logging object
    """

    def decorator(function):
    

        def wrapper(*args, **kwargs):
            
            logger.debug("-----"+function.__name__+"-------------------------")
            try:
                logger.debug("params:")
               
                for arg in args:
                    try:
                        logger.debug(str(arg))
        
                    except Exception as e:
                        logging.error(e, exc_info=True)

                for key,value in kwargs.items():
                    try:
                        logger.debug("     "+key+"="+value)
                    except Exception as e:
                        logging.error(e, exc_info=True)
                        logger.debug("     "+key+"=couldn't print args")

                retval = function(*args, **kwargs)
                logger.debug("----------------------------"+function.__name__+"--end.")
                return retval

            except Exception as e:
                # log the exception
                err = "There was an exception in  "
                err += function.__name__
                logging.error(err, e, exc_info=True)
     
                # re-raise the exception
                raise

        return wrapper
    
    return decorator