#include <stdio.h>
#include <sp/spBaseLib.h>
#include <sp/spComponentLib.h>
#include <sp/spComponentMain.h>

static spBool editable = SP_TRUE;
static spComponent text_area = NULL;

static void textCB(spComponent component, void *data)
{
    char *string;

    if ((string = xspGetTextString(component)) != NULL) {
        fprintf(stderr, "length = %d, %s\n", (int)strlen(string), string);
        printf("%s\n", string);
        xspFree(string);
    }
    
    return;
}

static void checkCB(spComponent component, void *data)
{
    if (spGetToggleState(component, &editable) == SP_TRUE) {
        spSetParams(text_area,
                    SppEditable, editable,
                    NULL);
    }

    return;
}

static void forwardCB(spComponent component, void *data)
{
    long pos;
    long incr = (long)data;

    if (spGetTextPosition(text_area, &pos) == SP_TRUE) {
        spSetTextPosition(text_area, pos + incr);
    }
    
    return;
}

static void selectionCB(spComponent component, void *data)
{
    long start = 0, end = 0;
    long incr = (long)data;

    fprintf(stderr, "selectionCB: incr = %ld\n", incr);
    
    if (spGetTextSelection(text_area, &start, &end) == SP_FALSE) {
        spDisplayMessage(component, NULL, "No selection!");
    } else {
        end += incr;
        if (end >= start) {
            spSetTextSelection(text_area, start, end);
        }
    }
    
    return;
}

static void selectCB(spComponent component, void *data)
{
    long start, end;
    
    if (spGetTextSelection(text_area, &start, &end) == SP_FALSE) {
        spSetTextSelection(text_area, 0, -1);
    } else {
        fprintf(stderr, "start = %ld, end = %ld\n", start, end);
        spSetTextSelection(text_area, -1, 0);

        /* go to end */
        spSetTextPosition(text_area, -1);
    }
    return;
}

static void clipboardCB(spComponent component, void *data)
{
    const char *name;

    name = spGetName(component);

    if (streq(name, "Cut")) {
        fprintf(stderr, "cut\n");
        spCutText(text_area);
    } else if (streq(name, "Copy")) {
        fprintf(stderr, "copy\n");
        spCopyText(text_area);
    } else if (streq(name, "Paste")) {
        fprintf(stderr, "paste\n");
        spPasteText(text_area);
    } else if (streq(name, "Clear")) {
        fprintf(stderr, "clear\n");
        spClearText(text_area);
    }
    
    return;
}

static void chooseFontCB(spComponent component, void *data)
{
    char *orig_font_name = NULL;
    char *font_name;

    spGetParams(text_area,
                SppFontName, &orig_font_name,
                NULL);
    if (orig_font_name != NULL) {
        printf("orig_font_name = %s\n", orig_font_name);
    }

    if ((font_name = xspChooseFont(component, NULL,
                                   SppInitialFont, orig_font_name,
                                   NULL)) != NULL) {
        spSetParams(text_area,
                    SppFontName, font_name,
                    NULL);
        xspFree(font_name);
    }
    
    return;
}

static void setTextCB(spComponent component, void *data)
{
    spSetTextString(text_area, "Set text string!\nThis is Test.");
    return;
}

int spMain(int argc, char *argv[])
{
    spTopLevel toplevel;
    spComponent frame;
    spComponent menu_bar;
    spComponent menu;

    /*spSetDebugLevel(10);*/
    
    /* initialize toolkit */
    toplevel = spInitialize(&argc, &argv, NULL);
    
    /* create main window */
    frame = spCreateMainFrame("Text Area", NULL);

    /* create menu */
    menu_bar = spCreateMenuBar(frame, "menuBar", NULL);
    menu = spCreatePulldownMenu(menu_bar, "File", NULL);
    spAddMenuItem(menu, SP_QUIT_MENU_ITEM_NAME,
                  SppCallbackFunc, spQuitCB,
                  NULL);
    menu = spCreatePulldownMenu(menu_bar, "Edit", NULL);
    spAddMenuItem(menu, "Cut",
                  SppCallbackFunc, clipboardCB,
                  SppShortcut, "A-x",
                  NULL);
    spAddMenuItem(menu, "Copy",
                  SppCallbackFunc, clipboardCB,
                  SppShortcut, "A-c",
                  NULL);
    spAddMenuItem(menu, "Paste",
                  SppCallbackFunc, clipboardCB,
                  SppShortcut, "A-v",
                  NULL);
    spAddMenuItem(menu, "Clear",
                  SppCallbackFunc, clipboardCB,
                  NULL);
    spAddMenuSeparator(menu, "Separator", NULL);
    spAddMenuItem(menu, "Forward",
                  SppCallbackFunc, forwardCB,
                  SppCallbackData, (void *)1,
                  SppShortcut, "C-f",
                  NULL);
    spAddMenuItem(menu, "Backward",
                  SppCallbackFunc, forwardCB,
                  SppCallbackData, (void *)-1,
                  SppShortcut, "C-b",
                  NULL);
    spAddMenuItem(menu, "Increase Selection",
                  SppCallbackFunc, selectionCB,
                  SppCallbackData, (void *)1,
                  NULL);
    spAddMenuItem(menu, "Decrease Selection",
                  SppCallbackFunc, selectionCB,
                  SppCallbackData, (void *)-1,
                  NULL);
    spAddMenuItem(menu, "Select All/Deselect",
                  SppCallbackFunc, selectCB,
                  SppShortcut, "A-a",
                  NULL);
    spAddMenuSeparator(menu, "Separator2", NULL);
    spAddMenuItem(menu, "Choose Font...",
                  SppCallbackFunc, chooseFontCB,
                  SppShortcut, "A-t",
                  NULL);
    spAddMenuSeparator(menu, "Separator3", NULL);
    spAddMenuItem(menu, "Test Set Text",
                  SppCallbackFunc, setTextCB,
                  NULL);
    
    /* create check box */
    spCreateCheckBox(frame, "Editable",
                     SppSet, editable,
                     SppCallbackFunc, checkCB,
                     NULL);

    /* create text area */
    text_area = spCreateTextArea(frame, "text",
                                 SppCallbackFunc, textCB,
                                 SppTextString, "Hello!\nThis is text area.\n",
                                 SppFontName, "-*-*-medium-r-normal--24-*-*-*-*-*-*-*",
                                 NULL);

    /* popup window */
    spPopupWindow(frame);
    
    /* main loop */
    return spMainLoop(toplevel);
}
