/*
 * Copyright 2015 Google Inc. 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/layout/white_space_processing.h"

#include "cobalt/cssom/character_classification.h"
#include "cobalt/cssom/keyword_value.h"

namespace cobalt {
namespace layout {

namespace {

// Returns true if skipped at least one white space character.
bool SkipWhiteSpaceAndAdvance(
    std::string::const_iterator* input_iterator,
    const std::string::const_iterator& input_end_iterator) {
  bool skipped_at_least_one = false;

  for (; *input_iterator != input_end_iterator; ++*input_iterator) {
    if (!cssom::IsWhiteSpace(**input_iterator)) {
      break;
    }

    skipped_at_least_one = true;
  }

  return skipped_at_least_one;
}

// Returns true if copied at least one character that is not a white space.
bool CopyNonWhiteSpaceAndAdvance(
    std::string::const_iterator* input_iterator,
    const std::string::const_iterator& input_end_iterator,
    std::string::iterator* output_iterator) {
  bool copied_at_least_one = false;

  for (; *input_iterator != input_end_iterator; ++*input_iterator) {
    char character = **input_iterator;
    if (cssom::IsWhiteSpace(character)) {
      break;
    }

    copied_at_least_one = true;
    **output_iterator = character;
    ++*output_iterator;
  }

  return copied_at_least_one;
}

}  // namespace

// "white-space" property values "pre", "pre-line", and "pre-wrap" preserve
// segment breaks, while other values collapse it.
// https://www.w3.org/TR/css-text-3/#white-space
bool DoesCollapseSegmentBreaks(
    const scoped_refptr<cssom::PropertyValue>& value) {
  return value != cssom::KeywordValue::GetPre() &&
         value != cssom::KeywordValue::GetPreLine() &&
         value != cssom::KeywordValue::GetPreWrap();
}

// "white-space" property values "pre", and "pre-wrap" preserve whitespace,
// while other values collapse it.
// https://www.w3.org/TR/css-text-3/#white-space
bool DoesCollapseWhiteSpace(const scoped_refptr<cssom::PropertyValue>& value) {
  return value != cssom::KeywordValue::GetPre() &&
         value != cssom::KeywordValue::GetPreWrap();
}

// "white-space" property values "pre", and "nowrap" prevent wrapping, while
// other values allow it.
// https://www.w3.org/TR/css-text-3/#white-space
bool DoesAllowTextWrapping(const scoped_refptr<cssom::PropertyValue>& value) {
  return value != cssom::KeywordValue::GetPre() &&
         value != cssom::KeywordValue::GetNoWrap();
}

void CollapseWhiteSpace(std::string* text) {
  std::string::const_iterator input_iterator = text->begin();
  std::string::const_iterator input_end_iterator = text->end();
  std::string::iterator output_iterator = text->begin();

  // Per the specification, any space immediately following another
  // collapsible space is collapsed to have zero advance width. We approximate
  // this by replacing adjacent spaces with a single space.
  if (SkipWhiteSpaceAndAdvance(&input_iterator, input_end_iterator)) {
    *output_iterator++ = ' ';
  }
  while (CopyNonWhiteSpaceAndAdvance(&input_iterator, input_end_iterator,
                                     &output_iterator) &&
         SkipWhiteSpaceAndAdvance(&input_iterator, input_end_iterator)) {
    *output_iterator++ = ' ';
  }

  text->erase(output_iterator, text->end());
}

bool FindNextNewlineSequence(const std::string& utf8_text, size_t index,
                             size_t* sequence_start, size_t* sequence_length) {
  *sequence_start = utf8_text.size();
  *sequence_length = 0;

  // For CSS processing... CRLF sequence (U+000D U+000A), carriage return
  // (U+000D), and line feed (U+000A) in the text is treated as a segment break.
  //   https://www.w3.org/TR/css3-text/#white-space-processing
  for (; index < utf8_text.size(); ++index) {
    char character = utf8_text[index];
    if (character == '\r') {
      *sequence_start = index++;
      if (index < utf8_text.size() && utf8_text[index] == '\n') {
        *sequence_length = 2;
      } else {
        *sequence_length = 1;
      }
      break;
    } else if (character == '\n') {
      *sequence_start = index;
      *sequence_length = 1;
      break;
    }
  }

  return *sequence_length > 0;
}

}  // namespace layout
}  // namespace cobalt
