Calculation with a jinja type
===============================

.. objectives:: Objectives

   In this section we will learn how to create new ways of calculation.

   Up to now, our only way of dynamically (that is, during the runtime) calculating 
   a value is to point on another variable's value. But this is not the only way. 

.. todo:: on peut aussi faire un exercice de ce genre pour la propriété mandatory


A jinja calculated variable's hidden property
------------------------------------------------

We can hide or disable some variables or families with other techniques than 
pointing on a variable's value.

Let's reason on the previous HTTPS proxy configuration's manual mode:

.. code-block:: yaml

    manual:

      use_for_https:
        description: Also use this proxy for HTTPS
        default: true

      https_proxy:
        type: family
        description: HTTPS Proxy
        hidden:
          variable: manual.use_for_https


This is extracted from the proxy's manual configuration we discussed before.

We see here that there is an `https_proxy` family that is going to be hidden 
depending on the value of another variable:

.. code-block:: yaml

      https_proxy:
        type: family
        hidden:
          variable: manual.use_for_https

Now we could write it like that: 

.. code-block:: yaml

    manual:

      use_for_https:
        description: Also use this proxy for HTTPS
        default: true

      https_proxy:
        description: HTTPS Proxy
        type: family
        hidden:
          type: jinja
          jinja: |
            {% if rougail.manual.use_for_https %}
            the HTTPS Proxy family is hidden 
            {% endif %}

Yes, it's done in a more complicated (but more powerful) way. 
Let's explain this a little: 

We have replaced this simple hidden property declaration:

.. code-block:: yaml

        hidden:
          variable: manual.use_for_https

by this (more complicated) hidden property declaration:

.. code-block:: yaml

        hidden:
          type: jinja
          jinja: |
            {% if rougail.manual.use_for_https %}
            the HTTPS Proxy family is hidden
            {% endif %}

The fact is that it has same result, but here we have more possibilities. 
The hidden process is done by a calculation. 

Another jinja calculation type sample 
---------------------------------------

We can now hide or disable some variables or families with other techniques than 
pointing on a variable's value.

Let's reason upon the proxy's manual configuration we discussed before.
We have the :file:`dict/02-proxy_manual.yml` structure file:

.. code-block:: yaml
   :caption: the :file:`structfile/02-proxy_manual.yml` file

      ---
      version: '1.1'
      manual:
        description: Manual proxy configuration
        type: family
        disabled:
          type: jinja
          jinja: |
            {% if rougail.proxy.proxy_mode != 'Manual proxy configuration' %}
            the proxy mode is not manual
            {% endif %}

.. questions:: Question

   **question**: OK then. What happens when you select the "Manual proxy configuration"?

Here if the user selects the "Manual proxy configuration" proxy mode, 
the the `manual` family will be disabled. This is what the jinja code says. 
Let's explain it more precisely. 


.. note:: The "the proxy mode is not manual" output is be used in the log outputs
          for example while 

Why Jinja?
---------------

.. questions:: What about this `Jinja` type?

If the :term:`Jinja` template returns some text, then the family will be `disabled`. Otherwise it is accessible.
Deactivating a family means that we will not be able to access it as well as the variables or families included in this family.

.. note:: If the Jinja template does not return any text, the variable will be **enabled**.
          Here we are using the Jinja condition statement.

.. glossary::

    Jinja

        `Jinja <https://jinja.palletsprojects.com>`_ is a template engine.
        we are using Jinja in a classical way, that is, Jinja allows us to handle different cases,
        for example with the `if` statement.

What can be calculated?
---------------------------

We have seen that the `disabled` or `hidden` properties could be calculated.
The default values can be calculated too. 

.. todo:: montrer un exemple de valeur par défaut calculées (type jinja)

.. todo:: montrer aussi ici des exemples de calculs de valeurs variables, ce qui est un des usages principaux de jinja

