/*  Gnometab -- a guitar tablature editor for GNOME
    Copyright (C) 2001  William L. Guelker

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <math.h>
#include <string.h>
#include <gnome.h>
#include <libgnomeprint/gnome-print.h>
#include <libgnomeprint/gnome-print-job.h>
#include <libgnomeprintui/gnome-print-dialog.h>
#include <libgnomeprintui/gnome-print-job-preview.h>
#include <libgnomecanvas/gnome-canvas.h>
#include "tab_canvas.h"
#include "tab_canvas_print.h"
#include "tab_objects.h"

typedef struct _GnometabPrintJobInfo    GnometabPrintJobInfo;

struct _GnometabPrintJobInfo {

    xmlDocPtr              doc;
    
    gboolean              preview;

    GnomePrintConfig     *config;
    gint                 range_type;

    GnomePrintJob    *print_job;
    GnomePrintContext    *print_ctx;

    gint                 page_num;
    gchar                 *tab_font;
    gchar                 *tab_font_large;
    gchar                 *tab_font_small;
    gchar                 *tab_font_tiny;
};

Color black = { 0.0f, 0.0f, 0.0f };
Color grey = { 0.1f, 0.1f, 0.1f };

static GnomeFont*
gnome_font_from_string(gchar *font_string)
{
    PangoFontDescription *font;
    GnomeFont *print_font;
    gboolean italic = FALSE;
    
    font = pango_font_description_from_string(font_string);
    
    if (pango_font_description_get_style(font) == PANGO_STYLE_OBLIQUE ||
        pango_font_description_get_style(font) == PANGO_STYLE_ITALIC) {
            italic = TRUE;
        }
    print_font = gnome_font_find_closest_from_weight_slant(
                        pango_font_description_get_family(font),
                        pango_font_description_get_weight(font),
                        italic,
                        (gdouble ) (pango_font_description_get_size(font))/1024);

    pango_font_description_free(font);
    return print_font;
}

static GnometabPrintJobInfo* 
gnometab_print_job_info_new (xmlDocPtr doc)
{    
    GnometabPrintJobInfo *pji;
    
    g_return_val_if_fail (doc != NULL, NULL);
    
    pji = g_new0 (GnometabPrintJobInfo, 1);
    
    pji->config = gnome_print_config_default ();
    g_return_val_if_fail (pji->config != NULL, NULL);

    gnome_print_config_set (pji->config, "Printer", "GENERIC");
    gnome_print_config_set (pji->config, "Settings.Transport.Backend", "lpr");
    gnome_print_config_set (pji->config, "Settings.Output.Media.PhysicalSize", "USLetter");

    pji->doc = doc;
    pji->preview = FALSE;
    pji->range_type = GNOME_PRINT_RANGE_ALL;

    pji->page_num = 0;

    gnome_print_config_ref (pji->config);

    return pji;
}    

static void
gnometab_print_job_info_destroy (GnometabPrintJobInfo *pji)
{
    g_return_if_fail (pji != NULL);
    
    if (pji->tab_font != NULL) g_free(pji->tab_font);
    if (pji->tab_font_large != NULL) g_free(pji->tab_font_large);
    if (pji->tab_font_small != NULL) g_free(pji->tab_font_small);
    if (pji->tab_font_tiny != NULL) g_free(pji->tab_font_tiny);
    
    if (pji->config != NULL)
        gnome_print_config_unref (pji->config);

    if (pji->print_ctx != NULL)
        g_object_unref (pji->print_ctx);

    if (pji->print_job != NULL)
        g_object_unref (pji->print_job);

    g_free (pji);
}

static void 
print_preview(GnometabPrintJobInfo *pji)
{
    GtkWidget *gpmp;
    gchar *title;
    
    title = g_strdup_printf (_("Gnometab - Print Preview"));
    gpmp = gnome_print_job_preview_new (pji->print_job, title);
    g_free (title);
    gtk_widget_show (gpmp);
    
}

static void 
translate_y(Point *point)
{
    /* this is just an ugly hack since I can't figure out how to get
            gnome-print to do it for me -- and there's no frigging docs!!  */
    
    point->y = -(point->y) + 1000.0;
}

static void 
print_render_tab_text(GnometabPrintJobInfo *pji, xmlNodePtr txtnode)
{
    Point pos;
    gchar *x_char, *y_char, *text_char;
    GnomeFont *gfont;
    
    gfont = gnome_font_from_string(pji->tab_font);
        
    gnome_print_setfont(pji->print_ctx, gfont);
        
    x_char = get_prop(txtnode, "x_create");
    y_char = get_prop(txtnode, "y_create");
    text_char = get_prop(txtnode, "text");
    
    pos.x = atof(x_char);
    pos.y = atof(y_char) + 4.0;
    translate_y(&pos);
    
    draw_string(pji->print_ctx, text_char, &pos, 0, &black);
    
    g_free(x_char);
    g_free(y_char);
    g_free(text_char);
}

static void 
print_render_tab_bar(GnomePrintContext *ctx, xmlNodePtr barnode)
{
    Point p1, p2, p3;
    gint bar_size;
    double total_length;
    gchar *x_char, *y_char, *size_char;
    
    x_char = get_prop(barnode, "x_create");
    y_char = get_prop(barnode, "y_create");
    size_char = get_prop(barnode, "bar_size");
    
    p1.x = atof(x_char);
    p1.y = atof(y_char) + 5.0;
    bar_size = atoi(size_char);
    total_length = 12*bar_size;
    
    p2.x = p1.x - 7.0;
    p2.y = p1.y - total_length/2.0;
    p3.x = p1.x;
    p3.y = p1.y - total_length;
    
    translate_y(&p1);
    translate_y(&p2);
    translate_y(&p3);
    
    set_linewidth(ctx, 1.0);
    draw_arc(ctx, &p1, &p2, &p3, &black);
    set_linewidth(ctx, 0.0);
    g_free(x_char);
    g_free(y_char);
    g_free(size_char);
}

static void 
print_render_tab_slur(GnometabPrintJobInfo *pji, xmlNodePtr slurnode)
{
    Point p1, p2, p3;
    Point textpos;
    double total_length;
    gint slur_type;
    gchar slur_text[4];
    gchar *x_char, *y_char, *pos_char, *type_char;
    GnomeFont *gfont;
    
    gfont = gnome_font_from_string(pji->tab_font_tiny);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    x_char = get_prop(slurnode, "x_create");
    y_char = get_prop(slurnode, "y_create");
    pos_char = get_prop(slurnode, "positions");
    type_char = get_prop(slurnode, "type");
    
    p1.x = atof(x_char);
    p1.y = atof(y_char) - 5.0;
    total_length = 12*atof(pos_char);
    
    p2.x = p1.x + total_length/2.0;
    p2.y = p1.y - 7.0;
    p3.x = p1.x + total_length;
    p3.y = p1.y;
    
    translate_y(&p1);
    translate_y(&p2);
    translate_y(&p3);
    
    set_linewidth(pji->print_ctx, 1.0);
    draw_arc(pji->print_ctx, &p1, &p2, &p3, &black);
    set_linewidth(pji->print_ctx, 0.0);
    
    if (type_char != NULL)    {
        slur_type = atoi(type_char);
        
        switch (slur_type)    {
            case SLUR_HAMMER:
                g_snprintf(slur_text, 2, "h");
                break;
            case SLUR_PULLOFF:
                g_snprintf(slur_text, 2, "p");
                break;
            case SLUR_SLIDE:
                g_snprintf(slur_text, 3, "sl");
                break;
            default:
                g_snprintf(slur_text, 2, " ");
                break;
        }
        
        textpos.x = p1.x + total_length/2 - 2.0;
        textpos.y = atof(y_char) - 10.0;
        
        translate_y(&textpos);
        draw_string(pji->print_ctx, slur_text, &textpos, 0, &black);
                    
    }
    
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    g_free(x_char);
    g_free(y_char);
    g_free(pos_char);
    g_free(type_char);
}
    
