*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_FILE_STATUS
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_file_status DEFINITION
*----------------------------------------------------------------------*
CLASS ltcl_file_status DEFINITION DEFERRED.
CLASS ltcl_file_status2 DEFINITION DEFERRED.

CLASS lcl_file_status DEFINITION FINAL
  FRIENDS ltcl_file_status ltcl_file_status2.

  PUBLIC SECTION.

    CLASS-METHODS status
      IMPORTING io_repo           TYPE REF TO lcl_repo
                io_log            TYPE REF TO lcl_log OPTIONAL
      RETURNING VALUE(rt_results) TYPE ty_results_tt
      RAISING   lcx_exception.

  PRIVATE SECTION.

    CLASS-METHODS:
      calculate_status
        IMPORTING iv_devclass       TYPE devclass
                  it_local          TYPE ty_files_item_tt
                  it_remote         TYPE ty_files_tt
                  it_cur_state      TYPE ty_file_signatures_tt
        RETURNING VALUE(rt_results) TYPE ty_results_tt,
      run_checks
        IMPORTING io_log     TYPE REF TO lcl_log
                  it_results TYPE ty_results_tt
                  io_dot     TYPE REF TO lcl_dot_abapgit
                  iv_top     TYPE devclass
        RAISING   lcx_exception,
      build_existing
        IMPORTING is_local         TYPE ty_file_item
                  is_remote        TYPE ty_file
                  it_state         TYPE ty_file_signatures_ts
        RETURNING VALUE(rs_result) TYPE ty_result,
      build_new_local
        IMPORTING is_local         TYPE ty_file_item
        RETURNING VALUE(rs_result) TYPE ty_result,
      build_new_remote
        IMPORTING iv_devclass      TYPE devclass
                  is_remote        TYPE ty_file
                  it_items         TYPE ty_items_ts
                  it_state         TYPE ty_file_signatures_ts
        RETURNING VALUE(rs_result) TYPE ty_result,
      identify_object
        IMPORTING iv_filename TYPE string
        EXPORTING es_item     TYPE ty_item
                  ev_is_xml   TYPE abap_bool.

ENDCLASS.                    "lcl_file_status DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_file_status IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_file_status IMPLEMENTATION.

  METHOD run_checks.

    DATA: lv_path     TYPE string,
          ls_item     TYPE ty_item,
          ls_file     TYPE ty_file_signature,
          lt_res_sort LIKE it_results,
          lt_item_idx LIKE it_results.

    FIELD-SYMBOLS: <ls_res1> LIKE LINE OF it_results,
                   <ls_res2> LIKE LINE OF it_results.

    IF io_log IS INITIAL.
      RETURN.
    ENDIF.

    " Collect object indexe
    lt_res_sort = it_results.
    SORT lt_res_sort BY obj_type ASCENDING obj_name ASCENDING.

    LOOP AT it_results ASSIGNING <ls_res1> WHERE NOT obj_type IS INITIAL.
      IF NOT ( <ls_res1>-obj_type = ls_item-obj_type
          AND <ls_res1>-obj_name = ls_item-obj_name ).
        APPEND INITIAL LINE TO lt_item_idx ASSIGNING <ls_res2>.
        <ls_res2>-obj_type = <ls_res1>-obj_type.
        <ls_res2>-obj_name = <ls_res1>-obj_name.
        <ls_res2>-path     = <ls_res1>-path.
        MOVE-CORRESPONDING <ls_res1> TO ls_item.
      ENDIF.
    ENDLOOP.

    " Check files for one object is in the same folder

    LOOP AT it_results ASSIGNING <ls_res1> WHERE NOT obj_type IS INITIAL.
      READ TABLE lt_item_idx ASSIGNING <ls_res2>
        WITH KEY obj_type = <ls_res1>-obj_type obj_name = <ls_res1>-obj_name
        BINARY SEARCH. " Sorted above

      IF sy-subrc <> 0 OR <ls_res1>-path <> <ls_res2>-path. " All paths are same
        io_log->add( iv_msg = |Files for object { <ls_res1>-obj_type }{
                       <ls_res1>-obj_name }are not placed in the same folder|
                     iv_type = 'W'
                     iv_rc    = '1' ) ##no_text.
      ENDIF.
    ENDLOOP.

    " Check that objects are created in package corresponding to folder
    LOOP AT it_results ASSIGNING <ls_res1>
        WHERE NOT package IS INITIAL AND NOT path IS INITIAL.
      lv_path = lcl_folder_logic=>package_to_path( iv_top     = iv_top
                                                   io_dot     = io_dot
                                                   iv_package = <ls_res1>-package ).
      IF lv_path <> <ls_res1>-path.
        io_log->add( iv_msg = |Package and path does not match for object, {
                       <ls_res1>-obj_type } { <ls_res1>-obj_name }|
                     iv_type = 'W'
                     iv_rc    = '2' ) ##no_text.
      ENDIF.
    ENDLOOP.

    " Check for multiple files with same filename
    SORT lt_res_sort BY filename ASCENDING.

    LOOP AT lt_res_sort ASSIGNING <ls_res1>.
      IF <ls_res1>-filename IS NOT INITIAL AND <ls_res1>-filename = ls_file-filename.
        io_log->add( iv_msg  = |Multiple files with same filename, { <ls_res1>-filename }|
                     iv_type = 'W'
                     iv_rc   = '3' ) ##no_text.
      ENDIF.

      IF <ls_res1>-filename IS INITIAL.
        io_log->add( iv_msg  = |Filename is empty for object { <ls_res1>-obj_type } { <ls_res1>-obj_name }|
                     iv_type = 'W'
                     iv_rc   = '4' ) ##no_text.
      ENDIF.

      MOVE-CORRESPONDING <ls_res1> TO ls_file.
    ENDLOOP.

  ENDMETHOD.                    "check

  METHOD status.

    DATA: lv_index       LIKE sy-tabix,
          lo_dot_abapgit TYPE REF TO lcl_dot_abapgit.

    FIELD-SYMBOLS <ls_result> LIKE LINE OF rt_results.

    rt_results = calculate_status(
      iv_devclass  = io_repo->get_package( )
      it_local     = io_repo->get_files_local( io_log = io_log )
      it_remote    = io_repo->get_files_remote( )
      it_cur_state = io_repo->get_local_checksums_per_file( ) ).

    lo_dot_abapgit = io_repo->get_dot_abapgit( ).

    " Remove ignored files, fix .abapgit
    LOOP AT rt_results ASSIGNING <ls_result>.
      lv_index = sy-tabix.

      IF lo_dot_abapgit->is_ignored(
          iv_path     = <ls_result>-path
          iv_filename = <ls_result>-filename ) = abap_true.
        DELETE rt_results INDEX lv_index.
      ENDIF.
    ENDLOOP.

    run_checks(
      io_log     = io_log
      it_results = rt_results
      io_dot     = lo_dot_abapgit
      iv_top     = io_repo->get_package( ) ).

  ENDMETHOD.  "status

  METHOD calculate_status.

    DATA: lt_remote    LIKE it_remote,
          lt_items     TYPE ty_items_tt,
          ls_item      LIKE LINE OF lt_items,
          lv_is_xml    TYPE abap_bool,
          lt_items_idx TYPE ty_items_ts,
          lt_state_idx TYPE ty_file_signatures_ts. " Sorted by path+filename

    FIELD-SYMBOLS: <ls_remote> LIKE LINE OF it_remote,
                   <ls_result> LIKE LINE OF rt_results,
                   <ls_local>  LIKE LINE OF it_local.

    lt_state_idx = it_cur_state. " Force sort it
    lt_remote    = it_remote.
    SORT lt_remote BY path filename.

    " Process local files and new local files
    LOOP AT it_local ASSIGNING <ls_local>.
      APPEND INITIAL LINE TO rt_results ASSIGNING <ls_result>.
      IF <ls_local>-item IS NOT INITIAL.
        APPEND <ls_local>-item TO lt_items. " Collect for item index
      ENDIF.

      READ TABLE lt_remote ASSIGNING <ls_remote>
        WITH KEY path = <ls_local>-file-path filename = <ls_local>-file-filename
        BINARY SEARCH.
      IF sy-subrc = 0.  " Exist local and remote
        <ls_result> = build_existing(
          is_local  = <ls_local>
          is_remote = <ls_remote>
          it_state  = lt_state_idx ).
        ASSERT <ls_remote>-sha1 IS NOT INITIAL.
        CLEAR <ls_remote>-sha1. " Mark as processed
      ELSE.             " Only L exists
        <ls_result> = build_new_local( is_local = <ls_local> ).
      ENDIF.
    ENDLOOP.

    " Complete item index for unmarked remote files
    LOOP AT lt_remote ASSIGNING <ls_remote> WHERE sha1 IS NOT INITIAL.
      identify_object( EXPORTING iv_filename = <ls_remote>-filename
                       IMPORTING es_item     = ls_item
                                 ev_is_xml   = lv_is_xml ).

      CHECK lv_is_xml = abap_true. " Skip all but obj definitions

      ls_item-devclass = lcl_tadir=>get_object_package(
                           iv_object   = ls_item-obj_type
                           iv_obj_name = ls_item-obj_name ).
      APPEND ls_item TO lt_items.
    ENDLOOP.

    SORT lt_items. " Default key - type, name, pkg
    DELETE ADJACENT DUPLICATES FROM lt_items.
    lt_items_idx = lt_items. " Self protection + UNIQUE records assertion

    " Process new remote files (marked above with empty SHA1)
    LOOP AT lt_remote ASSIGNING <ls_remote> WHERE sha1 IS NOT INITIAL.
      APPEND INITIAL LINE TO rt_results ASSIGNING <ls_result>.
      <ls_result> = build_new_remote( iv_devclass = iv_devclass
                                      is_remote   = <ls_remote>
                                      it_items    = lt_items_idx
                                      it_state    = lt_state_idx ).
    ENDLOOP.

    SORT rt_results BY
      obj_type ASCENDING
      obj_name ASCENDING
      filename ASCENDING.

  ENDMETHOD.  "calculate_status.

  METHOD identify_object.

    DATA: lv_name TYPE tadir-obj_name,
          lv_type TYPE string,
          lv_ext  TYPE string.

    " Guess object type and name
    SPLIT to_upper( iv_filename ) AT '.' INTO lv_name lv_type lv_ext.

    " Handle namespaces
    REPLACE ALL OCCURRENCES OF '#' IN lv_name WITH '/'.
    REPLACE ALL OCCURRENCES OF '#' IN lv_type WITH '/'.
    REPLACE ALL OCCURRENCES OF '#' IN lv_ext WITH '/'.

    CLEAR es_item.
    es_item-obj_type = lv_type.
    es_item-obj_name = lv_name.
    ev_is_xml        = boolc( lv_ext = 'XML' AND strlen( lv_type ) = 4 ).

  ENDMETHOD.  "identify_object.

  METHOD build_existing.

    DATA: ls_file_sig LIKE LINE OF it_state.

    " Item
    rs_result-obj_type = is_local-item-obj_type.
    rs_result-obj_name = is_local-item-obj_name.
    rs_result-package  = is_local-item-devclass.

    " File
    rs_result-path     = is_local-file-path.
    rs_result-filename = is_local-file-filename.

    " Match against current state
    READ TABLE it_state INTO ls_file_sig
      WITH KEY path = is_local-file-path
      filename = is_local-file-filename
      BINARY SEARCH.

    IF sy-subrc = 0.
      IF ls_file_sig-sha1 <> is_local-file-sha1.
        rs_result-lstate = gc_state-modified.
      ENDIF.
      IF ls_file_sig-sha1 <> is_remote-sha1.
        rs_result-rstate = gc_state-modified.
      ENDIF.
      rs_result-match = boolc( rs_result-lstate IS INITIAL
        AND rs_result-rstate IS INITIAL ).
    ELSE.
      " This is a strange situation. As both local and remote exist
      " the state should also be present. Maybe this is a first run of the code.
      " In this case just compare hashes directly and mark both changed
      " the user will presumably decide what to do after checking the actual diff
      rs_result-match = boolc( is_local-file-sha1 = is_remote-sha1 ).
      IF rs_result-match = abap_false.
        rs_result-lstate = gc_state-modified.
        rs_result-rstate = gc_state-modified.
      ENDIF.
    ENDIF.

  ENDMETHOD.  "build_existing

  METHOD build_new_local.

    " Item
    rs_result-obj_type = is_local-item-obj_type.
    rs_result-obj_name = is_local-item-obj_name.
    rs_result-package  = is_local-item-devclass.

    " File
    rs_result-path     = is_local-file-path.
    rs_result-filename = is_local-file-filename.

    " Match
    rs_result-match    = abap_false.
    rs_result-lstate   = gc_state-added.

  ENDMETHOD.  "build_new_local

  METHOD build_new_remote.

    DATA: ls_item     LIKE LINE OF it_items,
          ls_file_sig LIKE LINE OF it_state.

    " Common and default part
    rs_result-path     = is_remote-path.
    rs_result-filename = is_remote-filename.
    rs_result-match    = abap_false.
    rs_result-rstate   = gc_state-added.

    identify_object( EXPORTING iv_filename = is_remote-filename
                     IMPORTING es_item     = ls_item ).

    " Check if in item index + get package
    READ TABLE it_items INTO ls_item
      WITH KEY obj_type = ls_item-obj_type obj_name = ls_item-obj_name
      BINARY SEARCH.

    IF sy-subrc = 0.

      " Completely new (xml, abap) and new file in an existing object
      rs_result-obj_type = ls_item-obj_type.
      rs_result-obj_name = ls_item-obj_name.
      rs_result-package  = ls_item-devclass.

      READ TABLE it_state INTO ls_file_sig
        WITH KEY path = is_remote-path filename = is_remote-filename
        BINARY SEARCH.

      " Existing file but from another package
      " was not added during local file proc as was not in tadir for repo package
      IF sy-subrc = 0.
        IF ls_file_sig-sha1 = is_remote-sha1.
          rs_result-match = abap_true.
          CLEAR rs_result-rstate.
        ELSE.
          rs_result-rstate = gc_state-modified.
        ENDIF.

        " Item is in state and in cache but with no package - it was deleted
        " OR devclass is the same as repo package (see #532)
        IF ls_item-devclass IS INITIAL OR ls_item-devclass = iv_devclass.
          rs_result-match  = abap_false.
          rs_result-lstate = gc_state-deleted.
        ENDIF.
      ENDIF.

    ELSE. " Completely unknown file, probably non-abapgit
      ASSERT 1 = 1. " No action, just follow defaults
    ENDIF.

  ENDMETHOD.  "build_new_remote

