text: from django.conf import settings
  from django.apps import apps
  from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist, ValidationError
  from django.forms import fields, widgets, ModelChoiceField
  from django.template import TemplateDoesNotExist
  from django.template.loader import select_template
  from django.utils.html import format_html
  from django.utils.module_loading import import_string
  from django.utils.translation import ugettext_lazy as _, pgettext_lazy
  from entangled.forms import EntangledModelFormMixin, get_related_object
  
  if 'cmsplugin_cascade' not in settings.INSTALLED_APPS:
      raise ImproperlyConfigured("Please add 'cmsplugin_cascade' to your INSTALLED_APPS")
  
  from cms.plugin_pool import plugin_pool
  from cmsplugin_cascade.plugin_base import CascadePluginBase
  from cmsplugin_cascade.link.forms import LinkForm
  from cmsplugin_cascade.link.plugin_base import LinkPluginBase
  from django_select2.forms import HeavySelect2Widget
  from shop.conf import app_settings
  from shop.forms.base import DialogFormMixin
  from shop.models.cart import CartModel
  from shop.models.product import ProductModel
  
  
  class ShopPluginBase(CascadePluginBase):
      module = "Shop"
      require_parent = False
      allow_children = False
  
  
  class ProductSelectField(ModelChoiceField):
      widget = HeavySelect2Widget(data_view='shop:select-product')
  
      def __init__(self, *args, **kwargs):
          kwargs.setdefault('queryset', ProductModel.objects.all())
          super().__init__(*args, **kwargs)
  
  
  class CatalogLinkForm(LinkForm):
      """
      Alternative implementation of `cmsplugin_cascade.link.forms.LinkForm`, which allows to link onto
      the Product model, using its method ``get_absolute_url``.
  
      Note: In this form class the field ``product`` is missing. It is added later, when the shop's
      Product knows about its materialized model.
      """
      LINK_TYPE_CHOICES = [
          ('cmspage', _("CMS Page")),
          ('product', _("Product")),
          ('download', _("Download File")),
          ('exturl', _("External URL")),
          ('email', _("Mail To")),
      ]
  
      product = ProductSelectField(
          label=_("Product"),
          required=False,
          help_text=_("An internal link onto a product from the catalog"),
      )
  
      class Meta:
          entangled_fields = {'glossary': ['product']}
  
      def clean(self):
          cleaned_data = super().clean()
          link_type = cleaned_data.get('link_type')
          error = None
          if link_type == 'product':
              if cleaned_data['product'] is None:
                  error = ValidationError(_("Product to link to is missing."))
                  self.add_error('product', error)
          if error:
              raise error
          return cleaned_data
  
  
  class CatalogLinkPluginBase(LinkPluginBase):
      """
      Alternative implementation to ``cmsplugin_cascade.link.DefaultLinkPluginBase`` which adds
      another link type, namely "Product", to set links onto arbitrary products of this shop.
      """
      ring_plugin = 'ShopLinkPlugin'
  
      class Media:
          js = ['admin/js/jquery.init.js', 'shop/js/admin/shoplinkplugin.js']
  
      @classmethod
      def get_link(cls, obj):
          link_type = obj.glossary.get('link_type')
          if link_type == 'product':
              relobj = get_related_object(obj.glossary, 'product')
              if relobj:
                  return relobj.get_absolute_url()
          else:
              return super().get_link(obj) or link_type
  
  
  class DialogPluginBaseForm(EntangledModelFormMixin):
      RENDER_CHOICES = [
          ('form', _("Form dialog")),
          ('summary', _("Static summary")),
      ]
  
      render_type = fields.ChoiceField(
          choices=RENDER_CHOICES,
          widget=widgets.RadioSelect,
          label=_("Render as"),
          initial='form',
          help_text=_("A dialog can also be rendered as a box containing a read-only summary."),
      )
  
      headline_legend = fields.BooleanField(
          label=_("Headline Legend"),
          initial=True,
          required=False,
          help_text=_("Render a legend inside the dialog's headline."),
      )
  
      class Meta:
          entangled_fields = {'glossary': ['render_type', 'headline_legend']}
  
  
  class DialogFormPluginBase(ShopPluginBase):
      """
      Base class for all plugins adding a dialog form to a placeholder field.
      """
      require_parent = True
      parent_classes = ['BootstrapColumnPlugin', 'ProcessStepPlugin', 'BootstrapPanelPlugin',
          'SegmentPlugin', 'SimpleWrapperPlugin', 'ValidateSetOfFormsPlugin']
      form = DialogPluginBaseForm
  
      @classmethod
      def register_plugin(cls, plugin):
          """
          Register plugins derived from this class with this function instead of
          `plugin_pool.register_plugin`, so that dialog plugins without a corresponding
          form class are not registered.
          """
          if not issubclass(plugin, cls):
              msg = "Can not register plugin class `{}`, since is does not inherit from `{}`."
              raise ImproperlyConfigured(msg.format(plugin.__name__, cls.__name__))
          plugin_pool.register_plugin(plugin)
  
      def get_form_class(self, instance):
          try:
              return import_string(self.form_class)
          except AttributeError:
              msg = "Can not register plugin class '{}', since it neither defines 'form_class' " \
                    "nor overrides 'get_form_class()'."
              raise ImproperlyConfigured(msg.format(self.__name__))
  
      @classmethod
      def get_identifier(cls, instance):
          render_type = instance.glossary.get('render_type')
          render_type = dict(cls.form.RENDER_CHOICES).get(render_type, '')
          return format_html(pgettext_lazy('get_identifier', "as {}"), render_type)
  
      def get_form_data(self, context, instance, placeholder):
          """
          Returns data to initialize the corresponding dialog form.
          This method must return a dictionary containing
           * either `instance` - a Python object to initialize the form class for this plugin,
           * or `initial` - a dictionary containing initial form data, or if both are set, values
             from `initial` override those of `instance`.
          """
          if issubclass(self.get_form_class(instance), DialogFormMixin):
              try:
                  cart = CartModel.objects.get_from_request(context['request'])
                  cart.update(context['request'])
              except CartModel.DoesNotExist:
                  cart = None
              return {'cart': cart}
          return {}
  
      def get_render_template(self, context, instance, placeholder):
          render_type = instance.glossary.get('render_type')
          if render_type not in ('form', 'summary',):
              render_type = 'form'
          try:
              template_names = [
                  '{0}/checkout/{1}'.format(app_settings.APP_LABEL, self.template_leaf_name).format(render_type),
                  'shop/checkout/{}'.format(self.template_leaf_name).format(render_type),
              ]
              return select_template(template_names)
          except (AttributeError, TemplateDoesNotExist):
              return self.render_template
  
      def render(self, context, instance, placeholder):
          """
          Return the context to render a DialogFormPlugin
          """
          request = context['request']
          form_data = self.get_form_data(context, instance, placeholder)
          request._plugin_order = getattr(request, '_plugin_order', 0) + 1
          if not isinstance(form_data.get('initial'), dict):
              form_data['initial'] = {}
          form_data['initial'].update(plugin_id=instance.pk, plugin_order=request._plugin_order)
          bound_form = self.get_form_class(instance)(**form_data)
          context[bound_form.form_name] = bound_form
          context['headline_legend'] = bool(instance.glossary.get('headline_legend', True))
          return self.super(DialogFormPluginBase, self).render(context, instance, placeholder)
  