###############################################################################
#
# dump_dependencies ==> generates the include preprocessor directives for the
# module
#
###############################################################################

proc dump_dependencies { module fp } {
	set deps [$module get connections]
	foreach dep $deps {
	  if { [$dep get objectType] == "dependency" } {
		 # check if this is the client
		 if { [$dep get to] == $module } continue
		 set supplier [$dep get to]
		 puts $fp "#include <[$supplier get name]>"
	  }
	}
	puts $fp ""
}

###############################################################################
#
# dump_attributes ==>generates C++ code for a attributes in a class declaration
#
###############################################################################
proc dump_attributes {fp cls exportControl} {
	set attlist [$cls get attributes]
	foreach att $attlist {
		if {[$att get exportControl] == $exportControl } {
		  #
		  if {[$att get isStatic] == 1} { puts -nonewline $fp "static " }
		  if {[$att get isConst] == 1} { puts -nonewline $fp "const " }

		  puts -nonewline $fp "[$att get className] "
		  if {[$att get isPointer] == 1} { puts -nonewline $fp "* " }
		  if {[$att get isReference] == 1} { puts -nonewline $fp "& " }
		  puts $fp "[$att get name];"
		}
	}
# dump the has relations as attributes
  set item_list [$cls get views];
  foreach  cv $item_list {
	 # check all the relations connected to this
	 set rel_list [$cv  get connections]
	 foreach rel $rel_list {
		if { [$rel get objectType] == "relation" } {
		  if {[$rel get exportControl] != $exportControl } continue;
		  set scls [$rel get to]
		  if {[$scls get class] == $cls} continue
		  # check if a relation of the correct type relations
		  if { [$rel get relationType] == "has"} {

			  # check the cardinality
			  set card [$rel get toCardinality]
			  set by_value [$rel get containment]
			  set name [$rel get name]
			  if (![expr [string length $name]]) {
				set name "no_name"
			  }
			  switch $card {
				"0..n" -
				"1..n" -
				"n" {
					if {$by_value == "value"} {
					  puts $fp "LIST\([$scls get name]\) $name\;"
					} else {
					  puts $fp "PLIST\([$scls get name]\) $name\;"
					}
				}
				"1" {
					if {$by_value == "value"} {
						puts $fp "[$scls get name] $name\;"
					} else {
						puts $fp "[$scls get name] \* $name\;"
					}
				}
				"0..1" {
				  puts $fp "[$scls get name] \* $name\;"
				}
				"unspecified"  {
					if {$by_value == "value"} {
						puts $fp "[$scls get name] $name\;"
					} else {
						puts $fp "[$scls get name] \* $name\;"
					}

				}

				default {
					if {$by_value == "value"} {
					  puts $fp "LIST\([$scls get name]\) $name\;"
					} else {
					  puts $fp "PLIST\([$scls get name]\) $name\;"
					}
				}
 				#end switch

			  }
		  #end has
		  }
		  #end relation
		}
	  #end for each relation
	 }
	 #end for each class view
  }
}
###############################################################################
#
# dump_operations ==>generates C++ code for a operations in a class declaration
#
###############################################################################
proc dump_operations {fp cls exportControl} {
	set oplist [$cls get operations]
	foreach op $oplist {
		if {[$op get exportControl] == $exportControl } {
		  if {[$op get isStatic] == 1} { puts -nonewline $fp "static " }
		  if {[$op get isVirtual] == 1} { puts -nonewline $fp "virtual " }
		  if {[$op get isReturnTypeConst] == 1} { puts -nonewline $fp "const " }

		  puts -nonewline $fp "[$op get returnType]"
		  if {[$op get isReturnTypePointer] == 1} { puts -nonewline $fp "\* " }
		  if {[$op get isReturnTypeReference] == 1} { puts -nonewline $fp "\& " }
		  puts -nonewline $fp " [$op get name]\("
		  set par_list [$op get parameters]
		  set count 0
		  foreach p $par_list {
			 if {$count > 0 } { puts -nonewline $fp "\," }
			 puts -nonewline $fp [$p get name]
			 incr count
		  }
		  puts -nonewline $fp "\)"
		  if { [$op get isConst]  == 1 } { puts -nonewline $fp " const " }
		  if { [$op get isPure]  == 1 } { puts -nonewline $fp " = 0 " }
		  if { [$op get isInline] == 1 } { puts $fp "\n\{\n\}\n" } else { puts $fp ";" }
		}
	}
}


