*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_WAPA
*&---------------------------------------------------------------------*

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

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

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_page,
             attributes     TYPE o2pagattr,
             event_handlers TYPE o2pagevh_tabletype,
             parameters     TYPE o2pagpar_tabletype,
             types          TYPE rswsourcet,
           END OF ty_page.

    TYPES: ty_pages_tt TYPE STANDARD TABLE OF ty_page WITH DEFAULT KEY.

    CONSTANTS: c_active TYPE so2_version VALUE 'A'.

    METHODS:
      get_page_content
        IMPORTING io_page           TYPE REF TO cl_o2_api_pages
        RETURNING VALUE(rv_content) TYPE xstring,
      to_page_content
        IMPORTING iv_content        TYPE xstring
        RETURNING VALUE(rt_content) TYPE o2pageline_table,
      read_page
        IMPORTING is_page        TYPE o2pagattr
        RETURNING VALUE(rs_page) TYPE ty_page
        RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_TRAN DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_wapa IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_wapa IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_name   TYPE o2applname,
          lt_pages  TYPE STANDARD TABLE OF o2pagdir WITH DEFAULT KEY,
          ls_latest LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    SELECT * FROM o2pagdir INTO TABLE lt_pages WHERE applname = lv_name.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
      RETURN.
    ENDIF.

    SORT lt_pages BY changedon DESCENDING changetime DESCENDING.

    READ TABLE lt_pages INDEX 1 INTO ls_latest.
    ASSERT sy-subrc = 0.

    rv_user = ls_latest-changedby.

  ENDMETHOD.

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

  METHOD lif_object~exists.

    DATA: lv_name TYPE o2applname.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'    " Operation
        object_name         = ms_item-obj_name     " Object Name
        object_type         = ms_item-obj_type    " Object Type
        in_new_window       = abap_true
      EXCEPTIONS
        not_executed        = 1
        invalid_object_type = 2
        OTHERS              = 3.

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_name    TYPE o2applname,
          lo_bsp     TYPE REF TO cl_o2_api_application,
          ls_pagekey TYPE o2pagkey,
          lv_object  TYPE seu_objkey,
          lt_pages   TYPE o2pagelist.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    ASSERT sy-subrc = 0.

    lo_bsp->set_changeable(
      p_changeable           = abap_true
      p_complete_application = abap_true ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      CLEAR ls_pagekey.
      ls_pagekey-applname = lv_name.
      ls_pagekey-pagekey  = <ls_page>-pagekey.

      cl_o2_page=>delete_page_for_application(
        EXPORTING
          p_pagekey           = ls_pagekey
        EXCEPTIONS
          object_not_existing = 1
          error_occured       = 2 ).
      ASSERT sy-subrc = 0.
    ENDLOOP.

    lo_bsp->delete( ).

* release lock
    lv_object = lv_name.
    cl_o2_api_application=>call_access_permission(
      p_mode                 = 'FREE'
      p_object               = lv_object
      p_complete_application = abap_true ).

  ENDMETHOD.                    "delete

  METHOD lif_object~deserialize.

    DATA: lo_bsp        TYPE REF TO cl_o2_api_application,
          lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_nodes      TYPE o2applnode_table,
          lt_navgraph   TYPE o2applgrap_table,
          lv_objkey     TYPE seu_objkey,
          ls_item       LIKE ms_item,
          lv_extra      TYPE string,
          lv_content    TYPE xstring,
          lv_ext        TYPE string,
          lo_page       TYPE REF TO cl_o2_api_pages,
          lt_pages_info TYPE ty_pages_tt.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages_info.

    lv_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'ATTRIBUTES'
                  CHANGING cg_data = ls_attributes ).
    io_xml->read( EXPORTING iv_name = 'NAVGRAPH'
                  CHANGING cg_data = lt_navgraph ).
    io_xml->read( EXPORTING iv_name = 'PAGES'
                  CHANGING cg_data = lt_pages_info ).

    ls_attributes-devclass = iv_package.