static void 
print_render_tab_bend(GnomePrintContext *ctx, xmlNodePtr bendnode)
{
    Point p1, p2, p3;
    Point end_1, end_2;
    gchar *x_char, *y_char;
    
    x_char = get_prop(bendnode, "x_create");
    y_char = get_prop(bendnode, "y_create");
    
    p1.x = atof(x_char) + 5.0;
    p1.y = atof(y_char) - 2.0;
    
    p2.x = p1.x + 8.0;
    p2.y = p1.y - 3.0;
    p3.x = p1.x + 10.0;
    p3.y = p1.y - 12.0;
    
    translate_y(&p1);
    translate_y(&p2);
    translate_y(&p3);
    
    set_linewidth(ctx, 1.0);
    draw_arc(ctx, &p1, &p2, &p3, &black);
    
    /* must translate p3 back to tab_canvas coord 
        system before we can use it again */
    
    translate_y(&p3);
    end_1.x = p3.x - 3.0;
    end_1.y = p3.y + 1.0;
    end_2.x = p3.x + 2.0;
    end_2.y = p3.y + 3.0;
    
    translate_y(&p3);
    translate_y(&end_1);
    translate_y(&end_2);
    
    draw_line(ctx, &p3, &end_1, &black);
    draw_line(ctx, &p3, &end_2, &black);
    
    set_linewidth(ctx, 0.0);
    g_free(x_char);
    g_free(y_char);
    
}
    
static void 
print_render_tab_measure(GnomePrintContext *ctx, xmlNodePtr measurenode)
{
    Point p1, p2;
    gchar *x_char, *y_char;
    
    x_char = get_prop(measurenode, "x_create");
    y_char = get_prop(measurenode, "y_create");
        
    p1.x = atof(x_char);
    p1.y = atof(y_char);
    p1.y = (ceil(p1.y/140))*140 - 60;
    p2.x = p1.x;
    p2.y = p1.y - 60.0;
    
    translate_y(&p1);
    translate_y(&p2);
    
    set_linewidth(ctx, 1.0);
    draw_line(ctx, &p1, &p2, &black);
    set_linewidth(ctx, 0.0);
    g_free(x_char);
    g_free(y_char);
}

static void 
print_render_tab_legato(GnomePrintContext *ctx, xmlNodePtr legatonode)
{
    Point points[21];
    gdouble leg_size;
    gint i;
    gchar *x_char, *y_char, *size_char;
    
    x_char = get_prop(legatonode, "x_create");
    y_char = get_prop(legatonode, "y_create");
    size_char = get_prop(legatonode, "legato_size");
    
    leg_size = 12*(atoi(size_char));
    
    points[0].x = atof(x_char) - 6.0;
    points[0].y = atof(y_char) + 6.0;
    points[1].x = points[0].x - 1.0;
    points[1].y = points[0].y - (leg_size/20);
    points[2].x = points[0].x;
    points[2].y = points[0].y - 2*(leg_size/20);
    points[3].x = points[0].x + 1.0;
    points[3].y = points[0].y - 3*(leg_size/20);
    points[4].x = points[0].x;
    points[4].y = points[0].y - 4*(leg_size/20);
    points[5].x = points[0].x - 1.0;
    points[5].y = points[0].y - 5*(leg_size/20);
    points[6].x = points[0].x;
    points[6].y = points[0].y - 6*(leg_size/20);
    points[7].x = points[0].x + 1.0;
    points[7].y = points[0].y - 7*(leg_size/20);
    points[8].x = points[0].x;
    points[8].y = points[0].y - 8*(leg_size/20);
    points[9].x = points[0].x - 1.0;
    points[9].y = points[0].y - 9*(leg_size/20);
    points[10].x = points[0].x;
    points[10].y = points[0].y - 10*(leg_size/20);
    points[11].x = points[0].x + 1.0;
    points[11].y = points[0].y - 11*(leg_size/20);
    points[12].x = points[0].x;
    points[12].y = points[0].y - 12*(leg_size/20);
    points[13].x = points[0].x - 1.0;
    points[13].y = points[0].y - 13*(leg_size/20);
    points[14].x = points[0].x;
    points[14].y = points[0].y - 14*(leg_size/20);
    points[15].x = points[0].x + 1.0;
    points[15].y = points[0].y - 15*(leg_size/20);
    points[16].x = points[0].x;
    points[16].y = points[0].y - 16*(leg_size/20);
    points[17].x = points[0].x - 1.0;
    points[17].y = points[0].y - 17*(leg_size/20);
    points[18].x = points[0].x;
    points[18].y = points[0].y - 18*(leg_size/20);
    points[19].x = points[0].x + 1.0;
    points[19].y = points[0].y - 19*(leg_size/20);
    points[20].x = points[0].x;
    points[20].y = points[0].y - leg_size;
    
    for (i = 0; i < 21; i++)    {
        translate_y(&points[i]);
    }
    
    draw_polyline(ctx, points, 21, &black);
    g_free(x_char);
    g_free(y_char);
    g_free(size_char);
    
}
    
static void
print_render_tab_strum(GnomePrintContext *ctx, xmlNodePtr strumnode)
{
    Point p1, p2, end_1;
    double total_length;
    gboolean upstroke;
    gchar *x_char, *y_char, *up_char, *size_char;
    
    x_char = get_prop(strumnode, "x_create");
    y_char = get_prop(strumnode, "y_create");
    up_char = get_prop(strumnode, "upstroke");
    size_char = get_prop(strumnode, "size");
    
    upstroke = atoi(up_char);
    
    p1.x = atof(x_char) + 1.0;
    p1.y = atof(y_char) + 6.0;
    
    total_length = 12*(atoi(size_char)) - 5.0;
    
    p2.x = p1.x;
    p2.y = p1.y - total_length;
    
    translate_y(&p1);
    translate_y(&p2);
    
    set_linewidth(ctx, 1.0);
    
    draw_line(ctx, &p1, &p2, &black);
    
    if (upstroke)    {
        end_1.x = p2.x - 3.0;
        end_1.y = p2.y - 3.0;
        draw_line(ctx, &p2, &end_1, &black);
        end_1.x = p2.x + 3.0;
        draw_line(ctx, &p2, &end_1, &black);
    }
    else    {
        end_1.x = p1.x - 3.0;
        end_1.y = p1.y + 3.0;
        draw_line(ctx, &p1, &end_1, &black);
        end_1.x = p1.x + 3.0;
        draw_line(ctx, &p1, &end_1, &black);
    }
    set_linewidth(ctx, 0.0);
    
    g_free(x_char);
    g_free(y_char);
    g_free(up_char);
    g_free(size_char);
}
        
