/*
 * Copyright (c) 2004 Alex Leigh, All Rights Reserved
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH The copyright
 * notice above does not evidence any actual or intended publication of such
 * source code.
 *
 * Use, disclosure, copying, distribution, or transmission of this code without
 * express permission is prohibited.
 */

#include <continuity.h>
#include <site.h>

struct tasSstat {
    unsigned int tas_ctime;
    struct tasSstat *tas_next;

    char tas_module[TA_STAT_STRLEN];
    int tas_instance;
    char tas_name[TA_STAT_STRLEN];
    int tas_type;
    char tas_class[TA_STAT_STRLEN];
    unsigned char tas_flags;
    void *tas_data;
    size_t tas_data_size;
    unsigned int tas_ndata;
};

struct tasSctl {
    struct tasSstat *chain;
};

int beaconFstatpage(httpTtrans *t, lstTset *set)
{       
    tasTstat *p;
    char *v1 = "TAS Chain empty.\n";
    char buf[1024];
    struct timeval tv;
    const char *uri;
         
    uri = lstFset_get(t->vars, "uri");

    if (strcmp(uri, "/.sc_stat") != 0)
        return STATUS_PROCEED;
            
    lstFset_update(t->res_hdrs, "Content-Type", "text/plain");
    httpFset_status(t, 200, NULL);
    httpFstart_response(t);
        
    p = tasFget_chain();
        
    if (p == NULL) {
        httpFwrite(t, v1, strlen(v1));
        return STATUS_EXIT;
    }
    while (1) {
        gettimeofday(&tv, NULL);        /* $$$ but accurate */
 
        sprintf(buf,
                "ta,%s.%d.%s,",
                p->tas_module, p->tas_instance, p->tas_name);
    
        httpFwrite(t, buf, strlen(buf));
    
        if (p->tas_type == TA_STAT_INT) {
            int *ip;
            ip = p->tas_data;
            sprintf(buf, "%d", *ip);
            httpFwrite(t, buf, strlen(buf));
        }
        if (p->tas_type == TA_STAT_UINT) {
            unsigned int *ip;
            ip = p->tas_data;
            sprintf(buf, "%u", *ip);
            httpFwrite(t, buf, strlen(buf));
        }
        sprintf(buf, ",%lu,%lu\n", tv.tv_sec, tv.tv_usec);
        httpFwrite(t, buf, strlen(buf));
        
        if (p->tas_next == NULL)
            break;
        p = p->tas_next;
    }   
        
    return STATUS_EXIT;
}               

static void beaconFthread(void)
{
    uint32_t pages_total, pages_free, phys_mem, availr_mem, free_mem;
    uint32_t idle, user, kernel, wait;
    uint32_t n_idle, n_user, n_kernel, n_wait;
    uint32_t o_idle, o_user, o_kernel, o_wait;
    uint32_t ibytes, obytes, ipkts, opkts;

    /* Since we are dealing with deltas, we will load the "old" values
     * and do nothing about them. This will prevent an apparently huge
     * spike appearing in the graphs when the first response from the server
     * are the since-rollover values. 
     */
    sysFcpu_usage(&o_idle,&o_user,&o_kernel,&o_wait);
    
    while(1) {
        sysFmem_usage(&pages_total,&pages_free,
                      &phys_mem,&availr_mem,&free_mem);
        tasFstat_set("sys",0,"pagestotal",pages_total);
        tasFstat_set("sys",0,"pagesfree",pages_free);
        tasFstat_set("sys",0,"physmem",phys_mem);
        tasFstat_set("sys",0,"availrmem",availr_mem);
        tasFstat_set("sys",0,"freemem",free_mem);


        sysFcpu_usage(&idle,&user,&kernel,&wait);
        n_idle=idle-o_idle;
        n_user=user-o_user;
        n_kernel=kernel-o_kernel;
        n_wait=wait-o_wait;
        
        tasFstat_set("cpu",0,"idle_time",n_idle);
        tasFstat_set("cpu",0,"user_time",n_user);
        tasFstat_set("cpu",0,"kernel_time",n_kernel);
        tasFstat_set("cpu",0,"wait_time",n_wait);
        tasFstat_set("cpu",0,"total_time",n_idle+n_user+n_kernel+n_wait);

        o_idle=idle;
        o_user=user;
        o_kernel=kernel;
        o_wait=wait;

        sysFnet_usage(&obytes, &ibytes, &opkts, &ipkts);
        tasFstat_set("net",0,"bytes_out",obytes);
        tasFstat_set("net",0,"bytes_in",ibytes);

        thrFsleep(5000);
    }
}


int beaconFinit(void *p, lstTset * o)
{
    pthread_t tid;

    logFmsg(0,"mod/beacon: System metrics beacon.");
    logFmsg(0,"Copyright (c) 2004, Alex Leigh");
    
    pthread_create(&tid,NULL,(void *(*)(void *))&beaconFthread,NULL);

    return STATUS_PROCEED;
}

int tasFrts_stream(httpTtrans * t, lstTset * opts)
{
    tasTstat *p;
    char *v1 = "TAS Chain empty.\n";
    char buf[1024];
    struct timeval tv;
    char *uri;
            
    uri = lstFset_get(t->vars, "uri");
    if (strcmp(uri, "/continuity.rts") != 0)
        return STATUS_PROCEED;
                
    lstFset_update(t->res_hdrs, "Content-Type", "text/plain");
    httpFset_status(t, 200, NULL);
    httpFstart_response(t);
            
    p = tasFget_chain();
                
    if (p == NULL) {
        httpFwrite(t, v1, strlen(v1));
        return STATUS_EXIT;
    }
    while (1) {
        p = tasFget_chain();
    
        while (1) {
            gettimeofday(&tv, NULL);    /* $$$ but accurate */

            sprintf(buf,
                    "ty=u&na=%s.%d.%s",
                    p->tas_module, p->tas_instance, p->tas_name);
 
            httpFwrite(t, buf, strlen(buf));
    
            if (p->tas_type == TA_STAT_INT) {
                int *ip;
                ip = p->tas_data;
                sprintf(buf, "&va=%d", *ip);
                httpFwrite(t, buf, strlen(buf));
            }
            if (p->tas_type == TA_STAT_UINT) {
                unsigned int *ip;
                ip = p->tas_data;
                sprintf(buf, "&va=%u", *ip);
                httpFwrite(t, buf, strlen(buf));
    }
            sprintf(buf, "&ti=%lu.%lu\n", tv.tv_sec, tv.tv_usec);
            httpFwrite(t, buf, strlen(buf));
            
            if (p->tas_next == NULL)  
                break;
            p = p->tas_next;
        }
        thrFsleep(1000);
    }
    return STATUS_EXIT; 
}