* todo: overwrite existing
    cl_o2_api_application=>create_new(
      EXPORTING
        p_application_data      = ls_attributes
        p_nodes                 = lt_nodes
        p_navgraph              = lt_navgraph
      IMPORTING
        p_application           = lo_bsp
      EXCEPTIONS
        object_already_existing = 1
        object_just_created     = 2
        not_authorized          = 3
        undefined_name          = 4
        author_not_existing     = 5
        action_cancelled        = 6
        error_occured           = 7
        invalid_parameter       = 8 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( |WAPA - error from create_new: { sy-subrc }| ).
    ENDIF.

    lo_bsp->save( ).

    lo_bsp->set_changeable(
      p_changeable           = abap_false
      p_complete_application = abap_true ).

    ls_item-obj_type = 'WAPD'.
    ls_item-obj_name = ms_item-obj_name.
    lcl_objects_activation=>add_item( ls_item ).

    lv_objkey = ls_item-obj_name.
* todo, hmm, the WAPD is not added to the worklist during activation
    cl_o2_api_application=>activate( lv_objkey ).

    LOOP AT lt_pages_info ASSIGNING <ls_page>.
      cl_o2_api_pages=>create_new_page(
        EXPORTING
          p_pageattrs = <ls_page>-attributes
        IMPORTING
          p_page      = lo_page ).

      SPLIT <ls_page>-attributes-pagename AT '.' INTO lv_extra lv_ext.
      REPLACE ALL OCCURRENCES OF '_-' IN lv_extra WITH '/'.
      lv_content = mo_files->read_raw( iv_extra = lv_extra
                                       iv_ext   = lv_ext ).
      lo_page->set_page( to_page_content( lv_content ) ).

      lo_page->set_event_handlers( <ls_page>-event_handlers ).
      lo_page->set_parameters( <ls_page>-parameters ).
      lo_page->set_type_source( <ls_page>-types ).

      lo_page->save( p_with_all_texts = abap_true ).

      ls_item-obj_type = 'WAPP'.
      ls_item-obj_name = cl_wb_object_type=>get_concatenated_key_from_id(
        p_key_component1 = <ls_page>-attributes-applname
        p_key_component2 = <ls_page>-attributes-pagekey
        p_external_id    = 'WG ' ).
      lcl_objects_activation=>add_item( ls_item ).
    ENDLOOP.

  ENDMETHOD.                    "deserialize

  METHOD lif_object~serialize.

    DATA: lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_navgraph   TYPE o2applgrap_table,
          lt_pages      TYPE o2pagelist,
          lt_pages_info TYPE ty_pages_tt,
          lo_bsp        TYPE REF TO cl_o2_api_application.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    lo_bsp->get_attributes(
      EXPORTING
        p_version    = c_active
      IMPORTING
        p_attributes = ls_attributes ).

    CLEAR: ls_attributes-author,
           ls_attributes-createdon,
           ls_attributes-changedby,
           ls_attributes-changedon,
           ls_attributes-devclass.

    io_xml->add( iv_name = 'ATTRIBUTES'
                 ig_data = ls_attributes ).

    lo_bsp->get_navgraph(
      EXPORTING
        p_version  = c_active
      IMPORTING
        p_navgraph = lt_navgraph ).

    io_xml->add( iv_name = 'NAVGRAPH'
                 ig_data = lt_navgraph ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      APPEND read_page( <ls_page> ) TO lt_pages_info.
    ENDLOOP.

    io_xml->add( iv_name = 'PAGES'
                 ig_data = lt_pages_info ).

  ENDMETHOD.                    "serialize

  METHOD read_page.

    DATA: lv_name    TYPE o2applname,
          ls_pagekey TYPE o2pagkey,
          lv_content TYPE xstring,
          lv_extra   TYPE string,
          lv_ext     TYPE string,
          lo_page    TYPE REF TO cl_o2_api_pages.

    lv_name = ms_item-obj_name.

    ls_pagekey-applname = lv_name.
    ls_pagekey-pagekey = is_page-pagekey.

    cl_o2_api_pages=>load(
      EXPORTING
        p_pagekey = ls_pagekey
      IMPORTING
        p_page    = lo_page ).

    lo_page->get_event_handlers(
      IMPORTING
        p_ev_handler = rs_page-event_handlers
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2 ).
    ASSERT sy-subrc = 0.

    lo_page->get_parameters(
      IMPORTING
        p_parameters = rs_page-parameters
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lo_page->get_type_source(
      IMPORTING
        p_source     = rs_page-types
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lv_content = get_page_content( lo_page ).
    SPLIT is_page-pagename AT '.' INTO lv_extra lv_ext.
    REPLACE ALL OCCURRENCES OF '/' IN lv_extra WITH '_-'.
    mo_files->add_raw(
      iv_extra = lv_extra
      iv_ext   = lv_ext
      iv_data  = lv_content ).

    rs_page-attributes = is_page.

    CLEAR: rs_page-attributes-author,
           rs_page-attributes-createdon,
           rs_page-attributes-changedby,
           rs_page-attributes-changedon,
           rs_page-attributes-implclass,
           rs_page-attributes-gendate,
           rs_page-attributes-gentime.

  ENDMETHOD.

  METHOD to_page_content.

    DATA: lv_string TYPE string.

    lv_string = lcl_convert=>xstring_to_string_utf8( iv_content ).

    SPLIT lv_string AT gc_newline INTO TABLE rt_content.

  ENDMETHOD.

  METHOD get_page_content.

    DATA: lt_content TYPE o2pageline_table,
          lv_string  TYPE string.

    io_page->get_page(
      IMPORTING
        p_content = lt_content ).

    CONCATENATE LINES OF lt_content INTO lv_string SEPARATED BY gc_newline RESPECTING BLANKS.

    rv_content = lcl_convert=>string_to_xstring_utf8( lv_string ).

  ENDMETHOD.

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

ENDCLASS.                    "lcl_object_tran IMPLEMENTATION

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_WAPA
*&---------------------------------------------------------------------*

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

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

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_page,
             attributes     TYPE o2pagattr,
             event_handlers TYPE o2pagevh_tabletype,
             parameters     TYPE o2pagpar_tabletype,
             types          TYPE rswsourcet,
           END OF ty_page.

    TYPES: ty_pages_tt TYPE STANDARD TABLE OF ty_page WITH DEFAULT KEY.

    CONSTANTS: c_active TYPE so2_version VALUE 'A'.

    METHODS:
      get_page_content
        IMPORTING io_page           TYPE REF TO cl_o2_api_pages
        RETURNING VALUE(rv_content) TYPE xstring,
      to_page_content
        IMPORTING iv_content        TYPE xstring
        RETURNING VALUE(rt_content) TYPE o2pageline_table,
      read_page
        IMPORTING is_page        TYPE o2pagattr
        RETURNING VALUE(rs_page) TYPE ty_page
        RAISING   lcx_exception.

ENDCLASS.                    "lcl_object_TRAN DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_object_wapa IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_object_wapa IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_name   TYPE o2applname,
          lt_pages  TYPE STANDARD TABLE OF o2pagdir WITH DEFAULT KEY,
          ls_latest LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    SELECT * FROM o2pagdir INTO TABLE lt_pages WHERE applname = lv_name.
    IF sy-subrc <> 0.
      rv_user = c_user_unknown.
      RETURN.
    ENDIF.

    SORT lt_pages BY changedon DESCENDING changetime DESCENDING.

    READ TABLE lt_pages INDEX 1 INTO ls_latest.
    ASSERT sy-subrc = 0.

    rv_user = ls_latest-changedby.

  ENDMETHOD.

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

  METHOD lif_object~exists.

    DATA: lv_name TYPE o2applname.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    rv_bool = boolc( sy-subrc = 0 ).

  ENDMETHOD.                    "lif_object~exists

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation           = 'SHOW'    " Operation
        object_name         = ms_item-obj_name     " Object Name
        object_type         = ms_item-obj_type    " Object Type
        in_new_window       = abap_true.

  ENDMETHOD.                    "jump

  METHOD lif_object~delete.

    DATA: lv_name    TYPE o2applname,
          lo_bsp     TYPE REF TO cl_o2_api_application,
          ls_pagekey TYPE o2pagkey,
          lv_object  TYPE seu_objkey,
          lt_pages   TYPE o2pagelist.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    ASSERT sy-subrc = 0.

    lo_bsp->set_changeable(
      p_changeable           = abap_true
      p_complete_application = abap_true ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      CLEAR ls_pagekey.
      ls_pagekey-applname = lv_name.
      ls_pagekey-pagekey  = <ls_page>-pagekey.

      cl_o2_page=>delete_page_for_application(
        EXPORTING
          p_pagekey           = ls_pagekey
        EXCEPTIONS
          object_not_existing = 1
          error_occured       = 2 ).
      ASSERT sy-subrc = 0.
    ENDLOOP.

    lo_bsp->delete( ).

* release lock
    lv_object = lv_name.
    cl_o2_api_application=>call_access_permission(
      p_mode                 = 'FREE'
      p_object               = lv_object
      p_complete_application = abap_true ).

  ENDMETHOD.                    "delete

  METHOD lif_object~deserialize.

    DATA: lo_bsp        TYPE REF TO cl_o2_api_application,
          lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_nodes      TYPE o2applnode_table,
          lt_navgraph   TYPE o2applgrap_table,
          lv_objkey     TYPE seu_objkey,
          ls_item       LIKE ms_item,
          lv_extra      TYPE string,
          lv_content    TYPE xstring,
          lv_ext        TYPE string,
          lo_page       TYPE REF TO cl_o2_api_pages,
          lt_pages_info TYPE ty_pages_tt.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages_info.

    lv_name = ms_item-obj_name.

    io_xml->read( EXPORTING iv_name = 'ATTRIBUTES'
                  CHANGING cg_data = ls_attributes ).
    io_xml->read( EXPORTING iv_name = 'NAVGRAPH'
                  CHANGING cg_data = lt_navgraph ).
    io_xml->read( EXPORTING iv_name = 'PAGES'
                  CHANGING cg_data = lt_pages_info ).

    ls_attributes-devclass = iv_package.

* todo: overwrite existing
    cl_o2_api_application=>create_new(
      EXPORTING
        p_application_data      = ls_attributes
        p_nodes                 = lt_nodes
        p_navgraph              = lt_navgraph
      IMPORTING
        p_application           = lo_bsp
      EXCEPTIONS
        object_already_existing = 1
        object_just_created     = 2
        not_authorized          = 3
        undefined_name          = 4
        author_not_existing     = 5
        action_cancelled        = 6
        error_occured           = 7
        invalid_parameter       = 8 ).
    IF sy-subrc <> 0.
      lcx_exception=>raise( |WAPA - error from create_new: { sy-subrc }| ).
    ENDIF.

    lo_bsp->save( ).

    lo_bsp->set_changeable(
      p_changeable           = abap_false
      p_complete_application = abap_true ).

    ls_item-obj_type = 'WAPD'.
    ls_item-obj_name = ms_item-obj_name.
    lcl_objects_activation=>add_item( ls_item ).

    lv_objkey = ls_item-obj_name.
* todo, hmm, the WAPD is not added to the worklist during activation
    cl_o2_api_application=>activate( lv_objkey ).

    LOOP AT lt_pages_info ASSIGNING <ls_page>.
      cl_o2_api_pages=>create_new_page(
        EXPORTING
          p_pageattrs = <ls_page>-attributes
        IMPORTING
          p_page      = lo_page ).

      SPLIT <ls_page>-attributes-pagename AT '.' INTO lv_extra lv_ext.
      REPLACE ALL OCCURRENCES OF '_-' IN lv_extra WITH '/'.
      lv_content = mo_files->read_raw( iv_extra = lv_extra
                                       iv_ext   = lv_ext ).
      lo_page->set_page( to_page_content( lv_content ) ).

      lo_page->set_event_handlers( <ls_page>-event_handlers ).
      lo_page->set_parameters( <ls_page>-parameters ).
      lo_page->set_type_source( <ls_page>-types ).

      lo_page->save( p_with_all_texts = abap_true ).

      ls_item-obj_type = 'WAPP'.
      ls_item-obj_name = cl_wb_object_type=>get_concatenated_key_from_id(
        p_key_component1 = <ls_page>-attributes-applname
        p_key_component2 = <ls_page>-attributes-pagekey
        p_external_id    = 'WG ' ).
      lcl_objects_activation=>add_item( ls_item ).
    ENDLOOP.

  ENDMETHOD.                    "deserialize

  METHOD lif_object~serialize.

    DATA: lv_name       TYPE o2applname,
          ls_attributes TYPE o2applattr,
          lt_navgraph   TYPE o2applgrap_table,
          lt_pages      TYPE o2pagelist,
          lt_pages_info TYPE ty_pages_tt,
          lo_bsp        TYPE REF TO cl_o2_api_application.

    FIELD-SYMBOLS: <ls_page> LIKE LINE OF lt_pages.

    lv_name = ms_item-obj_name.

    cl_o2_api_application=>load(
      EXPORTING
        p_application_name  = lv_name
      IMPORTING
        p_application       = lo_bsp
      EXCEPTIONS
        object_not_existing = 1
        permission_failure  = 2
        error_occured       = 3 ).
    IF sy-subrc <> 0.
      RETURN.
    ENDIF.

    lo_bsp->get_attributes(
      EXPORTING
        p_version    = c_active
      IMPORTING
        p_attributes = ls_attributes ).

    CLEAR: ls_attributes-author,
           ls_attributes-createdon,
           ls_attributes-changedby,
           ls_attributes-changedon,
           ls_attributes-devclass.

    io_xml->add( iv_name = 'ATTRIBUTES'
                 ig_data = ls_attributes ).

    lo_bsp->get_navgraph(
      EXPORTING
        p_version  = c_active
      IMPORTING
        p_navgraph = lt_navgraph ).

    io_xml->add( iv_name = 'NAVGRAPH'
                 ig_data = lt_navgraph ).

    cl_o2_api_pages=>get_all_pages(
      EXPORTING
        p_applname = lv_name
        p_version  = c_active
      IMPORTING
        p_pages    = lt_pages ).

    LOOP AT lt_pages ASSIGNING <ls_page>.
      APPEND read_page( <ls_page> ) TO lt_pages_info.
    ENDLOOP.

    io_xml->add( iv_name = 'PAGES'
                 ig_data = lt_pages_info ).

  ENDMETHOD.                    "serialize

  METHOD read_page.

    DATA: lv_name    TYPE o2applname,
          ls_pagekey TYPE o2pagkey,
          lv_content TYPE xstring,
          lv_extra   TYPE string,
          lv_ext     TYPE string,
          lo_page    TYPE REF TO cl_o2_api_pages.

    lv_name = ms_item-obj_name.

    ls_pagekey-applname = lv_name.
    ls_pagekey-pagekey = is_page-pagekey.

    cl_o2_api_pages=>load(
      EXPORTING
        p_pagekey = ls_pagekey
      IMPORTING
        p_page    = lo_page ).

    lo_page->get_event_handlers(
      IMPORTING
        p_ev_handler = rs_page-event_handlers
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2 ).
    ASSERT sy-subrc = 0.

    lo_page->get_parameters(
      IMPORTING
        p_parameters = rs_page-parameters
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lo_page->get_type_source(
      IMPORTING
        p_source     = rs_page-types
      EXCEPTIONS
        page_deleted = 1
        invalid_call = 2
        OTHERS       = 3 ).
    ASSERT sy-subrc = 0.

    lv_content = get_page_content( lo_page ).
    SPLIT is_page-pagename AT '.' INTO lv_extra lv_ext.
    REPLACE ALL OCCURRENCES OF '/' IN lv_extra WITH '_-'.
    mo_files->add_raw(
      iv_extra = lv_extra
      iv_ext   = lv_ext
      iv_data  = lv_content ).

    rs_page-attributes = is_page.

    CLEAR: rs_page-attributes-author,
           rs_page-attributes-createdon,
           rs_page-attributes-changedby,
           rs_page-attributes-changedon,
           rs_page-attributes-implclass,
           rs_page-attributes-gendate,
           rs_page-attributes-gentime.

  ENDMETHOD.

  METHOD to_page_content.

    DATA: lv_string TYPE string.

    lv_string = lcl_convert=>xstring_to_string_utf8( iv_content ).

    SPLIT lv_string AT gc_newline INTO TABLE rt_content.

  ENDMETHOD.

  METHOD get_page_content.

    DATA: lt_content TYPE o2pageline_table,
          lv_string  TYPE string.

    io_page->get_page(
      IMPORTING
        p_content = lt_content ).

    CONCATENATE LINES OF lt_content INTO lv_string SEPARATED BY gc_newline RESPECTING BLANKS.

    rv_content = lcl_convert=>string_to_xstring_utf8( lv_string ).

  ENDMETHOD.

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

ENDCLASS.                    "lcl_object_tran IMPLEMENTATION

Update zabapgit_object_wapa.prog.abap

Update zabapgit_object_wapa.prog.abap


CLASS zcl_abapgit_migrations DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    CLASS-METHODS run
      RAISING zcx_abapgit_exception.

  PRIVATE SECTION.

    CLASS-METHODS rebuild_local_checksums_161112
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS local_dot_abapgit
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_MIGRATIONS IMPLEMENTATION.

  METHOD local_dot_abapgit.

    DATA: lt_repos       TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
          lv_shown       TYPE abap_bool,
          lo_dot_abapgit TYPE REF TO zcl_abapgit_dot_abapgit,
          lv_txt1        TYPE string,
          lv_txt2        TYPE string,
          lx_exception   TYPE REF TO zcx_abapgit_exception.

    FIELD-SYMBOLS: <lo_repo> LIKE LINE OF lt_repos.

    lt_repos = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repos ASSIGNING <lo_repo>.
      lo_dot_abapgit = <lo_repo>->get_dot_abapgit( ).
      IF lo_dot_abapgit->get_data( ) IS INITIAL.
        IF <lo_repo>->is_offline( ) = abap_true.
          lo_dot_abapgit = zcl_abapgit_dot_abapgit=>build_default( ).
        ELSE.
          IF lv_shown = abap_false.
            CALL FUNCTION 'POPUP_TO_INFORM'
              EXPORTING
                titel = 'Migration'
                txt1  = '.abapgit.xml is migrated to local state'
                txt2  = 'Login to remote repositories if needed'.
            lv_shown = abap_true.
          ENDIF.

          " Skip repos that cannot be fetched.
          " Particuarly useful on systems where users do not allow
          " everybody to fetch their repos.
          TRY.
              <lo_repo>->refresh( ).
            CATCH zcx_abapgit_exception INTO lx_exception.
              lv_txt1 = lx_exception->get_text( ).
              lv_txt2 = |Please do not use the "{ <lo_repo>->get_name( ) }" repository until migrated|.
              CALL FUNCTION 'POPUP_TO_INFORM'
                EXPORTING
                  titel = 'Migration has failed'
                  txt1  = lv_txt1
                  txt2  = lv_txt2
                  txt3  = 'You will be prompted to migrate the repository every time you run abapGit.'
                  txt4  = 'You can safely remove the repository in its ''Advanced -> Remove'' menu.'.
              CONTINUE.
          ENDTRY.

          lo_dot_abapgit = <lo_repo>->find_remote_dot_abapgit( ).
          IF lo_dot_abapgit IS INITIAL. " .abapgit.xml is not in the remote repo yet
            lo_dot_abapgit = zcl_abapgit_dot_abapgit=>build_default( ).
          ENDIF.
        ENDIF.
        <lo_repo>->set_dot_abapgit( lo_dot_abapgit ).
      ENDIF.

    ENDLOOP.

  ENDMETHOD.

  METHOD rebuild_local_checksums_161112.

    DATA: lt_repos     TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
          lv_repo_list TYPE string,
          lv_question  TYPE string,
          lv_answer    TYPE c,
          lv_index     TYPE i,
          lo_repo      TYPE REF TO zcl_abapgit_repo_online.

    FIELD-SYMBOLS: <lo_repo> LIKE LINE OF lt_repos.

    lt_repos = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repos ASSIGNING <lo_repo>.
      lv_index = sy-tabix.

      IF <lo_repo>->is_offline( ) = abap_true. " Skip local repos
        DELETE lt_repos INDEX lv_index.
        CONTINUE.
      ENDIF.

      " Ignore empty repos or repos with file checksums
      IF lines( <lo_repo>->get_local_checksums( ) ) = 0
          OR lines( <lo_repo>->get_local_checksums_per_file( ) ) > 0.
        DELETE lt_repos INDEX lv_index.
        CONTINUE.
      ENDIF.

      lv_repo_list = lv_repo_list && `, ` && <lo_repo>->get_name( ).

    ENDLOOP.

    IF lines( lt_repos ) = 0.
      RETURN. " All OK
    ENDIF.

    SHIFT lv_repo_list BY 2 PLACES LEFT. " Remove leading ', '

    lv_question = 'abapGit wants to rebuild missing local checksums'
               && ' (changes from 2016-12-11).'
               && ' Generally this is safe except if there are both local '
               && ' and remote changes at the same time. If unsure, please'
               && ' skip and update repos individually'
               && ' by "Advances/Update local checksums" command.'
               && | Repos affected: { lv_repo_list }|.

    lv_answer = zcl_abapgit_popups=>popup_to_confirm(
      titlebar              = 'Warning'
      text_question         = lv_question
      text_button_1         = 'OK'
      icon_button_1         = 'ICON_OK'
      text_button_2         = 'Skip update'
      icon_button_2         = 'ICON_CANCEL'
      default_button        = '2'
      display_cancel_button = abap_false ).                 "#EC NOTEXT

    IF lv_answer = '2'.
      RETURN.
    ENDIF.

    LOOP AT lt_repos ASSIGNING <lo_repo>.
      lo_repo ?= <lo_repo>.
      lo_repo->rebuild_local_checksums( ).
    ENDLOOP.

  ENDMETHOD.  " rebuild_local_checksums_20161112.

  METHOD run.

    " Migrate STDTEXT to TABLE
    zcl_abapgit_persist_migrate=>run( ).

    " Rebuild local file checksums
    rebuild_local_checksums_161112( ).

    " local .abapgit.xml state, issue #630
    local_dot_abapgit( ).

  ENDMETHOD.  " run.
ENDCLASS.

CLASS zcl_abapgit_migrations DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    CLASS-METHODS run
      RAISING zcx_abapgit_exception.

  PRIVATE SECTION.

    CLASS-METHODS rebuild_local_checksums_161112
      RAISING
        zcx_abapgit_exception .
    CLASS-METHODS local_dot_abapgit
      RAISING
        zcx_abapgit_exception .
ENDCLASS.

CLASS ZCL_ABAPGIT_MIGRATIONS IMPLEMENTATION.

  METHOD local_dot_abapgit.

    DATA: lt_repos       TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
          lo_dot_abapgit TYPE REF TO zcl_abapgit_dot_abapgit.

    FIELD-SYMBOLS: <lo_repo> LIKE LINE OF lt_repos.

    lt_repos = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repos ASSIGNING <lo_repo>.
      lo_dot_abapgit = <lo_repo>->get_dot_abapgit( ).
      IF lo_dot_abapgit->get_data( ) IS INITIAL.
        CALL FUNCTION 'POPUP_TO_INFORM'
          EXPORTING
            titel = 'Migration'
            txt1  = 'Automatic migration of .abapgit.xml removed'
            txt2  = 'Remove all repos and install latest abapGit version'.
      ENDIF.

    ENDLOOP.

  ENDMETHOD.

  METHOD rebuild_local_checksums_161112.

    DATA: lt_repos     TYPE zif_abapgit_definitions=>ty_repo_ref_tt,
          lv_repo_list TYPE string,
          lv_index     TYPE i,
          lo_repo      TYPE REF TO zcl_abapgit_repo_online.

    FIELD-SYMBOLS: <lo_repo> LIKE LINE OF lt_repos.

    lt_repos = zcl_abapgit_repo_srv=>get_instance( )->list( ).

    LOOP AT lt_repos ASSIGNING <lo_repo>.
      lv_index = sy-tabix.

      IF <lo_repo>->is_offline( ) = abap_true. " Skip local repos
        DELETE lt_repos INDEX lv_index.
        CONTINUE.
      ENDIF.

      " Ignore empty repos or repos with file checksums
      IF lines( <lo_repo>->get_local_checksums( ) ) = 0
          OR lines( <lo_repo>->get_local_checksums_per_file( ) ) > 0.
        DELETE lt_repos INDEX lv_index.
        CONTINUE.
      ENDIF.

      lv_repo_list = lv_repo_list && `, ` && <lo_repo>->get_name( ).
    ENDLOOP.

    IF lines( lt_repos ) = 0.
      RETURN. " All OK
    ENDIF.

    CALL FUNCTION 'POPUP_TO_INFORM'
      EXPORTING
        titel = 'Migration'
        txt1  = 'Automatic migration of local checksums removed'
        txt2  = 'Remove all repos and install latest abapGit version'.

  ENDMETHOD.

  METHOD run.

    " Migrate STDTEXT to TABLE
    zcl_abapgit_persist_migrate=>run( ).

    " Rebuild local file checksums
    rebuild_local_checksums_161112( ).

    " local .abapgit.xml state, issue #630
    local_dot_abapgit( ).

  ENDMETHOD.  " run.
ENDCLASS.

remove old migrations #1373

remove old migrations #1373


CLASS zcl_abapgit_gui_component DEFINITION ABSTRACT
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS constructor RAISING zcx_abapgit_exception.
  PROTECTED SECTION.
    DATA mi_gui_services TYPE REF TO zif_abapgit_gui_services.
  PRIVATE SECTION.
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_COMPONENT IMPLEMENTATION.

  METHOD constructor.
    mi_gui_services = zcl_abapgit_ui_factory=>get_gui_services( ).
  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_gui_component DEFINITION
  PUBLIC
  ABSTRACT
  CREATE PUBLIC .

  PUBLIC SECTION.
    METHODS constructor RAISING zcx_abapgit_exception.
  PROTECTED SECTION.
    DATA mi_gui_services TYPE REF TO zif_abapgit_gui_services.
  PRIVATE SECTION.
ENDCLASS.

CLASS ZCL_ABAPGIT_GUI_COMPONENT IMPLEMENTATION.

  METHOD constructor.
    mi_gui_services = zcl_abapgit_ui_factory=>get_gui_services( ).
  ENDMETHOD.
ENDCLASS.

Fix zcl_abapgit_gui_component definition (#3299)

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_ENHS
*&---------------------------------------------------------------------*

* For complete list of tool_type - see ENHSPOTTOOLS table

INTERFACE lif_object_enhs.

  METHODS:
    deserialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_input
                iv_package       TYPE devclass
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception,

    serialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_output
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception.

ENDINTERFACE.                    "lif_object_enho

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

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

  PRIVATE SECTION.
    METHODS:
      factory
        IMPORTING
          iv_tool        TYPE enhtooltype
        RETURNING
          VALUE(ri_enho) TYPE REF TO lif_object_enhs
        RAISING
          zcx_abapgit_exception.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_hook_def,
             pgmid     TYPE pgmid,
             obj_name  TYPE trobj_name,
             obj_type  TYPE trobjtype,
             main_type TYPE trobjtype,
             main_name TYPE eu_aname,
             program   TYPE progname,
             def_hooks TYPE enh_hook_def_ext_it,
           END OF ty_hook_def.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).
        li_spot_ref->get_attributes( IMPORTING changedby = rv_user ).

      CATCH cx_enh_root.
        rv_user = c_user_unknown.
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: lv_parent    TYPE enhspotcompositename,
          lv_spot_name TYPE enhspotname,
          lv_tool      TYPE enhspottooltype,
          lv_package   LIKE iv_package,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs,
          lx_root      TYPE REF TO cx_root.

    IF lif_object~exists( ) = abap_true.
      lif_object~delete( ).
    ENDIF.

    io_xml->read( EXPORTING iv_name = 'TOOL'
                  CHANGING  cg_data = lv_tool ).

    lv_spot_name = ms_item-obj_name.
    lv_package   = iv_package.

    TRY.
        cl_enh_factory=>create_enhancement_spot(
          EXPORTING
            spot_name      = lv_spot_name
            tooltype       = lv_tool
            dark           = abap_false
            compositename  = lv_parent
          IMPORTING
            spot           = li_spot_ref
          CHANGING
            devclass       = lv_package ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( lv_tool ).

    li_enhs->deserialize( io_xml           = io_xml
                          iv_package       = iv_package
                          ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "deserialize

  METHOD lif_object~serialize.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs,
          lx_root      TYPE REF TO cx_root.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( li_spot_ref->get_tool( ) ).

    li_enhs->serialize( io_xml           = io_xml
                        ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "serialize

  METHOD lif_object~exists.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

        rv_bool = abap_true.

      CATCH cx_enh_root.
        rv_bool = abap_false.
    ENDTRY.

  ENDMETHOD.  "exists

  METHOD lif_object~delete.

    DATA: lv_spot_name  TYPE enhspotname,
          li_enh_object TYPE REF TO if_enh_object,
          lx_root       TYPE REF TO cx_root.

    lv_spot_name  = ms_item-obj_name.

    TRY.
        li_enh_object ?= cl_enh_factory=>get_enhancement_spot( spot_name = lv_spot_name
                                                               lock      = abap_true ).

        li_enh_object->delete( nevertheless_delete = abap_true
                               run_dark            = abap_true ).

        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

  ENDMETHOD.  "delete

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

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'ENHS'
        in_new_window = abap_true.

  ENDMETHOD.  "jump

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

  METHOD factory.

    CASE iv_tool.
      WHEN cl_enh_tool_badi_def=>tooltype.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_badi_def.
      WHEN cl_enh_tool_hook_def=>tool_type.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_hook_def.
      WHEN OTHERS.
        zcx_abapgit_exception=>raise( |ENHS: Unsupported tool { iv_tool }| ).
    ENDCASE.

  ENDMETHOD.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_parent          TYPE enhspotcompositename,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shorttext   TYPE string,
          lv_package         LIKE iv_package,
          li_enh_object      TYPE REF TO if_enh_object,
          li_enh_object_docu TYPE REF TO if_enh_object_docu,
          lv_text            TYPE string,
          lx_error           TYPE REF TO cx_enh_root.

    FIELD-SYMBOLS: <ls_enh_badi> LIKE LINE OF lt_enh_badi.

    io_xml->read( EXPORTING iv_name = 'PARENT_COMP'
                  CHANGING  cg_data = lv_parent ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = lt_enh_badi ).

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shorttext ).

    lv_package = iv_package.

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shorttext ).

        lo_badidef_tool ?= ii_enh_spot_tool.

        LOOP AT lt_enh_badi ASSIGNING <ls_enh_badi>.
          lo_badidef_tool->add_badi_def( <ls_enh_badi> ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lv_spot_name       TYPE enhspotname,
          lv_parent          TYPE enhspotcompositename,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shorttext   TYPE string,
          li_enh_object_docu TYPE REF TO if_enh_object_docu.

    lo_badidef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shorttext = li_enh_object_docu->get_shorttext( ).

    "get parent = composite enhs (ENHC)
    lv_parent = cl_r3standard_persistence=>enh_find_parent_composite( lv_spot_name ).
    "get subsequent BADI definitions
    lt_enh_badi = lo_badidef_tool->get_badi_defs( ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shorttext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = lv_parent
                 iv_name = 'PARENT_COMP' ).

    io_xml->add( ig_data = lt_enh_badi
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_enh_shorttext       TYPE string,
          ls_enh_hook_definition TYPE enh_hook_def,
          ls_hook_definition     TYPE ty_hook_def,
          li_enh_object          TYPE REF TO if_enh_object,
          li_enh_object_docu     TYPE REF TO if_enh_object_docu,
          lo_hookdef_tool        TYPE REF TO cl_enh_tool_hook_def,
          lx_error               TYPE REF TO cx_enh_root,
          lv_text                TYPE string.

    FIELD-SYMBOLS: <ls_hook_definition> TYPE enh_hook_def_ext.

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shorttext ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = ls_hook_definition ).

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shorttext ).

        lo_hookdef_tool ?= ii_enh_spot_tool.

        LOOP AT ls_hook_definition-def_hooks ASSIGNING <ls_hook_definition>.
          MOVE-CORRESPONDING <ls_hook_definition> TO ls_enh_hook_definition.
          lo_hookdef_tool->add_hook_def( ls_enh_hook_definition ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lo_hookdef_tool    TYPE REF TO cl_enh_tool_hook_def,
          lv_enh_shorttext   TYPE string,
          li_enh_object_docu TYPE REF TO if_enh_object_docu,
          lv_include_bound   TYPE enhboolean,
          ls_hook_definition TYPE ty_hook_def.

    lo_hookdef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shorttext = li_enh_object_docu->get_shorttext( ).

    ls_hook_definition-def_hooks = lo_hookdef_tool->get_hook_defs( ).
    lv_include_bound = lo_hookdef_tool->get_include_bound( ).

    lo_hookdef_tool->get_original_object(
      IMPORTING
        pgmid     = ls_hook_definition-pgmid
        obj_name  = ls_hook_definition-obj_name
        obj_type  = ls_hook_definition-obj_type
        main_type = ls_hook_definition-main_type
        main_name = ls_hook_definition-main_name
        program   = ls_hook_definition-program       ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shorttext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = ls_hook_definition
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_OBJECT_ENHS
*&---------------------------------------------------------------------*

* For complete list of tool_type - see ENHSPOTTOOLS table

INTERFACE lif_object_enhs.

  METHODS:
    deserialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_input
                iv_package       TYPE devclass
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception,

    serialize
      IMPORTING io_xml           TYPE REF TO lcl_xml_output
                ii_enh_spot_tool TYPE REF TO if_enh_spot_tool
      RAISING   zcx_abapgit_exception.

ENDINTERFACE.                    "lif_object_enho

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

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

  PRIVATE SECTION.
    METHODS:
      factory
        IMPORTING
          iv_tool        TYPE enhtooltype
        RETURNING
          VALUE(ri_enho) TYPE REF TO lif_object_enhs
        RAISING
          zcx_abapgit_exception.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def DEFINITION.

  PUBLIC SECTION.
    INTERFACES: lif_object_enhs.

  PRIVATE SECTION.
    TYPES: BEGIN OF ty_hook_defifnition,
             pgmid     TYPE pgmid,
             obj_name  TYPE trobj_name,
             obj_type  TYPE trobjtype,
             main_type TYPE trobjtype,
             main_name TYPE eu_aname,
             program   TYPE progname,
             def_hooks TYPE enh_hook_def_ext_it,
           END OF ty_hook_defifnition.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs IMPLEMENTATION.

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

  METHOD lif_object~changed_by.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).
        li_spot_ref->get_attributes( IMPORTING changedby = rv_user ).

      CATCH cx_enh_root.
        rv_user = c_user_unknown.
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object~deserialize.

    DATA: lv_parent    TYPE enhspotcompositename,
          lv_spot_name TYPE enhspotname,
          lv_tool      TYPE enhspottooltype,
          lv_package   LIKE iv_package,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs,
          lx_root      TYPE REF TO cx_root.

    IF lif_object~exists( ) = abap_true.
      lif_object~delete( ).
    ENDIF.

    io_xml->read( EXPORTING iv_name = 'TOOL'
                  CHANGING  cg_data = lv_tool ).

    lv_spot_name = ms_item-obj_name.
    lv_package   = iv_package.

    TRY.
        cl_enh_factory=>create_enhancement_spot(
          EXPORTING
            spot_name      = lv_spot_name
            tooltype       = lv_tool
            dark           = abap_false
            compositename  = lv_parent
          IMPORTING
            spot           = li_spot_ref
          CHANGING
            devclass       = lv_package ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( lv_tool ).

    li_enhs->deserialize( io_xml           = io_xml
                          iv_package       = iv_package
                          ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "deserialize

  METHOD lif_object~serialize.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool,
          li_enhs      TYPE REF TO lif_object_enhs,
          lx_root      TYPE REF TO cx_root.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

    li_enhs = factory( li_spot_ref->get_tool( ) ).

    li_enhs->serialize( io_xml           = io_xml
                        ii_enh_spot_tool = li_spot_ref ).

  ENDMETHOD.  "serialize

  METHOD lif_object~exists.

    DATA: lv_spot_name TYPE enhspotname,
          li_spot_ref  TYPE REF TO if_enh_spot_tool.

    lv_spot_name = ms_item-obj_name.

    TRY.
        li_spot_ref = cl_enh_factory=>get_enhancement_spot( lv_spot_name ).

        rv_bool = abap_true.

      CATCH cx_enh_root.
        rv_bool = abap_false.
    ENDTRY.

  ENDMETHOD.  "exists

  METHOD lif_object~delete.

    DATA: lv_spot_name  TYPE enhspotname,
          li_enh_object TYPE REF TO if_enh_object,
          lx_root       TYPE REF TO cx_root.

    lv_spot_name  = ms_item-obj_name.

    TRY.
        li_enh_object ?= cl_enh_factory=>get_enhancement_spot( spot_name = lv_spot_name
                                                               lock      = abap_true ).

        li_enh_object->delete( nevertheless_delete = abap_true
                               run_dark            = abap_true ).

        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_root.
        zcx_abapgit_exception=>raise( 'Error from CL_ENH_FACTORY' ).
    ENDTRY.

  ENDMETHOD.  "delete

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

  METHOD lif_object~jump.

    CALL FUNCTION 'RS_TOOL_ACCESS'
      EXPORTING
        operation     = 'SHOW'
        object_name   = ms_item-obj_name
        object_type   = 'ENHS'
        in_new_window = abap_true.

  ENDMETHOD.  "jump

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

  METHOD factory.

    CASE iv_tool.
      WHEN cl_enh_tool_badi_def=>tooltype.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_badi_def.
      WHEN cl_enh_tool_hook_def=>tool_type.
        CREATE OBJECT ri_enho TYPE lcl_object_enhs_hook_def.
      WHEN OTHERS.
        zcx_abapgit_exception=>raise( |ENHS: Unsupported tool { iv_tool }| ).
    ENDCASE.

  ENDMETHOD.

ENDCLASS. "lcl_object_enhs

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_badi_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_badi_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_parent          TYPE enhspotcompositename,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shorttext   TYPE string,
          lv_package         LIKE iv_package,
          li_enh_object      TYPE REF TO if_enh_object,
          li_enh_object_docu TYPE REF TO if_enh_object_docu,
          lv_text            TYPE string,
          lx_error           TYPE REF TO cx_enh_root.

    FIELD-SYMBOLS: <ls_enh_badi> LIKE LINE OF lt_enh_badi.

    io_xml->read( EXPORTING iv_name = 'PARENT_COMP'
                  CHANGING  cg_data = lv_parent ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = lt_enh_badi ).

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shorttext ).

    lv_package = iv_package.

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shorttext ).

        lo_badidef_tool ?= ii_enh_spot_tool.

        LOOP AT lt_enh_badi ASSIGNING <ls_enh_badi>.
          lo_badidef_tool->add_badi_def( <ls_enh_badi> ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lv_spot_name       TYPE enhspotname,
          lv_parent          TYPE enhspotcompositename,
          lt_enh_badi        TYPE enh_badi_data_it,
          lo_badidef_tool    TYPE REF TO cl_enh_tool_badi_def,
          lv_enh_shorttext   TYPE string,
          li_enh_object_docu TYPE REF TO if_enh_object_docu.

    lo_badidef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shorttext = li_enh_object_docu->get_shorttext( ).

    "get parent = composite enhs (ENHC)
    lv_parent = cl_r3standard_persistence=>enh_find_parent_composite( lv_spot_name ).
    "get subsequent BADI definitions
    lt_enh_badi = lo_badidef_tool->get_badi_defs( ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shorttext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = lv_parent
                 iv_name = 'PARENT_COMP' ).

    io_xml->add( ig_data = lt_enh_badi
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

*----------------------------------------------------------------------*
*       CLASS lcl_object_enhs_hook_def IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_object_enhs_hook_def IMPLEMENTATION.

  METHOD lif_object_enhs~deserialize.

    DATA: lv_enh_shorttext       TYPE string,
          ls_enh_hook_definition TYPE enh_hook_def,
          ls_hook_definition     TYPE ty_hook_defifnition,
          li_enh_object          TYPE REF TO if_enh_object,
          li_enh_object_docu     TYPE REF TO if_enh_object_docu,
          lo_hookdef_tool        TYPE REF TO cl_enh_tool_hook_def,
          lx_error               TYPE REF TO cx_enh_root,
          lv_text                TYPE string.

    FIELD-SYMBOLS: <ls_hook_definition> TYPE enh_hook_def_ext.

    io_xml->read( EXPORTING iv_name = 'SHORTTEXT'
                  CHANGING  cg_data = lv_enh_shorttext ).

    io_xml->read( EXPORTING iv_name = 'BADI_DATA'
                  CHANGING  cg_data = ls_hook_definition ).

    li_enh_object ?= ii_enh_spot_tool.
    li_enh_object_docu ?= ii_enh_spot_tool.

    TRY.
        li_enh_object_docu->set_shorttext( lv_enh_shorttext ).

        lo_hookdef_tool ?= ii_enh_spot_tool.

        lo_hookdef_tool->set_original_object( pgmid     = ls_hook_definition-pgmid
                                              obj_name  = ls_hook_definition-obj_name
                                              obj_type  = ls_hook_definition-obj_type
                                              program   = ls_hook_definition-program
                                              main_type = ls_hook_definition-main_type
                                              main_name = ls_hook_definition-main_name ).

        LOOP AT ls_hook_definition-def_hooks ASSIGNING <ls_hook_definition>.
          MOVE-CORRESPONDING <ls_hook_definition> TO ls_enh_hook_definition.
          lo_hookdef_tool->add_hook_def( ls_enh_hook_definition ).
        ENDLOOP.

        li_enh_object->save( ).
        li_enh_object->activate( ).
        li_enh_object->unlock( ).

      CATCH cx_enh_root INTO lx_error.
        lv_text = lx_error->get_text( ).
        zcx_abapgit_exception=>raise( lv_text ).
    ENDTRY.

  ENDMETHOD.

  METHOD lif_object_enhs~serialize.

    DATA: lo_hookdef_tool    TYPE REF TO cl_enh_tool_hook_def,
          lv_enh_shorttext   TYPE string,
          li_enh_object_docu TYPE REF TO if_enh_object_docu,
          ls_hook_definition TYPE ty_hook_defifnition.

    lo_hookdef_tool ?= ii_enh_spot_tool.

    li_enh_object_docu ?= ii_enh_spot_tool.
    lv_enh_shorttext = li_enh_object_docu->get_shorttext( ).

    ls_hook_definition-def_hooks = lo_hookdef_tool->get_hook_defs( ).

    lo_hookdef_tool->get_original_object(
      IMPORTING
        pgmid     = ls_hook_definition-pgmid
        obj_name  = ls_hook_definition-obj_name
        obj_type  = ls_hook_definition-obj_type
        main_type = ls_hook_definition-main_type
        main_name = ls_hook_definition-main_name
        program   = ls_hook_definition-program       ).

    io_xml->add( ig_data = ii_enh_spot_tool->get_tool( )
                 iv_name = 'TOOL' ).

    io_xml->add( ig_data = lv_enh_shorttext
                 iv_name = 'SHORTTEXT' ).

    io_xml->add( ig_data = ls_hook_definition
                 iv_name = 'BADI_DATA' ).

  ENDMETHOD.

ENDCLASS.

Add call to set_original_object + cleanup


*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_PAGE_SETTINGS
*&---------------------------------------------------------------------*

CLASS lcl_gui_page_settings DEFINITION FINAL INHERITING FROM lcl_gui_page.

  PUBLIC SECTION.
    CONSTANTS:
      BEGIN OF c_action,
        save_settings TYPE string VALUE 'save_settings',
      END OF c_action.

    METHODS constructor.
    METHODS lif_gui_page~on_event REDEFINITION.

  PROTECTED SECTION.
    METHODS render_content REDEFINITION.

  PRIVATE SECTION.

    DATA:
      mo_settings TYPE REF TO lcl_settings,
      mv_error    TYPE abap_bool.

    METHODS render_proxy
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_development_internals
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_form_begin
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_form_end
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_max_lines
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_adt_jump_enabled
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_commit_msg
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS build_settings
      IMPORTING
        it_post_fields TYPE tihttpnvp.
    METHODS validate_settings.
    METHODS parse_post
      IMPORTING
        it_postdata           TYPE cnht_post_data_tab
      RETURNING
        VALUE(rt_post_fields) TYPE tihttpnvp.
    METHODS persist_settings
      RAISING
        lcx_exception.
    METHODS read_settings.

ENDCLASS.

CLASS lcl_gui_page_settings IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_title = 'SETTINGS'.
  ENDMETHOD.  " constructor.

  METHOD render_content.

    CREATE OBJECT ro_html.

    read_settings( ).

    ro_html->add( render_form_begin( ) ).
    ro_html->add( render_proxy( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_max_lines( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_adt_jump_enabled( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_commit_msg( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_development_internals( ) ).
    ro_html->add( render_form_end( ) ).

  ENDMETHOD.  "render_content

  METHOD render_proxy.

    CREATE OBJECT ro_html.

    ro_html->add( |
Proxy
| ).
    ro_html->add( |Proxy URL| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="proxy_url" type="text" size="50" value="` &&
      mo_settings->get_proxy_url( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |Proxy Port| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="proxy_port" type="text" size="5" value="` &&
      mo_settings->get_proxy_port( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |Proxy Authentication| ).
    IF mo_settings->get_proxy_authentication( ) = abap_true.
      ro_html->add( `<input name="proxy_auth" type="checkbox" checked>` ).
    ELSE.
      ro_html->add( `<input name="proxy_auth" type="checkbox">` ).
    ENDIF.
    ro_html->add( |
| ).

    ro_html->add( |
| ).

  ENDMETHOD.

  METHOD lif_gui_page~on_event.
* todo, check input values eg INT

    DATA:
      lt_post_fields TYPE tihttpnvp.

    CASE iv_action.
      WHEN c_action-save_settings.
        lt_post_fields = parse_post( it_postdata ).

        build_settings( lt_post_fields ).
        validate_settings( ).

        IF mv_error = abap_true.
          MESSAGE 'Error when saving settings. Open an issue at https://github.com/larshp/abapGit' TYPE 'E'.
        ELSE.
          persist_settings( ).
        ENDIF.

        ev_state = gc_event_state-go_back.
    ENDCASE.

  ENDMETHOD.

  METHOD build_settings.

    DATA: lv_i_param_value         TYPE i.
    FIELD-SYMBOLS: <ls_post_field> TYPE ihttpnvp.

    CREATE OBJECT mo_settings.
    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_url'.
    IF sy-subrc <> 0.
      mv_error = abap_true.
    ENDIF.
    mo_settings->set_proxy_url( <ls_post_field>-value ).

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_port'.
    IF sy-subrc <> 0.
      mv_error = abap_true.
    ENDIF.
    mo_settings->set_proxy_port( <ls_post_field>-value ).

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_auth'.
    IF sy-subrc = 0.
      mo_settings->set_proxy_authentication( abap_true ).
    ELSE.
      mo_settings->set_proxy_authentication( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'critical_tests'.
    IF sy-subrc = 0.
      mo_settings->set_run_critical_tests( abap_true ).
    ELSE.
      mo_settings->set_run_critical_tests( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'max_lines'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      mo_settings->set_max_lines( lv_i_param_value ).
    ELSE.
      mo_settings->set_max_lines( 0 ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'adt_jump_enabled'.
    IF sy-subrc = 0.
      mo_settings->set_adt_jump_enanbled( abap_true ).
    ELSE.
      mo_settings->set_adt_jump_enanbled( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'comment_length'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      IF lv_i_param_value < lcl_settings=>c_commitmsg_comment_length_dft.
        lv_i_param_value = lcl_settings=>c_commitmsg_comment_length_dft.
      ENDIF.
      mo_settings->set_commitmsg_comment_length( lv_i_param_value ).
    ELSE.
      mo_settings->set_commitmsg_comment_length( lcl_settings=>c_commitmsg_comment_length_dft ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'body_size'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      IF lv_i_param_value < lcl_settings=>c_commitmsg_body_size_dft.
        lv_i_param_value = lcl_settings=>c_commitmsg_body_size_dft.
      ENDIF.
      mo_settings->set_commitmsg_body_size( lv_i_param_value ).
    ELSE.
      mo_settings->set_commitmsg_body_size( lcl_settings=>c_commitmsg_body_size_dft ).
    ENDIF.

  ENDMETHOD.

  METHOD validate_settings.

    IF ( mo_settings->get_proxy_url( ) IS NOT INITIAL AND  mo_settings->get_proxy_port( ) IS INITIAL ) OR
                 ( mo_settings->get_proxy_url( ) IS INITIAL AND  mo_settings->get_proxy_port( ) IS NOT INITIAL ).
      MESSAGE 'If specifying proxy, specify both URL and port' TYPE 'W'.
    ENDIF.

  ENDMETHOD.

  METHOD parse_post.

    DATA lv_serialized_post_data TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_serialized_post_data.
    rt_post_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_serialized_post_data ).

  ENDMETHOD.

  METHOD persist_settings.

    DATA lo_settings_persistence TYPE REF TO lcl_persistence_settings.

    lo_settings_persistence = lcl_app=>settings( ).
    lo_settings_persistence->modify( mo_settings ).
    MESSAGE 'Settings succesfully saved' TYPE 'S'.

  ENDMETHOD.

  METHOD render_form_begin.

    CREATE OBJECT ro_html.
    ro_html->add( '
' ).
    ro_html->add( `<form id="settings_form" method="post" action="sapevent:` && c_action-save_settings && `">` ).

  ENDMETHOD.

  METHOD render_form_end.

    CREATE OBJECT ro_html.
    ro_html->add( '<input type="submit" value="Save" class="submit">' ).
    ro_html->add( '</form>' ).
    ro_html->add( '
' ).

  ENDMETHOD.

  METHOD read_settings.

    DATA lo_settings_persistence TYPE REF TO lcl_persistence_settings.

    lo_settings_persistence = lcl_app=>settings( ).
    mo_settings = lo_settings_persistence->read( ).

  ENDMETHOD.

  METHOD render_development_internals.

    DATA lv_checked TYPE string.

    IF mo_settings->get_run_critical_tests( ) = abap_true.
      lv_checked = 'checked'.
    ENDIF.

    CREATE OBJECT ro_html.
    ro_html->add( |
abapGit Development Internals settings
| ).
    ro_html->add( `<input type="checkbox" name="critical_tests" value="X" `
                   && lv_checked && ` > Enable critical unit tests (see LTCL_DANGEROUS)` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).

  ENDMETHOD.

  METHOD render_max_lines.
    CREATE OBJECT ro_html.

    ro_html->add( |
List size
| ).
    ro_html->add( |Max. # of objects listed (0 = all)| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="max_lines" type="text" size="5" value="` && mo_settings->get_max_lines( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

  METHOD render_adt_jump_enabled.

    DATA lv_checked TYPE string.

    IF mo_settings->get_adt_jump_enabled( ) = abap_true.
      lv_checked = 'checked'.
    ENDIF.

    CREATE OBJECT ro_html.
    ro_html->add( |
ABAP Development Tools (ADT)
| ).
    ro_html->add( `<input type="checkbox" name="adt_jump_enabled" value="X" `
                   && lv_checked && ` > Enable jump to ADT first` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

  METHOD render_commit_msg.
    CREATE OBJECT ro_html.

    ro_html->add( |
Commit Message
| ).
    ro_html->add( |Max. length of comment (recommendation 50)| ).
    ro_html->add( |
| ).
    ro_html->add( |<input name="comment_length" type="number" step="10" size="3" maxlength="3" min="50"| &&
                  | value="{ mo_settings->get_commitmsg_comment_length( ) }">| ).
    ro_html->add( |
| ).
    ro_html->add( |Max. line size of body (recommendation 72)| ).
    ro_html->add( |
| ).
    ro_html->add( |<input name="body_size" type="number" step="10" size="3" maxlength="3" min="50"| &&
                  | value="{ mo_settings->get_commitmsg_body_size( ) }">| ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

ENDCLASS.

*&---------------------------------------------------------------------*
*&  Include           ZABAPGIT_PAGE_SETTINGS
*&---------------------------------------------------------------------*

CLASS lcl_gui_page_settings DEFINITION FINAL INHERITING FROM lcl_gui_page.

  PUBLIC SECTION.
    CONSTANTS:
      BEGIN OF c_action,
        save_settings TYPE string VALUE 'save_settings',
      END OF c_action.

    METHODS constructor.
    METHODS lif_gui_page~on_event REDEFINITION.

  PROTECTED SECTION.
    METHODS render_content REDEFINITION.

  PRIVATE SECTION.

    DATA:
      mo_settings TYPE REF TO lcl_settings,
      mv_error    TYPE abap_bool.

    METHODS render_proxy
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_development_internals
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_form_begin
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_form_end
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_max_lines
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_adt_jump_enabled
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS render_commit_msg
      RETURNING VALUE(ro_html) TYPE REF TO lcl_html.
    METHODS build_settings
      IMPORTING
        it_post_fields TYPE tihttpnvp.
    METHODS validate_settings.
    METHODS parse_post
      IMPORTING
        it_postdata           TYPE cnht_post_data_tab
      RETURNING
        VALUE(rt_post_fields) TYPE tihttpnvp.
    METHODS persist_settings
      RAISING
        lcx_exception.
    METHODS read_settings.

ENDCLASS.

CLASS lcl_gui_page_settings IMPLEMENTATION.

  METHOD constructor.
    super->constructor( ).
    ms_control-page_title = 'SETTINGS'.
  ENDMETHOD.  " constructor.

  METHOD render_content.

    CREATE OBJECT ro_html.

    read_settings( ).

    ro_html->add( render_form_begin( ) ).
    ro_html->add( render_proxy( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_max_lines( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_adt_jump_enabled( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_commit_msg( ) ).
    ro_html->add( |
| ).
    ro_html->add( render_development_internals( ) ).
    ro_html->add( render_form_end( ) ).

  ENDMETHOD.  "render_content

  METHOD render_proxy.

    CREATE OBJECT ro_html.

    ro_html->add( |
Proxy
| ).
    ro_html->add( |Proxy URL| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="proxy_url" type="text" size="50" value="` &&
      mo_settings->get_proxy_url( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |Proxy Port| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="proxy_port" type="text" size="5" value="` &&
      mo_settings->get_proxy_port( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |Proxy Authentication| ).
    IF mo_settings->get_proxy_authentication( ) = abap_true.
      ro_html->add( `<input name="proxy_auth" type="checkbox" checked>` ).
    ELSE.
      ro_html->add( `<input name="proxy_auth" type="checkbox">` ).
    ENDIF.
    ro_html->add( |
| ).

    ro_html->add( |
| ).

  ENDMETHOD.

  METHOD lif_gui_page~on_event.
* todo, check input values eg INT

    DATA:
      lt_post_fields TYPE tihttpnvp.

    CASE iv_action.
      WHEN c_action-save_settings.
        lt_post_fields = parse_post( it_postdata ).

        build_settings( lt_post_fields ).
        validate_settings( ).

        IF mv_error = abap_true.
          MESSAGE 'Error when saving settings. Open an issue at https://github.com/larshp/abapGit' TYPE 'E'.
        ELSE.
          persist_settings( ).
        ENDIF.

        ev_state = gc_event_state-go_back.
    ENDCASE.

  ENDMETHOD.

  METHOD build_settings.

    DATA: lv_i_param_value         TYPE i.
    FIELD-SYMBOLS: <ls_post_field> TYPE ihttpnvp.

    CREATE OBJECT mo_settings.
    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_url'.
    IF sy-subrc <> 0.
      mv_error = abap_true.
    ENDIF.
    mo_settings->set_proxy_url( <ls_post_field>-value ).

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_port'.
    IF sy-subrc <> 0.
      mv_error = abap_true.
    ENDIF.
    mo_settings->set_proxy_port( <ls_post_field>-value ).

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'proxy_auth'.
    IF sy-subrc = 0.
      mo_settings->set_proxy_authentication( abap_true ).
    ELSE.
      mo_settings->set_proxy_authentication( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'critical_tests'.
    IF sy-subrc = 0.
      mo_settings->set_run_critical_tests( abap_true ).
    ELSE.
      mo_settings->set_run_critical_tests( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'max_lines'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      mo_settings->set_max_lines( lv_i_param_value ).
    ELSE.
      mo_settings->set_max_lines( 0 ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'adt_jump_enabled'.
    IF sy-subrc = 0.
      mo_settings->set_adt_jump_enanbled( abap_true ).
    ELSE.
      mo_settings->set_adt_jump_enanbled( abap_false ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'comment_length'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      IF lv_i_param_value < lcl_settings=>c_commitmsg_comment_length_dft.
        lv_i_param_value = lcl_settings=>c_commitmsg_comment_length_dft.
      ENDIF.
      mo_settings->set_commitmsg_comment_length( lv_i_param_value ).
    ELSE.
      mo_settings->set_commitmsg_comment_length( lcl_settings=>c_commitmsg_comment_length_dft ).
    ENDIF.

    READ TABLE it_post_fields ASSIGNING <ls_post_field> WITH KEY name = 'body_size'.
    IF sy-subrc = 0.
      lv_i_param_value = <ls_post_field>-value.
      IF lv_i_param_value < lcl_settings=>c_commitmsg_body_size_dft.
        lv_i_param_value = lcl_settings=>c_commitmsg_body_size_dft.
      ENDIF.
      mo_settings->set_commitmsg_body_size( lv_i_param_value ).
    ELSE.
      mo_settings->set_commitmsg_body_size( lcl_settings=>c_commitmsg_body_size_dft ).
    ENDIF.

  ENDMETHOD.

  METHOD validate_settings.

    IF ( mo_settings->get_proxy_url( ) IS NOT INITIAL AND  mo_settings->get_proxy_port( ) IS INITIAL ) OR
                 ( mo_settings->get_proxy_url( ) IS INITIAL AND  mo_settings->get_proxy_port( ) IS NOT INITIAL ).
      MESSAGE 'If specifying proxy, specify both URL and port' TYPE 'W'.
    ENDIF.

  ENDMETHOD.

  METHOD parse_post.

    DATA lv_serialized_post_data TYPE string.

    CONCATENATE LINES OF it_postdata INTO lv_serialized_post_data.
    rt_post_fields = cl_http_utility=>if_http_utility~string_to_fields( lv_serialized_post_data ).

  ENDMETHOD.

  METHOD persist_settings.

    DATA lo_settings_persistence TYPE REF TO lcl_persistence_settings.

    lo_settings_persistence = lcl_app=>settings( ).
    lo_settings_persistence->modify( mo_settings ).
    MESSAGE 'Settings succesfully saved' TYPE 'S'.

  ENDMETHOD.

  METHOD render_form_begin.

    CREATE OBJECT ro_html.
    ro_html->add( '
' ).
    ro_html->add( `<form id="settings_form" method="post" action="sapevent:` && c_action-save_settings && `">` ).

  ENDMETHOD.

  METHOD render_form_end.

    CREATE OBJECT ro_html.
    ro_html->add( '<input type="submit" value="Save" class="submit">' ).
    ro_html->add( '</form>' ).
    ro_html->add( '
' ).

  ENDMETHOD.

  METHOD read_settings.

    DATA lo_settings_persistence TYPE REF TO lcl_persistence_settings.

    lo_settings_persistence = lcl_app=>settings( ).
    mo_settings = lo_settings_persistence->read( ).

  ENDMETHOD.

  METHOD render_development_internals.

    DATA lv_checked TYPE string.

    IF mo_settings->get_run_critical_tests( ) = abap_true.
      lv_checked = 'checked'.
    ENDIF.

    CREATE OBJECT ro_html.
    ro_html->add( |
abapGit Development Internals settings
| ).
    ro_html->add( `<input type="checkbox" name="critical_tests" value="X" `
                   && lv_checked && ` > Enable critical unit tests (see LTCL_DANGEROUS)` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).

  ENDMETHOD.

  METHOD render_max_lines.
    CREATE OBJECT ro_html.

    ro_html->add( |
List size
| ).
    ro_html->add( |Max. # of objects listed (0 = all)| ).
    ro_html->add( |
| ).
    ro_html->add( `<input name="max_lines" type="text" size="5" value="` && mo_settings->get_max_lines( ) && `">` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

  METHOD render_adt_jump_enabled.

    DATA lv_checked TYPE string.

    IF mo_settings->get_adt_jump_enabled( ) = abap_true.
      lv_checked = 'checked'.
    ENDIF.

    CREATE OBJECT ro_html.
    ro_html->add( |
ABAP Development Tools (ADT)
| ).
    ro_html->add( `<input type="checkbox" name="adt_jump_enabled" value="X" `
                   && lv_checked && ` > Enable jump to ADT first` ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

  METHOD render_commit_msg.
    CREATE OBJECT ro_html.

    ro_html->add( |
Commit Message
| ).
    ro_html->add( |Max. length of comment (recommendation 50)| ).
    ro_html->add( |
| ).
    ro_html->add( |<input name="comment_length" type="number" step="10" size="3" maxlength="3" min="50"| &&
                  | value="{ mo_settings->get_commitmsg_comment_length( ) }">| ).
    ro_html->add( |
| ).
    ro_html->add( |Max. line size of body (recommendation 72)| ).
    ro_html->add( |
| ).
    ro_html->add( |<input name="body_size" type="number" size="3" maxlength="3" min="50"| &&
                  | value="{ mo_settings->get_commitmsg_body_size( ) }">| ).
    ro_html->add( |
| ).
    ro_html->add( |
| ).
  ENDMETHOD.

ENDCLASS.

fix #739

fix #739

https://github.com/larshp/abapGit/issues/739


CLASS zcl_abapgit_file_deserialize DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS get_results
      IMPORTING
        !io_repo          TYPE REF TO zcl_abapgit_repo
        !ii_log           TYPE REF TO zif_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.

  PRIVATE SECTION.

    CLASS-METHODS filter_files_to_deserialize
      IMPORTING
        !it_results       TYPE zif_abapgit_definitions=>ty_results_tt
        !ii_log           TYPE REF TO zif_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt .
    CLASS-METHODS prioritize_deser
      IMPORTING
        !ii_log           TYPE REF TO zif_abapgit_log
        !it_results       TYPE zif_abapgit_definitions=>ty_results_tt
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt .
    CLASS-METHODS map_results_to_items
      IMPORTING
        !it_results     TYPE zif_abapgit_definitions=>ty_results_tt
      RETURNING
        VALUE(rt_items) TYPE zif_abapgit_definitions=>ty_items_tt .
ENDCLASS.

CLASS ZCL_ABAPGIT_FILE_DESERIALIZE IMPLEMENTATION.

  METHOD filter_files_to_deserialize.

    DATA lt_objects LIKE rt_results.
    DATA lr_object  TYPE REF TO zif_abapgit_definitions=>ty_result.
    DATA ls_item    TYPE zif_abapgit_definitions=>ty_item.
    DATA lv_tabix   TYPE sy-tabix.

    rt_results = it_results.

    "preparation for object logging, sort all file entries by objects
    IF ii_log IS BOUND.
      lt_objects = rt_results.
      SORT lt_objects
        BY obj_type
           obj_name.
      DELETE ADJACENT DUPLICATES FROM lt_objects COMPARING obj_type obj_name.
      DELETE lt_objects WHERE obj_type IS INITIAL AND obj_name IS INITIAL.
    ENDIF.

    "ignore objects w/o changes
    DELETE rt_results WHERE match = abap_true.     " Full match
    "log objects w/o changes
    IF sy-subrc = 0 AND ii_log IS BOUND.
      SORT rt_results BY obj_type obj_name.
      LOOP AT lt_objects REFERENCE INTO lr_object.
        lv_tabix = sy-tabix.
        READ TABLE rt_results WITH KEY obj_type = lr_object->obj_type
                                       obj_name = lr_object->obj_name
                              BINARY SEARCH TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          "all parts of the objects have not changed
          ls_item-devclass = lr_object->package.
          ls_item-obj_type = lr_object->obj_type.
          ls_item-obj_name = lr_object->obj_name.
          ii_log->add_success(
            iv_msg  = |Object { ls_item-obj_name } (type { ls_item-obj_type }) not changed; no import required|
            is_item = ls_item ).
          "ignore object for further messages
          DELETE lt_objects INDEX lv_tabix.
        ENDIF.
      ENDLOOP.
    ENDIF.

    "ignore objects w/o object type
    DELETE rt_results WHERE obj_type IS INITIAL.
    "log objects w/o object type
    IF sy-subrc = 0 AND ii_log IS BOUND.
      LOOP AT lt_objects REFERENCE INTO lr_object WHERE obj_type IS INITIAL.
        CHECK lr_object->obj_name IS NOT INITIAL.
        ls_item-devclass = lr_object->package.
        ls_item-obj_type = lr_object->obj_type.
        ls_item-obj_name = lr_object->obj_name.
        ii_log->add_warning(
          iv_msg  = |Object type for { ls_item-obj_name } not defined - will be ignored by abapGit|
          is_item = ls_item ).
      ENDLOOP.
      DELETE lt_objects WHERE obj_type IS INITIAL.
    ENDIF.

    "ignore objects that exists only local
    DELETE rt_results WHERE lstate = zif_abapgit_definitions=>c_state-added AND rstate IS INITIAL.
    "ignore objects that where deleted remotely
    DELETE rt_results WHERE rstate = zif_abapgit_definitions=>c_state-deleted.
    "log objects that exists only local or where deleted remotely
    IF sy-subrc = 0 AND ii_log IS BOUND.
      SORT rt_results BY obj_type obj_name.
      LOOP AT lt_objects REFERENCE INTO lr_object.
        lv_tabix = sy-tabix.
        READ TABLE rt_results WITH KEY obj_type = lr_object->obj_type
                                       obj_name = lr_object->obj_name
                              BINARY SEARCH TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          "all parts exists only local
          "no log message; ignore object for further messages
          DELETE lt_objects INDEX lv_tabix.
        ENDIF.
      ENDLOOP.
    ENDIF.

    SORT rt_results
      BY obj_type ASCENDING
         obj_name ASCENDING
         rstate   DESCENDING  " ensures that non-empty rstate is kept
         lstate   DESCENDING. " ensures that non-empty lstate is kept
    DELETE ADJACENT DUPLICATES FROM rt_results COMPARING obj_type obj_name.

  ENDMETHOD.

  METHOD get_results.

    DATA lt_results TYPE zif_abapgit_definitions=>ty_results_tt.

    lt_results = filter_files_to_deserialize(
      it_results = zcl_abapgit_file_status=>status( io_repo )
      ii_log     = ii_log ).

    rt_results = prioritize_deser(
      ii_log     = ii_log
      it_results = lt_results ).

  ENDMETHOD.

  METHOD map_results_to_items.

    DATA ls_item LIKE LINE OF rt_items.
    FIELD-SYMBOLS: <ls_result> TYPE zif_abapgit_definitions=>ty_result.

    LOOP AT it_results ASSIGNING <ls_result>.
      ls_item-devclass = <ls_result>-package.
      ls_item-obj_type = <ls_result>-obj_type.
      ls_item-obj_name = <ls_result>-obj_name.
      INSERT ls_item INTO TABLE rt_items.
    ENDLOOP.

  ENDMETHOD.

  METHOD prioritize_deser.

    DATA lt_items    TYPE zif_abapgit_definitions=>ty_items_tt.
    DATA ls_item     LIKE LINE OF lt_items.
    DATA lt_requires TYPE zif_abapgit_definitions=>ty_items_tt.
    DATA ls_require  LIKE LINE OF lt_requires.
    DATA ls_result   LIKE LINE OF it_results.
    DATA lo_graph    TYPE REF TO zcl_abapgit_item_graph.

    lt_items = map_results_to_items( it_results ).

    CREATE OBJECT lo_graph EXPORTING it_items = lt_items.

    LOOP AT lt_items INTO ls_item.
      CLEAR lt_requires.

* TODO: BEGIN extract to object handler method in ZIF_ABAPGIT_OBJECT:
*    METHODS get_deserialize_order
*      IMPORTING
*        it_items TYPE ty_items_tt
*      RETURNING
*        VALUE(rt_requries) TYPE ty_items_tt

      CASE ls_item-obj_type.
        WHEN 'SPRX'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'WEBI'.
        WHEN 'CLAS'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'
            AND obj_type <> 'INTF'
            AND obj_type <> 'XSLT'.
        WHEN 'PROG'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'XSLT'.
        WHEN 'INTF'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'
            AND obj_type <> 'XSLT'.
        WHEN 'TABL'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'.
        WHEN 'IARP'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IASP'.
        WHEN 'IATU' OR 'IAXU'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IASP'
            AND obj_type <> 'PROG'
            AND obj_type <> 'IARP'.
        WHEN 'DCLS'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'DDLS'.
        WHEN 'ODSO'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IOBJ'.
        WHEN 'SCP1'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'TOBJ'.
        WHEN 'CHAR'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'OTGR'.
        WHEN 'PINF'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'CLAS'
            AND obj_type <> 'INTF'
            AND obj_type <> 'TABL'
            AND obj_type <> 'DOMA'
            AND obj_type <> 'DTEL'.
        WHEN 'DEVC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'PINF'.
        WHEN 'ENHC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENHO'.
        WHEN 'ENHO'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENSC'.
        WHEN 'ENSC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENHS'.
      ENDCASE.
* TODO: END extract to object handler method

      LOOP AT lt_requires INTO ls_require.
        lo_graph->add_edge(
          is_from = ls_require
          is_to   = ls_item ).
      ENDLOOP.
    ENDLOOP.

    WHILE lo_graph->has_vertices( ) = abap_true.
      ls_item = lo_graph->get_next( ii_log ).
      READ TABLE it_results INTO ls_result WITH KEY
        obj_name = ls_item-obj_name
        obj_type = ls_item-obj_type.
      ASSERT sy-subrc = 0.
      APPEND ls_result TO rt_results.
    ENDWHILE.

  ENDMETHOD.
ENDCLASS.

CLASS zcl_abapgit_file_deserialize DEFINITION
  PUBLIC
  CREATE PUBLIC .

  PUBLIC SECTION.

    CLASS-METHODS get_results
      IMPORTING
        !io_repo          TYPE REF TO zcl_abapgit_repo
        !ii_log           TYPE REF TO zif_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt
      RAISING
        zcx_abapgit_exception .
  PROTECTED SECTION.

  PRIVATE SECTION.

    CLASS-METHODS filter_files_to_deserialize
      IMPORTING
        !it_results       TYPE zif_abapgit_definitions=>ty_results_tt
        !ii_log           TYPE REF TO zif_abapgit_log OPTIONAL
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt .
    CLASS-METHODS prioritize_deser
      IMPORTING
        !ii_log           TYPE REF TO zif_abapgit_log
        !it_results       TYPE zif_abapgit_definitions=>ty_results_tt
      RETURNING
        VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt .
    CLASS-METHODS map_results_to_items
      IMPORTING
        !it_results     TYPE zif_abapgit_definitions=>ty_results_tt
      RETURNING
        VALUE(rt_items) TYPE zif_abapgit_definitions=>ty_items_tt .
ENDCLASS.

CLASS ZCL_ABAPGIT_FILE_DESERIALIZE IMPLEMENTATION.

  METHOD filter_files_to_deserialize.

    DATA lt_objects LIKE rt_results.
    DATA lr_object  TYPE REF TO zif_abapgit_definitions=>ty_result.
    DATA ls_item    TYPE zif_abapgit_definitions=>ty_item.
    DATA lv_tabix   TYPE sy-tabix.

    rt_results = it_results.

    "preparation for object logging, sort all file entries by objects
    IF ii_log IS BOUND.
      lt_objects = rt_results.
      SORT lt_objects
        BY obj_type
           obj_name.
      DELETE ADJACENT DUPLICATES FROM lt_objects COMPARING obj_type obj_name.
      DELETE lt_objects WHERE obj_type IS INITIAL AND obj_name IS INITIAL.
    ENDIF.

    "ignore objects w/o changes
    DELETE rt_results WHERE match = abap_true.     " Full match
    "log objects w/o changes
    IF sy-subrc = 0 AND ii_log IS BOUND.
      SORT rt_results BY obj_type obj_name.
      LOOP AT lt_objects REFERENCE INTO lr_object.
        lv_tabix = sy-tabix.
        READ TABLE rt_results WITH KEY obj_type = lr_object->obj_type
                                       obj_name = lr_object->obj_name
                              BINARY SEARCH TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          "all parts of the objects have not changed
          ls_item-devclass = lr_object->package.
          ls_item-obj_type = lr_object->obj_type.
          ls_item-obj_name = lr_object->obj_name.
          ii_log->add_success(
            iv_msg  = |Object { ls_item-obj_name } (type { ls_item-obj_type }) not changed; no import required|
            is_item = ls_item ).
          "ignore object for further messages
          DELETE lt_objects INDEX lv_tabix.
        ENDIF.
      ENDLOOP.
    ENDIF.

    "ignore objects w/o object type
    DELETE rt_results WHERE obj_type IS INITIAL.
    "log objects w/o object type
    IF sy-subrc = 0 AND ii_log IS BOUND.
      LOOP AT lt_objects REFERENCE INTO lr_object WHERE obj_type IS INITIAL.
        CHECK lr_object->obj_name IS NOT INITIAL.
        ls_item-devclass = lr_object->package.
        ls_item-obj_type = lr_object->obj_type.
        ls_item-obj_name = lr_object->obj_name.
        ii_log->add_warning(
          iv_msg  = |Object type for { ls_item-obj_name } not defined - will be ignored by abapGit|
          is_item = ls_item ).
      ENDLOOP.
      DELETE lt_objects WHERE obj_type IS INITIAL.
    ENDIF.

    "ignore objects that exists only local
    DELETE rt_results WHERE lstate = zif_abapgit_definitions=>c_state-added AND rstate IS INITIAL.
    "ignore objects that where deleted remotely
    DELETE rt_results WHERE rstate = zif_abapgit_definitions=>c_state-deleted.
    "log objects that exists only local or where deleted remotely
    IF sy-subrc = 0 AND ii_log IS BOUND.
      SORT rt_results BY obj_type obj_name.
      LOOP AT lt_objects REFERENCE INTO lr_object.
        lv_tabix = sy-tabix.
        READ TABLE rt_results WITH KEY obj_type = lr_object->obj_type
                                       obj_name = lr_object->obj_name
                              BINARY SEARCH TRANSPORTING NO FIELDS.
        IF sy-subrc <> 0.
          "all parts exists only local
          "no log message; ignore object for further messages
          DELETE lt_objects INDEX lv_tabix.
        ENDIF.
      ENDLOOP.
    ENDIF.

    "ignore table content
    DELETE rt_results WHERE path = zif_abapgit_data_config=>c_default_path.

    SORT rt_results
      BY obj_type ASCENDING
         obj_name ASCENDING
         rstate   DESCENDING  " ensures that non-empty rstate is kept
         lstate   DESCENDING. " ensures that non-empty lstate is kept
    DELETE ADJACENT DUPLICATES FROM rt_results COMPARING obj_type obj_name.

  ENDMETHOD.

  METHOD get_results.

    DATA lt_results TYPE zif_abapgit_definitions=>ty_results_tt.

    lt_results = filter_files_to_deserialize(
      it_results = zcl_abapgit_file_status=>status( io_repo )
      ii_log     = ii_log ).

    rt_results = prioritize_deser(
      ii_log     = ii_log
      it_results = lt_results ).

  ENDMETHOD.

  METHOD map_results_to_items.

    DATA ls_item LIKE LINE OF rt_items.
    FIELD-SYMBOLS: <ls_result> TYPE zif_abapgit_definitions=>ty_result.

    LOOP AT it_results ASSIGNING <ls_result>.
      ls_item-devclass = <ls_result>-package.
      ls_item-obj_type = <ls_result>-obj_type.
      ls_item-obj_name = <ls_result>-obj_name.
      INSERT ls_item INTO TABLE rt_items.
    ENDLOOP.

  ENDMETHOD.

  METHOD prioritize_deser.

    DATA lt_items    TYPE zif_abapgit_definitions=>ty_items_tt.
    DATA ls_item     LIKE LINE OF lt_items.
    DATA lt_requires TYPE zif_abapgit_definitions=>ty_items_tt.
    DATA ls_require  LIKE LINE OF lt_requires.
    DATA ls_result   LIKE LINE OF it_results.
    DATA lo_graph    TYPE REF TO zcl_abapgit_item_graph.

    lt_items = map_results_to_items( it_results ).

    CREATE OBJECT lo_graph EXPORTING it_items = lt_items.

    LOOP AT lt_items INTO ls_item.
      CLEAR lt_requires.

* TODO: BEGIN extract to object handler method in ZIF_ABAPGIT_OBJECT:
*    METHODS get_deserialize_order
*      IMPORTING
*        it_items TYPE ty_items_tt
*      RETURNING
*        VALUE(rt_requries) TYPE ty_items_tt

      CASE ls_item-obj_type.
        WHEN 'SPRX'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'WEBI'.
        WHEN 'CLAS'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'
            AND obj_type <> 'INTF'
            AND obj_type <> 'XSLT'.
        WHEN 'PROG'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'XSLT'.
        WHEN 'INTF'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'
            AND obj_type <> 'XSLT'.
        WHEN 'TABL'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'SPRX'.
        WHEN 'IARP'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IASP'.
        WHEN 'IATU' OR 'IAXU'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IASP'
            AND obj_type <> 'PROG'
            AND obj_type <> 'IARP'.
        WHEN 'DCLS'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'DDLS'.
        WHEN 'ODSO'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'IOBJ'.
        WHEN 'SCP1'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'TOBJ'.
        WHEN 'CHAR'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'OTGR'.
        WHEN 'PINF'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'CLAS'
            AND obj_type <> 'INTF'
            AND obj_type <> 'TABL'
            AND obj_type <> 'DOMA'
            AND obj_type <> 'DTEL'.
        WHEN 'DEVC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'PINF'.
        WHEN 'ENHC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENHO'.
        WHEN 'ENHO'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENSC'.
        WHEN 'ENSC'.
          lt_requires = lt_items.
          DELETE lt_requires WHERE obj_type <> 'ENHS'.
      ENDCASE.
* TODO: END extract to object handler method

      LOOP AT lt_requires INTO ls_require.
        lo_graph->add_edge(
          is_from = ls_require
          is_to   = ls_item ).
      ENDLOOP.
    ENDLOOP.

    WHILE lo_graph->has_vertices( ) = abap_true.
      ls_item = lo_graph->get_next( ii_log ).
      READ TABLE it_results INTO ls_result WITH KEY
        obj_name = ls_item-obj_name
        obj_type = ls_item-obj_type.
      ASSERT sy-subrc = 0.
      APPEND ls_result TO rt_results.
    ENDWHILE.

  ENDMETHOD.
ENDCLASS.

Fix dump ASSERTION_FAILED during table content deserialization (#5586)

* Data import: fix dump ITAB_DUPLICATE_KEY

System dumps during serialization of customizing table comprizing of include structures. Example: WCFC_GIL_COMPROP.

* Fix error "Object type TABU is not supported"

* Fix date format incorrect during serialization

* Fix /data/ serialization package issue

* Commit table content after deserialization

* Cleaning some code

* Rollback code change concerning /data/ folder

Doesn't seem to be necessary in the end...

* Renamed variable <tab> to <lt_tab>

* Fix ASSERTION_FAILED table content deserialization

Issue https://github.com/abapGit/abapGit/issues/5585

Co-authored-by: Lars Hvam <721d1b171982cd84b755f6b25130d2b88cd1f696@hotmail.com>