static void 
print_render_tab_timesig(GnometabPrintJobInfo *pji, xmlNodePtr timesignode)
{
    double y;
    Point pos;
    GnomeFont *gfont;
    gchar *x_char, *y_char, *beats_char, *beatval_char;
    
    x_char = get_prop(timesignode, "x_create");
    y_char = get_prop(timesignode, "y_create");
    beats_char = get_prop(timesignode, "beats");
    beatval_char = get_prop(timesignode, "beatval");
    
    y = atof(y_char);
    
    find_staff(y);
    
    switch (current_staff)
    {

        case 1:
            y = 300.0;
            break;
        case 2:
            y = 440.0;
            break;
        case 3:
            y = 580.0;
            break;
        case 4:
            y = 720.0;
            break;
        case 5:
            y = 860.0;
            break;
        default:
            y = 160.0;
            break;
    }
    
    pos.x = atof(x_char);
    pos.y = y + 22;
    translate_y(&pos);
    
    gfont = gnome_font_from_string(pji->tab_font_large);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    draw_string(pji->print_ctx, beats_char, &pos, 0, &black);
    
    pos.y = y + 52;
    translate_y(&pos);
    
    draw_string(pji->print_ctx, beatval_char, &pos, 0, &black);
    
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
    g_free(x_char);
    g_free(y_char);
    g_free(beats_char);
    g_free(beatval_char);
    
}
    
static void 
print_render_tab_repeat(GnomePrintContext *ctx, xmlNodePtr repeatnode)
{
    Point p1, p2;
    double y;
    gboolean close;
    gchar *close_char, *x_char, *y_char;
    
    x_char = get_prop(repeatnode, "x_create");
    y_char = get_prop(repeatnode, "y_create");
    close_char = get_prop(repeatnode, "close");
    
    close = atoi(close_char);
        
    p1.x = atof(x_char);
    y = atof(y_char);
    y = (ceil(y/140))*140 - 60;
    p1.y = y;
    p2.x = p1.x;
    p2.y = p1.y - 60.0;
    
    translate_y(&p1);
    translate_y(&p2);
    set_linewidth(ctx, 1.0);
    
    draw_line(ctx, &p1, &p2, &black);
    p1.x = p1.x + 4.0;
    p2.x = p2.x + 4.0;
    draw_line(ctx, &p1, &p2, &black);
    
    if (close)    {
        p1.x = p1.x - 8.0;
        p2.x = p2.x - 6.0;
    }
    else    {
        p1.x = p1.x + 2.0;
        p2.x = p2.x + 4.0;
    }
    
    p1.y = y - 28.0;
    p2.y = y - 28.0;
    translate_y(&p1);
    translate_y(&p2);
    draw_line(ctx, &p1, &p2, &black);
    p1.y = y - 32.0;
    p2.y = y - 32.0;
    translate_y(&p1);
    translate_y(&p2);
    draw_line(ctx, &p1, &p2, &black);
    set_linewidth(ctx, 0.0);
        
    g_free(close_char);
    g_free(x_char);
    g_free(y_char);
}

static void
print_render_eighth_note_squiggle(GnomePrintContext *ctx, 
                                    double start_x, 
                                    double start_y)
{
    Point points[3];
    gint i;
    
    // this lines things up a bit better.
    
    start_y = start_y - 1;
    start_x = start_x - 1;
    
    points[0].x = start_x;
    points[0].y = start_y;
    points[1].x = start_x + 2.5;
    points[1].y = start_y - 5.0;
    points[2].x = start_x + 5.0;
    points[2].y = start_y;
    for (i = 0; i < 3; i++)    {
        translate_y(&points[i]);
    }
    set_linewidth(ctx, 1.0);
    draw_filled_arc(ctx, &points[0], &points[1], &points[2], &black);
    
    points[0].x = start_x + 5.0;
    points[0].y = start_y;
    points[1].x = start_x + 2.5;
    points[1].y = start_y + 5.0;
    points[2].x = start_x;
    points[2].y = start_y;
    for (i = 0; i < 3; i++)    {
        translate_y(&points[i]);
    }
    draw_filled_arc(ctx, &points[0], &points[1], &points[2], &black);
    
    points[0].x = start_x + 2.5;
    points[0].y = start_y - 2.0;
    points[1].x = start_x + 9.0;
    points[1].y = start_y + 2.0;
    points[2].x = start_x + 13.5;
    points[2].y = start_y - 2.0;
    for (i = 0; i < 3; i++)    {
        translate_y(&points[i]);
    }
    draw_arc(ctx, &points[0], &points[1], &points[2], &black);
    set_linewidth(ctx, 0.0);
}

