text: /***************************************************************************
   *
   * Project         _____    __   ____   _      _
   *                (  _  )  /__\ (_  _)_| |_  _| |_
   *                 )(_)(  /(__)\  )( (_   _)(_   _)
   *                (_____)(__)(__)(__)  |_|    |_|
   *
   *
   * Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
   *
   * 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 "StringTemplate.hpp"
  
  #include "oatpp/core/data/stream/BufferStream.hpp"
  
  namespace oatpp { namespace data { namespace share {
  
  StringTemplate::VectorValueProvider::VectorValueProvider(const std::vector<oatpp::String> *params)
    : m_params(params)
  {}
  
  oatpp::String StringTemplate::VectorValueProvider::getValue(const Variable& variable, v_uint32 index) {
    (void) variable;
    return m_params->at(index);
  }
  
  StringTemplate::MapValueProvider::MapValueProvider(const std::unordered_map<oatpp::String, oatpp::String> *params)
    : m_params(params)
  {}
  
  oatpp::String StringTemplate::MapValueProvider::getValue(const Variable& variable, v_uint32 index) {
    (void) index;
    auto it = m_params->find(variable.name);
    if(it != m_params->end()) {
      return it->second;
    }
    return nullptr;
  }
  
  StringTemplate::SingleValueProvider::SingleValueProvider(const oatpp::String& value)
    : m_value(value)
  {}
  
  oatpp::String StringTemplate::SingleValueProvider::getValue(const Variable& variable, v_uint32 index) {
    (void) variable;
    (void) index;
    return m_value;
  }
  
  StringTemplate::StringTemplate(const oatpp::String& text, std::vector<Variable>&& variables)
    : m_text(text)
    , m_variables(variables)
  {
    v_buff_size prevPos = 0;
    for(v_int32 i = 0; i < m_variables.size(); i++) {
      const auto& var = m_variables[i];
  
      if(var.posStart < prevPos) {
        throw std::runtime_error("[oatpp::data::share::StringTemplate::StringTemplate()]: Error. The template variable positions can't intersect.");
      }
  
      if(var.posEnd < var.posStart) {
        throw std::runtime_error("[oatpp::data::share::StringTemplate::StringTemplate()]: Error. The template variable can't have a negative size.");
      }
  
      if(var.posEnd >= m_text->getSize()) {
        throw std::runtime_error("[oatpp::data::share::StringTemplate::StringTemplate()]: Error. The template variable can't out-bound the template text.");
      }
    }
  }
  
  void StringTemplate::format(stream::ConsistentOutputStream* stream, ValueProvider* valueProvider) const {
  
    v_buff_size prevPos = 0;
    for(v_uint32 i = 0; i < m_variables.size(); i++) {
  
      const auto& var = m_variables[i];
      const auto& value = valueProvider->getValue(var, i);
  
      if(!value) {
        throw std::runtime_error("[oatpp::data::share::StringTemplate::format()]: "
                                 "Error. No value provided for the parameter name=" + var.name->std_str());
      }
  
      if(prevPos < var.posStart) {
        stream->writeSimple(m_text->getData() + prevPos, var.posStart - prevPos);
      }
  
      stream->writeSimple(value->getData(), value->getSize());
  
      prevPos = var.posEnd + 1;
  
    }
  
    if(prevPos < m_text->getSize()) {
      stream->writeSimple(m_text->getData() + prevPos, m_text->getSize() - prevPos);
    }
  
  }
  
  void StringTemplate::format(stream::ConsistentOutputStream* stream, const std::vector<oatpp::String>& params) const {
    VectorValueProvider vp(&params);
    format(stream, &vp);
  }
  
  void StringTemplate::format(stream::ConsistentOutputStream* stream, const std::unordered_map<oatpp::String, oatpp::String>& params) const {
    MapValueProvider vp(&params);
    format(stream, &vp);
  }
  
  void StringTemplate::format(stream::ConsistentOutputStream* stream, const oatpp::String& singleValue) const {
    SingleValueProvider vp(singleValue);
    format(stream, &vp);
  }
  
  oatpp::String StringTemplate::format(ValueProvider* valueProvider) const {
    stream::BufferOutputStream stream;
    format(&stream, valueProvider);
    return stream.toString();
  }
  
  oatpp::String StringTemplate::format(const std::vector<oatpp::String>& params) const {
    stream::BufferOutputStream stream;
    format(&stream, params);
    return stream.toString();
  }
  
  oatpp::String StringTemplate::format(const std::unordered_map<oatpp::String, oatpp::String>& params) const {
    stream::BufferOutputStream stream;
    format(&stream, params);
    return stream.toString();
  }
  
  oatpp::String StringTemplate::format(const oatpp::String& singleValue) const {
    stream::BufferOutputStream stream;
    format(&stream, singleValue);
    return stream.toString();
  }
  
  const std::vector<StringTemplate::Variable>& StringTemplate::getTemplateVariables() const {
    return m_variables;
  }
  
  void StringTemplate::setExtraData(const std::shared_ptr<void>& data) {
    m_extra = data;
  }
  
  std::shared_ptr<void> StringTemplate::getExtraData() const {
    return m_extra;
  }
  
  }}}
  