# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
# frozen_string_literal: true

module Contrast
  module Agent
    module Assess
      module Policy
        module Propagator
          # This class is specifically for String#tr(_s) propagation
          #
          # Disclaimer: there may be a better way, but we're
          # in a 'get it work' state. hopefully, we'll be in
          # a 'get it right' state soon.
          class Trim
            class << self
              def tr_tagger patcher, preshift, ret, _block
                return ret unless ret && !ret.empty?

                properties = Contrast::Agent::Assess::Tracker.properties(ret)
                return unless properties

                source = preshift.object
                args = preshift.args
                properties.copy_from(source, ret)
                replace_string = args[1]
                source_chars = source.chars
                # if the replace string is empty, then there's a bunch of deletes. this
                # functions the same as the Removal propagation.
                if replace_string == Contrast::Utils::ObjectShare::EMPTY_STRING
                  Contrast::Agent::Assess::Policy::Propagator::Remove.handle_removal(source_chars, ret)
                else
                  remove_ranges = []
                  ret_chars = ret.chars
                  start = nil
                  source_chars.each_with_index do |char, idx|
                    if ret_chars[idx] == char
                      next unless start

                      remove_ranges << (start...idx)
                      start = nil
                    else
                      start ||= idx
                    end
                  end
                  # account for the last char being different
                  remove_ranges << (start...source_chars.length) if start
                  properties.delete_tags_at_ranges(remove_ranges, false)
                end

                properties.build_event(
                    patcher,
                    ret,
                    source,
                    ret,
                    args,
                    1)
                ret
              end

              def tr_s_tagger patcher, preshift, ret, _block
                return unless ret && !ret.empty?

                properties = Contrast::Agent::Assess::Tracker.properties(ret)
                return unless properties

                source = preshift.object
                args = preshift.args
                properties.splat_from(source, ret)
                properties.build_event(
                    patcher,
                    ret,
                    source,
                    ret,
                    args)
                ret
              end
            end
          end
        end
      end
    end
  end
end