/*
 * rejoin.c
 * (C) Christian Magnusson 2000, Email: d1mag@dtek.chalmers.se
 * This program is copyright, and covered by the Gnu Public License.
 * The Q bot.
 */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "settings.h"
#include "bottypes.h"
#include "globals.h"
#include "dl.h"

void m_rejoin(char *a);

MODULE_PUBLIC int _init_rejoin(void *a, void *b)
{
  dl_command_entry_t *dl = a;
  if(!a) return 0;

  snprintf(dl->help, MAX_COMMAND_HELP_LEN,
	   "/msg %s REJOIN #channel\n/msg %s REJOIN [UPDATE]/[ALL [1] [500]]\nRejoin a channel. UPDATE will update counter causing autolimit problem.\n", BOT_NAME, BOT_NAME);
  snprintf(dl->summary, MAX_COMMAND_SUMMARY_LEN,
	   "Rejoin a channel.");
  dl->level = 950;
#if 0
  dl->func = m_rejoin;
#else
  dl->func = (void (*)(char*)) DL_sym(dl->val, "m_rejoin");
#endif
  return 1;
}

MODULE_PUBLIC int _remove_rejoin(char *a, char *b)
{
  remove_command("rejoin");
  return 1;
}


#if 0
static void inc_channel3(struct chan_stat *list, char *channel)
{
  struct chan_stat *c, *lc, *newc;
  lc = list;
  c = list->next;
  while (c) {
    if (strcasecmp(c->channel, channel) == 0) {
      c->count++;
      return;
    }
    lc = c;
    c = c->next;
  }
  newc = (struct chan_stat *) Malloc(sizeof(struct chan_stat));
  if (newc) {
    strncpy(newc->channel, channel, CHANNELLEN);
    newc->channel[CHANNELLEN] = '\0';
    newc->count = 1;
    newc->next = NULL;
    lc->next = newc;
  }
  return;
}
#endif

static void inc_channel_nr(struct chan_stat *list, char *channel, int nr)
{
  struct chan_stat *c, *lc, *newc;
  lc = list;
  c = list->next;
  while (c) {
    if (strcasecmp(c->channel, channel) == 0) {
      c->count += nr;
      return;
    }
    lc = c;
    c = c->next;
  }
  newc = (struct chan_stat *) Malloc(sizeof(struct chan_stat));
  if (newc) {
    strncpy(newc->channel, channel, CHANNELLEN);
    newc->channel[CHANNELLEN] = '\0';
    newc->count = nr;
    newc->next = NULL;
    lc->next = newc;
  }
  return;
}


