LCOV - code coverage report
Current view: top level - io/source - io_import_elements.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.70.2_covts Lines: 83.5 % 442 369
Test Date: 2026-05-03 11:56:31 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /* File: io_import_elements.c; Copyright and License: see below */
       2              : 
       3              : #include "io_import_elements.h"
       4              : #include "u8/u8_error.h"
       5              : #include "utf8stringbuf/utf8string.h"
       6              : #include "u8/u8_trace.h"
       7              : #include <assert.h>
       8              : #include "io_gtk.h"
       9              : #include <stdbool.h>
      10              : 
      11           20 : void io_import_elements_init( io_import_elements_t *this_,
      12              :                               data_database_reader_t *db_reader,
      13              :                               ctrl_controller_t *controller,
      14              :                               data_stat_t *io_stat,
      15              :                               utf8stream_writer_t *out_english_report )
      16              : {
      17           20 :     U8_TRACE_BEGIN();
      18           20 :     assert( NULL != db_reader );
      19           20 :     assert( NULL != controller );
      20           20 :     assert( NULL != io_stat );
      21           20 :     assert( NULL != out_english_report );
      22              : 
      23           20 :     (*this_).db_reader = db_reader;
      24           20 :     (*this_).controller = controller;
      25           20 :     (*this_).stat = io_stat;
      26           20 :     (*this_).english_report = out_english_report;
      27              : 
      28           20 :     (*this_).step = IO_IMPORT_STEP_CHECK;
      29           20 :     (*this_).paste_to_diagram = DATA_ROW_VOID;
      30              : 
      31           20 :     ctrl_multi_step_changer_init( &((*this_).multi_step_changer), controller, db_reader );
      32              : 
      33           20 :     data_rules_init ( &((*this_).data_rules) );
      34              : 
      35              :     /* get the id of the root diagram if there is one */
      36           20 :     (*this_).root_diagram = DATA_ROW_VOID;
      37              :     {
      38              :         data_small_set_t roots;
      39           20 :         data_small_set_init( &roots );
      40              :         const u8_error_t read_error
      41           20 :             = data_database_reader_get_diagram_ids_by_parent_id( (*this_).db_reader,
      42              :                                                                  DATA_ROW_VOID,
      43              :                                                                  &roots
      44              :                                                                );
      45           20 :         if ( read_error != U8_ERROR_NONE )
      46              :         {
      47            0 :             U8_LOG_ERROR_HEX( "error at reading root", read_error );
      48              :         }
      49              :         else
      50              :         {
      51           20 :             if ( 1 <= data_small_set_get_count( &roots ) )
      52              :             {
      53           16 :                 data_id_t first_root = data_small_set_get_id( &roots, 0 );
      54           16 :                 (*this_).root_diagram = data_id_get_row( &first_root );
      55              :             }
      56              :             else
      57              :             {
      58            4 :                 U8_LOG_EVENT( "importing to empty database" );
      59              :             }
      60              :         }
      61           20 :         data_small_set_destroy( &roots );
      62              :     }
      63              : 
      64           20 :     U8_TRACE_END();
      65           20 : }
      66              : 
      67           16 : void io_import_elements_init_for_paste( io_import_elements_t *this_,
      68              :                                         data_row_t paste_to_diagram,
      69              :                                         data_database_reader_t *db_reader,
      70              :                                         ctrl_controller_t *controller,
      71              :                                         data_stat_t *io_stat,
      72              :                                         utf8stream_writer_t *out_english_report )
      73              : {
      74           16 :     U8_TRACE_BEGIN();
      75              : 
      76           16 :     io_import_elements_init( this_, db_reader, controller, io_stat, out_english_report );
      77           16 :     (*this_).step = IO_IMPORT_STEP_CREATE_D_C_F_R;
      78              : 
      79              :     /* check if diagram id exists */
      80              :     {
      81           16 :         data_diagram_init_empty( &((*this_).temp_diagram) );
      82              :         const u8_error_t read_error1
      83           16 :             = data_database_reader_get_diagram_by_id( (*this_).db_reader,
      84              :                                                       paste_to_diagram,
      85              :                                                       &((*this_).temp_diagram)
      86              :                                                     );
      87           16 :         if ( U8_ERROR_NONE != read_error1 )
      88              :         {
      89            1 :             U8_LOG_ERROR_INT( "diagram id where to import json data to does not exist (anymore)", (*this_).paste_to_diagram );
      90            1 :             (*this_).paste_to_diagram = DATA_ROW_VOID;
      91              :         }
      92              :         else
      93              :         {
      94           15 :             (*this_).paste_to_diagram = paste_to_diagram;
      95              :         }
      96           16 :         data_diagram_destroy( &((*this_).temp_diagram) );
      97              :     }
      98              : 
      99           16 :     U8_TRACE_END();
     100           16 : }
     101              : 
     102           20 : void io_import_elements_destroy( io_import_elements_t *this_ )
     103              : {
     104           20 :     U8_TRACE_BEGIN();
     105           20 :     assert( NULL != (*this_).db_reader );
     106           20 :     assert( NULL != (*this_).controller );
     107           20 :     assert( NULL != (*this_).stat );
     108           20 :     assert( NULL != (*this_).english_report );
     109              : 
     110           20 :     data_rules_destroy ( &((*this_).data_rules) );
     111           20 :     ctrl_multi_step_changer_destroy( &((*this_).multi_step_changer) );
     112              :     /* do not change the stats here */
     113              : 
     114           20 :     (*this_).db_reader = NULL;
     115           20 :     (*this_).controller = NULL;
     116           20 :     (*this_).stat = NULL;
     117           20 :     (*this_).english_report = NULL;
     118              : 
     119           20 :     U8_TRACE_END();
     120           20 : }
     121              : 
     122            7 : void io_import_elements_set_mode( io_import_elements_t *this_, io_import_mode_t mode, io_import_step_t step )
     123              : {
     124            7 :     U8_TRACE_BEGIN();
     125            7 :     assert( ( step == IO_IMPORT_STEP_CHECK ) || ( mode != IO_IMPORT_MODE_CHECK ) );
     126            7 :     assert( ( step == IO_IMPORT_STEP_CREATE_D_C_F_R ) || ( mode != IO_IMPORT_MODE_PASTE ) );
     127            7 :     assert( ( step == IO_IMPORT_STEP_CREATE_D_C_L ) || ( step == IO_IMPORT_STEP_ADD_E_DP_F_R ) || ( mode != IO_IMPORT_MODE_IMPORT ) );
     128              : 
     129            7 :     (*this_).step = step;
     130              : 
     131            7 :     U8_TRACE_END();
     132            7 : }
     133              : 
     134           16 : u8_error_t io_import_elements_sync_diagram( io_import_elements_t *this_,
     135              :                                             const data_diagram_t *diagram_ptr,
     136              :                                             const char *parent_uuid )
     137              : {
     138           16 :     U8_TRACE_BEGIN();
     139           16 :     assert( NULL != diagram_ptr );
     140              :     /* parent_uuid is NULL if root diagram */
     141           16 :     u8_error_t sync_error = U8_ERROR_NONE;
     142              : 
     143              :     /* ANY MODE: determine parent id */
     144           16 :     data_row_t parent_row = (*this_).root_diagram;
     145           16 :     const bool parent_uuid_specified
     146           16 :         = (( parent_uuid != NULL )&&( ! utf8string_equals_str( parent_uuid, "" )));
     147           16 :     if ( parent_uuid_specified )
     148              :     {
     149            0 :         data_diagram_init_empty( &((*this_).temp_diagram ) );
     150              :         const u8_error_t read_error1
     151            0 :             = data_database_reader_get_diagram_by_uuid( (*this_).db_reader,
     152              :                                                         parent_uuid,
     153              :                                                         &((*this_).temp_diagram)
     154              :                                                       );
     155            0 :         if ( read_error1 == U8_ERROR_NOT_FOUND )
     156              :         {
     157            0 :             U8_TRACE_INFO_STR( "no parent found, uuid:", parent_uuid );
     158              :         }
     159            0 :         else if ( read_error1 != U8_ERROR_NONE )
     160              :         {
     161            0 :             U8_TRACE_INFO_STR( "error at searching for parent diagram:", parent_uuid );
     162              :         }
     163              :         else
     164              :         {
     165            0 :             parent_row = data_diagram_get_row( &((*this_).temp_diagram ) );
     166              :         }
     167            0 :         data_diagram_destroy( &((*this_).temp_diagram ) );
     168              :     }
     169              : 
     170              :     /* update default parent diagram id */
     171           16 :     if (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )&&( sync_error == U8_ERROR_NONE ))
     172              :     {
     173           10 :         if ( (*this_).paste_to_diagram == DATA_ROW_VOID )
     174              :         {
     175            0 :             data_row_t parent_row = (*this_).root_diagram;
     176            0 :             U8_TRACE_INFO_INT( "in paste-clipboard mode, missing parent diagram set to", parent_row );
     177              :         }
     178              :         else
     179              :         {
     180              :             /* overwrite the parent diagram id, do not keep the one provided via the clipboard */
     181           10 :             parent_row = (*this_).paste_to_diagram;
     182              :         }
     183              :     }
     184              : 
     185              :     /* if PASTE */
     186           16 :     if (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )&&( sync_error == U8_ERROR_NONE ))
     187              :     {
     188           10 :         data_diagram_copy( &((*this_).temp_diagram), diagram_ptr );
     189           10 :         data_diagram_set_parent_row( &((*this_).temp_diagram), parent_row );
     190              :         /* create new uuid for diagram if paste */
     191              :         {
     192              :             data_uuid_t new_uuid;
     193           10 :             data_uuid_init_new( &new_uuid );
     194           10 :             data_diagram_set_uuid( &((*this_).temp_diagram), data_uuid_get_string( &new_uuid ) );
     195           10 :             data_uuid_destroy( &new_uuid );
     196              :         }
     197              : 
     198              :         /* create the parsed diagram as child below the current diagram */
     199              :         u8_error_t modified_info;
     200           10 :         sync_error = ctrl_multi_step_changer_create_diagram( &((*this_).multi_step_changer),
     201              :                                                              &((*this_).temp_diagram),
     202              :                                                              &modified_info
     203              :                                                            );
     204           10 :         if ( sync_error == U8_ERROR_NONE )
     205              :         {
     206           10 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_CREATED );
     207              :         }
     208              :         else
     209              :         {
     210            0 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR );
     211              :         }
     212           10 :         if ( U8_ERROR_NONE != sync_error )
     213              :         {
     214            0 :             U8_LOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagram" );
     215              :         }
     216              :         else
     217              :         {
     218              :             /* insert all consecutive elements to this new diagram */
     219           10 :             (*this_).paste_to_diagram = data_diagram_get_row( &((*this_).temp_diagram) );
     220              :             /* this new diagram is root if it is the first diagram */
     221           10 :             if ( (*this_).root_diagram == DATA_ROW_VOID )
     222              :             {
     223            0 :                 (*this_).root_diagram = data_diagram_get_row( &((*this_).temp_diagram) );
     224              :             }
     225              :         }
     226           10 :         data_diagram_destroy( &((*this_).temp_diagram) );
     227              :     }
     228              : 
     229              :     /* if CREATE/LINK */
     230           16 :     if ((( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_L )||( (*this_).step == IO_IMPORT_STEP_ADD_E_DP_F_R ))
     231            4 :         &&( sync_error == U8_ERROR_NONE ))
     232              :     {
     233              :         /* check if the parsed diagram already exists in this database; if not, create it */
     234            4 :         data_diagram_init_empty( &((*this_).temp_diagram) );
     235              :         u8_error_t read_error;
     236            4 :         read_error = data_database_reader_get_diagram_by_uuid( (*this_).db_reader,
     237              :                                                                data_diagram_get_uuid_const( diagram_ptr ),
     238              :                                                                &((*this_).temp_diagram)
     239              :                                                              );
     240            4 :         const bool diagram_exists = ( U8_ERROR_NONE == read_error );
     241              : 
     242            4 :         if ( diagram_exists )
     243              :         {
     244            2 :             if ( (*this_).step == IO_IMPORT_STEP_ADD_E_DP_F_R )
     245              :             {
     246              :                 /* if (*this_).temp_diagram is the only valid root, set parent_row to DATA_ROW_VOID */
     247            2 :                 if ( data_diagram_get_row( &((*this_).temp_diagram) ) == (*this_).root_diagram )
     248              :                 {
     249            1 :                     parent_row = DATA_ROW_VOID;
     250              :                 }
     251              : 
     252              :                 /* update the parent if wrong parent stored */
     253            2 :                 if ( data_diagram_get_parent_row( &((*this_).temp_diagram) ) != parent_row )
     254              :                 {
     255            0 :                     sync_error = ctrl_multi_step_changer_update_diagram_parent_id( &((*this_).multi_step_changer),
     256            0 :                                                                                    data_diagram_get_row( &((*this_).temp_diagram) ),
     257              :                                                                                    parent_row
     258              :                                                                                  );
     259              : 
     260              :                     /* update root diag if this is root */
     261            0 :                     if (( parent_row == DATA_ROW_VOID )&&( sync_error == U8_ERROR_NONE ))
     262              :                     {
     263            0 :                         (*this_).root_diagram = data_diagram_get_row( &((*this_).temp_diagram) );
     264              :                     }
     265              :                 }
     266              :             }
     267              :             else
     268              :             {
     269              :                 /* do the statistics */
     270            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_IGNORED );
     271              :             }
     272              :         }
     273              :         else
     274              :         {
     275            2 :             data_diagram_replace( &((*this_).temp_diagram), diagram_ptr );
     276            2 :             data_diagram_set_parent_row( &((*this_).temp_diagram), parent_row );
     277              : 
     278              :             /* create the parsed diagram as child below the current diagram */
     279              :             u8_error_t modified_info;
     280            2 :             sync_error = ctrl_multi_step_changer_create_diagram( &((*this_).multi_step_changer),
     281              :                                                                  &((*this_).temp_diagram),
     282              :                                                                  &modified_info
     283              :                                                                );
     284            2 :             if ( sync_error == U8_ERROR_NONE )
     285              :             {
     286            2 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_CREATED );
     287              :             }
     288              :             else
     289              :             {
     290            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR );
     291              :             }
     292              : 
     293            2 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
     294              :             {
     295              :                 /* warn on changed diagram ids. This is important because links in description texts may be affected. */
     296            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_WARNING );
     297              :             }
     298              : 
     299            2 :             if ( U8_ERROR_NONE != sync_error )
     300              :             {
     301            0 :                 U8_LOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagram" );
     302              :             }
     303              :             else
     304              :             {
     305              :                 /* this new diagram is root if it is the first root diagram, further diagrams will not be root */
     306            2 :                 if (( (*this_).root_diagram == DATA_ROW_VOID )&&( parent_row == DATA_ROW_VOID )
     307            1 :                     &&( ! parent_uuid_specified ))
     308              :                 {
     309            1 :                     (*this_).root_diagram = data_diagram_get_row( &((*this_).temp_diagram) );
     310              :                 }
     311              :             }
     312              : 
     313              :             /* write report in case of anomalies */
     314            2 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
     315              :             {
     316            0 :                 io_import_elements_private_report_id_differs( this_,
     317              :                                                               data_diagram_get_data_id( diagram_ptr ),
     318            0 :                                                               data_diagram_get_data_id( &((*this_).temp_diagram ) )
     319              :                                                             );
     320              :             }
     321              :         }
     322            4 :         data_diagram_destroy( &((*this_).temp_diagram) );
     323              :     }
     324              : 
     325           16 :     U8_TRACE_END_ERR( sync_error );
     326           16 :     return sync_error;
     327              : }
     328              : 
     329           14 : u8_error_t io_import_elements_sync_diagramelement( io_import_elements_t *this_,
     330              :                                                    const data_diagramelement_t *diagramelement_ptr,
     331              :                                                    const char *diagram_uuid,
     332              :                                                    const char *node_uuid )
     333              : {
     334           14 :     U8_TRACE_BEGIN();
     335           14 :     assert( NULL != diagramelement_ptr );
     336           14 :     assert( NULL != diagram_uuid );
     337           14 :     assert( NULL != node_uuid );
     338           14 :     u8_error_t sync_error = U8_ERROR_NONE;
     339           14 :     const bool do_sync = ( (*this_).step == IO_IMPORT_STEP_ADD_E_DP_F_R );
     340           14 :     const bool do_check = ( (*this_).step == IO_IMPORT_STEP_CHECK );
     341              : 
     342              :     /* ANY MODE: determine classifier/feature id */
     343           14 :     data_row_t node_classifier_id = DATA_ROW_VOID;
     344           14 :     data_row_t node_feature_id = DATA_ROW_VOID;
     345           14 :     data_feature_type_t node_feature_type = DATA_FEATURE_TYPE_VOID;
     346           14 :     if (( do_check || do_sync )&&( node_uuid != NULL ))
     347              :     {
     348            4 :         if ( ! utf8string_equals_str( node_uuid, "" ) )
     349              :         {
     350              :             /* search source classifier id */
     351            4 :             data_classifier_init_empty( &((*this_).temp_classifier ) );
     352              :             const u8_error_t read_error1
     353            4 :                 = data_database_reader_get_classifier_by_uuid( (*this_).db_reader,
     354              :                                                                node_uuid,
     355              :                                                                &((*this_).temp_classifier)
     356              :                                                              );
     357            4 :             if ( U8_ERROR_NONE == read_error1 )
     358              :             {
     359            1 :                 node_classifier_id = data_classifier_get_row( &((*this_).temp_classifier) );
     360            1 :                 U8_TRACE_INFO_STR( "id found for classifier:", node_uuid );
     361              :             }
     362              :             else
     363              :             {
     364              :                 /* search source feature id */
     365            3 :                 data_feature_init_empty( &((*this_).temp_feature) );
     366              :                 const u8_error_t read_error2
     367            3 :                     = data_database_reader_get_feature_by_uuid( (*this_).db_reader,
     368              :                                                                 node_uuid,
     369              :                                                                 &((*this_).temp_feature)
     370              :                                                               );
     371            3 :                 if ( U8_ERROR_NONE == read_error2 )
     372              :                 {
     373            1 :                     node_classifier_id = data_feature_get_classifier_row( &((*this_).temp_feature) );
     374            1 :                     node_feature_id = data_feature_get_row( &((*this_).temp_feature) );
     375            1 :                     node_feature_type = data_feature_get_main_type( &((*this_).temp_feature) );
     376            1 :                     U8_TRACE_INFO_STR( "id found for feature:", node_uuid );
     377              :                 }
     378              :                 else
     379              :                 {
     380            2 :                     U8_TRACE_INFO_STR( "diagramelement node not found", node_uuid );
     381              :                 }
     382            3 :                 data_feature_destroy( &((*this_).temp_feature) );
     383              :             }
     384            4 :             data_classifier_destroy( &((*this_).temp_classifier ) );
     385              :         }
     386              :     }
     387              : 
     388              :     /* ANY MODE: determine diagram id */
     389           14 :     data_row_t diagram_row = DATA_ROW_VOID;
     390           14 :     if (( do_check || do_sync )&&( diagram_uuid != NULL )&&( sync_error == U8_ERROR_NONE ))
     391              :     {
     392            4 :         if ( ! utf8string_equals_str( diagram_uuid, "" ) )
     393              :         {
     394            4 :             data_diagram_init_empty( &((*this_).temp_diagram ) );
     395              :             const u8_error_t read_error3
     396            4 :                 = data_database_reader_get_diagram_by_uuid( (*this_).db_reader,
     397              :                                                             diagram_uuid,
     398              :                                                             &((*this_).temp_diagram)
     399              :                                                           );
     400            4 :             if ( read_error3 == U8_ERROR_NOT_FOUND )
     401              :             {
     402            2 :                 U8_TRACE_INFO_STR( "no diagram found, uuid:", diagram_uuid );
     403              :             }
     404            2 :             else if ( read_error3 != U8_ERROR_NONE )
     405              :             {
     406            0 :                 U8_TRACE_INFO_STR( "diagram not found:", diagram_uuid );
     407              :             }
     408              :             else
     409              :             {
     410            2 :                 diagram_row = data_diagram_get_row( &((*this_).temp_diagram ) );
     411              :             }
     412            4 :             data_diagram_destroy( &((*this_).temp_diagram ) );
     413              :         }
     414              :     }
     415              : 
     416              :     /* check preconditions */
     417           14 :     if ( do_sync )
     418              :     {
     419            2 :         if ( node_classifier_id == DATA_ROW_VOID )
     420              :         {
     421            0 :             sync_error |= U8_ERROR_VALUE_OUT_OF_RANGE;
     422            0 :             U8_LOG_ERROR( "diagramelement references a non-existing classifier." );
     423              :         }
     424            2 :         if (( node_feature_id != DATA_ROW_VOID )&&( node_feature_type != DATA_FEATURE_TYPE_LIFELINE ))
     425              :         {
     426            0 :             sync_error |= U8_ERROR_VALUE_OUT_OF_RANGE;
     427            0 :             U8_LOG_ERROR( "diagramelement references a feature which is not of type DATA_FEATURE_TYPE_LIFELINE." );
     428              :         }
     429            2 :         if ( diagram_row == DATA_ROW_VOID )
     430              :         {
     431            0 :             sync_error |= U8_ERROR_VALUE_OUT_OF_RANGE;
     432            0 :             U8_LOG_ERROR( "diagramelement references a non-existing classifier." );
     433              :         }
     434              :     }
     435              : 
     436           14 :     if ( do_sync && ( sync_error == U8_ERROR_NONE ) )
     437              :     {
     438              :         /* check if the parsed diagramelement already exists in this database; if not, create it */
     439            2 :         data_diagramelement_init_empty( &((*this_).temp_diagramelement ) );
     440              :         const u8_error_t read_error4
     441            2 :             = data_database_reader_get_diagramelement_by_uuid( (*this_).db_reader,
     442              :                                                                data_diagramelement_get_uuid_const( diagramelement_ptr ),
     443              :                                                                &((*this_).temp_diagramelement)
     444              :                                                              );
     445            2 :         const bool diagramelement_exists = ( U8_ERROR_NONE == read_error4 );
     446              : 
     447            2 :         if ( diagramelement_exists )
     448              :         {
     449              :             /* do the statistics */
     450            0 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_IGNORED );
     451            0 :             U8_TRACE_INFO_INT( "diagramelement did already exist:", data_diagramelement_get_row( &((*this_).temp_diagramelement) ) );
     452              :         }
     453              :         else
     454              :         {
     455              :             /* link the classifier to the current diagram */
     456            2 :             sync_error = data_diagramelement_reinit( &((*this_).temp_diagramelement),
     457              :                                                      data_diagramelement_get_row( diagramelement_ptr ),
     458              :                                                      diagram_row,
     459              :                                                      node_classifier_id,
     460              :                                                      data_diagramelement_get_display_flags( diagramelement_ptr ),
     461              :                                                      node_feature_id,  /* focused_feature_id */
     462              :                                                      data_diagramelement_get_uuid_const( diagramelement_ptr )
     463              :                                                    );
     464              :             u8_error_t modified_info;
     465              :             data_id_t created_lifeline;
     466            2 :             sync_error |= ctrl_multi_step_changer_create_diagramelement( &((*this_).multi_step_changer),
     467              :                                                                          &((*this_).temp_diagramelement),
     468              :                                                                          &modified_info,
     469              :                                                                          &created_lifeline
     470              :                                                                        );
     471            2 :             if ( sync_error == U8_ERROR_NONE )
     472              :             {
     473            2 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED );
     474            2 :                 if ( data_id_is_valid( &created_lifeline ) )
     475              :                 {
     476            0 :                     data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_LIFELINE, DATA_STAT_SERIES_CREATED );
     477              :                 }
     478              :             }
     479              :             else
     480              :             {
     481            0 :                 U8_LOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagramelement" );
     482            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_ERROR );
     483              :             }
     484              :             (void) created_lifeline;  /* currently unused */
     485              : 
     486              :             /* write report in case of anomalies */
     487            2 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
     488              :             {
     489            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_WARNING );
     490            0 :                 io_import_elements_private_report_id_differs( this_,
     491              :                                                               data_diagramelement_get_data_id( diagramelement_ptr ),
     492            0 :                                                               data_diagramelement_get_data_id( &((*this_).temp_diagramelement ) )
     493              :                                                             );
     494              :             }
     495              :         }
     496            2 :         data_diagramelement_destroy( &((*this_).temp_diagramelement ) );
     497              :     }
     498              : 
     499           14 :     if ( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )
     500              :     {
     501              :         /* in paste mode, ignore diagramelements */
     502            8 :         data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_IGNORED );
     503              :     }
     504              : 
     505           14 :     U8_TRACE_END_ERR( sync_error );
     506           14 :     return sync_error;
     507              : }
     508              : 
     509           17 : u8_error_t io_import_elements_private_create_diagramelement( io_import_elements_t *this_, data_row_t classifier_id )
     510              : {
     511           17 :     U8_TRACE_BEGIN();
     512           17 :     assert( DATA_ROW_VOID != classifier_id );
     513           17 :     u8_error_t sync_error = U8_ERROR_NONE;
     514              : 
     515           17 :     if ( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )
     516              :     {
     517              :         /* link the classifier to the current diagram */
     518           17 :         data_diagramelement_init_new( &((*this_).temp_diagramelement ),
     519              :                                       (*this_).paste_to_diagram,
     520              :                                       classifier_id,
     521              :                                       DATA_DIAGRAMELEMENT_FLAG_NONE,
     522              :                                       DATA_ROW_VOID
     523              :                                     );
     524              :         u8_error_t modified_info;
     525              :         data_id_t created_lifeline;
     526           17 :         sync_error = ctrl_multi_step_changer_create_diagramelement( &((*this_).multi_step_changer),
     527              :                                                                     &((*this_).temp_diagramelement ),
     528              :                                                                     &modified_info,
     529              :                                                                     &created_lifeline
     530              :                                                                   );
     531           17 :         if ( sync_error == U8_ERROR_NONE )
     532              :         {
     533           17 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_CREATED );
     534           17 :             if ( data_id_is_valid( &created_lifeline ) )
     535              :             {
     536            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_LIFELINE, DATA_STAT_SERIES_CREATED );
     537              :             }
     538              :         }
     539              :         else
     540              :         {
     541            0 :             U8_LOG_ERROR( "unexpected error at ctrl_diagram_controller_create_diagramelement" );
     542            0 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_ERROR );
     543              :         }
     544              :         (void) created_lifeline;  /* currently unused */
     545              : 
     546           17 :         data_diagramelement_destroy( &((*this_).temp_diagramelement ) );
     547              :     }
     548              :     else
     549              :     {
     550            0 :         U8_TRACE_INFO_INT( "no diagramelement created for new classifier:", classifier_id );
     551              :     }
     552              : 
     553           17 :     U8_TRACE_END_ERR( sync_error );
     554           17 :     return sync_error;
     555              : }
     556              : 
     557           21 : u8_error_t io_import_elements_sync_classifier( io_import_elements_t *this_,
     558              :                                                const data_classifier_t *classifier_ptr )
     559              : {
     560           21 :     U8_TRACE_BEGIN();
     561           21 :     assert( NULL != classifier_ptr );
     562           21 :     u8_error_t sync_error = U8_ERROR_NONE;
     563           21 :     const bool do_sync = (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )||( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_L ));
     564              :     /* const bool do_check = ( (*this_).step == IO_IMPORT_STEP_CHECK ); */
     565              : 
     566           21 :     if ( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )
     567              :     {
     568           18 :         if ( (*this_).paste_to_diagram == DATA_ROW_VOID )
     569              :         {
     570            1 :             sync_error = U8_ERROR_FOCUS_EMPTY;
     571            1 :             U8_TRACE_INFO( "in paste-clipboard mode, parent diagram must be valid" );
     572              :         }
     573              :     }
     574              : 
     575           21 :     if ( do_sync &&( sync_error == U8_ERROR_NONE ))
     576              :     {
     577              :         /* check if the parsed classifier already exists in this database; if not, create it */
     578           18 :         data_classifier_init_empty( &((*this_).temp_classifier ) );
     579              :         const u8_error_t read_error
     580           18 :             = data_database_reader_get_classifier_by_uuid( (*this_).db_reader,
     581              :                                                            data_classifier_get_uuid_const( classifier_ptr ),
     582              :                                                            &((*this_).temp_classifier)
     583              :                                                          );
     584           18 :         const bool classifier_exists = ( U8_ERROR_NONE == read_error );
     585              : 
     586           18 :         if ( classifier_exists )
     587              :         {
     588              :             /* do the statistics */
     589            4 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_IGNORED );
     590            4 :             U8_TRACE_INFO_INT( "classifier did already exist:", data_classifier_get_row( &((*this_).temp_classifier) ) );
     591              :         }
     592              :         else
     593              :         {
     594           14 :             data_classifier_replace( &((*this_).temp_classifier ), classifier_ptr );
     595              : 
     596              :             u8_error_t modified_info;
     597           14 :             sync_error = ctrl_multi_step_changer_create_classifier( &((*this_).multi_step_changer),
     598              :                                                                     &((*this_).temp_classifier ),
     599              :                                                                     &modified_info
     600              :                                                                   );
     601           14 :             if ( sync_error == U8_ERROR_NONE )
     602              :             {
     603           14 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_CREATED );
     604              :             }
     605              :             else
     606              :             {
     607            0 :                 U8_LOG_ERROR( "unexpected error at ctrl_classifier_controller_create_classifier/feature" );
     608            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_ERROR );
     609              :             }
     610              : 
     611              :             /* write report in case of anomalies */
     612           14 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
     613              :             {
     614              :                 /* warn on changed classifier ids. */
     615            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_WARNING );
     616            0 :                 io_import_elements_private_report_id_differs( this_,
     617              :                                                               data_classifier_get_data_id( classifier_ptr ),
     618            0 :                                                               data_classifier_get_data_id( &((*this_).temp_classifier ) )
     619              :                                                             );
     620              :             }
     621           14 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_NAME ) )
     622              :             {
     623              :                 /* warn on changed classifier names. */
     624            3 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_WARNING );
     625            6 :                 io_import_elements_private_report_name_differs( this_,
     626              :                                                                 data_classifier_get_name_const( classifier_ptr ),
     627            3 :                                                                 data_classifier_get_name_const( &((*this_).temp_classifier ) )
     628              :                                                               );
     629              :             }
     630              :         }
     631              : 
     632           18 :         if (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )&&( sync_error == U8_ERROR_NONE ))
     633              :         {
     634              :             /* in paste mode, create a diagramelement in the current diagram */
     635              :             /* after IO_IMPORT_STEP_CREATE_D_C_F_R there comes no other step to perform this. */
     636           17 :             const data_row_t classifier_row = data_classifier_get_row( &((*this_).temp_classifier ) );
     637           17 :             sync_error = io_import_elements_private_create_diagramelement( this_, classifier_row );
     638              :         }
     639              : 
     640           18 :         data_classifier_destroy( &((*this_).temp_classifier ) );
     641              :     }
     642              : 
     643           21 :     U8_TRACE_END_ERR( sync_error );
     644           21 :     return sync_error;
     645              : }
     646              : 
     647           22 : u8_error_t io_import_elements_sync_feature( io_import_elements_t *this_,
     648              :                                             const data_feature_t *feature_ptr,
     649              :                                             const char *classifier_uuid )
     650              : {
     651           22 :     U8_TRACE_BEGIN();
     652           22 :     assert( NULL != feature_ptr );
     653           22 :     assert( NULL != classifier_uuid );
     654           22 :     u8_error_t sync_error = U8_ERROR_NONE;
     655              :     const bool is_lifeline
     656           22 :         = data_rules_feature_is_scenario_cond( &((*this_).data_rules), data_feature_get_main_type( feature_ptr ) );
     657           44 :     const bool do_sync = (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )
     658           22 :         ||( is_lifeline ? ( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_L ) : ( (*this_).step == IO_IMPORT_STEP_ADD_E_DP_F_R ) ));
     659           22 :     const bool do_check = ( (*this_).step == IO_IMPORT_STEP_CHECK );
     660              : 
     661              :     /* ANY MODE: determine classifier id */
     662           22 :     data_row_t classifier_row = DATA_ROW_VOID;
     663           22 :     if (( do_check || do_sync )&&( classifier_uuid != NULL ))
     664              :     {
     665           20 :         if ( ! utf8string_equals_str( classifier_uuid, "" ) )
     666              :         {
     667           20 :             data_classifier_init_empty( &((*this_).temp_classifier ) );
     668              :             const u8_error_t read_error1
     669           20 :                 = data_database_reader_get_classifier_by_uuid( (*this_).db_reader,
     670              :                                                                classifier_uuid,
     671              :                                                                &((*this_).temp_classifier)
     672              :                                                              );
     673           20 :             if ( read_error1 == U8_ERROR_NOT_FOUND )
     674              :             {
     675            2 :                 U8_TRACE_INFO_STR( "no classifier found, uuid:", classifier_uuid );
     676              :             }
     677           18 :             else if ( read_error1 != U8_ERROR_NONE )
     678              :             {
     679            0 :                 U8_TRACE_INFO_STR( "parent classifier not found:", classifier_uuid );
     680              :             }
     681              :             else
     682              :             {
     683           18 :                 classifier_row = data_classifier_get_row( &((*this_).temp_classifier ) );
     684              :             }
     685           20 :             data_classifier_destroy( &((*this_).temp_classifier ) );
     686              :         }
     687              :     }
     688              : 
     689              :     /* check preconditions */
     690           22 :     if ( do_sync )
     691              :     {
     692           18 :         if ( classifier_row == DATA_ROW_VOID )
     693              :         {
     694            0 :             sync_error |= U8_ERROR_VALUE_OUT_OF_RANGE;
     695            0 :             U8_LOG_ERROR( "feature references a non-existing classifier." );
     696              :         }
     697              :     }
     698              : 
     699           22 :     if ( do_sync && ( sync_error == U8_ERROR_NONE ) )
     700              :     {
     701              :         /* check if the parsed feature already exists in this database; if not, create it */
     702           18 :         data_feature_init_empty( &((*this_).temp_feature ) );
     703              :         const u8_error_t read_error
     704           18 :             = data_database_reader_get_feature_by_uuid( (*this_).db_reader,
     705              :                                                         data_feature_get_uuid_const( feature_ptr ),
     706              :                                                         &((*this_).temp_feature)
     707              :                                                       );
     708           18 :         data_feature_destroy( &((*this_).temp_feature ) );
     709           18 :         const bool feature_exists = ( U8_ERROR_NONE == read_error );
     710              : 
     711           18 :         if ( feature_exists )
     712              :         {
     713              :             /* update statistics */
     714            2 :             const data_feature_type_t feat_type = data_feature_get_main_type( &((*this_).temp_feature) );
     715            2 :             const data_stat_table_t feat_or_lifeline
     716            2 :                 = ( feat_type == DATA_FEATURE_TYPE_LIFELINE ) ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE;
     717            2 :             data_stat_inc_count( (*this_).stat, feat_or_lifeline, DATA_STAT_SERIES_IGNORED );
     718              :         }
     719              :         else
     720              :         {
     721              :             /* filter lifelines */
     722           16 :             if (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )&&( is_lifeline ))
     723              :             {
     724              :                 /* lifeline in paste mode */
     725            8 :                 data_stat_inc_count( (*this_).stat,
     726              :                                      DATA_STAT_TABLE_LIFELINE, /* is_lifeline is true */
     727              :                                      DATA_STAT_SERIES_IGNORED
     728              :                                    );
     729            8 :                 U8_TRACE_INFO( "lifeline dropped at json import." );
     730              :             }
     731              :             else
     732              :             {
     733              :                 /* create feature */
     734            8 :                 data_feature_copy( &((*this_).temp_feature ), feature_ptr );
     735            8 :                 data_feature_set_classifier_row( &((*this_).temp_feature ), classifier_row );
     736              : 
     737              :                 u8_error_t modified_info;
     738              :                 const u8_error_t create_err
     739            8 :                     = ctrl_multi_step_changer_create_feature( &((*this_).multi_step_changer),
     740              :                                                               &((*this_).temp_feature ),
     741              :                                                               &modified_info
     742              :                                                             );
     743              : 
     744            8 :                 if ( create_err == U8_ERROR_DIAGRAM_HIDES_FEATURES )
     745              :                 {
     746              :                     /* add to ignored and to warning. */
     747              :                     /* ignored is needed for correct statistics */
     748              :                     /* warning is needed to indicate that this may be different from expectation */
     749            0 :                     data_stat_inc_count( (*this_).stat,
     750              :                                          is_lifeline ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE,
     751              :                                          DATA_STAT_SERIES_IGNORED
     752              :                                        );
     753            0 :                     data_stat_inc_count( (*this_).stat,
     754              :                                          is_lifeline ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE,
     755              :                                          DATA_STAT_SERIES_WARNING
     756              :                                        );
     757            0 :                     U8_LOG_WARNING( "invisible feature dropped at reading from data stream" );
     758              :                 }
     759            8 :                 else if ( create_err != U8_ERROR_NONE )
     760              :                 {
     761            0 :                     data_stat_inc_count( (*this_).stat,
     762              :                                          is_lifeline ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE,
     763              :                                          DATA_STAT_SERIES_ERROR
     764              :                                        );
     765            0 :                     sync_error |= create_err;
     766              :                 }
     767              :                 else
     768              :                 {
     769            8 :                     data_stat_inc_count( (*this_).stat,
     770              :                                          is_lifeline ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE,
     771              :                                          DATA_STAT_SERIES_CREATED
     772              :                                        );
     773              :                 }
     774            8 :                 if ( sync_error != U8_ERROR_NONE )
     775              :                 {
     776            0 :                     U8_LOG_ERROR( "unexpected error at ctrl_classifier_controller_create_feature" );
     777              :                 }
     778              : 
     779              :                 /* write report in case of anomalies */
     780            8 :                 if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
     781              :                 {
     782            0 :                     data_stat_inc_count( (*this_).stat,
     783              :                                          is_lifeline ? DATA_STAT_TABLE_LIFELINE : DATA_STAT_TABLE_FEATURE,
     784              :                                          DATA_STAT_SERIES_WARNING
     785              :                                        );
     786            0 :                     io_import_elements_private_report_id_differs( this_,
     787              :                                                                   data_feature_get_data_id( feature_ptr ),
     788            0 :                                                                   data_feature_get_data_id( &((*this_).temp_feature ) )
     789              :                                                                 );
     790              :                 }
     791              : 
     792            8 :                 data_feature_destroy( &((*this_).temp_feature ) );
     793              :             }
     794              :         }
     795              :     }
     796              : 
     797           22 :     U8_TRACE_END_ERR( sync_error );
     798           22 :     return sync_error;
     799              : }
     800              : 
     801           14 : u8_error_t io_import_elements_sync_relationship( io_import_elements_t *this_,
     802              :                                                  const data_relationship_t *relation_ptr,
     803              :                                                  const char *from_node_uuid,
     804              :                                                  const char *to_node_uuid )
     805              : {
     806           14 :     U8_TRACE_BEGIN();
     807           14 :     assert( NULL != relation_ptr );
     808           14 :     assert( NULL != from_node_uuid );
     809           14 :     assert( NULL != to_node_uuid );
     810           14 :     u8_error_t sync_error = U8_ERROR_NONE;
     811           14 :     const bool do_sync = (( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )||( (*this_).step == IO_IMPORT_STEP_ADD_E_DP_F_R ));
     812           14 :     const bool do_check = ( (*this_).step == IO_IMPORT_STEP_CHECK );
     813              : 
     814              :     /* ANY MODE: determine from classifier/feature */
     815           14 :     data_row_t from_classifier_id = DATA_ROW_VOID;
     816           14 :     data_row_t from_feature_id = DATA_ROW_VOID;
     817           14 :     data_feature_type_t from_feature_type = DATA_FEATURE_TYPE_VOID;
     818           14 :     if (( do_check || do_sync )&&( from_node_uuid != NULL ))
     819              :     {
     820           13 :         if ( ! utf8string_equals_str( from_node_uuid, "" ) )
     821              :         {
     822              :             /* search source classifier id */
     823           13 :             data_classifier_init_empty( &((*this_).temp_classifier ) );
     824              :             const u8_error_t read_error1
     825           13 :                 = data_database_reader_get_classifier_by_uuid( (*this_).db_reader,
     826              :                                                                from_node_uuid,
     827              :                                                                &((*this_).temp_classifier)
     828              :                                                              );
     829           13 :             if ( U8_ERROR_NONE == read_error1 )
     830              :             {
     831            8 :                 from_classifier_id = data_classifier_get_row( &((*this_).temp_classifier) );
     832            8 :                 U8_TRACE_INFO_STR( "id found for src classifier:", from_node_uuid );
     833              :             }
     834              :             else
     835              :             {
     836              :                 /* search source feature id */
     837            5 :                 data_feature_init_empty( &((*this_).temp_feature) );
     838              :                 const u8_error_t read_error2
     839            5 :                     = data_database_reader_get_feature_by_uuid( (*this_).db_reader,
     840              :                                                                 from_node_uuid,
     841              :                                                                 &((*this_).temp_feature)
     842              :                                                               );
     843            5 :                 if ( U8_ERROR_NONE == read_error2 )
     844              :                 {
     845            1 :                     from_classifier_id = data_feature_get_classifier_row( &((*this_).temp_feature) );
     846            1 :                     from_feature_id = data_feature_get_row( &((*this_).temp_feature) );
     847            1 :                     from_feature_type = data_feature_get_main_type( &((*this_).temp_feature) );
     848            1 :                     U8_TRACE_INFO_STR( "id found for src feature:", from_node_uuid );
     849              :                 }
     850              :                 else
     851              :                 {
     852            4 :                     U8_TRACE_INFO_STR( "relationship source not found", from_node_uuid );
     853              :                 }
     854            5 :                 data_feature_destroy( &((*this_).temp_feature) );
     855              :             }
     856           13 :             data_classifier_destroy( &((*this_).temp_classifier ) );
     857              :         }
     858              :     }
     859              : 
     860              :     /* ANY MODE: determine to classifier/feature */
     861           14 :     data_row_t to_classifier_id = DATA_ROW_VOID;
     862           14 :     data_row_t to_feature_id = DATA_ROW_VOID;
     863           14 :     data_feature_type_t to_feature_type = DATA_FEATURE_TYPE_VOID;
     864           14 :     if (( do_check || do_sync )&&( to_node_uuid != NULL ))
     865              :     {
     866           13 :         if ( ! utf8string_equals_str( to_node_uuid, "" ) )
     867              :         {
     868              :             /* search destination classifier id */
     869           13 :             data_classifier_init_empty( &((*this_).temp_classifier ) );
     870              :             const u8_error_t read_error3
     871           13 :                 = data_database_reader_get_classifier_by_uuid( (*this_).db_reader,
     872              :                                                                to_node_uuid,
     873              :                                                                &((*this_).temp_classifier)
     874              :                                                              );
     875           13 :             if ( U8_ERROR_NONE == read_error3 )
     876              :             {
     877            7 :                 to_classifier_id = data_classifier_get_row( &((*this_).temp_classifier) );
     878            7 :                 U8_TRACE_INFO_STR( "id found for dst classifier:", to_node_uuid );
     879              :             }
     880              :             else
     881              :             {
     882              :                 /* search dst feature id */
     883            6 :                 data_feature_init_empty( &((*this_).temp_feature) );
     884              :                 const u8_error_t read_error4
     885            6 :                     = data_database_reader_get_feature_by_uuid( (*this_).db_reader,
     886              :                                                                 to_node_uuid,
     887              :                                                                 &((*this_).temp_feature)
     888              :                                                               );
     889            6 :                 if ( U8_ERROR_NONE == read_error4 )
     890              :                 {
     891            2 :                     to_classifier_id = data_feature_get_classifier_row( &((*this_).temp_feature) );
     892            2 :                     to_feature_id = data_feature_get_row( &((*this_).temp_feature) );
     893            2 :                     to_feature_type = data_feature_get_main_type( &((*this_).temp_feature) );
     894            2 :                     U8_TRACE_INFO_STR( "id found for src feature:", to_node_uuid );
     895              :                 }
     896              :                 else
     897              :                 {
     898            4 :                     U8_TRACE_INFO_STR( "relationship destination not found", to_node_uuid );
     899              :                 }
     900            6 :                 data_feature_destroy( &((*this_).temp_feature) );
     901              :             }
     902           13 :             data_classifier_destroy( &((*this_).temp_classifier ) );
     903              :         }
     904              :     }
     905              : 
     906              :     /* check preconditions */
     907           14 :     bool valid_links = true;
     908           14 :     if ( do_sync )
     909              :     {
     910           12 :         if ( from_classifier_id == DATA_ROW_VOID )
     911              :         {
     912            3 :             valid_links = false;
     913            3 :             U8_LOG_ERROR( "A relationship could not be created because the source classifier could not be found." );
     914              :         }
     915           12 :         if ( to_classifier_id == DATA_ROW_VOID )
     916              :         {
     917            3 :             valid_links = false;
     918            3 :             U8_LOG_ERROR( "A relationship could not be created because the destination classifier could not be found." );
     919              :         }
     920           12 :         if ( ! valid_links )
     921              :         {
     922            3 :             const bool is_scenario = data_rules_relationship_is_scenario_cond( &((*this_).data_rules),
     923              :                                                                                from_feature_type,
     924              :                                                                                to_feature_type
     925              :                                                                              );
     926            3 :             U8_TRACE_INFO( is_scenario ? "relationship in interaction scenario dropped" : "general relationship dropped" );
     927              : 
     928            3 :             const bool features_ignored
     929            3 :                 = ( 0 < data_stat_get_count( (*this_).stat, DATA_STAT_TABLE_FEATURE, DATA_STAT_SERIES_IGNORED ) )
     930            3 :                 || ( 0 < data_stat_get_count( (*this_).stat, DATA_STAT_TABLE_LIFELINE, DATA_STAT_SERIES_IGNORED ) );
     931            3 :                 if ( features_ignored )
     932              :             {
     933            3 :                 U8_TRACE_INFO( "continuing despite illegal relationship because this may be caused by an invisible feature/lifeline" );
     934              :                 /* add to ignored and to warning. */
     935              :                 /* ignored is needed for correct statistics */
     936              :                 /* warning is needed to indicate that this may be different from expectation */
     937            3 :                 data_stat_inc_count( (*this_).stat,
     938              :                                      DATA_STAT_TABLE_RELATIONSHIP,
     939              :                                      DATA_STAT_SERIES_IGNORED
     940              :                                    );
     941            3 :                 data_stat_inc_count( (*this_).stat,
     942              :                                      DATA_STAT_TABLE_RELATIONSHIP,
     943              :                                      DATA_STAT_SERIES_WARNING
     944              :                                    );
     945              :             }
     946            0 :             else if ( (*this_).step == IO_IMPORT_STEP_CREATE_D_C_F_R )
     947              :             {
     948            0 :                 U8_TRACE_INFO( "continuing despite illegal relationship because this may be caused by incomplete model" );
     949              :                 /* add to ignored and warning. */
     950              :                 /* ignored is needed for correct statistics */
     951              :                 /* warning is needed to indicate that this may be different from expectation */
     952            0 :                 data_stat_inc_count( (*this_).stat,
     953              :                                      DATA_STAT_TABLE_RELATIONSHIP,
     954              :                                      DATA_STAT_SERIES_IGNORED
     955              :                                    );
     956            0 :                 data_stat_inc_count( (*this_).stat,
     957              :                                      DATA_STAT_TABLE_RELATIONSHIP,
     958              :                                      DATA_STAT_SERIES_WARNING
     959              :                                    );
     960              :             }
     961              :             else
     962              :             {
     963            0 :                 sync_error |= U8_ERROR_VALUE_OUT_OF_RANGE;
     964              :             }
     965              :         }
     966              :     }
     967              : 
     968           14 :     if ( do_sync && valid_links )
     969              :     {
     970              :         /* check if the parsed relationship already exists in this database; if not, create it */
     971            9 :         data_relationship_init_empty( &((*this_).temp_relationship ) );
     972              :         const u8_error_t read_error5
     973            9 :             = data_database_reader_get_relationship_by_uuid( (*this_).db_reader,
     974              :                                                              data_relationship_get_uuid_const( relation_ptr ),
     975              :                                                              &((*this_).temp_relationship)
     976              :                                                            );
     977            9 :         data_relationship_destroy( &((*this_).temp_relationship ) );
     978            9 :         const bool relationship_exists = ( U8_ERROR_NONE == read_error5 );
     979              : 
     980            9 :         if ( relationship_exists )
     981              :         {
     982              :             /* update statistics */
     983            1 :             data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_IGNORED );
     984              :         }
     985              :         else
     986              :         {
     987              :             /* create relationship */
     988            8 :             data_relationship_copy( &((*this_).temp_relationship ), relation_ptr );
     989            8 :             data_relationship_set_row( &((*this_).temp_relationship ), data_relationship_get_row( relation_ptr ) );
     990            8 :             data_relationship_set_from_classifier_row( &((*this_).temp_relationship ), from_classifier_id );
     991            8 :             data_relationship_set_from_feature_row( &((*this_).temp_relationship ), from_feature_id );
     992            8 :             data_relationship_set_to_classifier_row( &((*this_).temp_relationship ), to_classifier_id );
     993            8 :             data_relationship_set_to_feature_row( &((*this_).temp_relationship ), to_feature_id );
     994              : 
     995              :             /* create relationship */
     996              :             u8_error_t modified_info;
     997              :             const u8_error_t create_err
     998            8 :                 = ctrl_multi_step_changer_create_relationship( &((*this_).multi_step_changer),
     999              :                                                                &((*this_).temp_relationship ),
    1000              :                                                                &modified_info
    1001              :                                                              );
    1002            8 :             if ( create_err == U8_ERROR_DIAGRAM_HIDES_RELATIONSHIPS )
    1003              :             {
    1004              :                 /* add to ignored and to warning. */
    1005              :                 /* ignored is needed for correct statistics */
    1006              :                 /* warning is needed to indicate that this may be different from expectation */
    1007            0 :                 data_stat_inc_count( (*this_).stat,
    1008              :                                      DATA_STAT_TABLE_RELATIONSHIP,
    1009              :                                      DATA_STAT_SERIES_IGNORED
    1010              :                                    );
    1011            0 :                 data_stat_inc_count( (*this_).stat,
    1012              :                                      DATA_STAT_TABLE_RELATIONSHIP,
    1013              :                                      DATA_STAT_SERIES_WARNING
    1014              :                                    );
    1015            0 :                 U8_LOG_WARNING( "invisible relationship dropped at reading from data stream" );
    1016              :             }
    1017            8 :             else if ( create_err != U8_ERROR_NONE )
    1018              :             {
    1019            0 :                 U8_LOG_ERROR( "unexpected error at ctrl_classifier_controller_create_relationship" );
    1020            0 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR );
    1021            0 :                 sync_error |= create_err;
    1022              :             }
    1023              :             else
    1024              :             {
    1025            8 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_CREATED );
    1026              :             }
    1027              : 
    1028              :             /* write report in case of anomalies */
    1029            8 :             if ( u8_error_contains( modified_info, U8_ERROR_DUPLICATE_ID ) )
    1030              :             {
    1031            2 :                 data_stat_inc_count( (*this_).stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_WARNING );
    1032            4 :                 io_import_elements_private_report_id_differs( this_,
    1033              :                                                               data_relationship_get_data_id( relation_ptr ),
    1034            2 :                                                               data_relationship_get_data_id( &((*this_).temp_relationship ) )
    1035              :                                                             );
    1036              :             }
    1037              : 
    1038            8 :             data_relationship_destroy( &((*this_).temp_relationship ) );
    1039              :         }
    1040              :     }
    1041              : 
    1042           14 :     U8_TRACE_END_ERR( sync_error );
    1043           14 :     return sync_error;
    1044              : }
    1045              : 
    1046            2 : void io_import_elements_private_report_id_differs( io_import_elements_t *this_, data_id_t req_id, data_id_t act_id )
    1047              : {
    1048            2 :     U8_TRACE_BEGIN();
    1049            2 :     u8_error_t report_err = U8_ERROR_NONE;
    1050              : 
    1051            2 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, "Id changed: " );
    1052            2 :     report_err |= data_id_to_utf8_writer( &req_id, (*this_).english_report );
    1053            2 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, " -> " );
    1054            2 :     report_err |= data_id_to_utf8_writer( &act_id, (*this_).english_report );
    1055            2 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, ", " );
    1056            2 :     if ( report_err != U8_ERROR_NONE )
    1057              :     {
    1058            0 :         U8_LOG_ERROR_HEX( "Could not write report on import, ERR:", report_err );
    1059              :     }
    1060              : 
    1061            2 :     U8_TRACE_END();
    1062            2 : }
    1063              : 
    1064            3 : void io_import_elements_private_report_name_differs( io_import_elements_t *this_, const char *req_name, const char *act_name )
    1065              : {
    1066            3 :     U8_TRACE_BEGIN();
    1067            3 :     assert( NULL != req_name );
    1068            3 :     assert( NULL != act_name );
    1069            3 :     u8_error_t report_err = U8_ERROR_NONE;
    1070              : 
    1071            3 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, "Name changed: \"" );
    1072            3 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, req_name );
    1073            3 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, "\" -> \"" );
    1074            3 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, act_name );
    1075            3 :     report_err |= utf8stream_writer_write_str( (*this_).english_report, "\", " );
    1076            3 :     if ( report_err != U8_ERROR_NONE )
    1077              :     {
    1078            0 :         U8_LOG_ERROR_HEX( "Could not write report on import, ERR:", report_err );
    1079              :     }
    1080              : 
    1081            3 :     U8_TRACE_END();
    1082            3 : }
    1083              : 
    1084              : 
    1085              : /*
    1086              : Copyright 2021-2026 Andreas Warnke
    1087              : 
    1088              : Licensed under the Apache License, Version 2.0 (the "License");
    1089              : you may not use this file except in compliance with the License.
    1090              : You may obtain a copy of the License at
    1091              : 
    1092              :     http://www.apache.org/licenses/LICENSE-2.0
    1093              : 
    1094              : Unless required by applicable law or agreed to in writing, software
    1095              : distributed under the License is distributed on an "AS IS" BASIS,
    1096              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1097              : See the License for the specific language governing permissions and
    1098              : limitations under the License.
    1099              : */
        

Generated by: LCOV version 2.0-1