<% define 'GenerateMetamodel', :for => EPackage do |filename| %>

<% file filename do %>
  require 'rgen/metamodel_builder'
  <%nl%>
  <% if needClassReorder? %>
    <% expand 'GeneratePackagesOnly' %>
    <% expand 'GenerateClassesReordered' %>
  <% else %>
    <% expand 'GeneratePackage' %>
  <% end %>
  <%nl%>
  <% expand 'GenerateAssocs' %>
<% end %>

<% end %>

<% define 'GeneratePackage', :for => EPackage do %>

module <%= moduleName %><% iinc %>
  extend RGen::MetamodelBuilder::ModuleExtension
  include RGen::MetamodelBuilder::DataTypes
  <% expand 'annotations::Annotations' %>
  <%nl%>
  <% expand 'EnumTypes' %>
  <% for c in ownClasses %><%nl%>
    <% expand 'ClassHeader', this, :for => c %><%iinc%>
      <% if c.abstract %>abstract<% end %>
      <% expand 'annotations::Annotations', :for => c %>
      <% expand 'Attribute', this, :foreach => c.eAttributes %>
      <%idec%>
    end
  <% end %><%nl%>
  <% for p in eSubpackages %>
    <%nl%><% expand 'GeneratePackage', :for => p %>
  <% end %><%idec%>
end

<% end %>

<% define 'GenerateClassesReordered', :for => EPackage do %>

<% for c in allClassesSorted %><%nl%>
  <% expand 'ClassHeaderFullyQualified', this, :for => c %><%iinc%>
    <% if c.abstract %>abstract<% end %>
    <% expand 'annotations::Annotations', :for => c %>
    <% expand 'Attribute', this, :foreach => c.eAttributes %>
    <%idec%>
  end
<% end %><%nl%>

<% end %>

<% define 'GeneratePackagesOnly', :for => EPackage do %>

module <%= moduleName %><% iinc %>
  extend RGen::MetamodelBuilder::ModuleExtension
  include RGen::MetamodelBuilder::DataTypes
  <% expand 'annotations::Annotations' %>
  <%nl%>
  <% expand 'EnumTypes' %>
  <% for p in eSubpackages %>
    <%nl%><% expand 'GeneratePackagesOnly', :for => p %>
  <% end %><%idec%>
end

<% end %>

<% define 'Attribute', :for => EAttribute do |rootp| %>

<% if upperBound == 1%>has_attr<% else %>has_many_attr<% end %> '<%= name %>', <%nows%>
<% if eType.is_a?(EEnum) %><%nows%>
  <%= eType.qualifiedClassifierName(rootp) %><%nows%>
<% else %><%nows%>
  <%= eType && eType.instanceClass.to_s %><%nows%>
<% end %><%nows%>
<% for p in RGen::MetamodelBuilder::Intermediate::Attribute.properties %>
  <% unless p == :name || (p == :upperBound && (upperBound == 1 || upperBound == -1)) || 
    RGen::MetamodelBuilder::Intermediate::Attribute.default_value(p) == getGeneric(p) %>
      , :<%=p%> => <%nows%>
      <% if getGeneric(p).is_a?(String) %>
        "<%= getGeneric(p) %>"<%nows%>
      <% elsif getGeneric(p).is_a?(Symbol) %>
        :<%= getGeneric(p) %><%nows%>
      <% else %>
        <%= getGeneric(p) %><%nows%>
      <% end %>
  <% end %>
<% end %>
<%ws%><% expand 'annotations::Annotations' %><%nl%>

<% end %>

<% define 'EnumTypes', :for => EPackage do %>

<% for enum in eClassifiers.select{|c| c.is_a?(EEnum)} %>
  <%= enum.name %> = Enum.new(:name => '<%= enum.name %>', :literals =>[ <%nows%>
  <%= enum.eLiterals.collect { |lit| ":"+(lit.name =~ /^\d|\W/ ? "'"+lit.name+"'" : lit.name) }.join(', ') %> ])
<% end %>

<% end %>

<% define 'GenerateAssocs', :for => EPackage do %>

