/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2013 Red Hat, Inc.
 */

/**
 * SECTION:nmt-newt-textbox
 * @short_description: Multi-line text box
 *
 * #NmtNewtTextbox implements a multi-line text, optionally with
 * word-wrapping.
 */

#include "libnm-client-aux-extern/nm-default-client.h"

#include "nmt-newt-textbox.h"

#include "nmt-newt-utils.h"

G_DEFINE_TYPE(NmtNewtTextbox, nmt_newt_textbox, NMT_TYPE_NEWT_COMPONENT)

#define NMT_NEWT_TEXTBOX_GET_PRIVATE(o) \
    (G_TYPE_INSTANCE_GET_PRIVATE((o), NMT_TYPE_NEWT_TEXTBOX, NmtNewtTextboxPrivate))

typedef struct {
    int                 wrap_width;
    NmtNewtTextboxFlags flags;

    char *text;
    int   width, height;
} NmtNewtTextboxPrivate;

enum {
    PROP_0,
    PROP_TEXT,
    PROP_FLAGS,
    PROP_WRAP_WIDTH,

    LAST_PROP
};

/**
 * NmtNewtTextboxFlags:
 * @NMT_NEWT_TEXTBOX_SCROLLABLE: the textbox should be scrollable.
 * @NMT_NEWT_TEXTBOX_SET_BACKGROUND: the textbox should have a
 *   white background
 *
 * Flags for an #NmtNewtTextbox
 */

/**
 * nmt_newt_textbox_new:
 * @flags: the textbox's flags
 * @wrap_width: width in characters at which to word-wrap, or
 *   0 to not wrap.
 *
 * Creates a new #NmtNewtTextbox.
 *
 * Returns: a new #NmtNewtTextbox
 */
NmtNewtWidget *
nmt_newt_textbox_new(NmtNewtTextboxFlags flags, int wrap_width)
{
    return g_object_new(NMT_TYPE_NEWT_TEXTBOX, "flags", flags, "wrap-width", wrap_width, NULL);
}

/**
 * nmt_newt_textbox_get_text:
 * @textbox: an #NmtNewtTextbox
 *
 * Gets @textbox's text
 *
 * Returns: @textbox's text
 */
void
nmt_newt_textbox_set_text(NmtNewtTextbox *textbox, const char *text)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(textbox);
    char                 **lines;
    int                    i, width;

    if (!text)
        text = "";
    if (!strcmp(priv->text, text))
        return;

    g_free(priv->text);
    priv->text = g_strdup(text);

    priv->width = priv->height = 0;
    lines                      = g_strsplit(priv->text, "\n", -1);
    for (i = 0; lines[i]; i++) {
        width = nmt_newt_text_width(lines[i]);
        if (width > priv->width)
            priv->width = width;
    }
    g_free(lines);
    priv->height = NM_MAX(i, 1);

    g_object_notify(G_OBJECT(textbox), "text");
    nmt_newt_widget_needs_rebuild(NMT_NEWT_WIDGET(textbox));
}

/**
 * nmt_newt_textbox_get_text:
 * @textbox: an #NmtNewtTextbox
 *
 * Gets @textbox's text
 *
 * Returns: @textbox's text
 */
const char *
nmt_newt_textbox_get_text(NmtNewtTextbox *textbox)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(textbox);

    return priv->text;
}

static void
nmt_newt_textbox_init(NmtNewtTextbox *textbox)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(textbox);

    priv->text = g_strdup("");
}

static void
nmt_newt_textbox_finalize(GObject *object)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(object);

    g_free(priv->text);

    G_OBJECT_CLASS(nmt_newt_textbox_parent_class)->finalize(object);
}

static guint
convert_flags(NmtNewtTextboxFlags flags)
{
    guint newt_flags = 0;

    if (flags & NMT_NEWT_TEXTBOX_SCROLLABLE)
        newt_flags |= NEWT_FLAG_SCROLL;

    return newt_flags;
}

static newtComponent
nmt_newt_textbox_build_component(NmtNewtComponent *component, gboolean sensitive)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(component);
    newtComponent          co;
    const char            *text;
    char                  *text_lc;

    text = priv->text;
    if (!*text)
        text = "\n";

    text_lc = nmt_newt_locale_from_utf8(text);
    if (priv->wrap_width > 0) {
        co = newtTextboxReflowed(-1, -1, text_lc, priv->wrap_width, 0, 0, 0);
    } else {
        co = newtTextbox(-1, -1, priv->width, priv->height, convert_flags(priv->flags));
        newtTextboxSetText(co, text_lc);
    }
    g_free(text_lc);

    if (priv->flags & NMT_NEWT_TEXTBOX_SET_BACKGROUND)
        newtTextboxSetColors(co,
                             NMT_NEWT_COLORSET_TEXTBOX_WITH_BACKGROUND,
                             NEWT_COLORSET_ACTTEXTBOX);

    return co;
}

static void
nmt_newt_textbox_set_property(GObject      *object,
                              guint         prop_id,
                              const GValue *value,
                              GParamSpec   *pspec)
{
    NmtNewtTextbox        *textbox = NMT_NEWT_TEXTBOX(object);
    NmtNewtTextboxPrivate *priv    = NMT_NEWT_TEXTBOX_GET_PRIVATE(textbox);

    switch (prop_id) {
    case PROP_TEXT:
        nmt_newt_textbox_set_text(textbox, g_value_get_string(value));
        break;
    case PROP_FLAGS:
        priv->flags = g_value_get_uint(value);
        break;
    case PROP_WRAP_WIDTH:
        priv->wrap_width = g_value_get_int(value);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static void
nmt_newt_textbox_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
    NmtNewtTextboxPrivate *priv = NMT_NEWT_TEXTBOX_GET_PRIVATE(object);

    switch (prop_id) {
    case PROP_TEXT:
        g_value_set_string(value, priv->text);
        break;
    case PROP_FLAGS:
        g_value_set_uint(value, priv->flags);
        break;
    case PROP_WRAP_WIDTH:
        g_value_set_int(value, priv->wrap_width);
        break;
    default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
        break;
    }
}

static void
nmt_newt_textbox_class_init(NmtNewtTextboxClass *textbox_class)
{
    GObjectClass          *object_class    = G_OBJECT_CLASS(textbox_class);
    NmtNewtComponentClass *component_class = NMT_NEWT_COMPONENT_CLASS(textbox_class);

    g_type_class_add_private(textbox_class, sizeof(NmtNewtTextboxPrivate));

    /* virtual methods */
    object_class->set_property = nmt_newt_textbox_set_property;
    object_class->get_property = nmt_newt_textbox_get_property;
    object_class->finalize     = nmt_newt_textbox_finalize;

    component_class->build_component = nmt_newt_textbox_build_component;

    /**
     * NmtNewtTextbox:text:
     *
     * The textbox's text
     */
    g_object_class_install_property(
        object_class,
        PROP_TEXT,
        g_param_spec_string("text", "", "", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
    /**
     * NmtNewtTextbox:flags:
     *
     * The textbox's flags
     */
    g_object_class_install_property(
        object_class,
        PROP_FLAGS,
        g_param_spec_uint("flags",
                          "",
                          "",
                          0,
                          G_MAXUINT,
                          0,
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
    /**
     * NmtNewtTextbox:wrap-width:
     *
     * The width in characters at which the textbox's text
     * will wrap, or 0 if it does not wrap.
     */
    g_object_class_install_property(
        object_class,
        PROP_WRAP_WIDTH,
        g_param_spec_int("wrap-width",
                         "",
                         "",
                         0,
                         G_MAXINT,
                         0,
                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
