from core.models.xosbase import *
from core.models import ServiceInstance
{% set ns=namespace(any_legacy_tag = '') %}
{% for m in proto.messages %}
{% if file_exists(m.name|lower+'_header.py') -%}from {{m.name|lower }}_header import *{% endif %}
{% if file_exists(m.name|lower+'_top.py') -%}{{ include_file(m.name|lower+'_top.py') }} {% endif %}

{%- for l in m.links -%}{% set peer_name=l.peer.name %}

{% if peer_name not in proto.message_names -%}
from core.models import {{ peer_name }} 
{%- endif -%}
{%- endfor -%}
{%- for b in m.bases -%}
{%- if b.name!='XOSBase' and 'Mixin' not in b.name %}
{% if b.name not in proto.message_names %}
from core.models import {{ b.name }}
{% endif %}
{%- endif -%}
{% endfor %}

{% for policy,error in xproto_validations(m.options) %}
{{ xproto_fol_to_python_validator(policy, proto.policies[policy], m, error) }}
{% endfor %}

{% endfor %}

{# Compute any_legacy_tag by looking to see if any model in the service has legacy sete #}
{% for m in proto.messages %}
{%- if xproto_list_evaluates_true([m.options.custom_python, m.options.legacy, options.custom_python, options.legacy]) -%}
{% set ns.any_legacy_tag = '_decl' %}
{% endif %}
{% endfor %}

{% for m in proto.messages %}
{%- if xproto_list_evaluates_true([m.options.custom_python, m.options.legacy, options.custom_python, options.legacy]) -%}
{% set legacy_tag = '_decl' %}
{% set legacy = True %}
{% else %}
{% set legacy = False %}
{% set legacy_tag = '' %}
{% endif %}
class {{ m.name }}{{ ns.any_legacy_tag }}{{ xproto_base_def(m.name, m.bases, legacy_tag, proto.message_names) }}:
  plural_name = "{{ xproto_pluralize(m) }}"

  {%- set feedback_state_fields = xproto_optioned_fields_to_list(xproto_base_fields(m, proto.message_table) + m.fields, 'feedback_state', 'True')  %}
  {%- if feedback_state_fields|length > 0 %}
  feedback_state_fields = {{ feedback_state_fields }}
  {%- endif %}

  KIND = {{ xproto_first_non_empty([m.options.kind, options.kind, options.name, "Set a kind in your xproto!"]) }}

  {% if m.options.owner_class_name %}
  OWNER_CLASS_NAME = {{ m.options.owner_class_name }}
  {% endif %}

  class Meta:
      app_label = {{ xproto_first_non_empty([m.options.app_label, options.app_label, options.name, "Set an app label in your xproto!"]) | lower}}
      # name = {{ xproto_first_non_empty([m.options.name, options.name, "Set a name in your xproto!"]) }}
      verbose_name = "{{ xproto_unquote(xproto_first_non_empty([m.options.verbose_name, m.name])) }}"
  {%- set uniques = xproto_field_graph_components(m.fields, m) %}
  {%- if uniques %}
      unique_together = {{ xproto_tuplify(uniques) }}
  {%- endif %}

  # Primitive Fields (Not Relations)
  {% for f in m.fields %}
  {%- if not f.link -%}
  {{ f.name }} = {{ xproto_django_type(f.type, f.options) }}( {{ xproto_django_options_str(f) }} )
  {% endif %}
  {%- endfor %}

  # Relations
  {% for l in m.links %}{% set peer_name=l.peer.name %}
  {% if ns.any_legacy_tag!='' and peer_name in proto.message_names %}{% set peer_tag = ns.any_legacy_tag %}{% else %}{% set peer_tag = '' %}{% endif -%}
  {{ l.src_port }} = {{ xproto_django_link_type(l) }}( {%- if peer_name==m.name -%}'self'{%- else -%}{{ peer_name }}{{ peer_tag }} {%- endif -%}, {{ xproto_django_options_str(l, l.dst_port ) }} )
  {%- endfor %}

  {% if file_exists(m.name|lower + '_model.py') -%}{{ include_file(m.name|lower + '_model.py') | indent(width=2)}}{%- endif %}
  pass

  # Generated methods
  def save(self, *args, **kwds):
      if not self.leaf_model_name:
          self.leaf_model_name = "{{ m.name }}"

      {% for policy,error in xproto_validations(m.options) %}
      policy_{{policy}}_validator(self, None)
      {% endfor %}

      try:
          base_save_in_attic = self.__xos_save_base(*args, **kwds)
      except AttributeError:
          base_save_in_attic = False

      if not self.deleted:
          self.full_clean()

      if not base_save_in_attic:
          super({{ m.name }}{{ ns.any_legacy_tag }}, self).save(*args, **kwds)
  
  def can_access(self, ctx):
      {% if m.policy %}
      verdict = security.{{m.policy}}_security_check(self, ctx)
      return verdict,"{{ m.policy }}"
      {% else %}
      verdict = True
      return verdict,"xos_default_policy"
      {% endif %}

{# To maintain compatibility with migrations, we need to ensure that both the _decl and the non-_decl model #}
{# exist. So we automatically create all models as _decl, and then add these trivial stubs #}
{% if (not legacy) and (ns.any_legacy_tag) %}
class {{ m.name }}({{ m. name }}{{ ns.any_legacy_tag }}):
    class Meta:
        proxy = True
{% endif %}

{% if file_exists(m.name|lower+'_bottom.py') -%}{{ include_file(m.name|lower+'_bottom.py') }}{% endif %} 
{% endfor %}
+++ models{{ ns.any_legacy_tag }}.py
