/* vim: set encoding=utf8:
 *
 * buffer.c
 *
 * This file is part of Shiki.
 *
 * Copyright(C)2006 WAKATSUKI toshihiro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * $Id: buffer.c,v 1.7 2006/11/27 12:01:50 aloha Exp $
 */
#include"shiki.h"

/* GtkTextBuffer から，対応する ShikiBuffer 構造体を逆引き */
static gint compBuffer(gconstpointer a, gconstpointer b) {
  return ((ShikiBuffer *)a)->text_buffer == b ? 0 : b - a;
}

static GList *get_ShikiBufferListElement_By_GtkTextBuffer(GtkTextBuffer *b) {
  return g_list_find_custom(Shiki_EDITOR_BUFFER_LIST, b, compBuffer);
}

void Shiki_delete_buffer(GtkTextBuffer *buffer) {
  /* バッファリストから，リストの要素，バッファ，バッファの番号を逆引き */
  /* 効率が悪いが，Scheme の世界になるべく Gtk のオブジェクトを持ち込まないため */
  GList *bufListElem = get_ShikiBufferListElement_By_GtkTextBuffer(buffer);
  ShikiBuffer *tabInfo  = bufListElem->data;
  gint bufNum = g_list_position(Shiki_EDITOR_BUFFER_LIST, bufListElem);

  /* タブが 1 つしか残っていなかったら消させない */
  if(g_list_length(Shiki_EDITOR_BUFFER_LIST) == 1)
    return;
  /* デリートハンドラをエディタトップレベルのウィジットから取り除く */
  g_signal_handler_disconnect(Shiki_EDITOR_WINDOW, tabInfo->delete_handler_id);
  Shiki_EDITOR_BUFFER_LIST = g_list_delete_link(Shiki_EDITOR_BUFFER_LIST, bufListElem);  
  gtk_widget_destroy(GTK_WIDGET(tabInfo->tabpage));
  g_free(tabInfo->tabpage_label);
  g_free(tabInfo->name);
  g_free(tabInfo->filename);
  g_free(tabInfo);
  gtk_notebook_remove_page(Shiki_EDITOR_NOTEBOOK, bufNum);
  /* 強制再描画 */
  gtk_widget_queue_draw(GTK_WIDGET(Shiki_EDITOR_NOTEBOOK));
}

GtkTextBuffer *Shiki_find_buffer(const gchar *name) {
  GList *l;
  for(l = Shiki_EDITOR_BUFFER_LIST; l != NULL; l = l->next)
    if(strcmp(((ShikiBuffer *)l->data)->name, name) == 0)
      return ((ShikiBuffer *)l->data)->text_buffer;
  return NULL;
}

  gchar *Shiki_buffer_substring(gint start, gint end) {
    if(start >= end)
      return NULL;
    else {
      GtkTextIter s, e;
      gtk_text_buffer_get_iter_at_offset(Shiki_CURRENT_TEXT_BUFFER, &s, start); 
      gtk_text_buffer_get_iter_at_offset(Shiki_CURRENT_TEXT_BUFFER, &e, end);

      return gtk_text_buffer_get_text(Shiki_CURRENT_TEXT_BUFFER, &s, &e, FALSE);
    }
  }

  void Shiki_delete_region(gint start, gint end) {
    if(start >= end)
      return;
    else {
      GtkTextIter s, e;
      gtk_text_buffer_get_iter_at_offset(Shiki_CURRENT_TEXT_BUFFER, &s, start); 
      gtk_text_buffer_get_iter_at_offset(Shiki_CURRENT_TEXT_BUFFER, &e, end);

      return gtk_text_buffer_delete(Shiki_CURRENT_TEXT_BUFFER, &s, &e);
    }
  }

gint Shiki_point() {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  return gtk_text_iter_get_offset(&p);
}

gint Shiki_point_max() {
  GtkTextIter p;
  gtk_text_buffer_get_end_iter(Shiki_CURRENT_TEXT_BUFFER, &p);
  return gtk_text_iter_get_offset(&p);
}

gint Shiki_point_min() {
  return 0;
}