ENDCLASS.                    "lcl_file_status IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_FILE_STATUS
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_file_status DEFINITION
*----------------------------------------------------------------------*
CLASS ltcl_file_status DEFINITION DEFERRED.
CLASS ltcl_file_status2 DEFINITION DEFERRED.

CLASS lcl_file_status DEFINITION FINAL
  FRIENDS ltcl_file_status ltcl_file_status2.

  PUBLIC SECTION.

    CLASS-METHODS status
      IMPORTING io_repo           TYPE REF TO lcl_repo
                io_log            TYPE REF TO lcl_log OPTIONAL
      RETURNING VALUE(rt_results) TYPE ty_results_tt
      RAISING   lcx_exception.

  PRIVATE SECTION.

    CLASS-METHODS:
      calculate_status
        IMPORTING iv_devclass       TYPE devclass
                  it_local          TYPE ty_files_item_tt
                  it_remote         TYPE ty_files_tt
                  it_cur_state      TYPE ty_file_signatures_tt
        RETURNING VALUE(rt_results) TYPE ty_results_tt,
      run_checks
        IMPORTING io_log     TYPE REF TO lcl_log
                  it_results TYPE ty_results_tt
                  io_dot     TYPE REF TO lcl_dot_abapgit
                  iv_top     TYPE devclass
        RAISING   lcx_exception,
      build_existing
        IMPORTING is_local         TYPE ty_file_item
                  is_remote        TYPE ty_file
                  it_state         TYPE ty_file_signatures_ts
        RETURNING VALUE(rs_result) TYPE ty_result,
      build_new_local
        IMPORTING is_local         TYPE ty_file_item
        RETURNING VALUE(rs_result) TYPE ty_result,
      build_new_remote
        IMPORTING iv_devclass      TYPE devclass
                  is_remote        TYPE ty_file
                  it_items         TYPE ty_items_ts
                  it_state         TYPE ty_file_signatures_ts
        RETURNING VALUE(rs_result) TYPE ty_result,
      identify_object
        IMPORTING iv_filename TYPE string
        EXPORTING es_item     TYPE ty_item
                  ev_is_xml   TYPE abap_bool.

