/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: hxstatusfield.cpp,v 1.14.2.4 2004/07/09 01:48:55 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#include "hxstatusfield.h"

#include "hxplayer.h"
#include "hxplayer-i18n.h"


static void hxstatus_display_status_field_class_init (HXStatusDisplayStatusFieldClass* klass);
static void hxstatus_display_status_field_init       (HXStatusDisplayStatusField*      status,
                                                      HXStatusDisplayStatusFieldClass* klass);

static void hxstatus_display_status_field_set_player (HXStatusDisplay* status,
                                                      HXPlayer* player);
static void hxstatus_display_status_field_finalize   (GObject*         object);

static void hxstatus_display_status_field_size_request(GtkWidget*        widget,
                                                       GtkRequisition*   requisition);

static HXStatusDisplayClass* g_parent_class = NULL;

GType
hxstatus_display_status_field_get_type (void)
{
    static GType hxstatus_display_status_field_type = 0;

    if (!hxstatus_display_status_field_type)
    {
	static const GTypeInfo hxstatus_display_status_field_info =
	    {
		sizeof (HXStatusDisplayStatusFieldClass),
		NULL,		/* base_init */
		NULL,		/* base_finalize */
		(GClassInitFunc) hxstatus_display_status_field_class_init,
		NULL,		/* class_finalize */
		NULL,		/* class_data */
		sizeof (HXStatusDisplayStatusField),
		0,		/* n_preallocs */
		(GInstanceInitFunc) hxstatus_display_status_field_init,
		NULL,           /* value_table */
	    };

	hxstatus_display_status_field_type = g_type_register_static (HX_TYPE_STATUS_DISPLAY, "HXStatusDisplayStatusField",
                                                                     &hxstatus_display_status_field_info, (GTypeFlags)0);
    }

    return hxstatus_display_status_field_type;
}


static void
hxstatus_display_status_field_class_init (HXStatusDisplayStatusFieldClass *klass)
{
    HXStatusDisplayClass* status_class = HX_STATUS_DISPLAY_CLASS(klass);
    GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass); 
    GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
    
    g_parent_class = (HXStatusDisplayClass*)g_type_class_peek_parent (klass);
    
    status_class->set_player = hxstatus_display_status_field_set_player;
    widget_class->size_request = hxstatus_display_status_field_size_request;
    gobject_class->finalize = hxstatus_display_status_field_finalize;
}

static void
hxstatus_display_status_field_init(HXStatusDisplayStatusField* status, HXStatusDisplayStatusFieldClass* /* klass */)
{
    status->status_label = NULL;
    status->status_text = NULL;
    status->bandwidth_text = NULL;
    status->player_signal_handlers_array = NULL;
    status->player_signal_handlers_array_len = 0;
}

GtkWidget*
hxstatus_display_status_field_new(void)
{
    HXStatusDisplayStatusField* status = (HXStatusDisplayStatusField*)g_object_new(HX_TYPE_STATUS_DISPLAY_STATUS_FIELD, NULL);

    status->status_label = gtk_label_new("");
    gtk_label_set_justify (GTK_LABEL (status->status_label), GTK_JUSTIFY_LEFT);
    gtk_misc_set_alignment (GTK_MISC (status->status_label), 0, 0.5);
    gtk_widget_show(status->status_label);

    gtk_container_add(GTK_CONTAINER(status), status->status_label);

    status->player_signal_handlers_array = g_array_new (FALSE, FALSE, sizeof (gint));

    return GTK_WIDGET(status);
}

static void
update_status_label(HXStatusDisplayStatusField* status)
{
    GString* str;

    str = g_string_new("");

    if(status->status_text)
    {
        g_string_append(str, status->status_text);
    }

    if(status->bandwidth_text && status->show_bandwidth)
    {
        g_string_append(str, " (");
        g_string_append(str, status->bandwidth_text);
        g_string_append(str, ")");        
    }

    gtk_label_set_text(GTK_LABEL(status->status_label), str->str);
    g_string_free(str, TRUE);        
}

static void
set_status_text(HXStatusDisplayStatusField* status, const gchar* text)
{
    if(status->status_text)
    {
        g_free(status->status_text);
    }

    status->status_text = g_strdup(text);

    update_status_label(status);    
}


/* spw signal handlers:
 * ====================
 * designed to be connected to a player display
 */

static void
spw_title_changed(GtkWidget*, const gchar* title, HXStatusDisplayStatusField* status)
{
    set_status_text(status, title);
}

static void
spw_play(GtkWidget*, HXStatusDisplayStatusField* status)
{
    status->show_bandwidth = TRUE;
    set_status_text(status, _("Playing"));    
}

static void
spw_stop(GtkWidget*, HXStatusDisplayStatusField* status)
{
    status->show_bandwidth = FALSE;
    set_status_text(status, _("Stopped"));        
}

static void
spw_pause(GtkWidget*, HXStatusDisplayStatusField* status)
{
    status->show_bandwidth = FALSE;
    if(status->is_seeking)
    {
        set_status_text(status, _("Seeking"));
    }
    else
    {
        set_status_text(status, _("Paused"));
    }
}

