/**********
 * Copyright (c) 2004 Greg Parker.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY GREG PARKER ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 **********/

// fixme allow subsystems to register with Prefs for change notices 
// (rather than hardcoding those here)

#include "includes.h"
#include "formutils.h"
#include "data/prefs.h"
#include "ssh/ssh.h"
#include "rsrc/rsrc.h"
#include "forms/CollapseUtils.h"

#include "displayprefsform.h"


extern struct ssh_session_t *ss;

static void LoadDisplayPrefsForm(void) FORMS_SEGMENT;
static void SaveDisplayPrefsForm(void) FORMS_SEGMENT;
static Boolean SampleTextEventHandler(struct FormGadgetTypeInCallback *gadget, 
                                      UInt16 cmd, void *paramP) FORMS_SEGMENT;
static void InvalidateSampleText(void) FORMS_SEGMENT;
static void DrawSampleText(RectangleType bounds) FORMS_SEGMENT;

static void LoadDisplayPrefsForm(void)
{
    uint32_t value;
    char *str;

    // font
    value = PrefsGetInt(prefTerminalFont, font4x6);
    PrvSetControlValue(DisplayPrefsFormSmallFontCheckboxID, 
                       value == font4x6 ? 1 : 0);
    PrvSetControlValue(DisplayPrefsFormLargeFontCheckboxID, 
                       value == font6x10 ? 1 : 0);
    // else some future font size - ignore

    // colors
    value = PrefsGetInt(prefTerminalForeColor, blackColor);
    if (value < 8) {
        ListPtr lst = PrvGetObjectByID(DisplayPrefsFormForeColorListID);
        LstSetSelection(lst, value);
        PrvSetControlLabel(DisplayPrefsFormForeColorTriggerID, 
                           LstGetSelectionText(lst, value));
    }
    value = PrefsGetInt(prefTerminalBackColor, whiteColor);
    if (value < 8) {
        ListPtr lst = PrvGetObjectByID(DisplayPrefsFormBackColorListID);
        LstSetSelection(lst, value);
        PrvSetControlLabel(DisplayPrefsFormBackColorTriggerID, 
                           LstGetSelectionText(lst, value));
    }

    // scrollback lines
    value = PrefsGetInt(prefScrollbackLines, defaultScrollbackLines);
    if (value > maxScrollbackLines) value = defaultScrollbackLines;
    {
        char buf[5];
        snprintf(buf, sizeof(buf), "%lu", value);
        PrvSetFieldToValueByID(DisplayPrefsFormScrollbackFieldID, buf);
    }

    // scroll to bottom
    value = PrefsGetInt(prefScrollDownOnActivity, defaultScrollDownOnActivity);
    PrvSetControlValue(DisplayPrefsFormActivityCheckboxID, value ? 1 : 0);
    value = PrefsGetInt(prefScrollDownOnTyping, defaultScrollDownOnTyping);
    PrvSetControlValue(DisplayPrefsFormTypingCheckboxID, value ? 1 : 0);

    // bell
    value = PrefsGetInt(prefBellBeep, defaultBellBeep);
    PrvSetControlValue(DisplayPrefsFormBeepCheckboxID, value ? 1 : 0);
    value = PrefsGetInt(prefBellFlash, defaultBellFlash);
    PrvSetControlValue(DisplayPrefsFormFlashCheckboxID, value ? 1 : 0);
}


static void SaveDisplayPrefsForm(void)
{
    uint32_t value;
    int selection;
    Boolean sshChanged = false;

    // font
    value = PrefsGetInt(prefTerminalFont, font4x6);
    if (PrvGetControlValue(DisplayPrefsFormSmallFontCheckboxID) && value != font4x6) {
        PrefsPutInt(prefTerminalFont, font4x6);
        sshChanged = true;
    } else if (PrvGetControlValue(DisplayPrefsFormLargeFontCheckboxID) && value != font6x10) {
        PrefsPutInt(prefTerminalFont, font6x10);
        sshChanged = true;
    }

    // color
    value = PrefsGetInt(prefTerminalForeColor, defaultForeColor);
    selection = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormForeColorListID));
    if (selection != value  &&  selection != noListSelection) {
        PrefsPutInt(prefTerminalForeColor, selection);
        sshChanged = true;
    }
    value = PrefsGetInt(prefTerminalBackColor, defaultBackColor);
    selection = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormBackColorListID));
    if (selection != value  &&  selection != noListSelection) {
        PrefsPutInt(prefTerminalBackColor, selection);
        sshChanged = true;
    }

    // scrollback lines
    {
        char buf[5];
        uint32_t lines;
        value = PrefsGetInt(prefScrollbackLines, defaultScrollbackLines);
        PrvCopyFieldContents(DisplayPrefsFormScrollbackFieldID, buf);
        if (strlen(buf) > 0) {
            lines = StrAToI(buf);
            if (value != lines) {
                PrefsPutInt(prefScrollbackLines, lines);
                sshChanged = true;
            }
        }
    }

    // scroll to bottom
    value = PrefsGetInt(prefScrollDownOnActivity, defaultScrollDownOnActivity);
    selection = PrvGetControlValue(DisplayPrefsFormActivityCheckboxID);
    if (value != selection) {
        PrefsPutInt(prefScrollDownOnActivity, selection);
        sshChanged = true;
    }
    value = PrefsGetInt(prefScrollDownOnTyping, defaultScrollDownOnTyping);
    selection = PrvGetControlValue(DisplayPrefsFormTypingCheckboxID);
    if (value != selection) {
        PrefsPutInt(prefScrollDownOnTyping, selection);
        sshChanged = true;
    }

    // bell
    value = PrefsGetInt(prefBellBeep, defaultBellBeep);
    selection = PrvGetControlValue(DisplayPrefsFormBeepCheckboxID);
    if (value != selection) {
        PrefsPutInt(prefBellBeep, selection);
        sshChanged = true;
    }
    value = PrefsGetInt(prefBellFlash, defaultBellFlash);
    selection = PrvGetControlValue(DisplayPrefsFormFlashCheckboxID);
    if (value != selection) {
        PrefsPutInt(prefBellFlash, selection);
        sshChanged = true;
    }

    if (sshChanged) ssh_reread_prefs(ss);
}