ENDCLASS.                    "lcl_file_status DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_file_status IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_file_status IMPLEMENTATION.

  METHOD run_checks.

    DATA: lv_path     TYPE string,
          ls_item     TYPE ty_item,
          ls_file     TYPE ty_file_signature,
          lt_res_sort LIKE it_results,
          lt_item_idx LIKE it_results.

    FIELD-SYMBOLS: <ls_res1> LIKE LINE OF it_results,
                   <ls_res2> LIKE LINE OF it_results.

    IF io_log IS INITIAL.
      RETURN.
    ENDIF.

    " Collect object indexe
    lt_res_sort = it_results.
    SORT lt_res_sort BY obj_type ASCENDING obj_name ASCENDING.

    LOOP AT it_results ASSIGNING <ls_res1> WHERE NOT obj_type IS INITIAL.
      IF NOT ( <ls_res1>-obj_type = ls_item-obj_type
          AND <ls_res1>-obj_name = ls_item-obj_name ).
        APPEND INITIAL LINE TO lt_item_idx ASSIGNING <ls_res2>.
        <ls_res2>-obj_type = <ls_res1>-obj_type.
        <ls_res2>-obj_name = <ls_res1>-obj_name.
        <ls_res2>-path     = <ls_res1>-path.
        MOVE-CORRESPONDING <ls_res1> TO ls_item.
      ENDIF.
    ENDLOOP.

    " Check files for one object is in the same folder

    LOOP AT it_results ASSIGNING <ls_res1> WHERE NOT obj_type IS INITIAL.
      READ TABLE lt_item_idx ASSIGNING <ls_res2>
        WITH KEY obj_type = <ls_res1>-obj_type obj_name = <ls_res1>-obj_name
        BINARY SEARCH. " Sorted above

      IF sy-subrc <> 0 OR <ls_res1>-path <> <ls_res2>-path. " All paths are same
        io_log->add( iv_msg = |Files for object { <ls_res1>-obj_type } {
                       <ls_res1>-obj_name } are not placed in the same folder|
                     iv_type = 'W'
                     iv_rc    = '1' ) ##no_text.
      ENDIF.
    ENDLOOP.

    " Check that objects are created in package corresponding to folder
    LOOP AT it_results ASSIGNING <ls_res1>
        WHERE NOT package IS INITIAL AND NOT path IS INITIAL.
      lv_path = lcl_folder_logic=>package_to_path( iv_top     = iv_top
                                                   io_dot     = io_dot
                                                   iv_package = <ls_res1>-package ).
      IF lv_path <> <ls_res1>-path.
        io_log->add( iv_msg = |Package and path does not match for object, {
                       <ls_res1>-obj_type } { <ls_res1>-obj_name }|
                     iv_type = 'W'
                     iv_rc    = '2' ) ##no_text.
      ENDIF.
    ENDLOOP.

    " Check for multiple files with same filename
    SORT lt_res_sort BY filename ASCENDING.

    LOOP AT lt_res_sort ASSIGNING <ls_res1>.
      IF <ls_res1>-filename IS NOT INITIAL AND <ls_res1>-filename = ls_file-filename.
        io_log->add( iv_msg  = |Multiple files with same filename, { <ls_res1>-filename }|
                     iv_type = 'W'
                     iv_rc   = '3' ) ##no_text.
      ENDIF.

      IF <ls_res1>-filename IS INITIAL.
        io_log->add( iv_msg  = |Filename is empty for object { <ls_res1>-obj_type } { <ls_res1>-obj_name }|
                     iv_type = 'W'
                     iv_rc   = '4' ) ##no_text.
      ENDIF.

      MOVE-CORRESPONDING <ls_res1> TO ls_file.
    ENDLOOP.

  ENDMETHOD.                    "check

  METHOD status.

    DATA: lv_index       LIKE sy-tabix,
          lo_dot_abapgit TYPE REF TO lcl_dot_abapgit.

    FIELD-SYMBOLS <ls_result> LIKE LINE OF rt_results.

    rt_results = calculate_status(
      iv_devclass  = io_repo->get_package( )
      it_local     = io_repo->get_files_local( io_log = io_log )
      it_remote    = io_repo->get_files_remote( )
      it_cur_state = io_repo->get_local_checksums_per_file( ) ).

    lo_dot_abapgit = io_repo->get_dot_abapgit( ).

    " Remove ignored files, fix .abapgit
    LOOP AT rt_results ASSIGNING <ls_result>.
      lv_index = sy-tabix.

      IF lo_dot_abapgit->is_ignored(
          iv_path     = <ls_result>-path
          iv_filename = <ls_result>-filename ) = abap_true.
        DELETE rt_results INDEX lv_index.
      ENDIF.
    ENDLOOP.

    run_checks(
      io_log     = io_log
      it_results = rt_results
      io_dot     = lo_dot_abapgit
      iv_top     = io_repo->get_package( ) ).

  ENDMETHOD.  "status

  METHOD calculate_status.

    DATA: lt_remote    LIKE it_remote,
          lt_items     TYPE ty_items_tt,
          ls_item      LIKE LINE OF lt_items,
          lv_is_xml    TYPE abap_bool,
          lt_items_idx TYPE ty_items_ts,
          lt_state_idx TYPE ty_file_signatures_ts. " Sorted by path+filename

    FIELD-SYMBOLS: <ls_remote> LIKE LINE OF it_remote,
                   <ls_result> LIKE LINE OF rt_results,
                   <ls_local>  LIKE LINE OF it_local.

    lt_state_idx = it_cur_state. " Force sort it
    lt_remote    = it_remote.
    SORT lt_remote BY path filename.

    " Process local files and new local files
    LOOP AT it_local ASSIGNING <ls_local>.
      APPEND INITIAL LINE TO rt_results ASSIGNING <ls_result>.
      IF <ls_local>-item IS NOT INITIAL.
        APPEND <ls_local>-item TO lt_items. " Collect for item index
      ENDIF.

      READ TABLE lt_remote ASSIGNING <ls_remote>
        WITH KEY path = <ls_local>-file-path filename = <ls_local>-file-filename
        BINARY SEARCH.
      IF sy-subrc = 0.  " Exist local and remote
        <ls_result> = build_existing(
          is_local  = <ls_local>
          is_remote = <ls_remote>
          it_state  = lt_state_idx ).
        ASSERT <ls_remote>-sha1 IS NOT INITIAL.
        CLEAR <ls_remote>-sha1. " Mark as processed
      ELSE.             " Only L exists
        <ls_result> = build_new_local( is_local = <ls_local> ).
      ENDIF.
    ENDLOOP.

    " Complete item index for unmarked remote files
    LOOP AT lt_remote ASSIGNING <ls_remote> WHERE sha1 IS NOT INITIAL.
      identify_object( EXPORTING iv_filename = <ls_remote>-filename
                       IMPORTING es_item     = ls_item
                                 ev_is_xml   = lv_is_xml ).

      CHECK lv_is_xml = abap_true. " Skip all but obj definitions

      ls_item-devclass = lcl_tadir=>get_object_package(
                           iv_object   = ls_item-obj_type
                           iv_obj_name = ls_item-obj_name ).
      APPEND ls_item TO lt_items.
    ENDLOOP.

    SORT lt_items. " Default key - type, name, pkg
    DELETE ADJACENT DUPLICATES FROM lt_items.
    lt_items_idx = lt_items. " Self protection + UNIQUE records assertion

    " Process new remote files (marked above with empty SHA1)
    LOOP AT lt_remote ASSIGNING <ls_remote> WHERE sha1 IS NOT INITIAL.
      APPEND INITIAL LINE TO rt_results ASSIGNING <ls_result>.
      <ls_result> = build_new_remote( iv_devclass = iv_devclass
                                      is_remote   = <ls_remote>
                                      it_items    = lt_items_idx
                                      it_state    = lt_state_idx ).
    ENDLOOP.

    SORT rt_results BY
      obj_type ASCENDING
      obj_name ASCENDING
      filename ASCENDING.

  ENDMETHOD.  "calculate_status.

  METHOD identify_object.

    DATA: lv_name TYPE tadir-obj_name,
          lv_type TYPE string,
          lv_ext  TYPE string.

    " Guess object type and name
    SPLIT to_upper( iv_filename ) AT '.' INTO lv_name lv_type lv_ext.

    " Handle namespaces
    REPLACE ALL OCCURRENCES OF '#' IN lv_name WITH '/'.
    REPLACE ALL OCCURRENCES OF '#' IN lv_type WITH '/'.
    REPLACE ALL OCCURRENCES OF '#' IN lv_ext WITH '/'.

    CLEAR es_item.
    es_item-obj_type = lv_type.
    es_item-obj_name = lv_name.
    ev_is_xml        = boolc( lv_ext = 'XML' AND strlen( lv_type ) = 4 ).

  ENDMETHOD.  "identify_object.

  METHOD build_existing.

    DATA: ls_file_sig LIKE LINE OF it_state.

    " Item
    rs_result-obj_type = is_local-item-obj_type.
    rs_result-obj_name = is_local-item-obj_name.
    rs_result-package  = is_local-item-devclass.

    " File
    rs_result-path     = is_local-file-path.
    rs_result-filename = is_local-file-filename.

    " Match against current state
    READ TABLE it_state INTO ls_file_sig
      WITH KEY path = is_local-file-path
      filename = is_local-file-filename
      BINARY SEARCH.

    IF sy-subrc = 0.
      IF ls_file_sig-sha1 <> is_local-file-sha1.
        rs_result-lstate = gc_state-modified.
      ENDIF.
      IF ls_file_sig-sha1 <> is_remote-sha1.
        rs_result-rstate = gc_state-modified.
      ENDIF.
      rs_result-match = boolc( rs_result-lstate IS INITIAL
        AND rs_result-rstate IS INITIAL ).
    ELSE.
      " This is a strange situation. As both local and remote exist
      " the state should also be present. Maybe this is a first run of the code.
      " In this case just compare hashes directly and mark both changed
      " the user will presumably decide what to do after checking the actual diff
      rs_result-match = boolc( is_local-file-sha1 = is_remote-sha1 ).
      IF rs_result-match = abap_false.
        rs_result-lstate = gc_state-modified.
        rs_result-rstate = gc_state-modified.
      ENDIF.
    ENDIF.

  ENDMETHOD.  "build_existing

  METHOD build_new_local.

    " Item
    rs_result-obj_type = is_local-item-obj_type.
    rs_result-obj_name = is_local-item-obj_name.
    rs_result-package  = is_local-item-devclass.

    " File
    rs_result-path     = is_local-file-path.
    rs_result-filename = is_local-file-filename.

    " Match
    rs_result-match    = abap_false.
    rs_result-lstate   = gc_state-added.

  ENDMETHOD.  "build_new_local

  METHOD build_new_remote.

    DATA: ls_item     LIKE LINE OF it_items,
          ls_file_sig LIKE LINE OF it_state.

    " Common and default part
    rs_result-path     = is_remote-path.
    rs_result-filename = is_remote-filename.
    rs_result-match    = abap_false.
    rs_result-rstate   = gc_state-added.

    identify_object( EXPORTING iv_filename = is_remote-filename
                     IMPORTING es_item     = ls_item ).

    " Check if in item index + get package
    READ TABLE it_items INTO ls_item
      WITH KEY obj_type = ls_item-obj_type obj_name = ls_item-obj_name
      BINARY SEARCH.

    IF sy-subrc = 0.

      " Completely new (xml, abap) and new file in an existing object
      rs_result-obj_type = ls_item-obj_type.
      rs_result-obj_name = ls_item-obj_name.
      rs_result-package  = ls_item-devclass.

      READ TABLE it_state INTO ls_file_sig
        WITH KEY path = is_remote-path filename = is_remote-filename
        BINARY SEARCH.

      " Existing file but from another package
      " was not added during local file proc as was not in tadir for repo package
      IF sy-subrc = 0.
        IF ls_file_sig-sha1 = is_remote-sha1.
          rs_result-match = abap_true.
          CLEAR rs_result-rstate.
        ELSE.
          rs_result-rstate = gc_state-modified.
        ENDIF.

        " Item is in state and in cache but with no package - it was deleted
        " OR devclass is the same as repo package (see #532)
        IF ls_item-devclass IS INITIAL OR ls_item-devclass = iv_devclass.
          rs_result-match  = abap_false.
          rs_result-lstate = gc_state-deleted.
        ENDIF.
      ENDIF.

    ELSE. " Completely unknown file, probably non-abapgit
      ASSERT 1 = 1. " No action, just follow defaults
    ENDIF.

  ENDMETHOD.  "build_new_remote

ENDCLASS.                    "lcl_file_status IMPLEMENTATION

fix spaces in error message

fix spaces in error message


*&---------------------------------------------------------------------*
*&  Include  zabapgit_object_prag
*&---------------------------------------------------------------------*

CLASS lcl_object_prag DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_pragma,
             pragma      TYPE c LENGTH 40,
             extension   TYPE c LENGTH 1,
             signature   TYPE c LENGTH 10,
             description TYPE c LENGTH 255,
           END OF ty_pragma.

    METHODS:
      _raise_pragma_not_exists
        RAISING
          lcx_exception,

      _raise_pragma_exists
        RAISING
          lcx_exception,

      _raise_pragma_enqueue
        RAISING
          lcx_exception.

ENDCLASS.

CLASS lcl_object_prag IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD lif_object~changed_by.

    rv_user = sy-uname.

  ENDMETHOD.

  METHOD lif_object~get_metadata.

    rs_metadata = get_metadata( ).
    rs_metadata-delete_tadir = abap_true.

  ENDMETHOD.

  METHOD lif_object~exists.

    TRY.
        cl_abap_pragma=>get_ref( ms_item-obj_name ).

      CATCH cx_abap_pragma_not_exists.
        rv_bool = abap_false.
        RETURN.
    ENDTRY.

    rv_bool = abap_true.

  ENDMETHOD.

  METHOD lif_object~serialize.

    DATA: lo_pragma TYPE REF TO cl_abap_pragma,
          pragma    TYPE lcl_object_prag=>ty_pragma.

    TRY.
        lo_pragma = cl_abap_pragma=>get_ref( ms_item-obj_name ).

        pragma-pragma      = lo_pragma->pragma.
        pragma-extension   = lo_pragma->extension.
        pragma-signature   = lo_pragma->signature.
        pragma-description = lo_pragma->description.

        io_xml->add( iv_name = 'PRAG'
                     ig_data = pragma ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: pragma    TYPE ty_pragma,
          lo_pragma TYPE REF TO cl_abap_pragma.

    TRY.
        io_xml->read(
          EXPORTING
            iv_name = 'PRAG'
          CHANGING
            cg_data = pragma ).

        lo_pragma = cl_abap_pragma=>create( p_pragma  = ms_item-obj_name
                                            p_package = iv_package ).

        lo_pragma->set_info( p_description = pragma-description
                             p_signature   = pragma-signature
                             p_extension   = pragma-extension ).

        lo_pragma->save( ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
      CATCH cx_abap_pragma_exists.
        _raise_pragma_exists( ).
      CATCH cx_abap_pragma_enqueue.
        _raise_pragma_enqueue( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~delete.

    DATA: lo_pragma TYPE REF TO cl_abap_pragma.

    TRY.
        lo_pragma = cl_abap_pragma=>get_ref( ms_item-obj_name ).

        lo_pragma->delete( ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
      CATCH cx_abap_pragma_enqueue.
        _raise_pragma_enqueue( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

  ENDMETHOD.

  METHOD lif_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.

  ENDMETHOD.

  METHOD _raise_pragma_enqueue.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } enqueue error| ).

  ENDMETHOD.

  METHOD _raise_pragma_exists.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } exists| ).

  ENDMETHOD.

  METHOD _raise_pragma_not_exists.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } doesn't exist| ).

  ENDMETHOD.

