/*  $Id: notif.c,v 1.4 2001/02/23 11:52:58 remlali Exp $
 *
 * Copyright 2000 Larry Liimatainen
 * notif.c -- perform notification
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
 *
 *  notif.c
 *
 */

/* 
* notification works in a simple buffered mode.
* where all updates from clients
* gets added into the 'notiflist'.
* the notiflist has information about
* what client updated what table/field.
* The server will periodically call
* notification_send, that traverse
* the 'notiflist', and sends an 'notice'
* to all connected clients.
* after done, the notiflist is emptied.
*/

#include <stdio.h>
#include <glib.h>

#include "dbapi.h"
#include "ddserver.h"
#include "pdu.h"

extern GList *tranq;
extern GList *profiles;
extern GList *notiflist;
extern GList *table_desc;
extern G_sql_connection *dbhandler;

/* notification_add()
*
*
*/

void
notification_add(profile *prf, db_table_descriptor *tbl)
{
GList *gl;
db_table_descriptor *table;
notification *notif;

  gl = table_desc;

  while(gl){
    table = gl->data;
    if(table == tbl){ 
      /* table already exists to be notified */
      return;
    }
    gl = gl->next;
  }
  notif = g_malloc(sizeof(notification));
  notif->prf = prf;
  notif->table = tbl;
  notiflist = g_list_append(notiflist, notif);
}

void
notification_list_empty()
{
notification *notif;

  while(notiflist){
    notif = notiflist->data;
    g_free(notif);
    notiflist = notiflist->next;
  }
  g_list_free(notiflist);
  notiflist = NULL;
}

/* notification_send()
*
*/
void
notification_send(profile *prf, notification *notif)
{
gchar packet[4000]; /* so ugly, but easy :-) */
gint h,n, num_write;

  h = NOTIFY;
  memcpy(packet, &h, sizeof(gint));
  h = DB_NOTIF_TABLE_CHANGED; /* TABLE CHANGED */
  memcpy(packet+sizeof(gint)*2, &h, sizeof(gint));
  h = notif->rowid; /* target ROWID */
  memcpy(packet+sizeof(gint)*3, &h, sizeof(gint));
  n = sizeof(gint) * 4;
  add_asciiz(&n, packet,notif->table->name);
  add_asciiz(&n, packet, "");
  memcpy(packet+sizeof(gint), &n, sizeof(gint)); /* total packet length */
  g_io_channel_write(prf->source, packet, n, &num_write);
fprintf(stderr,"Sending notification to %u\n", prf->source);
}

/* notification_traverse()
*
*/
void
notification_traverse()
{
GList *gl, *pgl;
notification *notif;
profile *prf;

  gl = notiflist;
  while(gl){          /* for each notification */
    notif = gl->data;
    pgl = profiles;
    while(pgl){       /* send to each connected client */
      prf = pgl->data;
      if(prf->source == notif->prf->source){
        pgl = pgl->next;
        continue;   /* but not to the client who triggered its notif */
      }
      notification_send(prf, notif);
      pgl = pgl->next;
    }
    gl = gl->next;
  }
}

/* notification_build_and_add()
*
* build a notification and
* add it to notiflist buffer.
*
*/
gint
notification_build_and_add(db_table_descriptor *table, profile *prf, gpointer row)
{
notification *notif;
gint a,b,n;
#if 0
union _member {
gchar string[2049];
guint integer;
gdouble dbl;
} member;
union _member2 {
gchar string[2049];
guint integer;
gdouble dbl;
} member2;
#endif

pdumember member, member2;

  n = 0;
  a = get_member(&n, row, &member);
  b = get_member(&n, row, &member2);
  if(a != PDUMEMTYPE_STR || b != PDUMEMTYPE_INT ){
    fprintf(stderr,"notificaton_build(): expected a proper encoded rowid\n");
    return FALSE;
  } 
  notif = g_malloc(sizeof(notification));
  notif->rowid = member2.integer;
  notif->prf = prf;
  notif->table = table;
  notiflist = g_list_append(notiflist, notif);
  return TRUE;
}
