' ------------------------------------------------------------------------
'
' AdaML Modeling Language - v0.1
' Copyright (C) 2019, Francesc Rocher
'
' This library is free software;  you can redistribute it and/or modify it
' under terms of the  GNU General Public License  as published by the Free
' Software  Foundation;  either version 3,  or (at your  option) any later
' version. This library is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN-
' TABILITY or FITNESS FOR A PARTICULAR PURPOSE.
'
' You should have received a copy of the GNU General Public License and
' a copy of the GCC Runtime Library Exception along with this program;
' see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
' <http://www.gnu.org/licenses/>.
'
' ------------------------------------------------------------------------

'Skin parameters
skinparam {
  arrowColor black
  arrowThickness 0.8
  boxpadding 0
  classAttributeIconSize 10
  classBackgroundColor white
  classBorderColor black
  classBorderThickness 1.3
  classFontSize 14
  classFontName CMU Bright SemiBold
  classHeaderBackgroundColor #dadada
  classHeaderBackgroundColor<< object >> #ffd700
  classHeaderBackgroundColor<< protected object >> #ffd700
  circledCharacterFontName CMU Bright SemiBold
  circledCharacterFontSize 12
  circledCharacterRadius<< access >> 5
  circledCharacterRadius 10
  componentStyle uml2
  defaultFontName CMU Bright Roman
  defaultFontSize 12
  genericDisplay true
  handwritten false
  monochrome false
  NoteBackgroundColor #ffff99
  NoteBorderColor #333333
  NoteBorderThickness .88
  NoteFontColor #222222
  NoteFontName CMU Bright Regular
  NoteFontSize 10
  NoteShadowing true
  NoteTextAlignment left
  objectBorderThickness 0.8
  packageBackgroundColor #f6f6f6
  packageStyle frame
  packageFontName CMU Bright Bold
  packageFontStyle regular
  packageFontSize 14
  padding 2
  shadowing false
}

'Generic config
allow_mixing
hide empty attributes
hide empty methods
hide <<object>> circle
hide <<object>> stereotype
set namespaceSeparator .

'Entities Configuration
!abstract_char          = "A"
!abstract_color         = "#ff33f0"
!abstract_stereotype    = "abstract"
!access_association     = "all"
!access_char            = "a"
!access_color           = "#f0f0f0"
!access_stereotype      = "access"
!access_suffix          = "_Access"
!interface_char         = "I"
!interface_color        = "#aaccff"
!interface_stereotype   = ""
!package_char           = "P"
!package_color          = "#ffff33"
!package_stereotype     = ""
!protected_char         = "#"
!protected_color        = "#aaccff"
!protected_stereotype   = "protected"
!subtype_char           = "S"
!subtype_color          = "#ffccaa"
!subtype_stereotype     = ""
!task_char              = "•"
!task_color             = "#333333"
!task_stereotype        = "task"
!type_char              = "T"
!type_color             = "#ff6666"
!type_stereotype        = ""

'Other Configuration
!depends_stereotype = "use"
!array_association = "of"

'Private global variables
!__mod__ = 0
!__enum__ = 0
!__with__ = 0
!__range__ = 0
!__generic__ = 0
!__private__ = 0
!__type_line__ = 0
!__case_line__ = 0
!__attr_line__ = 0
!__method_line__ = 0
!__elements_level__ = 0
!__note_counter__ = 0

'Private functions
!function __get_default(value, default_value)
  !if (%strlen(value) == 0)
    !return default_value
  !else
    !return value
  !endif
!endfunction

!function __replace(string, text, replace)
  !_result = string
  !_pos = %strpos(string, text)
  !if (_pos >= 0)
    !_result = %substr(string, 0, _pos) + replace + %substr(string, _pos + %strlen(text))
  !endif
  !return _result
!endfunction

!function __str_guard(string)
  !_result = __replace(string, "<>", "//<>//")
  !return _result
!endfunction

!function __reset()
!__mod__ = 0
!__enum__ = 0
!__with__ = 0
!__range__ = 0
!__generic__ = 0
!__private__ = 0
!__type_line__ = 0
!__case_line__ = 0
!__attr_line__ = 0
!__method_line__ = 0
!__elements_level__ = 0
!endfunction

!function __detail(line, name, spec)
  !if (line == 0)
    .. name ..
  !endif
  ** ** spec
!endfunction

!function __type_line()
  !if (__type_line__ == 1)
== types ==
    !__type_line__ = 0
  !endif
!endfunction

!function __case_line()
  !if (__case_line__ == 0)