static void
print_render_tab_rest(GnomePrintContext *ctx, xmlNodePtr restnode)
{
    Point points[2];
    Point morepoints[3];
    gint i;
    gchar *x_char, *y_char, *value_char;
    double start_x, start_y;
    
    x_char = get_prop(restnode, "x_create");
    y_char = get_prop(restnode, "y_create");
    value_char = get_prop(restnode, "value");
    
    start_x = atof(x_char);
    start_y = atof(y_char);
    // start_y = (ceil(atof(y_char)/140))*140 - 90.0;
    
    
    switch (atoi(value_char)) {
    
        case 1:
            points[0].x = start_x;
            points[0].y = start_y - 4.0;
            points[1].x = start_x + 12;
            points[1].y = start_y - 4.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.0);
            draw_line(ctx, &points[0], &points[1], &black);
            
            points[0].x = start_x + 3.0;
            points[1].x = start_x + 9.0;
            points[0].y = start_y - 2.0;
            points[1].y = points[0].y;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 3.0);
            draw_line(ctx, &points[0], &points[1], &black);
            set_linewidth(ctx, 0.0);
            break;
        
        case 2:
            points[0].x = start_x;
            points[0].y = start_y + 5.0;
            points[1].x = start_x + 12;
            points[1].y = start_y + 5.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.0);
            draw_line(ctx, &points[0], &points[1], &black);
            
            points[0].x = start_x + 3.0;
            points[1].x = start_x + 9.0;
            points[0].y = start_y + 3.0;
            points[1].y = points[0].y;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 3.0);
            draw_line(ctx, &points[0], &points[1], &black);
            set_linewidth(ctx, 0.0);
            break;
        
        case 8:
            print_render_eighth_note_squiggle(ctx, (start_x - 4.5),
                                                    (start_y - 4.5));
            points[0].x = start_x + 9.0;
            points[0].y = start_y - 7.0;
            points[1].x = start_x + 5.0;
            points[1].y = start_y + 8.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.5);
            draw_line(ctx, &points[0], &points[1], &black);
            set_linewidth(ctx, 0.0);
            break;
        
        case 16:
            print_render_eighth_note_squiggle(ctx, (start_x - 4.5),
                                                    (start_y - 4.5));
            print_render_eighth_note_squiggle(ctx, (start_x - 5.5),
                                                    (start_y - 1.0));
            points[0].x = start_x + 9.0;
            points[0].y = start_y - 7.0;
            points[1].x = start_x + 5.0;
            points[1].y = start_y + 8.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.5);
            draw_line(ctx, &points[0], &points[1], &black);
            set_linewidth(ctx, 0.0);
            break;
        
        case 32:
            print_render_eighth_note_squiggle(ctx, (start_x - 4.5),
                                                    (start_y - 4.5));
            print_render_eighth_note_squiggle(ctx, (start_x - 5.5),
                                                    (start_y - 1.0));
            print_render_eighth_note_squiggle(ctx, (start_x - 6.5),
                                                    (start_y + 2.5));
            points[0].x = start_x + 9.0;
            points[0].y = start_y - 7.0;
            points[1].x = start_x + 5.0;
            points[1].y = start_y + 8.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.5);
            draw_line(ctx, &points[0], &points[1], &black);
            set_linewidth(ctx, 0.0);
            break;
        
        default:
            points[0].x = start_x;
            points[0].y = start_y - 10.0;
            points[1].x = start_x + 4.0;
            points[1].y = start_y - 5.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.0);
            draw_line(ctx, &points[0], &points[1], &black);
            
            points[0].x = start_x + 4.0;
            points[0].y = start_y - 5.0;
            points[1].x = start_x - 1.0;
            points[1].y = start_y;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 3.0);
            draw_line(ctx, &points[0], &points[1], &black);
            
            points[0].x = start_x - 1.0;
            points[0].y = start_y;
            points[1].x = start_x + 6.0;
            points[1].y = start_y + 8.0;
            translate_y(&points[0]);
            translate_y(&points[1]);
            set_linewidth(ctx, 1.0);
            draw_line(ctx, &points[0], &points[1], &black);
            
            morepoints[0].x = start_x + 6.0;
            morepoints[0].y = start_y + 8.0;
            morepoints[1].x = start_x - 2.0;
            morepoints[1].y = start_y + 4.5;
            morepoints[2].x = start_x + 1.0;
            morepoints[2].y = start_y + 12.5;
            for (i = 0; i < 3; i++)    {
                translate_y(&morepoints[i]);
            }
            set_linewidth(ctx, 1.5);
            set_linejoin(ctx, ART_PATH_STROKE_JOIN_ROUND);
            set_linecaps(ctx, ART_PATH_STROKE_CAP_ROUND);

            draw_arc(ctx, &morepoints[0], &morepoints[1], &morepoints[2], &black);
            set_linewidth(ctx, 0.0);
            set_linejoin(ctx, 0);
            set_linecaps(ctx, 0);
            break;
    }
    g_free(x_char);
    g_free(y_char);
    
}

static void 
print_render_tab_comment(GnometabPrintJobInfo *pji, xmlNodePtr commentnode)
{
    Point p1, p2;
    double y_start = 0;
    double y = 0;
    GnomeFont *gfont;
    gchar *text, *char_x, *char_y;
    
    char_x = get_prop(commentnode, "x_create");
    char_y = get_prop(commentnode, "y_create");
    text = get_prop(commentnode, "text");
    
    y_start = atof(char_y);
    y = y_start;
    
    find_staff(y);
    switch (current_staff)    {
        case 1:
            y = 280.0;
            break;
        case 2:
            y = 420.0;
            break;
        case 3:
            y = 560.0;
            break;
        case 4:
            y = 700.0;
            break;
        case 5:
            y = 840.0;
            break;
        default:
            y = 140.0;
            break;
    }
    
    p1.x = atof(char_x);
    p1.y = y_start;
    p2.x = p1.x + 10;
    p2.y = y;
    
    translate_y(&p1);
    translate_y(&p2);
    draw_line(pji->print_ctx, &p1, &p2, &black);
    
    gfont = gnome_font_from_string(pji->tab_font_small);
    gnome_print_setfont(pji->print_ctx, gfont);
    p2.x = p2.x - gnome_font_get_width_utf8(gfont, text)/2;
    p2.y = p2.y + 2.0;
    
    draw_string(pji->print_ctx, text, &p2, 0, &black);
    
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    g_free(text);
    g_free(char_x);
    g_free(char_y);
    
}

static void 
apply_chord_affine(Point *point)
{
    const double my_affine[6] = { 0.54, 0, 0, 0.54, 0, 0 };
    ArtPoint source_pt, dest_pt;
    
    if (chords_above_staff == FALSE) return;
        
    source_pt.x = point->x;
    source_pt.y = point->y;
    
    art_affine_point(&dest_pt, &source_pt, my_affine);
    // dest_pt.y = dest_pt.y - 32.0;
    
    point->x = dest_pt.x;
    point->y = dest_pt.y;
}

static void 
print_render_chord_grid(GnomePrintContext *ctx, Point start)
{
    double x, y;
    Point ul_corner, lr_corner;
    Point start_diff, step_diff, max_diff;
    
    set_linewidth(ctx, 0.2);
    
    start_diff.x = 7.0;
    start_diff.y = 24.0;
    step_diff.x = 14.0;
    step_diff.y = 12.0;
        
    apply_chord_affine(&start_diff);
    apply_chord_affine(&step_diff);
    apply_chord_affine(&max_diff);
    
    max_diff.x = 4*step_diff.x + start_diff.x + 0.4; //???
    max_diff.y = 4*step_diff.y + start_diff.y + 0.4; //???
    
    if (chords_above_staff) start.y = start.y - 36.0;
        
    for (x = start.x + start_diff.x; x <= start.x + max_diff.x; x = x + step_diff.x)    {
        for (y = start.y + start_diff.y; y <= start.y + max_diff.y; y = y + step_diff.y)    {
            ul_corner.x = x;
            ul_corner.y = y;
            lr_corner.x = x + step_diff.x;
            lr_corner.y = y + step_diff.y;
            
            translate_y(&ul_corner);
            translate_y(&lr_corner);
                    
            draw_rect(ctx, &ul_corner, &lr_corner, &black);
        }
     }
    set_linewidth(ctx, 0.0);
}    
    
static void 
print_render_chord_name(GnometabPrintJobInfo *pji, double x, double y, gchar *name)
{
    Point pos, diff;
    GnomeFont *gfont;
    
    diff.y = 12.0;
    
    apply_chord_affine(&diff);
    
    if (chords_above_staff) {
        y = y - 36.0;
        gfont = gnome_font_from_string(pji->tab_font_tiny);
        diff.x = (46.5 - gnome_font_get_width_utf8(gfont, name))/2;
    }
    else {
        gfont = gnome_font_from_string(pji->tab_font);
        diff.x = (86.11 - gnome_font_get_width_utf8(gfont, name))/2;
    }
    
    
    
    pos.x = x + diff.x;
    pos.y = y + diff.y;
    
    translate_y(&pos);
        
    gnome_print_setfont(pji->print_ctx, gfont);
    
    if (name != NULL)    {
        draw_string(pji->print_ctx, name, &pos, 0, &black);
    }
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
}