MODULE_PUBLIC void m_rejoin(char *a)
{
  int i, nr;
  char channel[CHANNELLEN+1];
  char first[CHANNELLEN+1];
  char last[CHANNELLEN+1];
  int first_nr, last_nr;
  struct chanopts *c;
  ListElem *el;

  struct dbaseuser *db;
  db = sender_au->dbuser;
  if(db) {
    log("From: %s rejoin [%s]\n", db->nick, a);
  } else
    return;

  if(!is_oper()) {
    say_sender("You are not an Oper.");
    log("To: %s Is not an Oper\n", db->nick);
    return;
  }

  i = 0;
  strncpy(channel,getword(a,&i),CHANNELLEN);
  channel[CHANNELLEN] = '\0';
  if(!strlen(channel)) {
    say_sender("You forgot the channel parameter");
    say_sender_( "/msg %s REJOIN #channel", BOT_NAME);
    return;
  }
  
  if(!strcasecmp(channel, "ALL")) {
    first_nr = 0;
    last_nr = 100000;

    strncpy(first,getword(a,&i),CHANNELLEN);
    first[CHANNELLEN] = '\0';
    if(strlen(first)) {
      sscanf(first, "%d", &first_nr);

      strncpy(last,getword(a,&i),CHANNELLEN);
      last[CHANNELLEN] = '\0';
      if(strlen(last)) {
	sscanf(last, "%d", &last_nr);
      }
    }


    nr = 0;
    i = 0;
    el = GetHead(channel_list);
    while(el) {
      nr++;
      if((nr >= first_nr) && (nr < last_nr)) {
	c = (struct chanopts *)el->data;
	if(!c->suspended) {
	  partchannel(c);
	  joinchannel(c);
	  //	  say_sender_("Rejoin %s", c->channel);
	}
      }
      el = GetSucc(el);
    }
    say_sender_("Rejoined %d channels (%d -> %d)", i, first_nr, first_nr+i);
    return;
  } else if(!strcasecmp(channel, "UPDATE")) {
#if 0
    struct chan_stat first_chanstat;
    struct chan_stat *cs, *cstmp;
    int matches;
#endif
    struct chanopts *co;
    struct chanmod *c;
    struct activeuser *u;
    ListElem *el;
    int channels;

    el = GetHead(channel_list);
    while (el) {
      co = (struct chanopts *)el->data;
      co->current_joined = 0;
      el = GetSucc(el);
    }
    i = 0;
    channels = 0;
    el = GetHead(auser_list);
    while (el) {
      u = (struct activeuser *) el->data;
      i++;
      c = u->chanmodes;
      while (c) {
	co = findchannel(c->channel);
	if(co) {
	  co->current_joined++;
	} else {
	  channels++;
	}
	c = c->next;
      }
      if((i % 1000) == 0) say_sender_("Update user (%d)", i);
      el = GetSucc(el);
    }
    say_sender_("Updated %d users (%d channels not found)", i, channels);

#if 0
    first_chanstat.next = NULL;
    first_chanstat.count = 0;
    first_chanstat.channel[0] = '\0';
    matches = 0;
    
    i = 0;
    el = GetHead(auser_list);
    while (el) {
      u = (struct activeuser *) el->data;
      c = u->chanmodes;
      while (c) {
	inc_channel3(&first_chanstat, c->channel);
	matches++;
	c = c->next;
      }
      i++;
      if((i % 5000) == 0) say_sender_("Build userlist (%d users)", i);
      el = GetSucc(el);
    }
    say_sender_("Userlist (%d users)", i);
    i = 0;
    channels = 0;
    if (matches) {
      cs = first_chanstat.next;
      while (cs) {
	channels++;
	if((channels % 1000) == 0) say_sender_("Update channels (%d)", channels);
	co = findchannel(cs->channel);
	if (co) {
	  if (co->current_joined != cs->count) {
	    i++;
	    log("CNT: cur=%d count=%d\n", co->current_joined, cs->count);
	    co->current_joined = cs->count;
	  }
	}
	cstmp = cs;
	cs = cs->next;
	Free(cstmp);        /* free it at once */
	cstmp = NULL;
      }
    }
    say_sender_("Channels updated %d", i);
#endif
    return;
  } else if(!strcasecmp(channel, "CHECK")) {
    struct chan_stat first_chanstat;
    struct chan_stat *cs, *cstmp;
    struct chanopts *co;
    struct chanmod *c;
    struct activeuser *u;
    ListElem *el;
    int channels;

    first_chanstat.next = NULL;
    first_chanstat.count = 0;
    first_chanstat.channel[0] = '\0';

    say_sender("Copy current channel counters");
    i = 0;
    el = GetHead(channel_list);
    while (el) {
      co = (struct chanopts *)el->data;
      inc_channel_nr(&first_chanstat, co->channel, co->current_joined);
      if((++i % 1000) == 0) say_sender_("Channel %d", i); 
      co->current_joined = 0;
      el = GetSucc(el);
    }
    say_sender("Copy finished.");
    i = 0;
    channels = 0;
    el = GetHead(auser_list);
    while (el) {
      u = (struct activeuser *) el->data;
      i++;
      c = u->chanmodes;
      while (c) {
	co = findchannel(c->channel);
	if(co) {
	  co->current_joined++;
	} else {
	  channels++;
	}
	c = c->next;
      }
      if((i % 1000) == 0) say_sender_("Check user (%d)", i);
      el = GetSucc(el);
    }
    say_sender_("%d users (%d channels not found)", i, channels);

    channels = 0;
    i = 0;
    cs = first_chanstat.next;
    while (cs) {
      channels++;
      if((channels % 1000) == 0) say_sender_("Check channel %d", channels);
      co = findchannel(cs->channel);
      if (co) {
	if (co->current_joined != cs->count) {
	  i++;
	  log("DIFF: cur=%d count=%d %s\n", co->current_joined, cs->count, cs->channel);
	  co->current_joined = cs->count;
	}
      }
      cstmp = cs;
      cs = cs->next;
      Free(cstmp);        /* free it at once */
      cstmp = NULL;
    }
    say_sender_("%d channels were wrong.", i);
    return;
  }

  /*
    couldn't find the channel for that user.
    Add it first in the linked list.
  */
  c = findchannel(channel);
  if(!c) {
    say_sender( "Couldn't find that channel in channel database.");
    return;
  }
  if(c->suspended) { say_sender("Channel is suspended"); return; }

  /* found the channel */
  partchannel(c);
  joinchannel(c);
  say_sender("Done.");
  return;
}
