
#include <stdio.h>

#include "m3_client.h"
#include "music_packet.h"
#include "shoutcast_metadata_writer.h"

/* the maximum ip addr size including the null */
#define MAX_IP_ADDR_SIZE    16

struct s_M3Client
{
    httpTtrans *trans;

    char ipAddress[MAX_IP_ADDR_SIZE];

    lstTlist *messages;

    pthread_mutex_t messagesMutex;
    pthread_cond_t messagesCond;

    ShoutcastMetadataWriter *metadataWriter;
};

M3Client *
m3_client_new (httpTtrans *trans, bool wantMetadata, int metadataInterval)
{
    M3Client *instance = (M3Client *) malloc (sizeof (M3Client));

    instance->trans = trans;

    utlFip_to_str (trans->cli_ipv4_addr, instance->ipAddress, MAX_IP_ADDR_SIZE);

    instance->messages = lstFlist_create (music_packet_destroy);

    pthread_mutex_init (&instance->messagesMutex, 0);
    pthread_cond_init (&instance->messagesCond, 0);

    instance->metadataWriter = shoutcast_metadata_writer_new (trans, wantMetadata, metadataInterval);

    return (instance);
}

void
m3_client_destroy (void *ptr)
{
    M3Client *instance = (M3Client *) ptr;

    pthread_cond_destroy (&instance->messagesCond);
    pthread_mutex_destroy (&instance->messagesMutex);

    lstFlist_free (instance->messages);

    shoutcast_metadata_writer_destroy (instance->metadataWriter);

    free (instance);
}

const char *
m3_client_ip_address_get (M3Client *instance)
{
    return (instance->ipAddress);
}

static void
m3_client_trim_old_messages (M3Client *instance)
{
    if (lstFlist_size (instance->messages) > 0)
    {
        MusicPacket *oldestPacket = (MusicPacket *) lstFlist_data (lstFlist_tail (instance->messages));
    
        if (time(0) > music_packet_timestamp_get (oldestPacket) + 6)
        {
            logFmsg (CONT_LOG_WARN, "%s: too far behind -- clearing queue of %d packets.",
                    instance->ipAddress, lstFlist_size (instance->messages));
    
            while (lstFlist_size (instance->messages) > 0)
            {
                lstFlist_remove (instance->messages, lstFlist_tail (instance->messages), (void **) &oldestPacket);
    
                music_packet_destroy (oldestPacket);
            }
        }
    }
}

void
m3_client_packet_add (M3Client *instance, MusicPacket *packet)
{
    pthread_mutex_lock (&instance->messagesMutex);

    m3_client_trim_old_messages (instance);

    lstFlist_add_prev (instance->messages, lstFlist_head (instance->messages), packet);

    pthread_cond_signal (&instance->messagesCond);
    pthread_mutex_unlock (&instance->messagesMutex);
}

void
m3_client_metadata_set (M3Client *instance, const char *title, const char *url)
{
    shoutcast_metadata_writer_set_metadata (instance->metadataWriter, title, url);
}

void
m3_client_process_request (M3Client *instance)
{
    while (true)
    {
        MusicPacket *packet;

        pthread_mutex_lock (&instance->messagesMutex);

        if (lstFlist_size (instance->messages) == 0)
        {
            pthread_cond_wait (&instance->messagesCond, &instance->messagesMutex);
        }

        lstFlist_remove (instance->messages, lstFlist_tail (instance->messages), (void **) &packet);

        pthread_mutex_unlock (&instance->messagesMutex);

        if (shoutcast_metadata_writer_write (instance->metadataWriter, 
                    music_packet_data_get (packet)) == false)
        {
            music_packet_destroy (packet);

            break;
        }

        music_packet_destroy (packet);
    }
}
