#!/bin/sh

data()
{
    ds="$1"
    object="$2"
    method="$3"
    if [ "$method" = "_data" ]; then
        echo "$ds"
    fi
}

get_d()
{
    [ $# -lt 2 ] && return
    object="$1"
    d="$2"
    eval "echo \$$($object $d)"
}

set_d()
{
    [ $# -lt 3 ] && return
    object="$1"
    d="$2"
    new_val="$3"
    eval "$($object $d)"="$new_val"
}

object_counter=0

new()
{
    [ $# -lt 2 ] && return
    class="$1"
    object_var="$2"
    ds="$($class null _data)"
    eval 'object_'"$object_counter"'()
          {
              [ "$#" -lt 1 ] && return
              method="$1"
              case "$method" in
                  "_class")
                      echo '"$class"';;
              '"$(for d in $ds; do
                  echo '"'$d'")
                      echo object_'$object_counter'_'$d';;'
              done)"'
              esac
          }'
    object="object_$object_counter"
    object_counter="$((object_counter + 1))"
    call "$object" _init
    eval "$object_var=$object"
}

call()
{
    [ $# -lt 2 ] && return
    object="$1"
    method="$2"
    class="$($object _class)"
    shift 2
    "$class" "$object" "$method" "$@"
}

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

BaseYoba()
{
    data "x y" "$@"
    case "$method" in
        "_init")
            set_d "$object" x 0
            set_d "$object" y 0 ;;
        "print")
            echo "x=$(get_d $object x) y=$(get_d $object y)" ;;
    esac
}

DerivedYoba1()
{
    BaseYoba "$@"
    case "$method" in
        "go")
            set_d "$object" x "$(($(get_d $object x) + $3))"
            set_d "$object" y "$(($(get_d $object y) + $3))" ;;
    esac
}

DerivedYoba2()
{
    case "$method" in
        "go")
            set_d "$object" x "$(($(get_d $object x) + $3 * 2))" ;;
        *)
            BaseYoba "$@" ;;
    esac
}

DerivedYoba3()
{
    data "z" "$@"
    case "$method" in
        "_init")
            DerivedYoba1 "$@"
            set_d "$object" z 0 ;;
        "go")
            DerivedYoba1 "$@"
            set_d "$object" z "$(($(get_d $object z) + $3 * 2))" ;;
        "print")
            echo "x=$(get_d $object x) y=$(get_d $object y) z=$(get_d $object z)" ;;
        *)
            DerivedYoba1 "$@"
    esac
}

fun()
{
    for i in `seq 5`; do
        call "$1" go $i
        call "$1" print
    done
}

new DerivedYoba1 yoba1
fun "$yoba1"
new DerivedYoba2 yoba2
fun "$yoba2"
new DerivedYoba3 yoba3
fun "$yoba3"