<% refDone = {} %>
<% for ref in eAllClassifiers.select{|c| c.is_a?(EClass)}.eReferences %>
  <% if !refDone[ref] && ref.eOpposite %>
    <% ref = ref.eOpposite if ref.eOpposite.containment %>
    <% refDone[ref] = refDone[ref.eOpposite] = true %>
    <% if !ref.many && !ref.eOpposite.many %>
      <% if ref.containment %>
        <% expand 'Reference', "contains_one", this, :for => ref %>
      <% else %>
        <% expand 'Reference', "one_to_one", this, :for => ref %>
      <% end %>
    <% elsif !ref.many && ref.eOpposite.many %>
      <% expand 'Reference', "many_to_one", this, :for => ref %>
    <% elsif ref.many && !ref.eOpposite.many %>
      <% if ref.containment %>
        <% expand 'Reference', "contains_many", this, :for => ref %>
      <% else %>
        <% expand 'Reference', "one_to_many", this, :for => ref %>
      <% end %>
    <% elsif ref.many && ref.eOpposite.many %>
      <% expand 'Reference', "many_to_many", this, :for => ref %>
    <% end %>
    <% expand 'annotations::Annotations', :for => ref %><%nl%>
  <% elsif !refDone[ref] %>
    <% refDone[ref] = true %>
    <% if !ref.many %>
      <% if ref.containment %>
        <% expand 'Reference', "contains_one_uni", this, :for => ref %>
      <% else %>
        <% expand 'Reference', "has_one", this, :for => ref %>
      <% end %>
    <% elsif ref.many %>
      <% if ref.containment %>
        <% expand 'Reference', "contains_many_uni", this, :for => ref %>
      <% else %>
        <% expand 'Reference', "has_many", this, :for => ref %>
      <% end %>
    <% end %>
    <% expand 'annotations::Annotations', :for => ref %><%nl%>
  <% end %>
<% end %>

<% end %>

<% define 'Reference', :for => EReference do |cmd, rootpackage| %>

<%= eContainingClass.qualifiedClassifierName(rootpackage) %>.<%= cmd %> '<%= name %>', <%= eType && eType.qualifiedClassifierName(rootpackage) %><%nows%>
<% if eOpposite %><%nows%>
  , '<%= eOpposite.name%>'<%nows%>
<% end %><%nows%>
<% pset = RGen::MetamodelBuilder::Intermediate::Reference.properties.reject{|p| p == :name || p == :upperBound || p == :containment} %>
<% for p in pset.reject{|p| RGen::MetamodelBuilder::Intermediate::Reference.default_value(p) == getGeneric(p)} %>
    , :<%=p%> => <%=getGeneric(p)%><%nows%>
<% end %>
<% if eOpposite %>
  <% for p in pset.reject{|p| RGen::MetamodelBuilder::Intermediate::Reference.default_value(p) == eOpposite.getGeneric(p)} %>
      , :opposite_<%=p%> => <%=eOpposite.getGeneric(p)%><%nows%>
  <% end %>
<% end %><%ws%>

<% end %>

<% define 'ClassHeader', :for => EClass do |rootp| %>

class <%= classifierName %> < <% nows %>
<% if eSuperTypes.size > 1 %><% nows %>
  RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierNameIfRequired(rootp)}.join(', ') %>)
<% elsif eSuperTypes.size > 0 %><% nows %>
  <%= eSuperTypes.first.qualifiedClassifierNameIfRequired(rootp) %>
<% else %><% nows %>
  RGen::MetamodelBuilder::MMBase
<% end %>

<% end %>

<% define 'ClassHeaderFullyQualified', :for => EClass do |rootp| %>

class <%= qualifiedClassifierName(rootp) %> < <% nows %>
<% if eSuperTypes.size > 1 %><% nows %>
  RGen::MetamodelBuilder::MMMultiple(<%= eSuperTypes.collect{|t| t.qualifiedClassifierName(rootp)}.join(', ') %>)
<% elsif eSuperTypes.size > 0 %><% nows %>
  <%= eSuperTypes.first.qualifiedClassifierName(rootp) %>
<% else %><% nows %>
  RGen::MetamodelBuilder::MMBase
<% end %>

<% end %>