static void 
print_render_chord_text(GnometabPrintJobInfo *pji, double x, double y, 
                                                double grid_x, double grid_y,
                                                gchar *text)
{
    Point pos, diff;
    GnomeFont *gfont;
    
    diff.x = grid_x;
    diff.y = grid_y;
    apply_chord_affine(&diff);
    
    if (chords_above_staff) y = y - 36.0;
        
    pos.x = x + diff.x;
    pos.y = y + diff.y;
    
    if (grid_x >= 84.0)    {
        if (chords_above_staff) {
            gfont = gnome_font_from_string(pji->tab_font_tiny);
        }
        else {
            gfont = gnome_font_from_string(pji->tab_font_small);
        }
    }
    else    {
        if (chords_above_staff) {
            gfont = gnome_font_from_string(pji->tab_font_tiny);
        } else {
            gfont = gnome_font_from_string(pji->tab_font);
        }        
    }
    
    gnome_print_setfont(pji->print_ctx, gfont);
        
    translate_y(&pos);
        
    if (strlen(text) >= 1)    {
        draw_string(pji->print_ctx, text, &pos, 0, &grey);
    }
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);

}

static void 
print_render_chord_bar(GnomePrintContext *ctx, double x, double y, 
                                double grid_x, double grid_y, int positions)
{
    double total_length;
    Point p1, p2, p3, diff, pos_diff, y_offset;
    
    diff.x = grid_x;
    diff.y = grid_y;
    pos_diff.x = 12.0;
    pos_diff.y = 7.0;
    y_offset.x = 0;
    y_offset.y = 29.0;
        
    apply_chord_affine(&diff);
    apply_chord_affine(&pos_diff);
    apply_chord_affine(&y_offset);
    
    if (chords_above_staff) y = y - 36.0;
        
    p1.x = x + diff.x;
    p1.y = y + diff.y - y_offset.y;
    
    total_length = pos_diff.x*positions;
    
    p2.x = p1.x + total_length/2.0;
    p2.y = p1.y - pos_diff.y;
    p3.x = p1.x + total_length;
    p3.y = p1.y;
    
    translate_y(&p1);
    translate_y(&p2);
    translate_y(&p3);
    
    
    set_linewidth(ctx, 1.0);
    draw_arc(ctx, &p1, &p2, &p3, &black);
    set_linewidth(ctx, 0.0);
    
}

static void 
print_render_translate_chord(xmlDocPtr tmp_chrd_doc, GnometabPrintJobInfo *pji)
{
    gchar *char_x, *char_y, *char_text, *char_int, *tmp;
    double grid_x, grid_y;
    Point orig_coords;
    xmlNodePtr node;
    
    char_x = get_prop(tmp_chrd_doc->xmlRootNode, "x_create");
    char_y = get_prop(tmp_chrd_doc->xmlRootNode, "y_create");
    
    orig_coords.x = atof(char_x);
    orig_coords.y = atof(char_y);
    
    g_free(char_x);
    g_free(char_y);
    
    find_staff(orig_coords.y);
    
    print_render_chord_grid(pji->print_ctx, orig_coords);
    
    for (node = tmp_chrd_doc->xmlRootNode->children; node != NULL; node = node->next)    {
        tmp = get_prop(node, "active");
        if (!tmp)    {
            if (g_ascii_strcasecmp(node->name, "chord_text") == 0)    {
                char_x = get_prop(node, "x_create");
                char_y = get_prop(node, "y_create");
                grid_x = atof(char_x);
                grid_y = atof(char_y) + 24.0; //????
                g_free(char_x);
                g_free(char_y);
                char_text = get_prop(node, "text");
                
                print_render_chord_text(pji, orig_coords.x, 
                                            orig_coords.y, 
                                            grid_x, 
                                            grid_y,
                                            char_text);
                g_free(char_text);
            }
            if (g_ascii_strcasecmp(node->name, "chord_bar") == 0)    {
                char_x = get_prop(node, "x_create");
                char_y = get_prop(node, "y_create");
                grid_x = atof(char_x);
                grid_y = atof(char_y) + 24.0; 
                g_free(char_x);
                g_free(char_y);
                char_int = get_prop(node, "positions");
                print_render_chord_bar(pji->print_ctx, orig_coords.x, 
                                            orig_coords.y, 
                                            grid_x, grid_y, 
                                            atoi(char_int));
                g_free(char_int);
                
            }
            if (g_ascii_strcasecmp(node->name, "chord_name") == 0)    {
                char_text = get_prop(node, "name_text");
                print_render_chord_name(pji, orig_coords.x, 
                                            orig_coords.y, 
                                            char_text);
                g_free(char_text);
            }
        }
        g_free(tmp);
    }
}

static void 
print_render_rhythm_vert_line(GnomePrintContext *ctx, xmlNodePtr staff_node, 
                                                double start_x, double start_y)
{
    gint num_texts;
    gint texts_index;
    double end_y;
    Point p1, p2;
    
    find_staff(start_y);
    
    num_texts = find_rhythm_num_segs(staff_node, start_x);
    
    if (num_texts != 0)    {
        for (texts_index = 0; texts_index < num_texts; texts_index++)    {
            
            end_y = find_rhythm_y2(staff_node, start_x, num_texts, texts_index);
            if (end_y != 0)    {
                p1.x = start_x;
                p1.y = start_y - 2;
                p2.x = start_x;
                p2.y = end_y - 2;
                    
                translate_y(&p1);
                translate_y(&p2);
                draw_line(ctx, &p1, &p2, &black);
                
                start_y = end_y - 12.0;
            }
        }
    }
}

static void 
print_render_rhythm_horiz_line(GnomePrintContext *ctx, 
                                    double start_x, double start_y,
                                    gboolean complete, gboolean flat, 
                                    gint direction)
{
    double end_x, end_y;
    Point p1, p2;
    
    switch (direction) {
        case -1:
            end_x = start_x - 4.0;
            end_y = start_y;
            break;
        
        default:
        
            if (complete == TRUE)    {
                end_x = start_x + 17.0;
                end_y = start_y;
            }
            else    {
                if (flat) {
                    end_x = start_x + 4.0;
                    end_y = start_y;
                }
                else {
                    end_x = start_x + 4.0;
                    end_y = start_y - 4.0;
                }
            }
            break;
    }
    
    p1.x = start_x;
    p1.y = start_y - 2;
    p2.x = end_x;
    p2.y = end_y - 2;
    
    translate_y(&p1);
    translate_y(&p2);
    set_linewidth(ctx, 1.0);
    draw_line(ctx, &p1, &p2, &black);
    set_linewidth(ctx, 0.0);
    
}

static void 
print_render_rhythm_dot(GnomePrintContext *ctx, double start_x, double start_y)
{
    double end_x, end_y;
    Point p1, p2;
    
    start_x = start_x + 2.0;
    end_x = start_x + 1.0;
    end_y = start_y;
 
    p1.x = start_x;
    p1.y = start_y;
    p2.x = end_x;
    p2.y = end_y;
    
    translate_y(&p1);
    translate_y(&p2);
    set_linewidth(ctx, 1.0);
    draw_line(ctx, &p1, &p2, &black);
    set_linewidth(ctx, 0.0);
    
}

