/*
 * front/dummy.c
 *   Dummy (default) frontend
 *
 * $Id: dummy.c,v 1.1.1.1 2002/01/24 20:19:48 sembera Exp $
 */
/*
 * IIRC - IIRC Is a Real Client (Modular IRC Client)
 * Copyright (C) 2001  Jan Sembera <fis@ji.cz>
 * Copyright (C) 2001  Petr Baudis <pasky@ji.cz>
 *
 * 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, Boston, MA  02111-1307  USA
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#include <config.h>
#include <debug.h>

#include "errors.h"
#include "../back/errors.h"
#include "../core/iface.h"
#include "iface.h"
#include "generic.h"
#include "cursio.h"
#include "dummy.h"

#define scprintf(fmt...) _cprintf(PROMPT " " fmt);

#define swin_add(fmt...) win_add(PROMPT " " fmt);

#define win_add(fmt...)\
{\
  char buf[1024];\
  _csprintf(buf, fmt);\
  window_add(buf);\
}

#define	PROMPT	"56[IIRC]"

typedef struct {
  int maxlen;
  int len;
  int ptr;
  char buf[100][256];
} window_t;

typedef struct {
  window_t *window;
} dummy_data;

dummy_data *data;

/**************************************************/
/* helpers                                        */
/**************************************************/

/* window */

void
window_add(char *str) {
  window_t *win;
  char final[1024];
  int maxx;

  maxx = io_maxx();

  win = data->window;
  
  sprintf(final, /*maxx,*/ "%s", str); /* TODO \n breaks str to more finals */
  
  win->ptr++;
  if (win->ptr >= win->maxlen) win->ptr = 0;
  if (win->len <  win->maxlen) win->len++;
  strcpy(win->buf[win->ptr], strdup(final));
}

void
window_update() {
  window_t *win;
  int maxx, maxy;
  int current;
  
  maxx = io_maxx();
  maxy = io_maxy();

  win = data->window;
  
  /* io_cls(); */
  io_move(1, 1);

  for (current = 0; current < win->maxlen; current++) {
    io_move(1+current, 1);
    io_cle();

    if (current == (win->ptr + 1))
      printf("\n");
    else
      if (current >= win->len)
	printf("\n");
      else
	printf("%s", win->buf[current]);
  }
}

/* status */

void
status_time() {
  struct tm *now;
  time_t t_now;
  
  t_now = time(NULL);
  now = localtime(&t_now);
  
  _cprintf("36,44[57,44%02d:%02d36,44]", now->tm_hour, now->tm_min);
}

void
status_nick() {
  _cprintf("36,44[37,44%s57,44(36,44-37,44abcd57,44)36,44]", "*YOU*");
}

void
status_lag() {
  _cprintf("36,44[37,44Lag 57,44%2d36,44]", 0);
}

void
status_chstat() {
  _cprintf("36,44[37,44X/0 Y/1 Z/236,44]");
}

void
status_update() {
  int maxx, maxy;

  maxx = io_maxx();
  maxy = io_maxy() - 1; /* XXX avoid scrolling and messing of all the screen when enter press'd at the very bottom prompt */
  
  io_move(maxy - 2, 1);

  _cprintf(",44 ");
  status_time();
  status_nick();
  io_color(-1, 44, 0, 0); io_cle();
  
  io_move(maxy - 1, 1);

  _cprintf(",44 ");
  status_lag();
  _cprintf(",44 ");
  status_chstat();
  io_color(-1, 44, 0, 0); io_cle();
  
  io_move(maxy, 1);

  _cprintf(",40[RAW] "); io_cle();
}

/**************************************************/
/* input hooks                                    */
/**************************************************/

int
in_hook_privmsg(parsed_t *pcmd, message_t *msg) {
  cmd_front_privmsg_t *ldata;
  
  if (pcmd->argc<2) {
    swin_add("At least two parameters required for %s.\n", pcmd->command);
    return FRONT_EAGAIN;
  }
  
  msg->type = CMD_FRONT_PRIVMSG;
  msg->data = malloc(sizeof(cmd_front_privmsg_t));
  ldata = (cmd_front_privmsg_t *) msg->data;
  
  ldata->target = (char *) malloc(strlen(pcmd->argv[0]));
  strcpy(ldata->target, pcmd->argv[0]);
  generic_front_parjoin(&ldata->string, 1, 0, pcmd);

  generic_front_destroy(pcmd);

  return 1;
}

int
in_hook_quit(parsed_t *pcmd, message_t *msg) {
  cmd_front_quit_t *ldata;
  
  msg->type = CMD_FRONT_QUIT;
  msg->data = malloc(sizeof(cmd_front_quit_t));
  ldata = (cmd_front_quit_t *) msg->data;
  
  if (pcmd->argc<1)
    ldata->reason="I will return and the lag will come with me!";
  else
    generic_front_parjoin(&ldata->reason, 0, 0, pcmd);

  generic_front_destroy(pcmd);

  return 1;
}

