========================
Using Progress Functions
========================

Sometimes making HOOPS perform a task won't give an immediate result.
And insofar as the API is not concurrent, performing any time consuming operation will block your application until it's finished.
This is the case when loading files or processing CAD models where the operation may take a little while.

To give you feedback on the evolution of such operations, you can provide the API with a set of callback functions which are automatically called to update you about the progress of a long running task.

************************
Setting Up the Callbacks
************************

To define the callback functions, call :func:`A3DDllSetCallbacksProgress`. It accepts 5 functions and a pointer to a control flag that can be used to stop the process:

.. code-block:: c

   A3DVoid on_start(A3DInt32 in_iCode);
   A3DVoid on_size(A3DInt32 in_iMax);
   A3DVoid on_increment(A3DInt32 in_iValue);
   A3DVoid on_end();
   A3DVoid on_title(A3DUTF8Char* in_pcTitle);

   A3DInt32 stop_process = 0;

   A3DDllSetCallbacksProgress(on_start, on_size, on_increment, on_end, on_title, &stop_process);

All functions must be set.

**********************
Progress Start and End
**********************

When the API starts a new progress, `on_start` is called. This function receives an indicator of the type of the performed operation:

* `0`: Undefined
* `1`: File Read
* `2`: File Write
* `3`: Any operation done after reading

.. warning::

   The current version of HOOPS API does not provide an exhaustive set of identifiers. For a more precise description of the task being performed, please see the description of the `on_title` callback below.

.. code-block:: c

   A3DVoid on_start(A3DInt32 in_iCode)
   {
     switch(in_iCode)
     {
       case 1:
         printf("File reading...\n");
         break;
       // ...
       default:
         break;
     }
   }

All incoming calls to your callback functions address the same progress until `on_end` is called by the API:

.. code-block:: c

   A3DVoid on_end()
   {
     printf("Done.\n");
   }

*******************************************
Getting a Description of the Executing Task
*******************************************

Right after the progress starts, `on_title` is called and is given a descriptive string of the performing task. If the current progress is the loading of a CAD file, the value contains the name of the file.

.. code-block:: c

   A3DVoid on_title(A3DUTF8Char* in_pcTitle)
   {
     printf("In Progress: %s\n", in_pcTitle);
   }

Please note that the lifetime of `in_pcTitle` is clamped to the call of this function.

*********************************
Being Notified About the Progress
*********************************

The progress of the task is expressed using a range of integer values where the maximum is passed to `on_size`.

.. code-block:: c

   A3DInt32 max = 0;

   A3DVoid on_size(A3DInt32 in_iMax)
   {
     max = in_iMax;
   }

.. warning::

   Please note that there is no direct relation between this value and a potential time estimation for the performed task. The value given for `in_iMax` in set internally and shouldn't be interpreted to any specific meaning.

Then each time HOOPS notifies about its progress, it calls `on_increment` which is given a value between 0 and `max`:

.. code-block:: c

   A3DVoid on_increment(A3DInt32 in_iValue)
   {
     const A3DInt32 p = (100 * in_iValue) / max;
     printf("Current Progress: %d%%\n", p);
   }

*********************
Stopping the Progress
*********************

Some operations may be canceled while running. To do so, simply change the value given to :func:`A3DDllSetCallbacksProgress` to any non-zero integer.

.. warning::

   Because the value passed to `A3DDllSetCallbacksProgress` is a pointer to a local variable, please be cautious with the lifetime of the actual variable.

************
Full Example
************

This complete example can be used to display any progress in the standard output.

Some elements of this code snippets are worth some precisions:

* Because there is no order guarantee in the function calls, `on_increment` shouldn't assume that `max` is non-zero. To avoid a zero-division, we display only the title of the progress in that case.
* For the same reason, `title` may not be set when `on_increment` is called. This is why is it initialized first to a default value.

.. code-block:: c

   struct {
     char        title[1024];
     A3DInt32    max;
     A3DInt32    stop;
   } progress;

   A3DVoid on_start(A3DInt32)
   {
     printf("Starting process...\n");
   }

   A3DVoid on_end()
   {
     printf("Done.\n");
   }

   A3DVoid on_size(A3DInt32 in_iMax)
   {
     progress.max = in_iMax;
   }

   A3DVoid on_increment(A3DInt32 in_iValue)
   {
     if(progress.max == 0)
     {
       printf("%s...\n", progress.title);
     }
     else
     {
       const A3DInt32 p = (100 * in_iValue) / progress.max;
       printf("%s: %d%%\n", process.title, p);
     }
   }

   A3DVoid on_title(A3DUTF8Char* in_pcTitle)
   {
     strcpy(progress.title, in_pcTitle);
   }

   int main(int argc, char* argv[])
   {
     // Initializing HOOPS API

     strcpy(progress.title, "Unknown");
     progress.max = 0;
     progress.stop = 0;
     A3DDllSetCallbacksProgress(on_start, on_size, on_increment, on_end, on_title, &progress.stop);

     // Using HOOPS API

     return EXIT_SUCCESS;
   }