static void 
print_render_tab_rhythm(GnomePrintContext *ctx, Tab_Rhythm rhythm,  
                        double start_x, double start_y, xmlNodePtr staff_node)
{
    gdouble dot_y;
    gboolean flat = FALSE;
    
    find_staff(start_y);
    
    switch (current_staff)    {
        case 1:
            start_y = 377.0;
            break;
        case 2:
            start_y = 517.0;
            break;
        case 3:
            start_y = 657.0;
            break;
        case 4:
            start_y = 797.0;

            break;
        case 5:
            start_y = 937.0;
            break;
        default:
            start_y = 237.0;
            break;
    }
    
    dot_y = start_y;
    
    if (rhythm.pos1.active == TRUE)    {
        if (rhythm.pos1.value >= 2) {
            print_render_rhythm_vert_line(ctx, staff_node, start_x, start_y);
        }
        
        if (rhythm.pos1.value > 4)    {
            if (rhythm.pos2.value > 4 && rhythm.pos2.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x, start_y, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                print_render_rhythm_horiz_line(ctx, start_x, start_y, FALSE, FALSE, 1);
            }
        }
        if (rhythm.pos1.value > 8)    {
            dot_y -= 3.0;
            
            if (rhythm.pos2.value > 8 && rhythm.pos2.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x, 
                                                start_y - 3.0, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (flat) {
                    print_render_rhythm_horiz_line(ctx, start_x, 
                                                start_y - 3.0, FALSE, TRUE, 1);
                }
                else {
                    print_render_rhythm_horiz_line(ctx, start_x,
                                                start_y - 3.0, FALSE, FALSE, 1);
                }
            }
        }
        if (rhythm.pos1.value > 16)    {
            dot_y -= 3.0;
            
            if (rhythm.pos2.value > 16 && rhythm.pos2.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x, 
                                                start_y - 6.0, TRUE, TRUE, 1);
                flat = TRUE;
                  
            }
            else    {
                if (flat) {
                    print_render_rhythm_horiz_line(ctx, start_x, 
                                                start_y - 6.0, FALSE, TRUE, 1);
                }
                else {
                    print_render_rhythm_horiz_line(ctx, start_x, 
                                                start_y - 6.0, FALSE, FALSE, 1);
                }
            }
        }
        if (rhythm.pos1.dotted == TRUE)    {
            if (!flat) dot_y -= 3.0;
            print_render_rhythm_dot(ctx, start_x, dot_y - 4.0);
        }
    }
    
    if (rhythm.pos2.active == TRUE)    {
        dot_y = start_y;
        flat = FALSE;
        
        if (rhythm.pos2.value >= 2) {
            print_render_rhythm_vert_line(ctx, staff_node, start_x + 17.0, start_y);
        }
        
        if (rhythm.pos2.value > 4)    {
            if (rhythm.pos3.value > 4 && rhythm.pos3.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos1.active == FALSE || rhythm.pos1.value <= 4)    {
                      print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y, FALSE, FALSE, 1);
                }
            }
        }
        if (rhythm.pos2.value > 8)    {
            dot_y -= 3.0;
            
            if (rhythm.pos3.value > 8 && rhythm.pos3.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 17.0,
                                                    start_y - 3.0, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos1.active == FALSE || rhythm.pos1.value <= 4)    {
                    if (flat) {
                        print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 3.0, FALSE, TRUE, 1);
                    }
                    else {
                        print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 3.0, FALSE, FALSE, 1);
                    }
                }
                else {
                    if (rhythm.pos1.value <= 8) {
                        print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 3.0, FALSE, TRUE, -1);
                    }
                }
            }
        }
        if (rhythm.pos2.value > 16)    {
            dot_y -= 3.0;
            
            if (rhythm.pos3.value > 16 && rhythm.pos3.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 6.0, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos1.active == FALSE || rhythm.pos1.value <= 4)    {
                    if (flat) {
                        print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 6.0, FALSE, TRUE, 1);
                    }
                    else {
                        print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 6.0, FALSE, FALSE, 1);
                    }
                }
                else {
                    if (rhythm.pos1.value <= 16) {
                        if (rhythm.pos3.value <= 4 ||
                            rhythm.pos3.active == FALSE) {
                            print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 6.0, FALSE, TRUE, -1);  
                        }
                        else {
                            print_render_rhythm_horiz_line(ctx, start_x + 17.0, 
                                                    start_y - 6.0, FALSE, TRUE, 1);
                        }
                    }
                }
            }
        }
        if (rhythm.pos2.dotted == TRUE)    {
            if (!flat) dot_y -= 3.0;
            print_render_rhythm_dot(ctx, start_x + 17.0, dot_y - 4.0);
        }
    }
    
    if (rhythm.pos3.active == TRUE)    {
        dot_y = start_y;
        flat = FALSE;
        
        if (rhythm.pos3.value >= 2) {
            print_render_rhythm_vert_line(ctx, staff_node, start_x + 34.0, start_y);
        }
        
        if (rhythm.pos3.value > 4)    {
            if (rhythm.pos4.value > 4 && rhythm.pos4.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 34.0,
                                                    start_y, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos2.active == FALSE || rhythm.pos2.value <= 4)    {
                      print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y, FALSE, FALSE, 1);
                }
            }
        }
        if (rhythm.pos3.value > 8)    {
            dot_y -= 3.0;
            
            if (rhythm.pos4.value > 8 && rhythm.pos4.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 3.0, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos2.active == FALSE || rhythm.pos2.value <= 4)    {
                    if (flat) {
                        print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 3.0, FALSE, TRUE, 1);
                    }
                    else {
                        print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 3.0, FALSE, FALSE, 1);
                    }
                }
                else {
                    if (rhythm.pos2.value <= 8) {
                        print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 3.0, FALSE, TRUE, -1);
                    }
                }
            }
        }
        if (rhythm.pos3.value > 16)    {
            dot_y -= 3.0;
            
            if (rhythm.pos4.value > 16 && rhythm.pos4.active == TRUE)    {
                print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 6.0, TRUE, TRUE, 1);
                flat = TRUE;
            }
            else    {
                if (rhythm.pos2.active == FALSE || rhythm.pos2.value <= 4)    {
                    if (flat) {
                        print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 6.0, FALSE, TRUE, 1);
                    }
                    else {
                        print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 6.0, FALSE, FALSE, 1);
                    }
                }
                else {
                    if (rhythm.pos2.value <= 16) {
                        if (rhythm.pos4.value <= 4 ||
                            rhythm.pos4.active == FALSE) {
                                print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 6.0, FALSE, TRUE, -1);
                        }
                        else {
                            print_render_rhythm_horiz_line(ctx, start_x + 34.0, 
                                                    start_y - 6.0, FALSE, TRUE, 1);
                        }
                    }
                }
            }
        }
        if (rhythm.pos3.dotted == TRUE)    {
            if (!flat) dot_y -= 3.0;
            print_render_rhythm_dot(ctx, start_x + 34.0, dot_y - 4.0);
        }
    }
    
    if (rhythm.pos4.active == TRUE)    {
        dot_y = start_y;
        
        if (rhythm.pos4.value >= 2) {
            print_render_rhythm_vert_line(ctx, staff_node, start_x + 51.0, start_y);
        }
        
        if (rhythm.pos4.value > 4) {
            if (rhythm.pos3.value <= 4 || rhythm.pos3.active == FALSE) {
                print_render_rhythm_horiz_line(ctx, start_x + 51.0, start_y,
                                                FALSE, FALSE, 1);
            }
        }
        
        if (rhythm.pos4.value > 8) {
            if (rhythm.pos3.value <= 4 || rhythm.pos3.active == FALSE) {
                dot_y -= 3.0;
                print_render_rhythm_horiz_line(ctx, start_x + 51.0, start_y - 3.0,
                                                FALSE, FALSE, 1);
            }
            else {
                if (rhythm.pos3.value <= 8) {
                    print_render_rhythm_horiz_line(ctx, start_x + 51.0, start_y - 3.0,
                                                FALSE, TRUE, -1);
                }
            }
        }
        
        if (rhythm.pos4.value > 16) {
            if (rhythm.pos3.value <= 4 || rhythm.pos3.value == FALSE) {
                dot_y -= 3.0;
                print_render_rhythm_horiz_line(ctx, start_x + 51.0, start_y - 6.0,
                                                FALSE, FALSE, 1);
            }
            else {
                if (rhythm.pos3.value <= 16) {
                    print_render_rhythm_horiz_line(ctx, start_x + 51.0, start_y - 6.0,
                                                FALSE, TRUE, -1);
                }
            }
        }
        
        if (rhythm.pos4.dotted == TRUE)    {
            if (!flat) dot_y -= 3.0;
            print_render_rhythm_dot(ctx, start_x + 51.0, dot_y - 4.0);
        }
    }
}

