/* lyric.c
 *
 * Functions for the manipulations of lyrics
 *
 * for Denemo, a gtk+ frontend for GNU Lilypond
 * (c)2009 Richard Shann
 */
#include <string.h> /* for strcmp() */
#include "lyric.h"
#include "objops.h"
#include "staffops.h"
#include "utils.h"

static GtkWidget *DummyVerse;/* a non-existent verse */

static gboolean lyric_keypress(GtkWidget *w, GdkEventKey *event) {
DenemoGUI *gui = Denemo.gui;
 if(gtk_text_buffer_get_modified(gtk_text_view_get_buffer(GTK_TEXT_VIEW(w)))) {
   score_status(Denemo.gui, TRUE);
   gtk_widget_queue_draw (Denemo.scorearea);
   gtk_text_buffer_set_modified(gtk_text_view_get_buffer(GTK_TEXT_VIEW(w)), FALSE);
 }
 return FALSE;
}
gboolean lyric_change(GtkTextBuffer *buffer) {
  DenemoGUI *gui = Denemo.gui;
  score_status(gui, TRUE);
  gtk_widget_queue_draw (Denemo.scorearea);
  return FALSE;
}

static GtkWidget *new_lyric_editor(void) {
 GtkWidget *view = gtk_text_view_new ();

  
  GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
				  GTK_POLICY_AUTOMATIC,
				  GTK_POLICY_AUTOMATIC);
  if(Denemo.prefs.newbie)
    gtk_widget_set_tooltip_text(sw, _("The text of a verse can be typed or pasted here. The space between syllables determines which syllable goes beneath which note(s).\nNew lines have no special significance for this. Slurs on notes make them take only one syllable. Use the underscore _ for blank syllables and the hyphen - for extending syllables."));
  gtk_container_add (GTK_CONTAINER (sw), view);

  
 return view;
}

DenemoObject *
newlyric (gint baseduration, gint numdots, gchar *lys) {
  g_warning("Not implemented");
  return NULL;
}

static void
switch_page (GtkNotebook *notebook,  gpointer dummy, guint pagenum, DenemoStaff *staff) {
    gtk_widget_queue_draw (Denemo.scorearea);
    staff->currentverse = g_list_nth(staff->verses, pagenum);
}
GtkWidget * add_verse_to_staff(DenemoScore *si, DenemoStaff *staff) {
  GtkWidget *notebook, *textview;
  if(staff->verses==NULL) {
    notebook = gtk_notebook_new();
    gtk_widget_show(notebook);
    g_signal_connect (G_OBJECT(notebook), "switch_page", G_CALLBACK(switch_page), staff);
    if(si->lyricsbox==NULL)
      install_lyrics_preview(si, gtk_widget_get_parent(gtk_widget_get_parent(Denemo.scorearea)));//FIXME we need a proper way of getting to the top vbox, that will not break when scorearea is moved in the widget hierarchy.
    gtk_box_pack_start(GTK_BOX(si->lyricsbox), notebook, TRUE, TRUE, 0);
    if(si->measurewidth==DENEMO_INITIAL_MEASURE_WIDTH)
      si->measurewidth = DENEMO_INITIAL_MEASURE_WIDTH*3;
  } else {
    GtkWidget *w = staff->verses->data;
    notebook = gtk_widget_get_parent(w);
  }
  // if(staff->currentverse)    
  //  gtk_widget_hide(staff->currentverse->data); 
  //if(si->currentstaff && si->currentstaff->data == staff)
  //  gtk_widget_show(staff->currentverse->data);
  textview = new_lyric_editor();
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW(textview), GTK_WRAP_WORD_CHAR);
  gtk_widget_show_all(gtk_widget_get_parent(textview));
  staff->verses = g_list_append(staff->verses, textview);
  staff->currentverse = g_list_last(staff->verses);
  //  g_print("Setting verse to %p\n", staff->currentverse);
  gint pagenum = gtk_notebook_append_page (GTK_NOTEBOOK (notebook), gtk_widget_get_parent(textview), NULL);
  gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook), pagenum);
  gchar *tablabel = g_strdup_printf("Verse %d", pagenum+1);
  gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(notebook), gtk_widget_get_parent(textview), tablabel);
  g_free(tablabel);
  if(pagenum)
    gtk_notebook_set_show_tabs (GTK_NOTEBOOK(notebook), TRUE);
  return textview;
}

void add_verse(GtkAction *action, gpointer param) {
DenemoGUI *gui = Denemo.gui;
DenemoScore *si = gui->si;
 if(gui->si->currentstaff) {
   DenemoStaff *staff = si->currentstaff->data;
   add_verse_to_staff(si, staff);
   signal_structural_change(gui);
   gtk_widget_show(staff->currentverse->data);
   g_signal_connect (G_OBJECT (gtk_text_view_get_buffer (staff->currentverse->data)), "changed", G_CALLBACK (lyric_change), NULL);
 }
}

void delete_verse(GtkAction *action, gpointer param) {
DenemoGUI *gui = Denemo.gui;
DenemoScore *si = gui->si;
 if(si->currentstaff) {
   DenemoStaff *staff = si->currentstaff->data;
   if(staff->currentverse) {
     staff->verses = g_list_remove_link(staff->verses, staff->currentverse);
     gtk_widget_destroy(staff->currentverse->data);
     staff->currentverse = staff->verses;
     signal_structural_change(gui);
     score_status(gui, TRUE);
     gtk_widget_queue_draw (Denemo.scorearea);
   }
 }

}


