# Lair Configuration DSL Case Study (Python 3)
# Class Variable-based DSL: Configuration Buider (builder11)
# H. Conrad Cunningham

# Developed for CSci 658, Software Language Engineering, Spring 2018

#234567890123456789012345678901234567890123456789012345678901234567890

# 2018-02-27: (V1) adapted from M. Fowler's Ruby version builder11.rb
#             and my Lua versiln builder11.lua

# Import Semantic Model for Configuration

from model import *

# Read and execute a DSL input file
def load_dsl(dsl_file):
    Configuration.load()
    with open(dsl_file, 'r') as f:
        dsl_str = f.read()
    exec(dsl_str)
    return Configuration.get_current()


# Dynamically add new Configuration class methods and class variable
# needed for building a Configuration in Semantic Model

def load():
    Configuration.current = Configuration()

Configuration.load = load

def item(arg):
    new_item = Item(arg)
    Configuration.current.add_item(new_item)
    return new_item

Configuration.item = item

def get_current():
    return Configuration.current

Configuration.get_current = get_current


# Dynamically add new Item instance methods needed for building
# Items in Semantic Model

# To follow Fowler, I wanted to stay with name "uses", but I am not
# yet sure how to handle the clash with the property "uses" in
# model.py. So I decided to use "consumes" for now.

def consumes(self,arg):
    self.add_usage(arg)
    return self

Item.consumes = consumes

def provides(self,arg):
    self.add_provision(arg)
    return self

Item.provides = provides

def depends_on(self,arg):
    self.add_dependency(Configuration.get_current().get_item(arg))
    return self

Item.depends_on = depends_on


# Dynamically add new Resource class methods needed for building
# resources in Semantic Model

def electricity(power):
    return Electricity(power)

Resource.electricity = electricity

def acid():
    return Acid()

Resource.acid = acid

# The following instance methods in Acid need to be fluent setters
# (to both change the value and return the object) for data in
# the semantic model. Fowler just switched out the new method
# function definitions for the old procedures in Ruby. I could do
# something similar in Lua, but so far I am unsure how to handle
# the replacement of the property methods in Python. So I chose
# different names.

def with_type(self,arg):
    self.type = arg
    return self

Acid.with_type = with_type

def with_grade(self,arg):
    self.grade = arg
    return self

Acid.with_grade = with_grade