static void 
print_render_doc_props(GnometabPrintJobInfo *pji, gchar *title, 
                                gchar *artist, gchar *tuning, gchar *pagenum)
{
    Point p1;
    GnomeFont *gfont;
    
    gfont = gnome_font_from_string(pji->tab_font_large);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    if (title) {
        p1.x = 50.0;
        p1.y = 60.0;
        translate_y(&p1);
        draw_string(pji->print_ctx, title, &p1, 0, &black);
    }
    
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
    
    if (artist) {
        p1.y = 90.0;
        translate_y(&p1);
        draw_string(pji->print_ctx, artist, &p1, 0, &black);
    }
    
    if (tuning) {
        p1.x = 750.0 - gnome_font_get_width_utf8(gfont, tuning);
        p1.y = 90.0;
        translate_y(&p1);
        draw_string(pji->print_ctx, tuning, &p1, 0, &black);
    }
    
    if (atoi(pagenum) > 1) {
        p1.x = 750.0 - gnome_font_get_width_utf8(gfont, pagenum);
        p1.y = 60.0;
        translate_y(&p1);
        draw_string(pji->print_ctx, pagenum, &p1, 0, &black);
    }
    
}    
    
static void 
print_render_staff(GnomePrintContext *ctx)
{
    double num_staffs;
    double num_strings;
    Point ul_corner;
    Point lr_corner;
    
    set_linewidth(ctx, 0.0);
    set_linejoin(ctx, 0.0);
    set_linecaps(ctx, 0.0);
    
    for (num_staffs = 160.0; num_staffs < 1000.0; 
                    num_staffs = num_staffs + 140.0)    {
        
        for (num_strings = 0.0; num_strings < 60.0; 
                    num_strings = num_strings + 12.0)    {
            ul_corner.x = 50.0;
            ul_corner.y = (num_strings + num_staffs);
            lr_corner.x = 750.0;
            lr_corner.y = (num_strings + num_staffs + 12.0);
    
            translate_y(&ul_corner);
            translate_y(&lr_corner);
            draw_rect(ctx, &ul_corner, &lr_corner, &black);
         }
        
      }
}

