anchor.diff:          !it_cur_state     TYPE zif_abapgit_definitions=>ty_file_signatures_tt
         RETURNING
           VALUE(rt_results) TYPE zif_abapgit_definitions=>ty_results_tt
  +      RAISING
  +        zcx_abapgit_exception .
  +    CLASS-METHODS prepare_remote
  +      IMPORTING
  +        !io_dot          TYPE REF TO zcl_abapgit_dot_abapgit
  +        !it_remote       TYPE zif_abapgit_definitions=>ty_files_tt
  +      RETURNING
  +        VALUE(rt_remote) TYPE zif_abapgit_definitions=>ty_files_tt
  +      RAISING
  +        zcx_abapgit_exception .
  +    CLASS-METHODS process_local
  +      IMPORTING
  +        !iv_devclass  TYPE devclass
  +        !io_dot       TYPE REF TO zcl_abapgit_dot_abapgit
  +        !it_local     TYPE zif_abapgit_definitions=>ty_files_item_tt
  +        !it_state_idx TYPE zif_abapgit_definitions=>ty_file_signatures_ts
  +      CHANGING
  +        !ct_remote    TYPE zif_abapgit_definitions=>ty_files_tt
  +        !ct_items     TYPE zif_abapgit_definitions=>ty_items_tt
  +        !ct_results   TYPE zif_abapgit_definitions=>ty_results_tt
  +      RAISING
  +        zcx_abapgit_exception .
  +    CLASS-METHODS process_items
  +      IMPORTING
  +        !iv_devclass TYPE devclass
  +        !io_dot      TYPE REF TO zcl_abapgit_dot_abapgit
  +        !it_local    TYPE zif_abapgit_definitions=>ty_files_item_tt
  +        !it_remote   TYPE zif_abapgit_definitions=>ty_files_tt
  +      CHANGING
  +        !ct_items    TYPE zif_abapgit_definitions=>ty_items_tt
  +      RAISING
  +        zcx_abapgit_exception .
  +    CLASS-METHODS process_remote
  +      IMPORTING
  +        !iv_devclass  TYPE devclass
  +        !io_dot       TYPE REF TO zcl_abapgit_dot_abapgit
  +        !it_local     TYPE zif_abapgit_definitions=>ty_files_item_tt
  +        !it_remote    TYPE zif_abapgit_definitions=>ty_files_tt
  +        !it_state_idx TYPE zif_abapgit_definitions=>ty_file_signatures_ts
  +        !it_items_idx TYPE zif_abapgit_definitions=>ty_items_ts
  +      CHANGING
  +        !ct_results   TYPE zif_abapgit_definitions=>ty_results_tt
         RAISING
           zcx_abapgit_exception .
       CLASS-METHODS run_checks
  