static void InvalidateSampleText(void)
{
    EventType e2;
    e2.eType = frmGadgetMiscEvent;
    e2.data.gadgetMisc.gadgetID = DisplayPrefsFormSampleTextGadgetID;
    e2.data.gadgetMisc.gadgetP = 
        PrvGetObjectByID(e2.data.gadgetMisc.gadgetID);
    e2.data.gadgetMisc.selector = 0;
    e2.data.gadgetMisc.dataP = NULL;
    EvtAddEventToQueue(&e2);
}


Boolean DisplayPrefsFormHandleEvent(EventPtr e)
{
    FormPtr frmP = FrmGetActiveForm();

    switch (e->eType) {
    case frmOpenEvent:
        CollapseSetState(frmP, collapseStateUser);
        FrmSetGadgetHandler(FrmGetActiveForm(), 
                            PrvGetObjectIndexByID(DisplayPrefsFormSampleTextGadgetID),
                            SampleTextEventHandler);
        LoadDisplayPrefsForm();
        FrmDrawForm(frmP);
        return true;

    case popSelectEvent: {
        // force sample text to redraw with new colors
        InvalidateSampleText();
        return false;
    }

    case ctlSelectEvent:
        switch (e->data.ctlSelect.controlID) {
        case DisplayPrefsFormOKButtonID:
            // save values; leave form
            SaveDisplayPrefsForm();
            FrmReturnToForm(0);
            return true;

        case DisplayPrefsFormCancelButtonID:
            // DON'T save values; leave form
            FrmReturnToForm(0);
            return true;

        // checkboxes

        case DisplayPrefsFormSmallFontCheckboxID:
            PrvSetControlValue(DisplayPrefsFormLargeFontCheckboxID, 0);
            InvalidateSampleText();
            return true;
        case DisplayPrefsFormLargeFontCheckboxID:
            PrvSetControlValue(DisplayPrefsFormSmallFontCheckboxID, 0);
            InvalidateSampleText();
            return true;

        default:
            return false;
        }

    case frmCloseEvent:
        return false;

    default:
        return false;
    }
}

// fixme
extern void set_palm_color(int fg_color, int bg_color);

static void DrawSampleText(RectangleType bounds)
{
    uint32_t fg_color;
    uint32_t bg_color;
    char *str = "Sample terminal text";
    Int16 width, height;
    Int16 x, y;

    WinPushDrawState();
    
    fg_color = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormForeColorListID));
    bg_color = LstGetSelection(PrvGetObjectByID(DisplayPrefsFormBackColorListID));
    set_palm_color(fg_color * 2, bg_color * 2);
    
    if (PrvGetControlValue(DisplayPrefsFormSmallFontCheckboxID)) {
        FntSetFont(font_for_screen(font4x6));
    } else {
        FntSetFont(font_for_screen(font6x10));
    }

    width = FntCharsWidth(str, strlen(str));
    height = FntLineHeight();

    x = bounds.topLeft.x + (bounds.extent.x / 2) - (width / 2);
    y = bounds.topLeft.y + (bounds.extent.y / 2) - (height / 2);
    
    WinEraseRectangle(&bounds, 0);
    WinDrawChars(str, strlen(str), x, y);
    
    WinPopDrawState();
}


static Boolean SampleTextEventHandler(struct FormGadgetTypeInCallback *gadget, 
                                      UInt16 cmd, void *paramP)
{
    Boolean handled = false; 

    switch (cmd) { 
    case formGadgetDrawCmd: 
        // Sent to active gadgets any time form is  
        // drawn or redrawn. 
        DrawSampleText(gadget->rect);
        handled = true; 
        break; 

    case formGadgetHandleEventCmd: {
        EventPtr e = (EventPtr)paramP;
        // Sent when form receives a gadget event.  
        // paramP points to EventType structure.  
        if (e->eType == frmGadgetEnterEvent) { 
            // penDown in gadget's bounds.  
            // do nothing
            handled = true; 
        } else if (e->eType == frmGadgetMiscEvent) { 
            // This event is sent by your application 
            // when it needs to send info to the gadget 
            DrawSampleText(gadget->rect);
            handled = true;
        } 
        break; 
    }

    case formGadgetDeleteCmd:  
        // Perform any cleanup prior to deletion. 
        break; 

    case formGadgetEraseCmd:  
        // FrmHideObject takes care of this if you  
        // return false.  
        handled = false; 
        break; 

    default:
        handled = false;
        break;
    } 

    return handled; 
} 