ENDCLASS.

*&---------------------------------------------------------------------*
*&  Include  zabapgit_object_prag
*&---------------------------------------------------------------------*

CLASS lcl_object_prag DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_pragma,
             pragma      TYPE c LENGTH 40,
             extension   TYPE c LENGTH 1,
             signature   TYPE c LENGTH 10,
             description TYPE c LENGTH 255,
           END OF ty_pragma.

    METHODS:
      _raise_pragma_not_exists
        RAISING
          lcx_exception,

      _raise_pragma_exists
        RAISING
          lcx_exception,

      _raise_pragma_enqueue
        RAISING
          lcx_exception.

ENDCLASS.

CLASS lcl_object_prag IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    rv_changed = abap_true.

  ENDMETHOD.

  METHOD lif_object~changed_by.

    rv_user = c_user_unknown.

  ENDMETHOD.

  METHOD lif_object~get_metadata.

    rs_metadata = get_metadata( ).
    rs_metadata-delete_tadir = abap_true.

  ENDMETHOD.

  METHOD lif_object~exists.

    TRY.
        cl_abap_pragma=>get_ref( ms_item-obj_name ).

      CATCH cx_abap_pragma_not_exists.
        rv_bool = abap_false.
        RETURN.
    ENDTRY.

    rv_bool = abap_true.

  ENDMETHOD.

  METHOD lif_object~serialize.

    DATA: lo_pragma TYPE REF TO cl_abap_pragma,
          pragma    TYPE lcl_object_prag=>ty_pragma.

    TRY.
        lo_pragma = cl_abap_pragma=>get_ref( ms_item-obj_name ).

        pragma-pragma      = lo_pragma->pragma.
        pragma-extension   = lo_pragma->extension.
        pragma-signature   = lo_pragma->signature.
        pragma-description = lo_pragma->description.

        io_xml->add( iv_name = 'PRAG'
                     ig_data = pragma ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: pragma    TYPE ty_pragma,
          lo_pragma TYPE REF TO cl_abap_pragma.

    TRY.
        io_xml->read(
          EXPORTING
            iv_name = 'PRAG'
          CHANGING
            cg_data = pragma ).

        lo_pragma = cl_abap_pragma=>create( p_pragma  = ms_item-obj_name
                                            p_package = iv_package ).

        lo_pragma->set_info( p_description = pragma-description
                             p_signature   = pragma-signature
                             p_extension   = pragma-extension ).

        lo_pragma->save( ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
      CATCH cx_abap_pragma_exists.
        _raise_pragma_exists( ).
      CATCH cx_abap_pragma_enqueue.
        _raise_pragma_enqueue( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~delete.

    DATA: lo_pragma TYPE REF TO cl_abap_pragma.

    TRY.
        lo_pragma = cl_abap_pragma=>get_ref( ms_item-obj_name ).

        lo_pragma->delete( ).

      CATCH cx_abap_pragma_not_exists.
        _raise_pragma_not_exists( ).
      CATCH cx_abap_pragma_enqueue.
        _raise_pragma_enqueue( ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'
        object_name         = ms_item-obj_name
        object_type         = ms_item-obj_type
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

  ENDMETHOD.

  METHOD lif_object~compare_to_remote_version.

    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.

  ENDMETHOD.

  METHOD _raise_pragma_enqueue.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } enqueue error| ).

  ENDMETHOD.

  METHOD _raise_pragma_exists.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } exists| ).

  ENDMETHOD.

  METHOD _raise_pragma_not_exists.

    lcx_exception=>raise( |Pragma { ms_item-obj_name } doesn't exist| ).

  ENDMETHOD.

ENDCLASS.

change 'changed_by' to user_unknown

change 'changed_by' to user_unknown


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_HTML_ACTION_UTILS
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_html_action_utils DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_html_action_utils DEFINITION FINAL.
  PUBLIC SECTION.

    CLASS-METHODS field_keys_to_upper
      CHANGING ct_fields TYPE tihttpnvp.

    CLASS-METHODS add_field
      IMPORTING name TYPE string
                iv   TYPE any
      CHANGING  ct   TYPE tihttpnvp.

    CLASS-METHODS get_field
      IMPORTING name TYPE string
                it   TYPE tihttpnvp
      CHANGING  cv   TYPE any.

    CLASS-METHODS jump_encode
      IMPORTING iv_obj_type      TYPE tadir-object
                iv_obj_name      TYPE tadir-obj_name
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS jump_decode
      IMPORTING iv_string   TYPE clike
      EXPORTING ev_obj_type TYPE tadir-object
                ev_obj_name TYPE tadir-obj_name
      RAISING   lcx_exception.

    CLASS-METHODS dir_encode
      IMPORTING iv_path          TYPE string
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS dir_decode
      IMPORTING iv_string      TYPE clike
      RETURNING VALUE(rv_path) TYPE string
      RAISING   lcx_exception.

    CLASS-METHODS file_encode
      IMPORTING iv_key           TYPE lcl_persistence_repo=>ty_repo-key
                ig_file          TYPE any "assuming ty_file
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS obj_encode
      IMPORTING iv_key           TYPE lcl_persistence_repo=>ty_repo-key
                ig_object        TYPE any "assuming ty_item
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS file_obj_decode
      IMPORTING iv_string TYPE clike
      EXPORTING ev_key    TYPE lcl_persistence_repo=>ty_repo-key
                eg_file   TYPE any "assuming ty_file
                eg_object TYPE any "assuming ty_item
      RAISING   lcx_exception.

    CLASS-METHODS dbkey_encode
      IMPORTING is_key           TYPE lcl_persistence_db=>ty_content
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS dbkey_decode
      IMPORTING iv_string     TYPE clike
      RETURNING VALUE(rs_key) TYPE lcl_persistence_db=>ty_content.

    CLASS-METHODS dbcontent_decode
      IMPORTING it_postdata       TYPE cnht_post_data_tab
      RETURNING VALUE(rs_content) TYPE lcl_persistence_db=>ty_content.

    CLASS-METHODS parse_commit_request
      IMPORTING it_postdata      TYPE cnht_post_data_tab
      EXPORTING es_fields        TYPE any.

    CLASS-METHODS decode_bg_update
      IMPORTING iv_getdata       TYPE clike
      RETURNING VALUE(rs_fields) TYPE lcl_persistence_background=>ty_background.

ENDCLASS.       "lcl_html_action_utils DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_html_action_utils IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_html_action_utils IMPLEMENTATION.

  METHOD field_keys_to_upper.

    FIELD-SYMBOLS <field> LIKE LINE OF ct_fields.

    LOOP AT ct_fields ASSIGNING <field>.
      <field>-name = to_upper( <field>-name ).
    ENDLOOP.

  ENDMETHOD.  "field_keys_to_upper

  METHOD add_field.

    DATA ls_field LIKE LINE OF ct.

    FIELD-SYMBOLS <src> TYPE any.

    ls_field-name = name.

    CASE cl_abap_typedescr=>describe_by_data( iv )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        ls_field-value = iv.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT name OF STRUCTURE iv TO <src>.
        ASSERT <src> IS ASSIGNED.
        ls_field-value = <src>.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

    APPEND ls_field TO ct.

  ENDMETHOD.  "add_field

  METHOD get_field.

    FIELD-SYMBOLS: <ls_field> LIKE LINE OF it,
                   <dest>     TYPE any.

    READ TABLE it ASSIGNING <ls_field> WITH KEY name = name.
    IF sy-subrc IS NOT INITIAL.
      RETURN.
    ENDIF.

    CASE cl_abap_typedescr=>describe_by_data( cv )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        cv = <ls_field>-value.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT name OF STRUCTURE cv TO <dest>.
        ASSERT <dest> IS ASSIGNED.
        <dest> = <ls_field>-value.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

  ENDMETHOD.  "get_field

  METHOD jump_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'TYPE' iv = iv_obj_type CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'NAME' iv = iv_obj_name CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "jump_encode

  METHOD jump_decode.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).

    get_field( EXPORTING name = 'TYPE' it = lt_fields CHANGING cv = ev_obj_type ).
    get_field( EXPORTING name = 'NAME' it = lt_fields CHANGING cv = ev_obj_name ).

  ENDMETHOD.                    "jump_decode

  METHOD dir_encode.

    DATA: lt_fields TYPE tihttpnvp.
    add_field( EXPORTING name = 'PATH' iv = iv_path CHANGING ct = lt_fields ).
    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "dir_encode

  METHOD dir_decode.

    DATA: lt_fields TYPE tihttpnvp.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    get_field( EXPORTING name = 'PATH' it = lt_fields CHANGING cv = rv_path ).

  ENDMETHOD.                    "dir_decode

  METHOD file_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'KEY'      iv = iv_key CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'PATH'     iv = ig_file CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'FILENAME' iv = ig_file CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "file_encode

  METHOD obj_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'KEY'      iv = iv_key CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'OBJ_TYPE' iv = ig_object CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'OBJ_NAME' iv = ig_object CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "obj_encode

  METHOD file_obj_decode.

    DATA: lt_fields TYPE tihttpnvp.

    ASSERT eg_file IS SUPPLIED OR eg_object IS SUPPLIED.

    CLEAR: ev_key, eg_file, eg_object.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'KEY'      it = lt_fields CHANGING cv = ev_key ).

    IF eg_file IS SUPPLIED.
      get_field( EXPORTING name = 'PATH'     it = lt_fields CHANGING cv = eg_file ).
      get_field( EXPORTING name = 'FILENAME' it = lt_fields CHANGING cv = eg_file ).
    ENDIF.

    IF eg_object IS SUPPLIED.
      get_field( EXPORTING name = 'OBJ_TYPE' it = lt_fields CHANGING cv = eg_object ).
      get_field( EXPORTING name = 'OBJ_NAME' it = lt_fields CHANGING cv = eg_object ).
    ENDIF.

  ENDMETHOD.                    "file_decode

  METHOD dbkey_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'TYPE'  iv = is_key-type CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'VALUE' iv = is_key-value CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "dbkey_encode

  METHOD dbkey_decode.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'TYPE'  it = lt_fields CHANGING cv = rs_key-type ).
    get_field( EXPORTING name = 'VALUE' it = lt_fields CHANGING cv = rs_key-value ).

  ENDMETHOD.                    "dbkey_decode

  METHOD dbcontent_decode.

    DATA: lt_fields TYPE tihttpnvp,
          lv_string TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_string.
    rs_content = dbkey_decode( lv_string ).

    lt_fields  = cl_http_utility=>if_http_utility~string_to_fields( lv_string ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'XMLDATA' it = lt_fields CHANGING cv = rs_content-data_str ).
    IF rs_content-data_str(1) <> '<' AND rs_content-data_str+1(1) = '<'. " Hmmm ???
      rs_content-data_str = rs_content-data_str+1.
    ELSE.
      CLEAR rs_content-data_str.
    ENDIF.

  ENDMETHOD.                    "dbcontent_decode

  METHOD parse_commit_request.

    CONSTANTS: lc_replace TYPE string VALUE '<<new>>'.

    DATA: lv_string TYPE string,
          lt_fields TYPE tihttpnvp.

    FIELD-SYMBOLS <body> TYPE string.

    CLEAR es_fields.

    CONCATENATE LINES OF it_postdata INTO lv_string.
    REPLACE ALL OCCURRENCES OF gc_newline IN lv_string WITH lc_replace.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_string ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'REPO_KEY' it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'USERNAME' it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'EMAIL'    it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'COMMENT'  it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'BODY'     it = lt_fields CHANGING cv = es_fields ).

    ASSIGN COMPONENT 'BODY' OF STRUCTURE es_fields TO <body>.
    ASSERT <body> IS ASSIGNED.
    REPLACE ALL OCCURRENCES OF lc_replace IN <body> WITH gc_newline.

    ASSERT es_fields IS NOT INITIAL.

  ENDMETHOD.                    "parse_commit_request

  METHOD decode_bg_update.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_getdata }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'METHOD'   it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'USERNAME' it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'PASSWORD' it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'AMETHOD'  it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'ANAME'    it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'AMAIL'    it = lt_fields CHANGING cv = rs_fields ).

    ASSERT NOT rs_fields IS INITIAL.

  ENDMETHOD.  "decode_bg_update