positive.code:         ENDIF.
        ENDIF.
      ENDLOOP.
  
      SORT rt_results BY
        obj_type ASCENDING
        obj_name ASCENDING
        filename ASCENDING
        path ASCENDING.
  
    ENDMETHOD.
  
  
    METHOD check_files_folder.
  
      DATA:
        ls_item     TYPE zif_abapgit_definitions=>ty_item,
        lt_res_sort LIKE it_results,
        lt_item_idx LIKE it_results.
  
      FIELD-SYMBOLS:
        <ls_result>     LIKE LINE OF it_results,
        <ls_result_idx> LIKE LINE OF it_results.
  
      " Collect object index
      lt_res_sort = it_results.
      SORT lt_res_sort BY obj_type ASCENDING obj_name ASCENDING.
  
      LOOP AT it_results ASSIGNING <ls_result> WHERE NOT obj_type IS INITIAL AND packmove = abap_false.
  
        IF NOT ( <ls_result>-obj_type = ls_item-obj_type
            AND <ls_result>-obj_name = ls_item-obj_name ).
          APPEND INITIAL LINE TO lt_item_idx ASSIGNING <ls_result_idx>.
          <ls_result_idx>-obj_type = <ls_result>-obj_type.
          <ls_result_idx>-obj_name = <ls_result>-obj_name.
          <ls_result_idx>-path     = <ls_result>-path.
          MOVE-CORRESPONDING <ls_result> TO ls_item.
        ENDIF.
  
      ENDLOOP.
  
      LOOP AT it_results ASSIGNING <ls_result>
        WHERE NOT obj_type IS INITIAL AND obj_type <> 'DEVC' AND packmove = abap_false.
  
        READ TABLE lt_item_idx ASSIGNING <ls_result_idx>
          WITH KEY obj_type = <ls_result>-obj_type obj_name = <ls_result>-obj_name
          BINARY SEARCH. " Sorted above
  
        IF sy-subrc <> 0 OR <ls_result>-path <> <ls_result_idx>-path. " All paths are same
          ii_log->add( iv_msg = |Files for object { <ls_result>-obj_type } {
                                <ls_result>-obj_name } are not placed in the same folder|
                       iv_type = 'W'
                       iv_rc   = '1' ).
        ENDIF.
  
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD check_multiple_files.
  
      DATA:
        lt_res_sort LIKE it_results,
        ls_file     TYPE zif_abapgit_definitions=>ty_file_signature.
  
      FIELD-SYMBOLS <ls_result> LIKE LINE OF it_results.
  
      lt_res_sort = it_results.
      SORT lt_res_sort BY filename ASCENDING.
  
      LOOP AT lt_res_sort ASSIGNING <ls_result> WHERE obj_type <> 'DEVC' AND packmove = abap_false.
        IF <ls_result>-filename IS NOT INITIAL AND <ls_result>-filename = ls_file-filename.
          ii_log->add( iv_msg  = |Multiple files with same filename, { <ls_result>-filename }|
                       iv_type = 'W'
                       iv_rc   = '3' ).
        ENDIF.
  
        IF <ls_result>-filename IS INITIAL.
          ii_log->add( iv_msg  = |Filename is empty for object { <ls_result>-obj_type } { <ls_result>-obj_name }|
                       iv_type = 'W'
                       iv_rc   = '4' ).
        ENDIF.
  
        MOVE-CORRESPONDING <ls_result> TO ls_file.
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD check_namespace.
  
      DATA:
        lv_namespace TYPE namespace,
        lt_namespace TYPE TABLE OF namespace,
        ls_trnspace  TYPE trnspace.
  
      FIELD-SYMBOLS <ls_result> LIKE LINE OF it_results.
  
      " Collect all namespaces based on name of xml-files
      LOOP AT it_results ASSIGNING <ls_result>.
        FIND REGEX '#([a-zA-Z0-9]+)#.*\..*\.xml' IN <ls_result>-filename SUBMATCHES lv_namespace.
        IF sy-subrc = 0.
          lv_namespace = '/' && to_upper( lv_namespace ) && '/'.
          COLLECT lv_namespace INTO lt_namespace.
        ENDIF.
      ENDLOOP.
  
      LOOP AT lt_namespace INTO lv_namespace.
        CALL FUNCTION 'TR_READ_NAMESPACE'
          EXPORTING
            iv_namespace           = lv_namespace
          IMPORTING
            es_trnspace            = ls_trnspace
          EXCEPTIONS
            namespace_not_existing = 1
            OTHERS                 = 2.
        IF sy-subrc <> 0.
          ii_log->add( iv_msg  = |Namespace { lv_namespace } does not exist. Create it in transaction SE03|
                       iv_type = 'W'
                       iv_rc   = '6' ).
        ELSEIF ls_trnspace-editflag <> 'X'.
          ii_log->add( iv_msg  = |Namespace { lv_namespace } is not modifiable. Check it in transaction SE03|
                       iv_type = 'W'
                       iv_rc   = '6' ).
        ENDIF.
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD check_package_folder.
  
      DATA:
        lv_path         TYPE string,
        lo_folder_logic TYPE REF TO zcl_abapgit_folder_logic.
  
      FIELD-SYMBOLS <ls_result> LIKE LINE OF it_results.
  
      lo_folder_logic = zcl_abapgit_folder_logic=>get_instance( ).
  
      LOOP AT it_results ASSIGNING <ls_result>
        WHERE NOT package IS INITIAL AND NOT path IS INITIAL AND packmove = abap_false.
  
        lv_path = lo_folder_logic->package_to_path(
          iv_top     = iv_top
          io_dot     = io_dot
          iv_package = <ls_result>-package ).
  
        IF lv_path <> <ls_result>-path.
          ii_log->add( iv_msg = |Package and path does not match for object, {
                         <ls_result>-obj_type } { <ls_result>-obj_name }|
                       iv_type = 'W'
                       iv_rc   = '2' ).
        ENDIF.
  
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD check_package_move.
  
      DATA:
        lt_move_idx LIKE it_results.
  
      FIELD-SYMBOLS:
        <ls_result>      LIKE LINE OF it_results,
        <ls_result_move> LIKE LINE OF it_results.
  
      LOOP AT it_results ASSIGNING <ls_result>
        WHERE lstate = zif_abapgit_definitions=>c_state-added AND packmove = abap_true.
  
        READ TABLE lt_move_idx TRANSPORTING NO FIELDS
          WITH KEY obj_type = <ls_result>-obj_type obj_name = <ls_result>-obj_name
          BINARY SEARCH. " Sorted since it_result is sorted
        IF sy-subrc <> 0.
          ii_log->add( iv_msg  = |Changed package assignment for object {
                                 <ls_result>-obj_type } { <ls_result>-obj_name }|
                       iv_type = 'W'
                       iv_rc   = '5' ).
          APPEND INITIAL LINE TO lt_move_idx ASSIGNING <ls_result_move>.
          <ls_result_move>-obj_type = <ls_result>-obj_type.
          <ls_result_move>-obj_name = <ls_result>-obj_name.
          <ls_result_move>-path     = <ls_result>-path.
        ENDIF.
  
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD get_object_package.
      DATA: lv_name    TYPE devclass,
            li_package TYPE REF TO zif_abapgit_sap_package.
  
      rv_devclass = zcl_abapgit_factory=>get_tadir( )->get_object_package(
        iv_object   = iv_object
        iv_obj_name = iv_obj_name ).
      IF rv_devclass IS INITIAL AND iv_object = 'DEVC' AND iv_obj_name(1) = '$'.
        " local packages usually have no tadir entry
        lv_name = iv_obj_name.
        li_package = zcl_abapgit_factory=>get_sap_package( lv_name ).
        IF li_package->exists( ) = abap_true.
          rv_devclass = lv_name.
        ENDIF.
      ENDIF.
    ENDMETHOD.
  
  
    METHOD identify_object.
  
      DATA: lv_name TYPE string,
            lv_type TYPE string,
            lv_ext  TYPE string.
  
      " Guess object type and name
      SPLIT to_upper( iv_filename ) AT '.' INTO lv_name lv_type lv_ext.
  
      " Handle namespaces
      REPLACE ALL OCCURRENCES OF '#' IN lv_name WITH '/'.
      REPLACE ALL OCCURRENCES OF '#' IN lv_type WITH '/'.
      REPLACE ALL OCCURRENCES OF '#' IN lv_ext WITH '/'.
  
      " The counter part to this logic must be maintained in ZCL_ABAPGIT_OBJECTS_FILES->FILENAME
      IF lv_type = 'DEVC'.
        " Try to get a unique package name for DEVC by using the path
        ASSERT lv_name = 'PACKAGE'.
        lv_name = zcl_abapgit_folder_logic=>get_instance( )->path_to_package(
          iv_top                  = iv_devclass
          io_dot                  = io_dot
          iv_create_if_not_exists = abap_false
          iv_path                 = iv_path ).
      ELSE.
        " Get original object name
        lv_name = cl_http_utility=>unescape_url( lv_name ).
      ENDIF.
  
      CLEAR es_item.
      es_item-obj_type = lv_type.
      es_item-obj_name = lv_name.
      ev_is_xml        = boolc( lv_ext = 'XML' AND strlen( lv_type ) = 4 ).
  
    ENDMETHOD.
  
  