static void 
print_render_staff_objects(GnometabPrintJobInfo *pji, xmlNodePtr node)
{
    xmlNodePtr object_node;
    xmlNodePtr obj_sub_node;
    xmlDocPtr  tmp_chrd_doc;
    double x;
    double y;
    Tab_Rhythm rhythm;
    gchar *is_active;
    gchar *tmp, *char_x, *char_y, *active, *value, *dotted;
    
    for (object_node = node->children; object_node != NULL; 
                            object_node = object_node->next)    {
        if (xmlIsBlankNode(object_node) == 1) continue;
        is_active = get_prop(object_node, "active");
        if (!is_active)    {
            /* fprintf(stderr, "Object node name: %s\n", object_node->name); */
        
            if (g_ascii_strcasecmp(object_node->name, "tab_text") == 0)    {
                print_render_tab_text(pji, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_bar") == 0)    {
                print_render_tab_bar(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_slur") == 0)    {
                print_render_tab_slur(pji, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_bend") == 0)    {
                print_render_tab_bend(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_measure") == 0)    {
                print_render_tab_measure(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_legato") == 0)    {
                print_render_tab_legato(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_strum") == 0)    {    
                print_render_tab_strum(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_chord") == 0)    {
                tmp_chrd_doc = xmlNewDoc("1.0");
                tmp_chrd_doc->xmlRootNode = xmlCopyNode(object_node, TRUE);
                print_render_translate_chord(tmp_chrd_doc, pji);
                xmlFreeDoc(tmp_chrd_doc);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_timesig") == 0)    {
                print_render_tab_timesig(pji, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_repeat") == 0)    {
                print_render_tab_repeat(pji->print_ctx, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_comment") == 0)    {
                print_render_tab_comment(pji, object_node);
            }
            if (g_ascii_strcasecmp(object_node->name, "tab_rest") == 0)    {
                print_render_tab_rest(pji->print_ctx, object_node);
            }
            
        }
        g_free(is_active);
        
    }
    /* Now cycle through again and render the rhythm */
    for (object_node = node->children; object_node != NULL; 
                            object_node = object_node->next)    {
        if (xmlIsBlankNode(object_node) == 1) continue;                        
        tmp = get_prop(object_node, "active");
        
        if (!tmp)    {
            char_x = get_prop(object_node, "x_create");
            char_y = get_prop(object_node, "y_create");
            x = atof(char_x);
            y = atof(char_y);
            g_free(char_x);
            g_free(char_y);
            if (g_ascii_strcasecmp(object_node->name, "tab_rhythm") == 0)    {
                
                gint rhythm_obj_cntr = 0;
                
                // rhythm.start_x = x;
                // rhythm.start_y = y;
                for (obj_sub_node = object_node->children; 
                     obj_sub_node != NULL;
                     obj_sub_node = obj_sub_node->next)    {
                         
                             if (xmlIsBlankNode(obj_sub_node) == 1) continue;
                                 
                             rhythm_obj_cntr++;
                             
                             switch (rhythm_obj_cntr)    {
                                 case 1:
                                     
                    
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos1.active = atoi(active);
                                    rhythm.pos1.value = atoi(value);
                                    rhythm.pos1.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 
                                 case 2:
                                     
                        
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos2.active = atoi(active);
                                    rhythm.pos2.value = atoi(value);
                                    rhythm.pos2.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 case 3:
                                     
                
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos3.active = atoi(active);
                                    rhythm.pos3.value = atoi(value);
                                    rhythm.pos3.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 case 4:
                                     
                
                                    active = get_prop(obj_sub_node, "active");
                                    value = get_prop(obj_sub_node, "value");
                                    dotted = get_prop(obj_sub_node, "dotted");
                                    rhythm.pos4.active = atoi(active);
                                    rhythm.pos4.value = atoi(value);
                                    rhythm.pos4.dotted = atoi(dotted);
                                    g_free(active);
                                    g_free(value);
                                    g_free(dotted);
                                    break;
                                 default:
                                    break;
                             }
                        }
                
                print_render_tab_rhythm(pji->print_ctx, rhythm, x, y, node);
            }
        }
        g_free(tmp);
                
    }
}

static void 
print_render_page(GnometabPrintJobInfo *pji, xmlNodePtr page_node)
{
    
    xmlNodePtr staff_tmp_node = NULL;
        
    for (staff_tmp_node = page_node->children; 
        staff_tmp_node != NULL; 
        staff_tmp_node = staff_tmp_node->next)    {
        if (xmlIsBlankNode(staff_tmp_node) == 1) continue;    
        print_render_staff_objects(pji, staff_tmp_node);
    }
}

static guint
print_page(GnometabPrintJobInfo *pji, gint pagenum, xmlNodePtr page_node, gchar *title,
                                            gchar *artist, gchar *tuning)
{
    GnomeFont *gfont;
    gchar pg_title[4];
    gdouble width, height, holder;
    const gchar *orient;
    gboolean result;
    
    g_snprintf(pg_title, 3, "%i", pagenum);
    
    gnome_print_beginpage(pji->print_ctx, pg_title);        
    
    gnome_print_gsave(pji->print_ctx);

    /* get info about the paper size and scale accordingly */
    
    result = gnome_print_job_get_page_size_from_config(pji->config, &width, &height);
    
    if (!result) {width = 612.0; height = 792.0;}
   
    orient = gnome_print_config_get(pji->config, GNOME_PRINT_KEY_PAGE_ORIENTATION);
    
    if (g_strcasecmp(orient, "R90") == 0 || g_strcasecmp(orient, "R270") == 0) {
        holder = height;
        height = width;
        width = holder;
    }
      
    /* fprintf(stderr, "dimensions: %f, %f\n", width, height);
    fprintf(stderr, "orientation: %s\n", orient); */
    
    gnome_print_scale(pji->print_ctx, .001225*width, .000970*height);
    
    // gnome_print_scale(pji->print_ctx, 0.750, 0.768);
    /* gnome_print_translate(ctx, 1.0, -1.0); */

    /* render the region */
 
    gfont = gnome_font_from_string(pji->tab_font);
    gnome_print_setfont(pji->print_ctx, gfont);
    print_render_doc_props(pji, title, artist, tuning, pg_title);
    print_render_staff(pji->print_ctx);
    print_render_page(pji, page_node);
        
    gnome_print_grestore(pji->print_ctx);

    /* print the page */
    gnome_print_showpage(pji->print_ctx);

    return (0);
}

static void
paginate_loaded_doc(GnometabPrintJobInfo *pji)
{
    xmlNodePtr page_node;
    gchar *tmp = NULL;
    gchar *tmp2 = NULL;
    gchar *tmp3 = NULL;
    gchar *tmp4 = NULL;
    
    /* NEED TO FIND DOC PROPERTIES */
    for (page_node = pji->doc->xmlRootNode->children; page_node != NULL; 
                                        page_node = page_node->next)    {
        if (xmlIsBlankNode(page_node) == 1) continue;
        if (g_ascii_strcasecmp(page_node->name, "PROPS") == 0)    {
            tmp = get_prop(page_node, "title");
            tmp2 = get_prop(page_node, "artist");
            tmp3 = get_prop(page_node, "tuning");
        }
    }
    
    /* NEED TO CYCLE THROUGH NODES OF loaded_doc */
    for (page_node = pji->doc->xmlRootNode->children; page_node != NULL; 
                                        page_node = page_node->next)    {
        if (xmlIsBlankNode(page_node) == 1) continue;
            
        if (g_ascii_strcasecmp(page_node->name, "PROPS") != 0)    {
            if (count_page_objects(page_node) > 0) {
                tmp4 = get_prop(page_node, "page");
                // fprintf(stderr, "Printing page: %i\n", atoi(tmp4));
                pji->page_num = atoi(tmp4);
                free(tmp4);
                
                print_page(pji, pji->page_num, page_node, tmp, tmp2, tmp3);
            }
        }
    }
    gnome_print_context_close(pji->print_ctx);
    
    // gtk_object_unref(GTK_OBJECT(ctx));
    g_free(tmp);
    g_free(tmp2);
    g_free(tmp3);
    
}

void
tab_canvas_print(GtabDoc *doc, gboolean preview)
{
    GtkWidget *dialog = NULL;
    gint btn = FALSE;
    GnometabPrintJobInfo *printjob;

    printjob = gnometab_print_job_info_new(doc->loaded_doc);
    
    printjob->tab_font = g_strdup(doc->parent->tab_font);
    printjob->tab_font_large = g_strdup(doc->parent->tab_font_large);
    printjob->tab_font_small = g_strdup(doc->parent->tab_font_small);
    printjob->tab_font_tiny = g_strdup(doc->parent->tab_font_tiny);
    
    if (printjob == NULL) return;
     
    if (! preview) {
        dialog = g_object_new (GNOME_TYPE_PRINT_DIALOG, "print_config", printjob->config, NULL);
        
        gnome_print_dialog_construct (GNOME_PRINT_DIALOG (dialog), 
                          _("Print"),
                              GNOME_PRINT_DIALOG_COPIES);
        
        gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
        btn = gtk_dialog_run(GTK_DIALOG(dialog));
        
        if (btn < 0)    {
            gtk_widget_destroy(dialog);
            return;
        }
    }
    else {
        printjob->preview = TRUE;
    }
    
    g_return_if_fail (printjob->config != NULL);

    printjob->print_job = gnome_print_job_new (printjob->config);
    g_return_if_fail (printjob->print_job != NULL);
   
    printjob->print_ctx = gnome_print_job_get_context (printjob->print_job);
    g_return_if_fail (printjob->print_ctx != NULL);

    g_return_if_fail (printjob->print_ctx != NULL);
    
    paginate_loaded_doc(printjob);
    
    if (btn == GNOME_PRINT_DIALOG_RESPONSE_PREVIEW) printjob->preview = TRUE;
      
    gnome_print_job_close (printjob->print_job);

    if (printjob->preview) {
        print_preview(printjob);
    } 
    else {
        gnome_print_job_print (printjob->print_job);
    }
    
    if (GTK_IS_WIDGET(dialog)) gtk_widget_destroy(dialog);        
    
    gnometab_print_job_info_destroy(printjob);
    
}