ENDCLASS.       "lcl_html_action_utils IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_HTML_ACTION_UTILS
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_html_action_utils DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_html_action_utils DEFINITION FINAL.
  PUBLIC SECTION.

    CLASS-METHODS field_keys_to_upper
      CHANGING ct_fields TYPE tihttpnvp.

    CLASS-METHODS add_field
      IMPORTING name TYPE string
                iv   TYPE any
      CHANGING  ct   TYPE tihttpnvp.

    CLASS-METHODS get_field
      IMPORTING name TYPE string
                it   TYPE tihttpnvp
      CHANGING  cv   TYPE any.

    CLASS-METHODS jump_encode
      IMPORTING iv_obj_type      TYPE tadir-object
                iv_obj_name      TYPE tadir-obj_name
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS jump_decode
      IMPORTING iv_string   TYPE clike
      EXPORTING ev_obj_type TYPE tadir-object
                ev_obj_name TYPE tadir-obj_name
      RAISING   lcx_exception.

    CLASS-METHODS dir_encode
      IMPORTING iv_path          TYPE string
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS dir_decode
      IMPORTING iv_string      TYPE clike
      RETURNING VALUE(rv_path) TYPE string
      RAISING   lcx_exception.

    CLASS-METHODS file_encode
      IMPORTING iv_key           TYPE lcl_persistence_repo=>ty_repo-key
                ig_file          TYPE any "assuming ty_file
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS obj_encode
      IMPORTING iv_key           TYPE lcl_persistence_repo=>ty_repo-key
                ig_object        TYPE any "assuming ty_item
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS file_obj_decode
      IMPORTING iv_string TYPE clike
      EXPORTING ev_key    TYPE lcl_persistence_repo=>ty_repo-key
                eg_file   TYPE any "assuming ty_file
                eg_object TYPE any "assuming ty_item
      RAISING   lcx_exception.

    CLASS-METHODS dbkey_encode
      IMPORTING is_key           TYPE lcl_persistence_db=>ty_content
      RETURNING VALUE(rv_string) TYPE string.

    CLASS-METHODS dbkey_decode
      IMPORTING iv_string     TYPE clike
      RETURNING VALUE(rs_key) TYPE lcl_persistence_db=>ty_content.

    CLASS-METHODS dbcontent_decode
      IMPORTING it_postdata       TYPE cnht_post_data_tab
      RETURNING VALUE(rs_content) TYPE lcl_persistence_db=>ty_content.

    CLASS-METHODS parse_commit_request
      IMPORTING it_postdata      TYPE cnht_post_data_tab
      EXPORTING es_fields        TYPE any.

    CLASS-METHODS decode_bg_update
      IMPORTING iv_getdata       TYPE clike
      RETURNING VALUE(rs_fields) TYPE lcl_persistence_background=>ty_background.

ENDCLASS.       "lcl_html_action_utils DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_html_action_utils IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_html_action_utils IMPLEMENTATION.

  METHOD field_keys_to_upper.

    FIELD-SYMBOLS <field> LIKE LINE OF ct_fields.

    LOOP AT ct_fields ASSIGNING <field>.
      <field>-name = to_upper( <field>-name ).
    ENDLOOP.

  ENDMETHOD.  "field_keys_to_upper

  METHOD add_field.

    DATA ls_field LIKE LINE OF ct.

    FIELD-SYMBOLS <src> TYPE any.

    ls_field-name = name.

    CASE cl_abap_typedescr=>describe_by_data( iv )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        ls_field-value = iv.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT name OF STRUCTURE iv TO <src>.
        ASSERT <src> IS ASSIGNED.
        ls_field-value = <src>.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

    APPEND ls_field TO ct.

  ENDMETHOD.  "add_field

  METHOD get_field.

    FIELD-SYMBOLS: <ls_field> LIKE LINE OF it,
                   <dest>     TYPE any.

    READ TABLE it ASSIGNING <ls_field> WITH KEY name = name.
    IF sy-subrc IS NOT INITIAL.
      RETURN.
    ENDIF.

    CASE cl_abap_typedescr=>describe_by_data( cv )->kind.
      WHEN cl_abap_typedescr=>kind_elem.
        cv = <ls_field>-value.
      WHEN cl_abap_typedescr=>kind_struct.
        ASSIGN COMPONENT name OF STRUCTURE cv TO <dest>.
        ASSERT <dest> IS ASSIGNED.
        <dest> = <ls_field>-value.
      WHEN OTHERS.
        ASSERT 0 = 1.
    ENDCASE.

  ENDMETHOD.  "get_field

  METHOD jump_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'TYPE' iv = iv_obj_type CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'NAME' iv = iv_obj_name CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "jump_encode

  METHOD jump_decode.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).

    get_field( EXPORTING name = 'TYPE' it = lt_fields CHANGING cv = ev_obj_type ).
    get_field( EXPORTING name = 'NAME' it = lt_fields CHANGING cv = ev_obj_name ).

  ENDMETHOD.                    "jump_decode

  METHOD dir_encode.

    DATA: lt_fields TYPE tihttpnvp.
    add_field( EXPORTING name = 'PATH' iv = iv_path CHANGING ct = lt_fields ).
    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "dir_encode

  METHOD dir_decode.

    DATA: lt_fields TYPE tihttpnvp.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    get_field( EXPORTING name = 'PATH' it = lt_fields CHANGING cv = rv_path ).

  ENDMETHOD.                    "dir_decode

  METHOD file_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'KEY'      iv = iv_key CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'PATH'     iv = ig_file CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'FILENAME' iv = ig_file CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "file_encode

  METHOD obj_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'KEY'      iv = iv_key CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'OBJ_TYPE' iv = ig_object CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'OBJ_NAME' iv = ig_object CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "obj_encode

  METHOD file_obj_decode.

    DATA: lt_fields TYPE tihttpnvp.

    ASSERT eg_file IS SUPPLIED OR eg_object IS SUPPLIED.

    CLEAR: ev_key, eg_file, eg_object.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'KEY'      it = lt_fields CHANGING cv = ev_key ).

    IF eg_file IS SUPPLIED.
      get_field( EXPORTING name = 'PATH'     it = lt_fields CHANGING cv = eg_file ).
      get_field( EXPORTING name = 'FILENAME' it = lt_fields CHANGING cv = eg_file ).
    ENDIF.

    IF eg_object IS SUPPLIED.
      get_field( EXPORTING name = 'OBJ_TYPE' it = lt_fields CHANGING cv = eg_object ).
      get_field( EXPORTING name = 'OBJ_NAME' it = lt_fields CHANGING cv = eg_object ).
    ENDIF.

  ENDMETHOD.                    "file_decode

  METHOD dbkey_encode.

    DATA: lt_fields TYPE tihttpnvp.

    add_field( EXPORTING name = 'TYPE'  iv = is_key-type CHANGING ct = lt_fields ).
    add_field( EXPORTING name = 'VALUE' iv = is_key-value CHANGING ct = lt_fields ).

    rv_string = cl_http_utility=>if_http_utility~fields_to_string( lt_fields ).

  ENDMETHOD.                    "dbkey_encode

  METHOD dbkey_decode.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_string }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'TYPE'  it = lt_fields CHANGING cv = rs_key-type ).
    get_field( EXPORTING name = 'VALUE' it = lt_fields CHANGING cv = rs_key-value ).

  ENDMETHOD.                    "dbkey_decode

  METHOD dbcontent_decode.

    DATA: lt_fields TYPE tihttpnvp,
          lv_string TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_string.
    rs_content = dbkey_decode( lv_string ).

    lt_fields  = cl_http_utility=>if_http_utility~string_to_fields( lv_string ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'XMLDATA' it = lt_fields CHANGING cv = rs_content-data_str ).
    IF rs_content-data_str(1) <> '<' AND rs_content-data_str+1(1) = '<'. " Hmmm ???
      rs_content-data_str = rs_content-data_str+1.