void Shiki_goto_char(gint offset) {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_offset(Shiki_CURRENT_TEXT_BUFFER, &p, offset);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

void Shiki_forward_char() {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  gtk_text_iter_forward_char(&p);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

void Shiki_backward_char() {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  gtk_text_iter_backward_char(&p);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

void Shiki_goto_line(gint line) {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_line(Shiki_CURRENT_TEXT_BUFFER, &p, line);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);  
}

void Shiki_goto_bol() {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  gtk_text_buffer_get_iter_at_line_offset(Shiki_CURRENT_TEXT_BUFFER, &p, gtk_text_iter_get_line(&p), 0);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

void Shiki_goto_eol() {
  GtkTextIter p;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  gtk_text_iter_forward_to_line_end(&p);
  gtk_text_iter_backward_char(&p);
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

void Shiki_forward_line(gint count) {
  GtkTextIter p;
  gint i;
  gtk_text_buffer_get_iter_at_mark(Shiki_CURRENT_TEXT_BUFFER,&p, gtk_text_buffer_get_insert(Shiki_CURRENT_TEXT_BUFFER));
  
  if(count >= 0) {
    for(i = count; i != 0; i--)
      gtk_text_view_forward_display_line(Shiki_CURRENT_TEXT_VIEW, &p);
  } else {
    for(i = count; i != 0; i++)
      gtk_text_view_backward_display_line(Shiki_CURRENT_TEXT_VIEW, &p);
  }
  gtk_text_buffer_place_cursor(Shiki_CURRENT_TEXT_BUFFER, &p);
}

const char *Shiki_buffer_name(GtkTextBuffer *buffer) {
  GList *l = get_ShikiBufferListElement_By_GtkTextBuffer(buffer);
  if(l)
    return ((ShikiBuffer *)(l->data))->name;
  else
    return NULL;
}

gboolean Shiki_deleted_buffer_p(GtkTextBuffer *buffer) {
  GList *l = get_ShikiBufferListElement_By_GtkTextBuffer(buffer);
  if(l)
    return FALSE;
  else
    return TRUE;
}

GtkTextBuffer *Shiki_get_next_buffer(GtkTextBuffer *buffer) {
  GList *l = get_ShikiBufferListElement_By_GtkTextBuffer(buffer);
  if(l && l->next)
    return ((ShikiBuffer *)(l->next->data))->text_buffer;
  else
    return NULL;
}

GtkTextBuffer *Shiki_get_previous_buffer(GtkTextBuffer *buffer) {
  GList *l = get_ShikiBufferListElement_By_GtkTextBuffer(buffer);
  if(l && l->prev)
    return ((ShikiBuffer *)(l->prev->data))->text_buffer;
  else
    return NULL;
}

ScmObj Shiki_buffer_list() {
  GList *l;
  GtkTextBuffer *b;
  ScmObj bl = SCM_NIL;

  for(l = Shiki_EDITOR_BUFFER_LIST; l != NULL; l = l->next) {
    b= ((ShikiBuffer *)(l->data))->text_buffer;
    bl = Scm_Cons(SHIKI_BUFFER_BOX(g_object_ref(b)), bl);
  }
  return bl;
}

void Shiki_erase_buffer(GtkTextBuffer *buffer) {
  GtkTextIter start, end;
  gtk_text_buffer_get_start_iter(buffer, &start);
  gtk_text_buffer_get_end_iter(buffer, &end);
  gtk_text_buffer_delete(buffer, &start, &end);
}

const gchar *Shiki_file_name_dialog(const gchar *msg) {

  GtkWidget *dialog = gtk_file_selection_new(msg);
  gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
  const gchar *filename = NULL;

  if(resp == GTK_RESPONSE_OK)
    filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(dialog));

  gtk_widget_destroy(dialog);
  return filename;
}

gboolean Shiki_yes_or_no_p(const gchar *msg) {
  GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(Shiki_EDITOR_WINDOW),
               GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
               GTK_BUTTONS_YES_NO, msg);
  
  gint resp = gtk_dialog_run(GTK_DIALOG(dialog));
  gtk_widget_destroy(dialog);
  if(GTK_RESPONSE_YES == resp)
    return TRUE;
  return FALSE;
}
