// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/browser/memory_tracker/tool/util.h"

#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

#include "base/time/time.h"
#include "nb/bit_cast.h"
#include "starboard/common/string.h"

namespace cobalt {
namespace browser {
namespace memory_tracker {

const char kQuote[] = "\"";
const char kDelimiter[] = ",";
const char kNewLine[] = "\n";

std::string RemoveString(const std::string& haystack, const char* needle) {
  const size_t kNotFound = std::string::npos;

  // Base case. No modification needed.
  size_t pos = haystack.find(needle);
  if (pos == kNotFound) {
    return haystack;
  }
  const size_t n = SbStringGetLength(needle);
  std::string output;
  output.reserve(haystack.size());

  // Copy string, omitting the portion containing the "needle".
  std::copy(haystack.begin(), haystack.begin() + pos,
            std::back_inserter(output));
  std::copy(haystack.begin() + pos + n, haystack.end(),
            std::back_inserter(output));

  // Recursively remove same needle in haystack.
  return RemoveString(output, needle);
}

std::string SanitizeCSVKey(std::string key) {
  key = RemoveString(key, kQuote);
  key = RemoveString(key, kDelimiter);
  key = RemoveString(key, kNewLine);
  return key;
}

std::string InsertCommasIntoNumberString(const std::string& input) {
  typedef std::vector<char> CharVector;
  typedef CharVector::iterator CharIt;

  CharVector chars(input.begin(), input.end());
  std::reverse(chars.begin(), chars.end());

  CharIt curr_it = chars.begin();
  CharIt mid = std::find(chars.begin(), chars.end(), '.');
  if (mid == chars.end()) {
    mid = curr_it;
  }

  CharVector out(curr_it, mid);

  int counter = 0;
  for (CharIt it = mid; it != chars.end(); ++it) {
    if (counter != 0 && (counter % 3 == 0)) {
      out.push_back(',');
    }
    if (*it != '.') {
      counter++;
    }
    out.push_back(*it);
  }

  std::reverse(out.begin(), out.end());
  std::stringstream ss;
  for (size_t i = 0; i < out.size(); ++i) {
    ss << out[i];
  }
  return ss.str();
}

Timer::Timer(base::TimeDelta delta_time) {
  start_time_ = Now();
  time_before_expiration_ = delta_time;
}

Timer::Timer(base::TimeDelta delta_time, Timer::TimeFunctor time_functor) {
  time_function_override_ = time_functor;
  start_time_ = Now();
  time_before_expiration_ = delta_time;
}

void Timer::Restart() { start_time_ = Now(); }

bool Timer::UpdateAndIsExpired() {
  base::TimeTicks now_time = Now();
  base::TimeDelta delta_time = now_time - start_time_;
  if (delta_time >= time_before_expiration_) {
    start_time_ = now_time;
    return true;
  } else {
    return false;
  }
}

base::TimeTicks Timer::Now() {
  if (time_function_override_.is_null()) {
    return base::TimeTicks::Now();
  } else {
    return time_function_override_.Run();
  }
}

void Timer::ScaleTriggerTime(double scale) {
  int64_t old_dt = time_before_expiration_.InMicroseconds();
  int64_t new_dt = static_cast<int64_t>(static_cast<double>(old_dt) * scale);
  time_before_expiration_ = base::TimeDelta::FromMicroseconds(new_dt);
}

Segment::Segment(const std::string* name, const char* start_address,
                 const char* end_address)
    : name_(name), begin_(start_address), end_(end_address) {}

void Segment::SplitAcrossPageBoundaries(size_t page_size,
                                        std::vector<Segment>* segments) const {
  if (size() == 0) {
    segments->push_back(*this);
    return;
  }

  uintptr_t page_start = nb::bit_cast<uintptr_t>(begin_) / page_size;
  uintptr_t page_end = nb::bit_cast<uintptr_t>(end_ - 1) / page_size;

  if (page_start == page_end) {
    segments->push_back(*this);
    return;
  }

  for (uintptr_t p = page_start; p <= page_end; ++p) {
    uintptr_t start_addr;
    if (p == page_start) {
      start_addr = nb::bit_cast<uintptr_t>(begin_);
    } else {
      start_addr = p * page_size;
    }

    uintptr_t end_addr;
    if (p == page_end) {
      end_addr = nb::bit_cast<uintptr_t>(end_);
    } else {
      end_addr = (p + 1) * page_size;
    }

    const char* start = nb::bit_cast<const char*>(start_addr);
    const char* end = nb::bit_cast<const char*>(end_addr);
    segments->push_back(Segment(name_, start, end));
  }
}

bool Segment::Intersects(const Segment& other) const {
  size_t total_span = std::distance(std::min(begin_, other.begin()),
                                    std::max(end_, other.end()));

  bool intersects = (size() + other.size()) > total_span;
  return intersects;
}

bool Segment::operator<(const Segment& other) const {
  return begin_ < other.begin();
}

bool Segment::operator==(const Segment& other) const {
  if (begin_ == other.begin() && end_ == other.end()) {
    DCHECK(name_ == other.name_);
    return true;
  }
  return false;
}

size_t Segment::size() const { return std::distance(begin_, end_); }

const char* BaseNameFast(const char* file_name) {
  // Case: Linux.
  const char* end_pos = file_name + SbStringGetLength(file_name);
  const char* last_forward_slash = SbStringFindLastCharacter(file_name, '/');
  if (last_forward_slash) {
    if (end_pos != last_forward_slash) {
      ++last_forward_slash;
    }
    return last_forward_slash;
  }

  // Case: Windows.
  const char* last_backward_slash = SbStringFindLastCharacter(file_name, '\\');
  if (last_backward_slash) {
    if (end_pos != last_backward_slash) {
      ++last_backward_slash;
    }
    return last_backward_slash;
  }
  return file_name;
}

}  // namespace memory_tracker
}  // namespace browser
}  // namespace cobalt
