/* terminal.cc
 *
 * Copyright (C) 2008, 2009 libvtemm Development Team
 *
 * This file is part of libvtemm.
 *
 * libvtemm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libvtemm 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 Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with libvtemm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <vte/vte.h>

#include <gtkmm/border.h>

#include "internalroutines.h"

namespace Gnome
{

namespace Vte
{

namespace Private
{

static gboolean
SignalProxy_selected_gtk_callback(VteTerminal *terminal G_GNUC_UNUSED, glong column, glong row, gpointer user_data)
{
  Gnome::Vte::Terminal::SlotSelectedCallback* the_slot = static_cast<Gnome::Vte::Terminal::SlotSelectedCallback*>(user_data);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
#endif // GLIBMM_EXCEPTIONS_ENABLED
    return static_cast<gboolean>((*the_slot)(column, row));
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  }
  catch (...)
  {
    Glib::exception_handlers_invoke();
  }
  return TRUE;
#endif // GLIBMM_EXCEPTIONS_ENABLED
}

} // namespace Private

Glib::Pid
Terminal::fork_command(const std::string& command, const StdStringArrayHandle& argv, const StdStringArrayHandle& envv, const std::string& directory, bool lastlog, bool utmp, bool wtmp)
{
  const char* c_command = get_c_string(command);
  char** c_argv = get_c_string_vector(argv);
  char** c_envv = get_c_string_vector(envv);
  const char* c_directory = get_c_string(directory);
  Glib::Pid pid = vte_terminal_fork_command(gobj(), c_command, c_argv, c_envv, c_directory, lastlog, utmp, wtmp);
  g_strfreev(c_argv);
  g_strfreev(c_envv);
  return pid;
}

Glib::Pid
Terminal::forkpty(const StdStringArrayHandle& envv, const std::string& directory, bool lastlog, bool utmp, bool wtmp)
{
  char** c_envv = get_c_string_vector(envv);
  const char* c_directory = get_c_string(directory);
  Glib::Pid pid = vte_terminal_forkpty(gobj(), c_envv, c_directory, lastlog, utmp, wtmp);
  g_strfreev(c_envv);
  return pid;
}

void
Terminal::feed(const Glib::ustring& data)
{
  vte_terminal_feed(gobj(), data.data(), data.size());
}

void
Terminal::feed_child(const Glib::ustring& text)
{
  vte_terminal_feed_child(gobj(), text.data(), text.size());
}

void
Terminal::feed_child_binary(const std::string& data)
{
  vte_terminal_feed_child_binary(gobj(), data.data(), data.size());
}

void
Terminal::set_default_color_cursor()
{
  vte_terminal_set_color_cursor(gobj(), 0);
}

void
Terminal::set_default_color_highlight()
{
  vte_terminal_set_color_highlight(gobj(), 0);
}

void
Terminal::set_colors(const Gdk::Color& foreground, const Gdk::Color& background, const Gdk::ArrayHandle_Color& palette)
{
  vte_terminal_set_colors(gobj(), foreground.gobj(), background.gobj(), palette.data(), palette.size());
}

void
Terminal::set_default_colors(const Gdk::ArrayHandle_Color& palette)
{
  vte_terminal_set_colors(gobj(), 0, 0, palette.data(), palette.size());
}

void
Terminal::unset_background_image()
{
  vte_terminal_set_background_image(gobj(), 0);
}

bool
Terminal::always_selected(long, long)
{
  return true;
}

bool
Terminal::never_selected(long, long)
{
  return false;
}

TextAndCharAttrs
Terminal::get_text(const Gnome::Vte::Terminal::SlotSelectedCallback& slot) const
{
  GArray* array = g_array_new(FALSE, FALSE, sizeof(VteCharAttributes));
  char* c_text = vte_terminal_get_text(const_cast<VteTerminal*>(gobj()), &Private::SignalProxy_selected_gtk_callback, const_cast<Gnome::Vte::Terminal::SlotSelectedCallback*>(&slot), array);
  Glib::ustring text(c_text);
  g_free(c_text);
  ArrayHandle_CharAttributes attributes(reinterpret_cast<VteCharAttributes*>(array->data), array->len, Glib::OWNERSHIP_DEEP);
  g_array_free(array, FALSE);
  return TextAndCharAttrs(text, attributes);
}

TextAndCharAttrs
Terminal::get_text_include_trailing_spaces(const Gnome::Vte::Terminal::SlotSelectedCallback& slot) const
{
  GArray* array = g_array_new(FALSE, FALSE, sizeof(VteCharAttributes));
  char* c_text = vte_terminal_get_text_include_trailing_spaces(const_cast<VteTerminal*>(gobj()), &Private::SignalProxy_selected_gtk_callback, const_cast<Gnome::Vte::Terminal::SlotSelectedCallback*>(&slot), array);
  Glib::ustring text(c_text);
  g_free(c_text);
  ArrayHandle_CharAttributes attributes(reinterpret_cast<VteCharAttributes*>(array->data), static_cast<size_t>(array->len), Glib::OWNERSHIP_DEEP);
  g_array_free(array, FALSE);
  return TextAndCharAttrs(text, attributes);
}

TextAndCharAttrs
Terminal::get_text_range(long start_row, long start_col, long end_row, long end_col, const Gnome::Vte::Terminal::SlotSelectedCallback& slot) const
{
  GArray* array = g_array_new(FALSE, FALSE, sizeof(VteCharAttributes));
  char* c_text = vte_terminal_get_text_range(const_cast<VteTerminal*>(gobj()), start_row, start_col, end_row, end_col, &Private::SignalProxy_selected_gtk_callback, const_cast<Gnome::Vte::Terminal::SlotSelectedCallback*>(&slot), array);
  Glib::ustring text(c_text);
  g_free(c_text);
  ArrayHandle_CharAttributes attributes(reinterpret_cast<VteCharAttributes*>(array->data), static_cast<size_t>(array->len), Glib::OWNERSHIP_DEEP);
  g_array_free(array, FALSE);
  return TextAndCharAttrs(text, attributes);
}

CursorPosition
Terminal::get_cursor_position() const
{
  long column(0), row(0);
  vte_terminal_get_cursor_position(const_cast<VteTerminal*>(gobj()), &column, &row);
  return CursorPosition(column, row);
}

Match
Terminal::match_check(long column, long row)
{
  int tag = 0;
  char* c_text = vte_terminal_match_check(gobj(), column, row, &tag);
  Glib::ustring text(c_text);
  g_free(c_text);
  return Match(text, tag);
}

void
Terminal::set_default_emulation()
{
  vte_terminal_set_emulation(gobj(), 0);
}

Padding
Terminal::get_padding() const
{
  Gtk::Border border;
  get_style_property("inner-border", border);
  return Padding(border.left + border.right, border.top + border.bottom);
}

#ifdef GLIBMM_EXCEPTIONS_ENABLED
bool
Terminal::write_contents(const Glib::RefPtr<Gio::OutputStream>& stream, const Glib::RefPtr<Gio::Cancellable>& cancellable, TerminalWriteFlags flags)
#else
bool
Terminal::write_contents(const Glib::RefPtr<Gio::OutputStream>& stream, const Glib::RefPtr<Gio::Cancellable>& cancellable, TerminalWriteFlags flags, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;
  bool retvalue = vte_terminal_write_contents(gobj(), Glib::unwrap(stream), static_cast<VteTerminalWriteFlags>(flags), Glib::unwrap(cancellable), &gerror);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if (gerror)
  {
    ::Glib::Error::throw_exception(gerror);
  }
#else
  if (gerror)
  {
    error = ::Glib::Error::throw_exception(gerror);
  }
#endif //GLIBMM_EXCEPTIONS_ENABLED

  return retvalue;
}

#ifdef GLIBMM_EXCEPTIONS_ENABLED
bool
Terminal::write_contents(const Glib::RefPtr<Gio::OutputStream>& stream, TerminalWriteFlags flags)
#else
bool
Terminal::write_contents(const Glib::RefPtr<Gio::OutputStream>& stream, TerminalWriteFlags flags, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;
  bool retvalue = vte_terminal_write_contents(gobj(), Glib::unwrap(stream), static_cast<VteTerminalWriteFlags>(flags), 0, &gerror);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if (gerror)
  {
    ::Glib::Error::throw_exception(gerror);
  }
#else
  if (gerror)
  {
    error = ::Glib::Error::throw_exception(gerror);
  }
#endif //GLIBMM_EXCEPTIONS_ENABLED

  return retvalue;
}

} // namespace Vte

} // namespace Gnome