.. case ..
    !__case_line__ = 1
    !__method_line__ = 1
  !endif
!endfunction

!function __attr_line()
  !if (__attr_line__ == 1)
    --
    !__attr_line__ = 0
  !endif
!endfunction

!function __method_line()
  !if (__method_line__ == 1)
    --
    !__method_line__ = 0
  !endif
!endfunction

!function __declare_entity(char, color, name, stereotype="", pre="", post="")
  __reset()
  !if (%strlen(char) == 0)
    hide name circle
    !if (%strlen(stereotype) == 0)
      pre class name post
    !else
      pre class name <<stereotype>> post
    !endif
  !else
    pre class name <<(char, color) stereotype>> post
  !endif
!endfunction

!function __begin_entity(char, color, name, stereotype="", pre="", post="")
  __reset()
  !__elements_level__ = 1
  !if (%strlen(char) == 0)
    pre class name <<stereotype>> post {
  !else
    pre class name <<(char, color) stereotype>> post {
  !endif
!endfunction

!function __check_type(name)
  !if (%strpos("types:Ada.Character,Ada.Boolean,Ada.Integer,Ada.Natural,Ada.Positive,Ada.String", name) > 0)
    !if (%not(%variable_exists("__type_" + name)))
      %set_variable_value("__type_" + name, 1)
      __declare_entity("T", type_color, name)
    !endif
  !endif
!endfunction

!function __type_new(type1, type2, comment="", note="")
  __reset()
  !if (%strlen(comment) == 0)
    type1 ^-- type2
  !else
    type1 ^-- type2 : comment
  !endif
!endfunction

!function __check_array(name, stereotype)
  !if (%variable_exists("__array_" + name))
    !if (%strlen(stereotype) == 0)
      !stereotype = "array"
    !else
      !stereotype = "array " + stereotype
    !endif
  !endif
  !return stereotype
!endfunction

'Public functions
!function begin_package_spec(name, stereotype="")
  !stereotype = __get_default(stereotype, package_stereotype)
  !$p_name_is = "package " + name + " is"
  !if (%strlen(stereotype) == 0)
    package "$p_name_is" {
  !else
    package "$p_name_is" <<stereotype>> {
  !endif
!endfunction

'Component view functions
!function package(name, stereotype="")
  !stereotype = __get_default(stereotype, package_stereotype)
  __declare_entity(package_char, package_color, name, __str_guard(stereotype))
!endfunction

!function abstract(name, stereotype="")
  !stereotype = __get_default(stereotype, abstract_stereotype)
  __declare_entity(abstract_char, abstract_color, name, __str_guard(stereotype))
!endfunction

!function interface(name, stereotype="")
  !stereotype = __get_default(stereotype, interface_stereotype)
  __declare_entity(interface_char, interface_color, name, __str_guard(stereotype))
!endfunction

!function subtype(name, stereotype="")
  !stereotype = __get_default(stereotype, subtype_stereotype)
  __declare_entity(subtype_char, subtype_color, name, __check_array(name, __str_guard(stereotype)))
!endfunction

!function task(name, stereotype="")
  !stereotype = __get_default(stereotype, task_stereotype)
  __declare_entity(task_char, task_color, name, __str_guard(stereotype))
!endfunction

!function type(name, stereotype="")
  !if (__elements_level__)
    __type_line()
    !if (__private__ == 0)
      !acc_str = "+"
    !else
      !acc_str = "-"
    !endif
    !if (%strlen(stereotype) == 0)
      acc_str name
    !else
      acc_str name : stereotype
    !endif
  !else
    !stereotype = __get_default(stereotype, type_stereotype)
    __declare_entity(type_char, type_color, name, __check_array(name,  __str_guard(stereotype)))
  !endif
!endfunction

!function type_access(type, suffix="", stereotype="")
  !suffix = __get_default(suffix, access_suffix)
  !stereotype = __get_default(stereotype, access_stereotype)
  !type_access = type + suffix
  __declare_entity(access_char, access_color, type_access, __str_guard(stereotype))
  !if (%strlen(access_association) == 0)
    type <.. type_access
  !else
    type <.. type_access : access_association
  !endif
!endfunction

!function type_new(type, name, stereotype="", comment="", note="")
  !stereotype = __get_default(stereotype, type_stereotype)
  __check_type(type)
  __declare_entity(type_char, type_color, name, __check_array(name, __str_guard(stereotype)))
  __type_new(type, name, comment, note)
!endfunction

!function type_protected(name, stereotype="")
  !stereotype = __get_default(stereotype, protected_stereotype)
  __declare_entity(protected_char, protected_color, name, __str_guard(stereotype))
!endfunction

!function type_task(name, stereotype="")
  !stereotype = __get_default(stereotype, task_stereotype)
  __declare_entity(task_char, task_color, name, __str_guard(stereotype))
!endfunction

!function object_protected(name, stereotype="")
  !stereotype = __get_default(stereotype, protected_stereotype)
  __declare_entity("", "", name, "object")
!endfunction

'Code view functions
!function begin_package(name, stereotype="")
  !stereotype = __get_default(stereotype, package_stereotype)
  __begin_entity(package_char, package_color, name, __str_guard(stereotype))
!endfunction

!function begin_abstract(name, stereotype="")
  !stereotype = __get_default(stereotype, abstract_stereotype)
  __begin_entity(abstract_char, abstract_color, name, __str_guard(stereotype), "abstract")
!endfunction

!function begin_interface(name, stereotype="")
  !stereotype = __get_default(stereotype, interface_stereotype)
  __begin_entity(interface_char, interface_color, name, __str_guard(stereotype))
!endfunction

!function begin_subtype(name, stereotype="")
  !stereotype = __get_default(stereotype, subtype_stereotype)
  __begin_entity(subtype_char, subtype_color, name, __check_array(name, __str_guard(stereotype)))
!endfunction

!function begin_type(name, stereotype="")
  !stereotype = __get_default(stereotype, type_stereotype)
  __begin_entity(type_char, type_color, name, __check_array(name, __str_guard(stereotype)))
!endfunction

!function begin_type_new(type, name, stereotype="", comment="", note="")
  !stereotype = __get_default(stereotype, type_stereotype)
  __check_type(type)
  __type_new(type, name, comment, note)
  __begin_entity(type_char, type_color, name, __check_array(name, __str_guard(stereotype)))
!endfunction

!function begin_type_protected(type, name, stereotype="", comment="", note="")
  !stereotype = __get_default(stereotype, protected_stereotype)
  __check_type(type)
  __type_new(type, name, comment, note)
  __begin_entity(protected_char, protected_color, name, __check_array(name, __str_guard(stereotype)))
!endfunction

!function begin_object_protected(name, stereotype="")
  !stereotype = __get_default(stereotype, protected_stereotype)
  hide name circle
  __begin_entity("", "", name, "protected object")
!endfunction

!function end()
  !__elements_level__ = 0
  }
!endfunction

'Details, attributes, constants and objects
'use access=0 for 'private', access=1 for 'public'
!function mod(spec)
  __detail(__mod__, "mod", spec)
  !__mod__ = 1
  !__type_line__ = 1
  !__attr_line__ = 1
  !__method_line__ = 1
!endfunction

!function enum(spec)
  __detail(__enum__, "enum", "(" + spec + ")" )
  !__enum__ = 1
  !__type_line__ = 1
  !__attr_line__ = 1
  !__method_line__ = 1
!endfunction

!function with(spec)
  __detail(__with__, "with", spec)
  !__with__ = 1
  !__type_line__ = 1
  !__attr_line__ = 1
  !__method_line__ = 1
!endfunction

!function range(spec="<>")
  __detail(__range__, "range", __str_guard(spec))
  !__range__ = 1
  !__type_line__ = 1
  !__attr_line__ = 1
  !__method_line__ = 1
!endfunction

!function generic_with(spec)
  __detail(__generic__, "generic with", spec)
  !__generic__ = 1
  !__type_line__ = 1
  !__attr_line__ = 1
  !__method_line__ = 1
!endfunction

!function case(spec)
  __case_line()
  !__method_line__ = 1
        when spec =>
!endfunction

!function private()
  !__private__ = 1
!endfunction

!function public()
  !__private__ = 0
  !endfunction

!function attribute(name, type, defval="")
  __attr_line()
  !if (__private__ == 0)
    !acc_str = "+"
  !else
    !acc_str = "-"
  !endif
  !if (%strlen(defval) == 0)
    acc_str {field} name : type
  !else
    acc_str {field} name : type := defval
  !endif
!endfunction

!function variable(name, type, defval="")
  !attribute(name, type, defval)
!endfunction

!function constant(name, type, value, aliased=0)
  !__attr_line()
  !if (__private__ == 0)
    !acc_str = "+"
  !else
    !acc_str = "-"
  !endif
  !if (aliased == 1)
    !als_str = "aliased"
  !else
    !als_str = ""
  !endif
  !if (%strpos(type, "String") >= 0)
    acc_str {field} name : constant als_str type := "value"
  !else
    acc_str {field} name : constant als_str type := value
  !endif
!endfunction

!function protected_object(name)
  !if (__private__ == 0)
    !acc_str = "+"
  !else
    !acc_str = "-"
  !endif
  acc_str {field} name
!endfunction

!function procedure(name, args="")
  __method_line()
  !if (__private__ == 0)
    !acc_str = "+"
  !else
    !acc_str = "-"
  !endif
  !if (%strlen(args) == 0)
    acc_str {method} name
  !else
    acc_str {method} name (args)
  !endif
!endfunction

!function function(name, args, return)
  __method_line()
  !if (__private__ == 0)
    !acc_str = "+"
  !else
    !acc_str = "-"
  !endif
  !if (%strlen(args) == 0)
    acc_str {method} name : return
  !else
    acc_str {method} name (args) : return
  !endif
!endfunction

'Associations
!function has(owner, element)
  owner --> element
!endfunction

!function owns(owner, element)
  owner *--> element
!endfunction

!function depends(client, supplier, stereotype="")
  !stereotype = __get_default(stereotype, depends_stereotype)
  !arrow = ""
  !len = %strlen(stereotype)
  !if (len < 2)
    client ..> supplier
  !else
    !len = len - 2
    !arrow = %substr(stereotype, len, 2)
    !if (arrow != " >") && (arrow != " <")
       client ..> supplier : stereotype
    !else
       client .. supplier : stereotype
    !endif
  !endif
!endfunction

!function array(array_type, element_type, association=array_association)
  %set_variable_value("__array_" + array_type, 1)
  !if (%strlen(association) == 0)
    array_type +--> element_type
  !else
    array_type +--> element_type : association
  !endif
!endfunction

'Notes
'
'Behaviour depending on the number of parameter supplied
'  arg1     --> floating note, arg1=Comment
'  arg1+2   --> note on an entity arg1=Entity, arg2=Comment
!function note(arg1, arg2="")
  !val = %intval(arg1)
  !if (%strlen(arg2) == 0)
    !__note_counter__ = __note_counter__ + 1
    !cntr = "__note__" + __note_counter__
    note "arg1" as cntr
  !else
    !if (val > 0)
      !note_name = "Note_" + arg1
      note "arg2" as note_name
    !else
      note arg1 : arg2
    !endif
  !endif
!endfunction

!function link(arg1, arg2)
  arg1 .. arg2
!endfunction

'Geometry hints
!function left_right(obj0, obj1, obj2="", obj3="", obj4="", obj5="", obj6="", obj7="", obj8="", obj9="")
  obj0 -[hidden]right- obj1
  !if (%strlen(obj2) > 0)
    obj1 -[hidden]right- obj2
  !endif
  !if (%strlen(obj3) > 0)
    obj2 -[hidden]right- obj3
  !endif
  !if (%strlen(obj4) > 0)
    obj3 -[hidden]right- obj4
  !endif
  !if (%strlen(obj5) > 0)
    obj4 -[hidden]right- obj5
  !endif
  !if (%strlen(obj6) > 0)
    obj5 -[hidden]right- obj6
  !endif
  !if (%strlen(obj7) > 0)
    obj6 -[hidden]right- obj7
  !endif
  !if (%strlen(obj8) > 0)
    obj7 -[hidden]right- obj8
  !endif
  !if (%strlen(obj9) > 0)
    obj8 -[hidden]right- obj9
  !endif
!endfunction

!function top_down(obj0, obj1, obj2="", obj3="", obj4="", obj5="", obj6="", obj7="", obj8="", obj9="")
  obj0 -[hidden]down- obj1
  !if (%strlen(obj2) > 0)
    obj1 -[hidden]down- obj2
  !endif
  !if (%strlen(obj3) > 0)
    obj2 -[hidden]down- obj3
  !endif
  !if (%strlen(obj4) > 0)
    obj3 -[hidden]down- obj4
  !endif
  !if (%strlen(obj5) > 0)
    obj4 -[hidden]down- obj5
  !endif
  !if (%strlen(obj6) > 0)
    obj5 -[hidden]down- obj6
  !endif
  !if (%strlen(obj7) > 0)
    obj6 -[hidden]down- obj7
  !endif
  !if (%strlen(obj8) > 0)
    obj7 -[hidden]down- obj8
  !endif
  !if (%strlen(obj9) > 0)
    obj8 -[hidden]down- obj9
  !endif
!endfunction