gchar *get_text_from_view(GtkWidget *textview) {
  GtkTextIter startiter, enditer; 
  GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(textview));    
  gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER(buffer), &startiter);
  gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(buffer), &enditer);
  return gtk_text_buffer_get_text (GTK_TEXT_BUFFER(buffer), &startiter, &enditer, FALSE);
}

gboolean scan_syllable(gchar **next, GString *gs) {
  gboolean result;
  result = pango_scan_string((const char **)next, gs);
  if(result && (*gs->str=='\\') && (*(gs->str+1)!='\\') && (*(gs->str+1)!='\"')) {
    while(**next && **next!='\n')
    (*next)++;//skip to end of line
    return scan_syllable(next, gs);
  } 
  if(result && ((!strcmp(gs->str, "--")||(!strcmp(gs->str, "__")))))
     return scan_syllable(next, gs);
  return result;
}

static gchar *lyric_iterator(GtkWidget *textview, gint count) {
  static  const gchar *next;
  static gchar *lyrics;
  static GString *gs;
  static start_count;
  if(gs==NULL)
    gs = g_string_new("");
  if(textview==NULL) {
    gboolean result = scan_syllable((gchar **)&next, gs);
    if(result && gs->len)
      return gs->str;
    else
      return NULL;
  }
  if(textview != DummyVerse) {
    if(lyrics) g_free(lyrics);
    lyrics = get_text_from_view(textview);
    next = lyrics;
    start_count = count;
    while(count--)
      scan_syllable((gchar **)&next, gs);
 }
  return NULL;
}


gchar *next_syllable(gint count) {
  return lyric_iterator(NULL, count);
}


/* rename reset_lyrics */
void reset_lyrics(DenemoStaff *staff, gint count) {
  if(DummyVerse==NULL)
    DummyVerse = gtk_text_view_new();
  if(staff && staff->currentverse)
    lyric_iterator(staff->currentverse->data, count);
  else lyric_iterator(DummyVerse, count);
}



void install_lyrics_preview(DenemoScore *si, GtkWidget *top_vbox){ 
  if(si->lyricsbox==NULL)
    si->lyricsbox = gtk_vbox_new (FALSE, 1);//box to hold notebook of textview widgets
  gtk_box_pack_start (GTK_BOX (top_vbox), si->lyricsbox, FALSE, TRUE, 0);
  if (Denemo.prefs.lyrics_pane)
    gtk_widget_show(si->lyricsbox);
}

/* hide the notebook of verses for the current staff */
void hide_lyrics(void) {
DenemoGUI *gui = Denemo.gui;
DenemoScore *si = gui->si;
 if(gui->si->currentstaff && ((DenemoStaff *)gui->si->currentstaff->data)->currentverse)
   gtk_widget_hide(gtk_widget_get_parent(((DenemoStaff *)gui->si->currentstaff->data)->currentverse->data));
}

/* show the notebook of verses for the current staff */
void show_lyrics(void) {
DenemoGUI *gui = Denemo.gui;
DenemoScore *si = gui->si;
 if(si->currentstaff && ((DenemoStaff *)si->currentstaff->data)->currentverse)
   gtk_widget_show(gtk_widget_get_parent(((DenemoStaff *)si->currentstaff->data)->currentverse->data));
}

/* hide the notebooks of verses for the non-current staffs */
void select_lyrics(void) {
DenemoGUI *gui = Denemo.gui;
DenemoScore *si = gui->si;
 GList *current = si->thescore;
 for(;current;current = current->next) {
   if(current != si->currentstaff && ((DenemoStaff *)current->data)->verses)
       gtk_widget_hide(gtk_widget_get_parent(((DenemoStaff *)current->data)->verses->data));
 }
}

gchar *get_lyrics_for_current_verse(DenemoStaff *thestaff) {
  if(thestaff->currentverse && thestaff->currentverse->data)
    return get_text_from_view(thestaff->currentverse->data);
  else
    return  NULL;
}

gboolean append_lyrics_for_current_verse(DenemoStaff *thestaff, gchar *text) {
  if(thestaff->currentverse && thestaff->currentverse->data) {
    GtkTextIter iter;
    GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (thestaff->currentverse->data);
    gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(textbuffer), &iter);  
    gtk_text_buffer_insert (textbuffer, &iter, text, -1);    
    return TRUE;
  }
  else
    return FALSE;
}
gboolean put_lyrics_for_current_verse(DenemoStaff *thestaff, gchar *text) {
  if(thestaff->currentverse && thestaff->currentverse->data) {
    GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (thestaff->currentverse->data);
    GtkTextIter startiter, enditer; 
    gtk_text_buffer_get_start_iter (GTK_TEXT_BUFFER(textbuffer), &startiter);
    gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(textbuffer), &enditer);
    gtk_text_buffer_delete (textbuffer, &startiter, &enditer);   
    gtk_text_buffer_get_end_iter (GTK_TEXT_BUFFER(textbuffer), &enditer);  
    gtk_text_buffer_insert (textbuffer, &enditer, text, -1);    
    return TRUE;
  }
  else
    return FALSE;
}
