###############################################################################
# NAME:             Makefile.py
#
# AUTHOR:           Ethan D. Twardy <edtwardy@mtu.edu>
#
# DESCRIPTION:      Provides an interface for creating Makefile rules.
#
# CREATED:          02/23/2021
#
# LAST EDITED:      02/28/2021
###

from datetime import datetime

PREAMBLE = """
# Generated by Makefile.py (Ethan D. Twardy),
# on: {}
"""
def getPreamble():
    return PREAMBLE.format(str(datetime.now()) + '\n')

COPY_RULE = """
{}: {}
	mkdir -p $(@D)
	cp -a -f $< $@
"""
def getCopyRule(target, prerequisite):
    return COPY_RULE.format(target, prerequisite)

class Makefile:
    def __init__(self):
        self.defaultRule = {'target' : '', 'prerequisites': [], 'recipe': ''}
        self.rules = []
        self.variables = {}

    def setDefaultRuleTarget(self, newDefaultRuleTarget):
        self.defaultRule['target'] = newDefaultRuleTarget

    def getDefaultRulePrerequisites(self):
        return self.defaultRule['prerequisites']

    def setDefaultRuleRecipe(self, recipe):
        self.defaultRule['recipe'] = recipe

    def addRule(self, newRule):
        self.rules.append(newRule)

    def appendToVariable(self, variableName, value):
        # assignmentType can be '', ':', '::', '?', '+', or others.
        # We automatically switch to using '+' after the first assignment.
        if variableName in self.variables:
            self.variables[variableName]['values'].append(value)
        else:
            self.variables[variableName] = {'values': [value]}

    def variableIsSet(self, variableName):
        return variableName in self.variables

    def addCopyRule(self, target, prerequisite):
        copyFileVar = 'copyFiles'
        if self.variableIsSet(copyFileVar) \
           and target in self.variables[copyFileVar]['values']:
            return
        if not self.variableIsSet(copyFileVar):
            self.getDefaultRulePrerequisites().insert(0, f'$({copyFileVar})')
        self.appendToVariable(copyFileVar, target)
        self.addRule(getCopyRule(target, prerequisite))

    def write(self, fileDescriptor):
        fileDescriptor.write(getPreamble())

        # Write the variables
        for variable in self.variables:
            for value in self.variables[variable]['values']:
                fileDescriptor.write(f'{variable}+={value}\n')
            fileDescriptor.write('\n')

        # Write default rule
        if not self.defaultRule['target']:
            raise AttributeError('target not defined for default rule')
        defaultRule = self.defaultRule['target'] + ':'
        if self.defaultRule['prerequisites']:
            defaultRule += ' ' + ' '.join(self.defaultRule['prerequisites'])
        fileDescriptor.write(defaultRule)
        if self.defaultRule['recipe']:
            fileDescriptor.write(self.defaultRule['recipe'] + '\n')

        # Write the other rules
        for rule in self.rules:
            fileDescriptor.write(rule)

###############################################################################
