# Frog Dynamic Composition Example, with Data Classes
# H. Conrad Cunningham

#234567890123456789012345678901234567890123456789012345678901234567890

# 2018-09-17: Adapted from 2010 Scala version

# This program is a Python 3 reimplementation of the Java Frog dynamic
# composition example from chapter 10 of Budd's Understanding
# Object-Oriented Progamming with Java.

# In Budd's Java example "growUp" is a side-effecting function, which
# this instructor considers bad design.  Thus, the "growUp" method is
# replaced by pure function "grownUp" and the increment is moved to
# the "grow" method.

# This version uses Python 3.7 data classes.

from dataclasses import dataclass    # 3.7

class FrogBehavior():
    
    def grow(self):
        pass
    
    def swim(self):
        pass

    def grownUp(self):
        return False

@dataclass
class TadpoleBehavior(FrogBehavior):
    metage: int = 24
    age:    int = 1
    
    def grow(self):
        print(f"Tadpole growing at age {self.age}")
        self.age += 1

    def swim(self):
        print("Tadpole swimming.")

    def grownUp(self):
        return self.age > self.metage

@dataclass
class AdultFrogBehavior(FrogBehavior):
    age: int
    
    def grow(self):
        print(f"AdultFrog growing at age {self.age}")
        self.age += 1

    def swim(self):
        print("AdultFrog swimming.") 

@dataclass
class Frog:
    behavior: FrogBehavior = TadpoleBehavior()

    def grow(self):
        if self.behavior.grownUp():
            self.behavior = AdultFrogBehavior(self.behavior.age)
        self.behavior.grow()
        self.behavior.swim()


# Smoke testing code 

if __name__ == '__main__':
    print("Frog program beginning.")
    frog = Frog()
    print(f"Initial frog is {frog}")
    for i in range(0,100):
        frog.grow()
    print(f"Final frog is {frog}")
    print("Frog program ending.")