negative.code:         ENDIF.
        ENDIF.
  
        APPEND ls_item TO ct_items.
      ENDLOOP.
  
      SORT ct_items DESCENDING. " Default key - type, name, pkg, inactive
      DELETE ADJACENT DUPLICATES FROM ct_items COMPARING obj_type obj_name devclass.
  
    ENDMETHOD.
  
  
    METHOD process_local.
  
      DATA lv_msg TYPE string.
  
      FIELD-SYMBOLS:
        <ls_remote> LIKE LINE OF ct_remote,
        <ls_result> LIKE LINE OF ct_results,
        <ls_state>  LIKE LINE OF it_state_idx,
        <ls_local>  LIKE LINE OF it_local.
  
      LOOP AT it_local ASSIGNING <ls_local>.
        " Skip ignored files
        IF io_dot->is_ignored( iv_path     = <ls_local>-file-path
                               iv_filename = <ls_local>-file-filename ) = abap_true.
          CONTINUE.
        ENDIF.
  
        APPEND INITIAL LINE TO ct_results ASSIGNING <ls_result>.
        IF <ls_local>-item IS NOT INITIAL.
          APPEND <ls_local>-item TO ct_items. " Collect for item index
        ENDIF.
  
        READ TABLE ct_remote ASSIGNING <ls_remote>
          WITH KEY path = <ls_local>-file-path filename = <ls_local>-file-filename
          BINARY SEARCH.
        IF sy-subrc = 0.  " Exist local and remote
          <ls_result> = build_existing(
            is_local  = <ls_local>
            is_remote = <ls_remote>
            it_state  = it_state_idx ).
          ASSERT <ls_remote>-sha1 IS NOT INITIAL.
          CLEAR <ls_remote>-sha1. " Mark as processed
        ELSE.             " Only L exists
          <ls_result> = build_new_local( <ls_local> ).
          " Check if same file exists in different location
          READ TABLE ct_remote ASSIGNING <ls_remote>
            WITH KEY filename = <ls_local>-file-filename.
          IF sy-subrc = 0 AND <ls_local>-file-sha1 = <ls_remote>-sha1.
            <ls_result>-packmove = abap_true.
          ELSEIF sy-subrc = 4.
            " Check if file existed before and was deleted remotely
            READ TABLE it_state_idx ASSIGNING <ls_state>
              WITH KEY path = <ls_local>-file-path filename = <ls_local>-file-filename
              BINARY SEARCH.
            IF sy-subrc = 0.
              IF <ls_local>-file-sha1 = <ls_state>-sha1.
                <ls_result>-lstate = zif_abapgit_definitions=>c_state-unchanged.
              ELSE.
                <ls_result>-lstate = zif_abapgit_definitions=>c_state-modified.
              ENDIF.
              <ls_result>-rstate = zif_abapgit_definitions=>c_state-deleted.
            ENDIF.
          ENDIF.
        ENDIF.
        <ls_result>-inactive = <ls_local>-item-inactive.
      ENDLOOP.
  
    ENDMETHOD.
  
  
    METHOD process_remote.
  
      FIELD-SYMBOLS:
        <ls_remote> LIKE LINE OF it_remote,
        <ls_result> LIKE LINE OF ct_results,
        <ls_local>  LIKE LINE OF it_local.
  
      LOOP AT it_remote ASSIGNING <ls_remote> WHERE sha1 IS NOT INITIAL.
        APPEND INITIAL LINE TO ct_results ASSIGNING <ls_result>.
  
        <ls_result> = build_new_remote(
          iv_devclass = iv_devclass
          io_dot      = io_dot
          is_remote   = <ls_remote>
          it_items    = it_items_idx
          it_state    = it_state_idx ).
  
        " Check if same file exists in different location
        READ TABLE it_local ASSIGNING <ls_local>
          WITH KEY file-filename = <ls_remote>-filename.
  