static void
spw_contacting(GtkWidget*, const gchar* contacting_text, HXStatusDisplayStatusField* status)
{
    if(!contacting_text)
    {
        contacting_text = "";
    }

    status->show_bandwidth = FALSE;
    set_status_text(status, contacting_text);
}

static void
spw_start_seeking(GtkWidget*, HXStatusDisplayStatusField* status)
{
    status->is_seeking = TRUE;
}

static void
spw_stop_seeking(GtkWidget*, HXStatusDisplayStatusField* status)
{
    status->is_seeking = FALSE;
}
    
static void
spw_buffering(GtkWidget*, HXBufferingReason reason, guint percent, HXStatusDisplayStatusField* status)
{    
    gchar* reason_string;
    gchar* hxstatus_string;

    g_return_if_fail(status != NULL);

    switch(reason)
    {
        case HX_BUFFERING_START_UP:
            reason_string = _("Start-up");
            break;

        case HX_BUFFERING_SEEK:
            reason_string = _("Seek");
            break;

        case HX_BUFFERING_CONGESTION:
            reason_string = _("Congestion");
            break;

        case HX_BUFFERING_LIVE_PAUSE:
            reason_string = _("Live Pause");
            break;

        default:
            reason_string = _("Unknown");
    }

    hxstatus_string = g_strdup_printf(_("Buffering %d%% - %s"), percent, reason_string);
    
    status->show_bandwidth = FALSE;
    set_status_text(status, hxstatus_string);

    g_free(hxstatus_string);
}

static void
spw_clip_bandwidth_changed(GtkWidget*, guint bandwidth, HXStatusDisplayStatusField* status)
{
    if(status->bandwidth_text)
    {
        g_free(status->bandwidth_text);
    }
    status->bandwidth_text = g_strdup_printf("%d kbps", bandwidth / 1000);

    update_status_label(status);
}


static void
hxstatus_display_status_field_set_player(HXStatusDisplay* status, HXPlayer* player)
{ 
    guint i;
    gint signal;
    
    HXStatusDisplayStatusField* status_field = HX_STATUS_DISPLAY_STATUS_FIELD(status);
    g_return_if_fail(status_field != NULL);
    static const struct
    {
        const gchar* name;
        GCallback callback;
    } signal_map[] = 
    {
        { "title_changed",          G_CALLBACK(spw_title_changed) },
        { "buffering",              G_CALLBACK(spw_buffering)     },
        { "contacting",             G_CALLBACK(spw_contacting)    },
        { "play",                   G_CALLBACK(spw_play)          },
        { "pause",                  G_CALLBACK(spw_pause)         },
        { "stop",                   G_CALLBACK(spw_stop)          },
        { "clip_bandwidth_changed", G_CALLBACK(spw_clip_bandwidth_changed) },
        { "start_seeking",          G_CALLBACK(spw_start_seeking) },
        { "stop_seeking",           G_CALLBACK(spw_stop_seeking)  }
    };

    /* Disconnect from the old player, if any */    
    if(status->player)
    {
        for(i = 0; i < status_field->player_signal_handlers_array_len; i++)
        {
            signal = g_array_index(status_field->player_signal_handlers_array, gint, i);
            g_signal_handler_disconnect(G_OBJECT(status->player), signal);
                                        
        }
    }        

    status_field->player_signal_handlers_array_len = 0;

    if(player)
    {
        /* Connect the new player */
        for(i = 0; i < sizeof(signal_map) / sizeof(*signal_map); i++)
        {    
            /* Hook up to the new player */
            signal = g_signal_connect(G_OBJECT(player),
                                      signal_map[i].name,
                                      signal_map[i].callback,
                                      status);

            g_array_insert_val(status_field->player_signal_handlers_array,
                               status_field->player_signal_handlers_array_len,
                               signal);
            status_field->player_signal_handlers_array_len++;
        }
    }

    HX_STATUS_DISPLAY_CLASS(g_parent_class)->set_player(status, player);
}

static void
hxstatus_display_status_field_finalize(GObject* object)
{
    HXStatusDisplayStatusField* status = HX_STATUS_DISPLAY_STATUS_FIELD(object);

    if(status->status_text)
    {
        g_free(status->status_text);
    }

    if(status->bandwidth_text)
    {
        g_free(status->bandwidth_text);
    }

    G_OBJECT_CLASS(g_parent_class)->finalize(object);

    if(status->player_signal_handlers_array)
    {
        g_array_free(status->player_signal_handlers_array, TRUE);
    }

    status->player_signal_handlers_array_len = 0;
}

static void
hxstatus_display_status_field_size_request (GtkWidget*        widget,
                                            GtkRequisition*   requisition)
{
    GtkRequisition req;
    
    GTK_WIDGET_CLASS(g_parent_class)->size_request(widget, &req);

    requisition->height = req.height;
    requisition->width = 1;
}