*    ELSE.
*      CLEAR rs_content-data_str.
    ENDIF.

  ENDMETHOD.                    "dbcontent_decode

  METHOD parse_commit_request.

    CONSTANTS: lc_replace TYPE string VALUE '<<new>>'.

    DATA: lv_string TYPE string,
          lt_fields TYPE tihttpnvp.

    FIELD-SYMBOLS <body> TYPE string.

    CLEAR es_fields.

    CONCATENATE LINES OF it_postdata INTO lv_string.
    REPLACE ALL OCCURRENCES OF gc_newline IN lv_string WITH lc_replace.
    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_string ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'REPO_KEY' it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'USERNAME' it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'EMAIL'    it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'COMMENT'  it = lt_fields CHANGING cv = es_fields ).
    get_field( EXPORTING name = 'BODY'     it = lt_fields CHANGING cv = es_fields ).

    ASSIGN COMPONENT 'BODY' OF STRUCTURE es_fields TO <body>.
    ASSERT <body> IS ASSIGNED.
    REPLACE ALL OCCURRENCES OF lc_replace IN <body> WITH gc_newline.

    ASSERT es_fields IS NOT INITIAL.

  ENDMETHOD.                    "parse_commit_request

  METHOD decode_bg_update.

    DATA: lt_fields TYPE tihttpnvp.

    lt_fields = cl_http_utility=>if_http_utility~string_to_fields( |{ iv_getdata }| ).
    field_keys_to_upper( CHANGING ct_fields = lt_fields ).

    get_field( EXPORTING name = 'METHOD'   it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'USERNAME' it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'PASSWORD' it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'AMETHOD'  it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'ANAME'    it = lt_fields CHANGING cv = rs_fields ).
    get_field( EXPORTING name = 'AMAIL'    it = lt_fields CHANGING cv = rs_fields ).

    ASSERT NOT rs_fields IS INITIAL.

  ENDMETHOD.  "decode_bg_update

ENDCLASS.       "lcl_html_action_utils IMPLEMENTATION

edit xml - fix dump, close #539

edit xml - fix dump, close #539


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_SICF
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    TYPES: ty_icfhandler_tt TYPE STANDARD TABLE OF icfhandler WITH DEFAULT KEY.

    TYPES: BEGIN OF ty_sicf_key,
             icf_name   TYPE icfservice-icf_name,
             icfparguid TYPE icfservice-icfparguid,
           END OF ty_sicf_key.

    METHODS read
      IMPORTING iv_clear      TYPE abap_bool DEFAULT abap_true
      EXPORTING es_icfservice TYPE icfservice
                es_icfdocu    TYPE icfdocu
                et_icfhandler TYPE ty_icfhandler_tt
                ev_url        TYPE string
      RAISING   lcx_exception.

    METHODS insert_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_url        TYPE string
      RAISING   lcx_exception.

    METHODS change_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_parent     TYPE icfparguid
      RAISING   lcx_exception.

    METHODS to_icfhndlist
      IMPORTING it_list        TYPE ty_icfhandler_tt
      RETURNING VALUE(rt_list) TYPE icfhndlist.

    METHODS find_parent
      IMPORTING iv_url           TYPE string
      RETURNING VALUE(rv_parent) TYPE icfparguid
      RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_sicf DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    DATA: ls_icfservice TYPE icfservice.

    read( EXPORTING iv_clear = abap_false
          IMPORTING es_icfservice = ls_icfservice ).

    rv_user = ls_icfservice-icf_muser.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).
    rv_bool = boolc( NOT ls_icfservice IS INITIAL ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~serialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    read( IMPORTING es_icfservice = ls_icfservice
                    es_icfdocu    = ls_icfdocu
                    et_icfhandler = lt_icfhandler
                    ev_url        = lv_url ).
    IF ls_icfservice IS INITIAL.
      RETURN.
    ENDIF.

    CLEAR ls_icfservice-icfnodguid.
    CLEAR ls_icfservice-icfparguid.
    CLEAR ls_icfservice-icf_user.
    CLEAR ls_icfservice-icf_cclnt.
    CLEAR ls_icfservice-icf_mclnt.

    io_xml->add( iv_name = 'URL'
                 ig_data = lv_url ).
    io_xml->add( iv_name = 'ICFSERVICE'
                 ig_data = ls_icfservice ).
    io_xml->add( iv_name = 'ICFDOCU'
                 ig_data = ls_icfdocu ).
    io_xml->add( iv_name = 'ICFHANDLER_TABLE'
                 ig_data = lt_icfhandler ).

  ENDMETHOD.                    "serialize

  METHOD read.

    DATA: lt_serv_info TYPE icfservtbl,
          ls_serv_info LIKE LINE OF lt_serv_info,
          ls_key       TYPE ty_sicf_key.

    FIELD-SYMBOLS: <ls_icfhandler> LIKE LINE OF et_icfhandler.

    CLEAR es_icfservice.
    CLEAR es_icfdocu.
    CLEAR et_icfhandler.
    CLEAR ev_url.

    ls_key = ms_item-obj_name.
    IF ls_key-icfparguid IS INITIAL.
* limitation: name must be unique
      SELECT SINGLE icfparguid FROM icfservice
        INTO ls_key-icfparguid
        WHERE icf_name = ls_key-icf_name
        AND icf_cuser <> 'SAP' ##warn_ok.
      IF sy-subrc <> 0.
        RETURN.
      ENDIF.
    ENDIF.

    cl_icf_tree=>if_icf_tree~get_info_from_serv(
      EXPORTING
        icf_name          = ls_key-icf_name
        icfparguid        = ls_key-icfparguid
        icf_langu         = mv_language
      IMPORTING
        serv_info         = lt_serv_info
        icfdocu           = es_icfdocu
        url               = ev_url
      EXCEPTIONS
        wrong_name        = 1
        wrong_parguid     = 2
        incorrect_service = 3
        no_authority      = 4
        OTHERS            = 5 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from get_info_from_serv' ).
    ENDIF.

    ASSERT lines( lt_serv_info ) = 1.
    READ TABLE lt_serv_info INDEX 1 INTO ls_serv_info.
    ASSERT sy-subrc = 0.

    MOVE-CORRESPONDING ls_serv_info-service TO es_icfservice.
    IF iv_clear = abap_true.
      CLEAR es_icfservice-icf_cuser.
      CLEAR es_icfservice-icf_cdate.
      CLEAR es_icfservice-icf_muser.
      CLEAR es_icfservice-icf_mdate.
    ENDIF.

    CLEAR es_icfdocu-icfparguid.

    APPEND LINES OF ls_serv_info-handlertbl TO et_icfhandler.
    LOOP AT et_icfhandler ASSIGNING <ls_icfhandler>.
      CLEAR <ls_icfhandler>-icfparguid.
    ENDLOOP.

  ENDMETHOD.                    "read

  METHOD lif_object~deserialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_read       TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    io_xml->read( EXPORTING iv_name = 'URL'
                  CHANGING cg_data = lv_url ).
    io_xml->read( EXPORTING iv_name = 'ICFSERVICE'
                  CHANGING cg_data = ls_icfservice ).
    io_xml->read( EXPORTING iv_name = 'ICFDOCU'
                  CHANGING cg_data = ls_icfdocu ).
    io_xml->read( EXPORTING iv_name = 'ICFHANDLER_TABLE'
                  CHANGING cg_data = lt_icfhandler ).

    read( IMPORTING es_icfservice = ls_read ).
    IF ls_read IS INITIAL.
      insert_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_url        = lv_url ).
    ELSE.
      change_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_parent     = ls_read-icfparguid ).
    ENDIF.

  ENDMETHOD.                    "deserialize

  METHOD to_icfhndlist.

    FIELD-SYMBOLS: <ls_list> LIKE LINE OF it_list.

* convert to sorted table
    LOOP AT it_list ASSIGNING <ls_list>.
      INSERT <ls_list>-icfhandler INTO TABLE rt_list.
    ENDLOOP.

  ENDMETHOD.                    "to_icfhndlist

  METHOD find_parent.

    cl_icf_tree=>if_icf_tree~service_from_url(
      EXPORTING
        url                   = iv_url
        hostnumber            = 0
      IMPORTING
        icfnodguid            = rv_parent
      EXCEPTIONS
        wrong_application     = 1
        no_application        = 2
        not_allow_application = 3
        wrong_url             = 4
        no_authority          = 5
        OTHERS                = 6 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from service_from_url' ).
    ENDIF.

  ENDMETHOD.                    "find_parent

  METHOD insert_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          ls_icfserdesc TYPE icfserdesc,
          ls_icfdocu    TYPE icfdocu,
          lv_parent     TYPE icfparguid.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).
    lv_parent = find_parent( iv_url ).

* nice, it seems that the structure should be mistreated
    ls_icfdocu = is_icfdocu-icf_docu.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~insert_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = lv_parent
        icfdocu                   = ls_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( |SICF - error from insert_node: { sy-subrc }| ).
    ENDIF.

  ENDMETHOD.                    "insert_sicf

  METHOD change_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          lt_existing   TYPE TABLE OF icfhandler,
          ls_icfserdesc TYPE icfserdesc.

    FIELD-SYMBOLS: <ls_existing> LIKE LINE OF lt_existing.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).

