# Frog Dynamic Composition Example, with Data Classes, Mypy checks
# 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 and type annotations for
# type checking by mypy.

from typing      import cast
from dataclasses import dataclass    # 3.7

class FrogBehavior():
    
    def grow(self) -> None:
        pass
    
    def swim(self) -> None:
        pass

    def grownUp(self) -> bool:
        return False

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

    def swim(self) -> None:
        print("Tadpole swimming.")

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

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

    def swim(self) -> None:
        print("AdultFrog swimming.") 

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

    def grow(self) -> None:
        if self.behavior.grownUp():
            self.behavior = AdultFrogBehavior(
                cast(TadpoleBehavior,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.")
