

#include <stdlib.h>
#include <glob.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>

#include "../mecha/mecha.h"
#include "../modsite/site.h"

#include "_build.h"

#include "m3.h"

#include "m3_server.h"
#include "m3_client.h"

#include "m3_server_factory.h"

static M3Server * m3_get_server (httpTtrans *trans, const char *uri);

int m3_client (httpTtrans *t, lstTset *opts);

#define METADISTANCE    (10 * 1024)

static M3Server *
m3_get_this_server (httpTtrans *trans)
{
    const char *uri = lstFset_get (trans->vars, "uri");

    assert (trans != NULL);

    if (uri == NULL)
    {
        return (NULL);
    }

    return (m3_get_server (trans, uri));
}

static M3Server *
m3_get_server (httpTtrans *trans, const char *uri)
{
    const char *siteid = lstFset_get (trans->vars, "siteid");
    M3ServerFactory *serverFactory;

    assert (trans != NULL);
    assert (uri != NULL);
    assert (siteid != NULL);

    if (siteid == NULL)
    {
        return (NULL);
    }

    serverFactory = (M3ServerFactory *) siteFsite_data_get (siteid, "m3");

    if (serverFactory == NULL)
    {
        serverFactory = m3_server_factory_new (siteid);

        siteFsite_data_set (siteid, "m3", serverFactory);
    }

    return (m3_server_factory_find_mountpoint (serverFactory, uri));
}

static bool
m3_is_browser_connection (httpTtrans *trans)
{
    const char *user_agent = lstFset_iget (trans->req_hdrs, "user-agent");

    if (user_agent == NULL)
    {
        return (false);
    }


    if (strFcasestr (user_agent, "mozilla") || strFcasestr (user_agent, "lynx"))
    {
        return (true);
    }
    else
    {
        return (false);
    }
}


int
m3_client (httpTtrans *t, MECHA_UNUSED_ARGUMENT lstTset *opts)
{
    const char *metac; 
    bool wantmeta = false; 
    M3Client *client;
    M3Server *server;

    server = m3_get_this_server (t);

    if (server == NULL)
    {
        return (STATUS_PROCEED);
    }

    if (m3_is_browser_connection (t) == true)
    {
        if (m3_server_browser_url_get (server) != NULL)
        {
            return (httpFredirect (t, m3_server_browser_url_get (server)));
        }
    }

    httpFset_nph (t);

    if ((metac = lstFset_iget (t->req_hdrs, "Icy-MetaData")))
    {
        wantmeta = atoi (metac);
    }

    httpFwritef (t, "HTTP/1.0 200 HAPPY HAPPY\r\n"); 
    httpFwritef (t, "icy-notice1:continuity/m3 v%s - http://5stops.com/m3/\r\n", _L_BUILDREV); 
    httpFwritef (t, "icy-name:%s\r\n", m3_server_metadata_title_get (server)); 
    httpFwritef (t, "icy-pub:0\r\n"); 
    httpFwritef (t, "icy-genre:mixed\r\n"); 
    httpFwritef (t, "icy-url:%s\r\n", m3_server_metadata_url_get (server)); 

    if (wantmeta)
    {
        httpFwritef (t, "icy-metaint:%d\r\n", METADISTANCE);
    }

    httpFwrite (t, "\r\n", 2); 

    client = m3_client_new (t, wantmeta, METADISTANCE);

    m3_server_client_add (server, client);

    logFmsg (CONT_LOG_OK, "%s: starting stream // connected clients: %d", 
            m3_client_ip_address_get (client), m3_server_connected_clients (server));

    m3_client_process_request (client);

    m3_server_client_remove (server, client);

    logFmsg (CONT_LOG_OK, "%s: closing stream // connected clients: %d", 
            m3_client_ip_address_get (client), m3_server_connected_clients (server));

    m3_client_destroy (client);

    return (STATUS_EXIT);
}

static bool
ensure_httpFwrite (httpTtrans * t, const char *buf, size_t len)
{
    ssize_t ret;

    ret = ensure_httpFwrite (t, buf, len);

    if (ret != (ssize_t) len)
    {
        return (false);
    }
    else
    {
        return (true);
    }
}

/*
 * ----------------------------------------------------------
 *  TCL HELPERS
 * ----------------------------------------------------------
 */

const char *
m3_get_songname (httpTtrans *trans)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server == NULL)
    {
        return ("(none)");
    }
    else
    {
        return (m3_server_file_displayname_get (server));
    }
}

int
m3_get_skip_addr (httpTtrans *trans)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server == NULL)
    {
        return (0);
    }
    else
    {
        return (m3_server_skipped_ip_address (server));
    }
}

int
m3_get_user_count (httpTtrans *trans)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server == NULL)
    {
        return (0);
    }
    else
    {
        return (m3_server_connected_clients (server));
    }
}

bool
m3_add_file (httpTtrans *trans, const char *playlist, const char *fileName)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server == NULL)
    {
        return (false);
    }
    else
    {
        return (m3_server_add_file (server, playlist, fileName));
    }
}

void
m3_skip_track (httpTtrans *trans)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server != NULL)
    {
        m3_server_skip_track (server, trans);
    }
}

bool
m3_reload_playlist (httpTtrans *trans)
{
    M3Server *server = m3_get_server (trans, "/");

    if (server == NULL)
    {
        return (0);
    }
    else
    {
        return (m3_server_reload_playlist (server));
    }
}