* Do not add handlers if they already exist, it will make the below
* call to SAP standard code raise an exception
    SELECT * FROM icfhandler INTO TABLE lt_existing
      WHERE icf_name = is_icfservice-icf_name.
    LOOP AT lt_existing ASSIGNING <ls_existing>.
      DELETE TABLE lt_icfhndlist FROM <ls_existing>-icfhandler.
    ENDLOOP.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~change_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = iv_parent
        icfdocu                   = is_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from change_node' ).
    ENDIF.

  ENDMETHOD.                    "change_sicf

  METHOD lif_object~delete.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).

    cl_icf_tree=>if_icf_tree~delete_node(
      EXPORTING
        icfparguid                  = ls_icfservice-icfparguid
      CHANGING
        icf_name                    = ls_icfservice-icf_name
      EXCEPTIONS
        no_virtual_host_delete      = 1
        special_service_error       = 2
        enqueue_error               = 3
        node_not_existing           = 4
        node_has_childs             = 5
        node_is_aliased             = 6
        node_not_in_original_system = 7
        transport_error             = 8
        tadir_error                 = 9
        db_error                    = 10
        no_authority                = 11
        OTHERS                      = 12 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from delete_node' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~jump.
    lcx_exception=>raise( 'todo, SICF, jump' ).
  ENDMETHOD.                    "jump

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_sicf IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_SICF
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

  PRIVATE SECTION.
    TYPES: ty_icfhandler_tt TYPE STANDARD TABLE OF icfhandler WITH DEFAULT KEY.

    TYPES: BEGIN OF ty_sicf_key,
             icf_name   TYPE icfservice-icf_name,
             icfparguid TYPE icfservice-icfparguid,
           END OF ty_sicf_key.

    METHODS read
      IMPORTING iv_clear      TYPE abap_bool DEFAULT abap_true
      EXPORTING es_icfservice TYPE icfservice
                es_icfdocu    TYPE icfdocu
                et_icfhandler TYPE ty_icfhandler_tt
                ev_url        TYPE string
      RAISING   lcx_exception.

    METHODS insert_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_url        TYPE string
      RAISING   lcx_exception.

    METHODS change_sicf
      IMPORTING is_icfservice TYPE icfservice
                is_icfdocu    TYPE icfdocu
                it_icfhandler TYPE ty_icfhandler_tt
                iv_package    TYPE devclass
                iv_parent     TYPE icfparguid
      RAISING   lcx_exception.

    METHODS to_icfhndlist
      IMPORTING it_list        TYPE ty_icfhandler_tt
      RETURNING VALUE(rt_list) TYPE icfhndlist.

    METHODS find_parent
      IMPORTING iv_url           TYPE string
      RETURNING VALUE(rv_parent) TYPE icfparguid
      RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_sicf DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_sicf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_sicf IMPLEMENTATION.

  METHOD lif_object~has_changed_since.
    rv_changed = abap_true.
  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    DATA: ls_icfservice TYPE icfservice.

    read( EXPORTING iv_clear = abap_false
          IMPORTING es_icfservice = ls_icfservice ).

    rv_user = ls_icfservice-icf_muser.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).
    rv_bool = boolc( NOT ls_icfservice IS INITIAL ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~serialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    read( IMPORTING es_icfservice = ls_icfservice
                    es_icfdocu    = ls_icfdocu
                    et_icfhandler = lt_icfhandler
                    ev_url        = lv_url ).
    IF ls_icfservice IS INITIAL.
      RETURN.
    ENDIF.

    CLEAR ls_icfservice-icfnodguid.
    CLEAR ls_icfservice-icfparguid.
    CLEAR ls_icfservice-icf_user.
    CLEAR ls_icfservice-icf_cclnt.
    CLEAR ls_icfservice-icf_mclnt.

    io_xml->add( iv_name = 'URL'
                 ig_data = lv_url ).
    io_xml->add( iv_name = 'ICFSERVICE'
                 ig_data = ls_icfservice ).
    io_xml->add( iv_name = 'ICFDOCU'
                 ig_data = ls_icfdocu ).
    io_xml->add( iv_name = 'ICFHANDLER_TABLE'
                 ig_data = lt_icfhandler ).

  ENDMETHOD.                    "serialize

  METHOD read.

    DATA: lt_serv_info TYPE icfservtbl,
          ls_serv_info LIKE LINE OF lt_serv_info,
          ls_key       TYPE ty_sicf_key.

    FIELD-SYMBOLS: <ls_icfhandler> LIKE LINE OF et_icfhandler.

    CLEAR es_icfservice.
    CLEAR es_icfdocu.
    CLEAR et_icfhandler.
    CLEAR ev_url.

    ls_key = ms_item-obj_name.
    IF ls_key-icfparguid IS INITIAL.
* limitation: name must be unique
      SELECT SINGLE icfparguid FROM icfservice
        INTO ls_key-icfparguid
        WHERE icf_name = ls_key-icf_name
        AND icf_cuser <> 'SAP' ##warn_ok.
      IF sy-subrc <> 0.
        RETURN.
      ENDIF.
    ENDIF.

    cl_icf_tree=>if_icf_tree~get_info_from_serv(
      EXPORTING
        icf_name          = ls_key-icf_name
        icfparguid        = ls_key-icfparguid
        icf_langu         = mv_language
      IMPORTING
        serv_info         = lt_serv_info
        icfdocu           = es_icfdocu
        url               = ev_url
      EXCEPTIONS
        wrong_name        = 1
        wrong_parguid     = 2
        incorrect_service = 3
        no_authority      = 4
        OTHERS            = 5 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from get_info_from_serv' ).
    ENDIF.

    ASSERT lines( lt_serv_info ) = 1.
    READ TABLE lt_serv_info INDEX 1 INTO ls_serv_info.
    ASSERT sy-subrc = 0.

    MOVE-CORRESPONDING ls_serv_info-service TO es_icfservice.
    IF iv_clear = abap_true.
      CLEAR es_icfservice-icf_cuser.
      CLEAR es_icfservice-icf_cdate.
      CLEAR es_icfservice-icf_muser.
      CLEAR es_icfservice-icf_mdate.
    ENDIF.

    CLEAR es_icfdocu-icfparguid.

    APPEND LINES OF ls_serv_info-handlertbl TO et_icfhandler.
    LOOP AT et_icfhandler ASSIGNING <ls_icfhandler>.
      CLEAR <ls_icfhandler>-icfparguid.
    ENDLOOP.

  ENDMETHOD.                    "read

  METHOD lif_object~deserialize.

    DATA: ls_icfservice TYPE icfservice,
          ls_read       TYPE icfservice,
          ls_icfdocu    TYPE icfdocu,
          lv_url        TYPE string,
          lt_icfhandler TYPE TABLE OF icfhandler.

    io_xml->read( EXPORTING iv_name = 'URL'
                  CHANGING cg_data = lv_url ).
    io_xml->read( EXPORTING iv_name = 'ICFSERVICE'
                  CHANGING cg_data = ls_icfservice ).
    io_xml->read( EXPORTING iv_name = 'ICFDOCU'
                  CHANGING cg_data = ls_icfdocu ).
    io_xml->read( EXPORTING iv_name = 'ICFHANDLER_TABLE'
                  CHANGING cg_data = lt_icfhandler ).

    read( IMPORTING es_icfservice = ls_read ).
    IF ls_read IS INITIAL.
      insert_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_url        = lv_url ).
    ELSE.
      change_sicf( is_icfservice = ls_icfservice
                   is_icfdocu    = ls_icfdocu
                   it_icfhandler = lt_icfhandler
                   iv_package    = iv_package
                   iv_parent     = ls_read-icfparguid ).
    ENDIF.

  ENDMETHOD.                    "deserialize

  METHOD to_icfhndlist.

    FIELD-SYMBOLS: <ls_list> LIKE LINE OF it_list.

* convert to sorted table
    LOOP AT it_list ASSIGNING <ls_list>.
      INSERT <ls_list>-icfhandler INTO TABLE rt_list.
    ENDLOOP.

  ENDMETHOD.                    "to_icfhndlist

  METHOD find_parent.

    cl_icf_tree=>if_icf_tree~service_from_url(
      EXPORTING
        url                   = iv_url
        hostnumber            = 0
      IMPORTING
        icfnodguid            = rv_parent
      EXCEPTIONS
        wrong_application     = 1
        no_application        = 2
        not_allow_application = 3
        wrong_url             = 4
        no_authority          = 5
        OTHERS                = 6 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from service_from_url' ).
    ENDIF.

  ENDMETHOD.                    "find_parent

  METHOD insert_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          ls_icfserdesc TYPE icfserdesc,
          ls_icfdocu    TYPE icfdocu,
          lv_parent     TYPE icfparguid.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).
    lv_parent = find_parent( iv_url ).

* nice, it seems that the structure should be mistreated
    ls_icfdocu = is_icfdocu-icf_docu.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~insert_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = lv_parent
        icfdocu                   = ls_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( |SICF - error from insert_node: { sy-subrc }| ).
    ENDIF.

  ENDMETHOD.                    "insert_sicf

  METHOD change_sicf.

    DATA: lt_icfhndlist TYPE icfhndlist,
          lt_existing   TYPE TABLE OF icfhandler,
          ls_icfserdesc TYPE icfserdesc.

    FIELD-SYMBOLS: <ls_existing> LIKE LINE OF lt_existing.

    lt_icfhndlist = to_icfhndlist( it_icfhandler ).

* Do not add handlers if they already exist, it will make the below
* call to SAP standard code raise an exception
    SELECT * FROM icfhandler INTO TABLE lt_existing
      WHERE icf_name = is_icfservice-icf_name.
    LOOP AT lt_existing ASSIGNING <ls_existing>.
      DELETE TABLE lt_icfhndlist FROM <ls_existing>-icfhandler.
    ENDLOOP.

    MOVE-CORRESPONDING is_icfservice TO ls_icfserdesc.

    cl_icf_tree=>if_icf_tree~change_node(
      EXPORTING
        icf_name                  = is_icfservice-orig_name
        icfparguid                = iv_parent
        icfdocu                   = is_icfdocu
        doculang                  = mv_language
        icfhandlst                = lt_icfhndlist
        package                   = iv_package
        application               = space
        icfserdesc                = ls_icfserdesc
        icfactive                 = abap_true
      EXCEPTIONS
        empty_icf_name            = 1
        no_new_virtual_host       = 2
        special_service_error     = 3
        parent_not_existing       = 4
        enqueue_error             = 5
        node_already_existing     = 6
        empty_docu                = 7
        doculang_not_installed    = 8
        security_info_error       = 9
        user_password_error       = 10
        password_encryption_error = 11
        invalid_url               = 12
        invalid_otr_concept       = 13
        formflg401_error          = 14
        handler_error             = 15
        transport_error           = 16
        tadir_error               = 17
        package_not_found         = 18
        wrong_application         = 19
        not_allow_application     = 20
        no_application            = 21
        invalid_icfparguid        = 22
        alt_name_invalid          = 23
        alternate_name_exist      = 24
        wrong_icf_name            = 25
        no_authority              = 26
        OTHERS                    = 27 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from change_node' ).
    ENDIF.

  ENDMETHOD.                    "change_sicf

  METHOD lif_object~delete.

    DATA: ls_icfservice TYPE icfservice.

    read( IMPORTING es_icfservice = ls_icfservice ).

    cl_icf_tree=>if_icf_tree~delete_node(
      EXPORTING
        icfparguid                  = ls_icfservice-icfparguid
      CHANGING
        icf_name                    = ls_icfservice-icf_name
      EXCEPTIONS
        no_virtual_host_delete      = 1
        special_service_error       = 2
        enqueue_error               = 3
        node_not_existing           = 4
        node_has_childs             = 5
        node_is_aliased             = 6
        node_not_in_original_system = 7
        transport_error             = 8
        tadir_error                 = 9
        db_error                    = 10
        no_authority                = 11
        OTHERS                      = 12 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'SICF - error from delete_node' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~jump.

    DATA: ls_bcdata TYPE bdcdata,
          lt_bcdata TYPE STANDARD TABLE OF bdcdata.

    ls_bcdata-program  = 'RSICFTREE'.
    ls_bcdata-dynpro   = '1000'.
    ls_bcdata-dynbegin = 'X'.
    APPEND ls_bcdata TO lt_bcdata.

    ls_bcdata-dynpro   = space.
    ls_bcdata-dynbegin = space.
    ls_bcdata-fnam     = 'ICF_SERV'.
    ls_bcdata-fval     = ms_item-obj_name.
    APPEND ls_bcdata TO lt_bcdata.

    ls_bcdata-fnam = 'BDC_OKCODE'.
    ls_bcdata-fval = '=ONLI'.
    APPEND ls_bcdata TO lt_bcdata.

    CALL FUNCTION 'ABAP4_CALL_TRANSACTION'
      STARTING NEW TASK 'GIT'
      EXPORTING
        tcode                   = 'SICF'
        mode_val                = 'E'
      TABLES
        using_tab               = lt_bcdata
      EXCEPTIONS
        OTHERS                  = 1.

    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from ABAP4_CALL_TRANSACTION, SICF' ).
    ENDIF.

  ENDMETHOD.                    "jump

  METHOD lif_object~compare_to_remote_version.
    CREATE OBJECT ro_comparison_result TYPE lcl_comparison_null.
  ENDMETHOD.

ENDCLASS.                    "lcl_object_sicf IMPLEMENTATION

add SICF jump

add SICF jump


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_TTYP
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_ttyp DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_ttyp DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

ENDCLASS.                    "lcl_object_dtel DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_ttyp IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_ttyp IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    DATA: lv_date    TYPE dats,
          lv_time    TYPE tims,
          lv_ts      TYPE timestamp.

    SELECT SINGLE as4date as4time FROM dd40l
      INTO (lv_date, lv_time)
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.

    _object_check_timestamp lv_date lv_time.

  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    SELECT SINGLE as4user FROM dd40l INTO rv_user
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: lv_typename TYPE dd40l-typename.

    SELECT SINGLE typename FROM dd40l INTO lv_typename
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    jump_se11( iv_radio = 'RSRD1-DDTYPE'
               iv_field = 'RSRD1-DDTYPE_VAL' ).

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_objname TYPE rsedd0-ddobjname.

    lv_objname = ms_item-obj_name.

    CALL FUNCTION 'RS_DD_DELETE_OBJ'
      EXPORTING
        no_ask               = abap_true
        objname              = lv_objname
        objtype              = 'A'
      EXCEPTIONS
        not_executed         = 1
        object_not_found     = 2
        object_not_specified = 3
        permission_failure   = 4.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from RS_DD_DELETE_OBJ, TTYP' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~serialize.

    DATA: lv_name  TYPE ddobjname,
          lt_dd42v TYPE dd42v_tab,
          lt_dd43v TYPE dd43v_tab,
          ls_dd40v TYPE dd40v.

    lv_name = ms_item-obj_name.

    CALL FUNCTION 'DDIF_TTYP_GET'
      EXPORTING
        name          = lv_name
        state         = 'A'
        langu         = mv_language
      IMPORTING
        dd40v_wa      = ls_dd40v
      TABLES
        dd42v_tab     = lt_dd42v
        dd43v_tab     = lt_dd43v
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DDIF_TTYP_GET' ).
    ENDIF.
    IF ls_dd40v IS INITIAL.
      RETURN. " does not exist in system
    ENDIF.

    CLEAR: ls_dd40v-as4user,
           ls_dd40v-as4date,
           ls_dd40v-as4time.

    io_xml->add( iv_name = 'DD40V'
                 ig_data = ls_dd40v ).
    io_xml->add( iv_name = 'DD42V'
                 ig_data = lt_dd42v ).
    io_xml->add( iv_name = 'DD43V'
                 ig_data = lt_dd43v ).

  ENDMETHOD.                    "serialize

  METHOD lif_object~deserialize.

    DATA: lv_name  TYPE ddobjname,
          lt_dd42v TYPE dd42v_tab,
          lt_dd43v TYPE dd43v_tab,
          ls_dd40v TYPE dd40v.

    io_xml->read( EXPORTING iv_name = 'DD40V'
                  CHANGING cg_data = ls_dd40v ).
    io_xml->read( EXPORTING iv_name = 'DD42V'
                  CHANGING cg_data = lt_dd42v ).
    io_xml->read( EXPORTING iv_name = 'DD43V'
                  CHANGING cg_data = lt_dd43v ).

    corr_insert( iv_package ).

    lv_name = ms_item-obj_name. " type conversion

    CALL FUNCTION 'DDIF_TTYP_PUT'
      EXPORTING
        name              = lv_name
        dd40v_wa          = ls_dd40v
      TABLES
        dd42v_tab         = lt_dd42v
        dd43v_tab         = lt_dd43v
      EXCEPTIONS
        ttyp_not_found    = 1
        name_inconsistent = 2
        ttyp_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DDIF_TTYP_PUT' ).
    ENDIF.

    lcl_objects_activation=>add_item( ms_item ).

  ENDMETHOD.                    "deserialize

ENDCLASS.                    "lcl_object_ttyp IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_TTYP
*&---------------------------------------------------------------------*

*----------------------------------------------------------------------*
*       CLASS lcl_object_ttyp DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_ttyp DEFINITION INHERITING FROM lcl_objects_super FINAL.

  PUBLIC SECTION.
    INTERFACES lif_object.
    ALIASES mo_files FOR lif_object~mo_files.

ENDCLASS.                    "lcl_object_dtel DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_ttyp IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_ttyp IMPLEMENTATION.

  METHOD lif_object~has_changed_since.

    DATA: lv_date TYPE dats,
          lv_time TYPE tims,
          lv_ts   TYPE timestamp.

    SELECT SINGLE as4date as4time FROM dd40l
      INTO (lv_date, lv_time)
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.

    _object_check_timestamp lv_date lv_time.

  ENDMETHOD.  "lif_object~has_changed_since

  METHOD lif_object~changed_by.

    SELECT SINGLE as4user FROM dd40l INTO rv_user
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
    ENDIF.

  ENDMETHOD.

  METHOD lif_object~get_metadata.
    rs_metadata = get_metadata( ).
  ENDMETHOD.                    "lif_object~get_metadata

  METHOD lif_object~exists.

    DATA: lv_typename TYPE dd40l-typename.

    SELECT SINGLE typename FROM dd40l INTO lv_typename
      WHERE typename = ms_item-obj_name
      AND as4local = 'A'.
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    jump_se11( iv_radio = 'RSRD1-DDTYPE'
               iv_field = 'RSRD1-DDTYPE_VAL' ).

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_objname TYPE rsedd0-ddobjname.

    lv_objname = ms_item-obj_name.

    CALL FUNCTION 'RS_DD_DELETE_OBJ'
      EXPORTING
        no_ask               = abap_true
        objname              = lv_objname
        objtype              = 'A'
      EXCEPTIONS
        not_executed         = 1
        object_not_found     = 2
        object_not_specified = 3
        permission_failure   = 4.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from RS_DD_DELETE_OBJ, TTYP' ).
    ENDIF.

  ENDMETHOD.                    "delete

  METHOD lif_object~serialize.

    DATA: lv_name  TYPE ddobjname,
          lt_dd42v TYPE dd42v_tab,
          lt_dd43v TYPE dd43v_tab,
          ls_dd40v TYPE dd40v.

    lv_name = ms_item-obj_name.

    CALL FUNCTION 'DDIF_TTYP_GET'
      EXPORTING
        name          = lv_name
        state         = 'A'
        langu         = mv_language
      IMPORTING
        dd40v_wa      = ls_dd40v
      TABLES
        dd42v_tab     = lt_dd42v
        dd43v_tab     = lt_dd43v
      EXCEPTIONS
        illegal_input = 1
        OTHERS        = 2.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DDIF_TTYP_GET' ).
    ENDIF.
    IF ls_dd40v IS INITIAL.
      RETURN. " does not exist in system
    ENDIF.

    CLEAR: ls_dd40v-as4user,
           ls_dd40v-as4date,
           ls_dd40v-as4time.

    IF NOT ls_dd40v-rowkind IS INITIAL.
      CLEAR ls_dd40v-typelen.
    ENDIF.

    io_xml->add( iv_name = 'DD40V'
                 ig_data = ls_dd40v ).
    io_xml->add( iv_name = 'DD42V'
                 ig_data = lt_dd42v ).
    io_xml->add( iv_name = 'DD43V'
                 ig_data = lt_dd43v ).

  ENDMETHOD.                    "serialize

  METHOD lif_object~deserialize.

    DATA: lv_name  TYPE ddobjname,
          lt_dd42v TYPE dd42v_tab,
          lt_dd43v TYPE dd43v_tab,
          ls_dd40v TYPE dd40v.

    io_xml->read( EXPORTING iv_name = 'DD40V'
                  CHANGING cg_data = ls_dd40v ).
    io_xml->read( EXPORTING iv_name = 'DD42V'
                  CHANGING cg_data = lt_dd42v ).
    io_xml->read( EXPORTING iv_name = 'DD43V'
                  CHANGING cg_data = lt_dd43v ).

    corr_insert( iv_package ).

    lv_name = ms_item-obj_name. " type conversion

    CALL FUNCTION 'DDIF_TTYP_PUT'
      EXPORTING
        name              = lv_name
        dd40v_wa          = ls_dd40v
      TABLES
        dd42v_tab         = lt_dd42v
        dd43v_tab         = lt_dd43v
      EXCEPTIONS
        ttyp_not_found    = 1
        name_inconsistent = 2
        ttyp_inconsistent = 3
        put_failure       = 4
        put_refused       = 5
        OTHERS            = 6.
    IF sy-subrc <> 0.
      lcx_exception=>raise( 'error from DDIF_TTYP_PUT' ).
    ENDIF.

    lcl_objects_activation=>add_item( ms_item ).

  ENDMETHOD.                    "deserialize

ENDCLASS.                    "lcl_object_ttyp IMPLEMENTATION

clear TYPELEN

TTYP: clear TYPELEN