int
in_hook_nick(parsed_t *pcmd, message_t *msg) {
  cmd_front_nick_t *ldata;
  
  if (pcmd->argc!=1) {
    swin_add("Only and only one parameter required for %s.\n", pcmd->command);
    return FRONT_EAGAIN;
  }
  
  msg->type = CMD_FRONT_NICK;
  msg->data = malloc(sizeof(cmd_front_nick_t));
  ldata = (cmd_front_nick_t *) msg->data;

  ldata->nick = (char *) malloc(strlen(pcmd->argv[0]));
  strcpy(ldata->nick, pcmd->argv[0]);

  generic_front_destroy(pcmd);

  return 1;
}

int
in_hook_join(parsed_t *pcmd, message_t *msg) {
  cmd_front_join_t *ldata;
  
  if (pcmd->argc<1) {
    swin_add("At least one parameter required for %s.\n", pcmd->command);
    return FRONT_EAGAIN;
  }
  
  msg->type = CMD_FRONT_JOIN;
  msg->data = malloc(sizeof(cmd_front_join_t));
  ldata = (cmd_front_join_t *) msg->data;
  
  ldata->channel = (char *) malloc(strlen(pcmd->argv[0]));
  strcpy(ldata->channel, pcmd->argv[0]);

  generic_front_destroy(pcmd);

  return 1;
}

int
in_hook_part(parsed_t *pcmd, message_t *msg) {
  cmd_front_part_t *ldata;
  
  if (pcmd->argc<1) {
    swin_add("At least one parameter required for %s.\n", pcmd->command);
    return FRONT_EAGAIN;
  }
  
  msg->type = CMD_FRONT_PART;
  msg->data = malloc(sizeof(cmd_front_part_t));
  ldata = (cmd_front_part_t *) msg->data;
  
  ldata->channel = (char *) malloc(strlen(pcmd->argv[0]));
  strcpy(ldata->channel, pcmd->argv[0]);

  if (pcmd->argc>1)
    generic_front_parjoin(&ldata->reason, 1, 0, pcmd);
  else
    ldata->reason="Bubbling thru the reality";
  
  generic_front_destroy(pcmd);

  return 1;
}

hook_t in_hooks[]={
  {"PRIVMSG", in_hook_privmsg},
  {"MSG", in_hook_privmsg},
  {"QUIT", in_hook_quit},
  {"NICK", in_hook_nick},
  {"JOIN", in_hook_join},
  {"PART", in_hook_part},
  {NULL, NULL},
};

/**************************************************/
/* output hooks                                   */
/**************************************************/

int
out_hook_raw(message_t *msg) {
  win_add("55[RAW] %s\n",
      ((cmd_front_raw_t *) msg->data)->string);
  
  return 1;
}

int
out_hook_co_pre(message_t *msg) {
  swin_add("Connecting to %s...\n",
      ((cmd_front_connect_t *) msg->data)->server);
  
  return 1;
}

int
out_hook_co_post(message_t *msg) {
  swin_add("Connected to %s.\n",
      ((cmd_front_connect_t *) msg->data)->server);
  
  return 1;
}

int
out_hook_disco_pre(message_t *msg) {
  swin_add("Disconnecting from server...\n");
  
  return 1;
}

int
out_hook_disco_post(message_t *msg) {
  swin_add("Disconnected from server.\n");
  
  return 1;
}

int
out_hook_error(message_t *msg) {
  cmd_front_error_t *ldata;
  
  ldata = (cmd_front_error_t *) msg->data;
  
  swin_add("51ERROR at %s/%d: %s (%d)",
      ldata->file, ldata->line,
      ldata->origin?
        front_errors[-(ldata->code+1)]:
	back_errors[-(ldata->code+1)],
      ldata->code);
  
  if (ldata->code == (ldata->origin? BACK_ESOCKET: FRONT_ETERM))
    printf(" - %s (%d)", strerror(ldata->err_no), ldata->err_no);
  
  putc('\n', stdout);

  return 1;
}

int
out_hook_quit(message_t *msg) {
  swin_add("%s has quited IRC 50(%s50)\n",
      ((cmd_front_quit_t *) msg->data)->nick,
      ((cmd_front_quit_t *) msg->data)->reason);
  
  return 1;
}

int
out_hook_privmsg(message_t *msg) {
  win_add("54<%s50:%s54> %s\n",
      ((cmd_front_privmsg_t *) msg->data)->origin,
      ((cmd_front_privmsg_t *) msg->data)->target,
      ((cmd_front_privmsg_t *) msg->data)->string);
  
  return 1;
}

