/* Copyright (C) 2007 The glibmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <glibmm/utility.h>

namespace Glib
{

Glib::RefPtr<Glib::Regex> Regex::create(const Glib::ustring& pattern,
                                        RegexCompileFlags compile_options,
                                        RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  auto regex  = g_regex_new(pattern.c_str(), (GRegexCompileFlags)compile_options,
                               (GRegexMatchFlags)match_options, &gerror);

  if(gerror)
    Glib::Error::throw_exception(gerror);
  return Glib::wrap(regex);
}

// static
Glib::ustring Regex::escape_string(const Glib::ustring& string)
{
  const Glib::ScopedPtr<char> buf (g_regex_escape_string(string.raw().c_str(),
                                                         string.raw().size()));
  return Glib::ustring(buf.get());
}

bool Regex::match(
  const Glib::ustring& string,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GMatchInfo* ginfo = nullptr;
  bool const result = static_cast<bool>(g_regex_match(gobj(), string.c_str(),
    static_cast<GRegexMatchFlags>(match_options), &ginfo));
  match_info.set_gobject(ginfo);
  return result;
}

bool Regex::match(const Glib::ustring& string, RegexMatchFlags match_options)
{
  return g_regex_match(gobj(), string.c_str(), (GRegexMatchFlags)(match_options), nullptr);
}

bool Regex::match(
  const Glib::ustring& string,
  int start_position,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GError* gerror = nullptr;
  GMatchInfo* ginfo = nullptr;

  bool const result = static_cast<bool>(g_regex_match_full(gobj(),
    string.c_str(), -1, start_position,
    static_cast<GRegexMatchFlags>(match_options), &ginfo, &gerror));

  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  match_info.set_gobject(ginfo);
  return result;
}

bool Regex::match(
  const Glib::ustring& string,
  gssize string_len,
  int start_position,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GError* gerror = nullptr;
  GMatchInfo* ginfo = nullptr;

  bool const result = static_cast<bool>(g_regex_match_full(gobj(),
    string.c_str(), string_len, start_position,
    static_cast<GRegexMatchFlags>(match_options), &ginfo, &gerror));

  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  match_info.set_gobject(ginfo);
  return result;
}

bool Regex::match(const Glib::ustring& string, int start_position, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  bool retvalue = g_regex_match_full(gobj(), string.c_str(), -1, start_position, ((GRegexMatchFlags)(match_options)), nullptr, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}

bool Regex::match(const Glib::ustring& string, gssize string_len, int start_position, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  bool retvalue = g_regex_match_full(gobj(), string.c_str(), string_len, start_position, ((GRegexMatchFlags)(match_options)), nullptr, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}

bool Regex::match_all(
  const Glib::ustring& string,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GMatchInfo* ginfo = nullptr;
  bool const result = static_cast<bool>(g_regex_match_all(gobj(),
    string.c_str(), static_cast<GRegexMatchFlags>(match_options),
    &ginfo));
  match_info.set_gobject(ginfo);
  return result;
}

bool Regex::match_all(const Glib::ustring& string, RegexMatchFlags match_options)
{
  return g_regex_match_all(gobj(), string.c_str(), ((GRegexMatchFlags)(match_options)), nullptr);
}

bool Regex::match_all(
  const Glib::ustring& string,
  int start_position,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GError* gerror = nullptr;
  GMatchInfo* ginfo = nullptr;

  bool const retvalue = static_cast<bool>(g_regex_match_all_full(gobj(),
    string.c_str(), -1, start_position,
    static_cast<GRegexMatchFlags>(match_options), &ginfo, &gerror));

  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  match_info.set_gobject(ginfo);
  return retvalue;
}

bool Regex::match_all(
  const Glib::ustring& string,
  gssize string_len,
  int start_position,
  Glib::MatchInfo& match_info,
  RegexMatchFlags match_options
)
{
  GError* gerror = nullptr;
  GMatchInfo* ginfo = nullptr;

  bool const retvalue = static_cast<bool>(g_regex_match_all_full(gobj(),
    string.c_str(), string_len, start_position,
    static_cast<GRegexMatchFlags>(match_options), &ginfo, &gerror));

  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  match_info.set_gobject(ginfo);
  return retvalue;
}

bool Regex::match_all(const Glib::ustring& string, int start_position, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  bool retvalue = g_regex_match_all_full(gobj(), string.c_str(), -1, start_position, ((GRegexMatchFlags)(match_options)), nullptr, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}

bool Regex::match_all(const Glib::ustring& string, gssize string_len, int start_position, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  bool retvalue = g_regex_match_all_full(gobj(), string.c_str(), string_len, start_position, ((GRegexMatchFlags)(match_options)), nullptr, &(gerror));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}

Glib::ustring Regex::replace(const Glib::ustring& string, int start_position, const Glib::ustring& replacement, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  auto retvalue = Glib::convert_return_gchar_ptr_to_ustring(g_regex_replace(gobj(), string.c_str(), -1, start_position, replacement.c_str(), ((GRegexMatchFlags)(match_options)), &(gerror)));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}


Glib::ustring Regex::replace_literal(const Glib::ustring& string, int start_position, const Glib::ustring& replacement, RegexMatchFlags match_options)
{
  GError* gerror = nullptr;
  auto retvalue = Glib::convert_return_gchar_ptr_to_ustring(g_regex_replace_literal(gobj(), string.c_str(), -1, start_position, replacement.c_str(), ((GRegexMatchFlags)(match_options)), &(gerror)));
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}

Glib::StringArrayHandle Regex::split(const Glib::ustring& string, int start_position, RegexMatchFlags match_options, int max_tokens) const
{
  GError* gerror = nullptr;
  auto retvalue = Glib::StringArrayHandle(g_regex_split_full(const_cast<GRegex*>(gobj()), string.c_str(), -1, start_position, ((GRegexMatchFlags)(match_options)), max_tokens, &(gerror)), Glib::OWNERSHIP_DEEP);
  if(gerror)
    ::Glib::Error::throw_exception(gerror);

  return retvalue;
}


MatchInfo::MatchInfo()
: gobject_(nullptr),
  take_ownership(false)
{
}

MatchInfo::MatchInfo(GMatchInfo* castitem, bool take_the_ownership)
: gobject_(castitem),
  take_ownership(take_the_ownership)
{
}


MatchInfo::MatchInfo(MatchInfo&& other) noexcept
: gobject_(std::move(other.gobject_)),
  take_ownership(std::move(other.take_ownership))
{
  other.gobject_ = nullptr;
  other.take_ownership = false;
}

MatchInfo& MatchInfo::operator=(MatchInfo&& other) noexcept
{
  if(take_ownership && gobject_)
    g_match_info_free(gobject_);

  gobject_ = std::move(other.gobject_);
  take_ownership = std::move(other.take_ownership);

  other.gobject_ = nullptr;
  other.take_ownership = false;

  return *this;
}

void MatchInfo::set_gobject(GMatchInfo* castitem, bool take_the_ownership)
{
  if(gobject_ && this->take_ownership)
    g_match_info_free(gobject_);

  gobject_ = castitem;
  this->take_ownership = take_the_ownership;
}

MatchInfo::~MatchInfo()
{
  if(take_ownership && gobject_)
    g_match_info_free(gobject_);
}

} // namespace Glib