###############################################################################
#
# dump_specification ==>generates C++ code for a specification module
#
###############################################################################
proc dump_specification {module fp} {
	puts $fp "/*****************************************************************"
	puts $fp " Specification module : [$module get name]"
	puts $fp " Code generated by Object Domain script"
	puts $fp "     Copyright 95"
	puts $fp "******************************************************************/\n\n"

	dump_dependencies $module $fp

	# define the LIST and PLIST for which will be used for the has relation
	# note : the user should modify these to the container class they want to use
	puts $fp "// these are default define statements for one to many relations"
	puts $fp "// you should modify these to reflect the class library you use"
	puts $fp "#ifdef __BORLANDC__"
	puts $fp "#include <classlib\\dlistimp.h>"
	puts $fp "#define LIST(p) TDoubleListImp<p>"
	puts $fp "#define PLIST(p) TIDoubleListImp<p>"
	puts $fp "#else"
	puts $fp "#include <list.h>"
	puts $fp "#define LIST(p) list<p>"
	puts $fp "#define PLIST(p) list<p *>"
	puts $fp "#endif\n\n"

	set classlist [$module get classes]

	#generate forward declarations for each class
	foreach cl $classlist {
		# if a template class
		if {[$cl get type] == "parameterized_class"} {
			 set plist [$cl get parameters]
			 puts -nonewline $fp "template <"
			 set count 0
			 foreach p $plist {
				 if {$count > 0 } puts -nonewline $fp ","
				 puts -nonewline $fp [$p get name]
				 incr count
			 }
			 puts -nonewline $fp ">"
		 }
		 puts $fp "class [$cl get name];"
	}

	# now dump the real class contents
	foreach cl $classlist {
		puts $fp "/**************************************************************************"
		puts $fp [$cl get responsibilities]
		puts $fp "**************************************************************************/"
		if {[$cl get type] == "parameterized_class"} {
			 set plist [$cl get parameters]
			 puts -nonewline $fp "template <"
			 set count 0
			 foreach p $plist {
				 if {$count > 0 } puts -nonewline $fp ","
				 puts -nonewline $fp [$p get name]
				 incr count
			 }
			 puts -nonewline $fp ">"
		 }
		 puts -nonewline $fp "class [$cl get name]"
		 set superclasses [$cl get superclasses]
		 if  [expr [llength $superclasses]] {
			 puts -nonewline $fp  ":"
		 }
		 set count 0
		foreach sc $superclasses {
		  if {$count > 0} { puts -nonewline $fp "," }
		  set clsi [expr [llength $sc] - 1 ]
		  puts -nonewline $fp "    "
			 switch $clsi {
				1 { puts -nonewline $fp [ lindex $sc 0 ] }
				2 { puts -nonewline $fp [ lrange $sc 0 1 ] }
			 }
			 puts -nonewline $fp " "
			 set scls [lindex $sc $clsi]
			 puts -nonewline $fp  [$scls get name]
			 incr count
		}

		puts $fp "\{"
		# dump all the private attributes
		dump_attributes $fp $cl private
		# dump all the private operations
		dump_operations $fp $cl private
		puts $fp "protected:"
		# dump all the protected attributes
		dump_attributes $fp $cl protected
		# dump all the protected operations
		dump_operations $fp $cl protected
		puts $fp "public:"
		# dump all the public attributes
		dump_attributes $fp $cl public
		# dump all the public operations
		dump_operations $fp $cl public
		puts $fp "\};\n\n"
	}
}


###############################################################################
#
# dump_body ==>generates C++ code for a body module ( implementation )
#
###############################################################################
proc dump_body {module fp} {
	puts $fp "/*****************************************************************"
	puts $fp " Body module : [$module get name]"
	puts $fp " Code generated by Object Domain script"
	puts $fp "     Copyright 95"
	puts $fp "******************************************************************/\n\n"

	dump_dependencies $module $fp

	# get all the classes  for this module

	set classlist [$module get classes]

	foreach cl $classlist {
		# dump all operations templates
		set oplist [$cl get operations]
		foreach op $oplist {
			if {[$op get isInline] == 1} continue
			puts $fp "/*************************************************************************"
			puts $fp "  [$op get returnType] [$cl get name]::[$op get name] "
			puts $fp "  [$op get description]"
			puts $fp "**************************************************************************/"
			puts $fp [$op get returnType]
			puts $fp "[$cl get name]::[$op get name]("
			# dump the parameters
			set par_list [$op get parameters]
			set count 0
			foreach par $par_list {
				if {$count > 0} {
					puts -nonewline $fp "\t,"
				} else {
					puts -nonewline $fp "\t"
				}
				puts $fp [$par get name]
				incr count

			}
			puts $fp "\t) \{\n\n\}"
		}
	}
}
###############################################################################
#
# dump_main_program ==>generates C++ code for a main module ( implementation )
#
###############################################################################
proc dump_main_program {module fp} {
	 dump_body $module $fp
	 puts $fp "main (int argc,char *argv\[\]) \{\n\}"
}


###############################################################################
#
# dump_module ==>generates C++ code for a module
#
###############################################################################

proc dump_module module {
  # open the file
  set filename [$module get name]
  set fp [open $filename w]
	 
  # check which kind of module this is
  set mtype [$module get moduleType]
  switch $mtype {
	  mainprogram { dump_main_program $module $fp}
	  specification { dump_specification $module $fp}
	  body { dump_body $module $fp}
  }
  close $fp
}

	 set diagram [OD_getActiveDiagram]


	 set dt [$diagram get type]


	 if {"module" != $dt} {
		 # generate code for all selected modules in this
		 OD_giveMessage "Diagram is not a module diagram" "Diagram is not a module diagram" exclamation
	 } else {
		 # loop over all items in this diagram
		 set items [$diagram get objects]
		 foreach item $items {
			if { [$item get objectType] == "module" } {
				# only dump if the object is slected
				if { [$item get isSelected] == 1 } {
					dump_module $item
				}

			}

		 }

	 }