int
out_hook_nick(message_t *msg) {
  swin_add("%s %s is now known as 36%s\n",
      ((cmd_front_nick_t *) msg->data)->orignick,
      ((cmd_front_nick_t *) msg->data)->nick);
  
  return 1;
}

int
out_hook_join(message_t *msg) {
  swin_add("%s 56%s has jointed %s\n",
      ((cmd_front_join_t *) msg->data)->origin,
      ((cmd_front_join_t *) msg->data)->channel);
  
  return 1;
}

int
out_hook_part(message_t *msg) {
  swin_add("%s 36%s has parted %s, stating 50[%s50]\n",
      ((cmd_front_part_t *) msg->data)->origin,
      ((cmd_front_part_t *) msg->data)->channel,
      ((cmd_front_part_t *) msg->data)->reason);
  
  return 1;
}

int (*out_hooks[])(message_t *)={
  out_hook_raw,
  out_hook_co_pre,
  out_hook_co_post,
  out_hook_disco_pre,
  out_hook_disco_post,
  out_hook_error,
  out_hook_quit,
  out_hook_privmsg,
  out_hook_nick,
  out_hook_join,
  out_hook_part,
};

/**************************************************/
/* interface                                      */
/**************************************************/

int
front_init_dummy(struct IFACE_T *end)
{
  end->data = (dummy_data *) malloc(sizeof(dummy_data));
  if (end->data == NULL)
    return FRONT_EMEM;

  data = end->data;
  data->window = (window_t *) malloc(sizeof(window_t));
  data->window->len = 0;
  data->window->ptr = -1;

  io_init();
  data->window->maxlen = io_maxy()-4; /* -1 for allscroll-fix */
  
  io_cls();
  io_move(1, 1);
  
  swin_add("IIRC version %s, Copyright (c) 2001  Jan Sembera, Petr Baudis\n", IIRC_VERSION);
  swin_add("\n");
  swin_add("IIRC comes with ABSOLUTELY NO WARRANTY; This is free software,\n");
  swin_add("and you are welcomed to redistribute it under conditions contained\n");
  swin_add("in attached file COPYING. Contact us at pasky@ji.cz or fis@ji.cz,\n");
  swin_add("if you have any questions.\n");
  swin_add("\n");
  swin_add("Dummy frontend version v0.2.2, (c) 2001  Petr Baudis <pasky@ji.cz>\n");
  swin_add("\n");

  window_update();
  status_update();
	
  return 1;
}

int
front_put_dummy(message_t *msg, struct IFACE_T *end)
{ 
  int ret;

  data = end->data;
  
  if (! out_hooks[msg->type])
    fprintf(stderr,
	"-- IIRC -- !! YIKES !! **INTERNAL ERROR** Unexpected command from core - %ld (no handler).\n",
	msg->type);
  
  ret = out_hooks[msg->type](msg);

  status_update();
  window_update();

  return ret;
}

int
front_get_dummy(message_t *msg, struct IFACE_T *end)
{
  char in[1024];

  data = end->data;

  window_update();
  status_update();

  /*scprintf("-> ");*/
  fgets(in, 1024, stdin);
  in[strlen(in) - 1] = 0; /* strip newline */

  /* nothing around? */
  if (! in[0])
    return FRONT_EAGAIN; /* nothing around */
  
  /* command? */
  if (in[0] == '/') {
    parsed_t pcmd;
    int cmdid;

    /* command */
    
    generic_front_split(in, &pcmd);
    
    if ((cmdid = generic_front_lookup_in(in_hooks, &pcmd)) < 0) {
      swin_add("Unknown command %s.\n", pcmd.command);
      return FRONT_EAGAIN;
    }
  
    if (! in_hooks[cmdid].handler)
      fprintf(stderr,
	"-- IIRC -- !! YIKES !! **INTERNAL ERROR** Unexpected command from you - %d (no handler).\n",
	cmdid);

    return in_hooks[cmdid].handler(&pcmd, msg);
    
  } else {
    cmd_front_raw_t *ldata;

    /* normal input */
    
    msg->type = CMD_FRONT_RAW;
    msg->data = malloc(sizeof(cmd_front_error_t));
    ldata = (cmd_front_raw_t *) msg->data;
    
    ldata->string = (char *) malloc(strlen(in)+1);
    strcpy(ldata->string, in);
    
    return 1;
  }
}


int
front_done_dummy(struct IFACE_T *end)
{
  /*free(((dummy_data *) end->data)->window);*/
  free(end->data);
  
  io_move(io_maxy(), 1);
  
  io_done();
  
  return 1;
}