Using jinja in a dynamic family declaration
-----------------------------------------------

Let's come back to the previous section's :ref:`dynamic family example <conditional_hidden_family>`\ .

In a dynamic family, as seen before, you have the possibility to name your identifier. In the classic declaration, 
the identifier's variable is named "identifier" by default. Sounds logical:

.. code-block:: yaml

      "{{ identifier }}_proxy":
        description: "{{ identifier }} Proxy"
        dynamic:
          - HTTPS
          - SOCKS

Here the identifer's variable takes the value of the `dynamic` family parameter.

.. type-along:: Using a jinja calculation with a parameter

We have the possibility to use a given variable variable inside a jinja calculation:

.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_050/firefox/20-manual.yml
   :language: yaml
   :caption: firefox/20-proxy.yml

.. 
    manual:

      use_for_https:
        description: Also use this proxy for HTTPS
        default: true

      "{{ identifier }}_proxy":
        description: "{{ identifier }} Proxy"
        dynamic:
          - HTTPS
          - SOCKS
        hidden:
          jinja: |
            {% if my_identifier == 'HTTPS' and manual.use_for_https %}
            HTTPS is same has HTTP
            {% endif %}
          params:
            my_identifier:
              type: identifier
          description: |
            in HTTPS case if "manual.use_for_https" is set to True

        address:
          description: "{{ identifier }} address"
          default:
            variable: manual.http_proxy.address

        port:
          description: "{{ identifier }} port"
          default:
            variable: manual.http_proxy.port

        version:
          description: SOCKS host version used by proxy
          choices:
            - v4
            - v5
          default: v5
          disabled:
            type: identifier
            when: 'HTTPS'

This can be done by defining a `my_identifier` variable.

This jinja variable comes from the `params` parameter of the `hidden` property.

.. code-block:: yaml

          params:
            my_identifier:
              type: identifier

Here the `hidden` property's value is defined by a jinja calculation. 
In this jinja calculation we have a `my_identifier` jinja variable. 

.. code-block:: yaml

        hidden:
          jinja: |
            {% if my_identifier == 'HTTPS' and manual.use_for_https %}
            HTTPS is same has HTTP
            {% endif %}
          params:
            my_identifier:
              type: identifier
          description: |
            in HTTPS case if "manual.use_for_https" is set to True

.. type-along:: The `when` and `when_not` parameter notation

.. todo:: ça devrait être sur une autre page. déplacer cela ailleurs

Handling the SOCKS version
----------------------------

Now we need to handle the SOCKS version as show in the firefox configuration screenshot: 

.. image:: images/firefox_soks_version.png


We'll just add a choice variable with a default value and a disabled property: 

.. code-block:: yaml

    version:
      description: SOCKS host version used by proxy
      choices:
        - v4
        - v5
      default: v5
      disabled:
        type: identifier
        when: 'HTTPS'

There is still something new about this YAML, though. It is the `when` parameter 
of the `disabled` property. You have two possible notations: `when` or `when_not`. 
These two notations are just a short hand of what we could express in jinja as 
this code:

.. code-block:: jinja

    {% if identifier == 'HTTPS' %}
    when the identifer equals 'HTTPS' then the SOCKS version is disabled 
    {% endif %}
   
And the `when_not` parameter is just the logical opposite.

Here is the final version of our YAML dynamic family:

.. extinclude:: https://forge.cloud.silique.fr/stove/rougail-tutorials/raw/tag/v1.1_050/firefox/20-manual.yml
   :language: yaml
   :caption: firefox/20-proxy.yml


.. keypoints:: Key points

   **keywords**
      
   - calculation with a jinja type calculation
   - calculation with a `when` or `when_not` parameter
   - defining a jinja internal variable in a jinja calculation

   **progress**

   Here we have come to the possibility of making any kind of calculations based on the state of the :term:`configuration`.
   This is an important feature to manage the stateful aspect of a configuration.
   
