#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/un.h>
#include <netdb.h>
#include <X11/keysym.h>

#include "OXChannel.h"
#include "OXIrc.h"

//----------------------------------------------------------------------

extern OLayoutHints * topexpandxlayout;
extern OLayoutHints * leftexpandylayout;
extern OLayoutHints * expandxexpandylayout;

extern OXPopupMenu * _nick_actions;

extern const char * _menu_name;

OXChannel::OXChannel(const OXWindow *p, OXIrc * s, char * ch) :
  OXTransientFrame(p, s, 1, 1) {
  char wname[100];

  _server = s;
  _next = NULL;
  strcpy(_name, ch);

  SetLayoutManager(new OVerticalLayout(this));

  _f = new OXCompositeFrame(this, 10, 10, HORIZONTAL_FRAME);

  _logw = new OXView(_f, _log = new OTextDoc(), 10, 10, MAIN_FRAME);
  _logw->SetScrollOptions(FORCE_VSCROLL | NO_HSCROLL);
  _f->AddFrame(_logw, expandxexpandylayout);

  if (_name[0] == '#') {
    _canvas = new OXCanvas(_f, 120, 1, FIXED_WIDTH);
    _canvas->GetViewPort()->SetBackgroundPixmap(ParentRelative);
    _nlist = new OXNameList(_canvas->GetViewPort(), _nick_actions, 1, 100,
                                                    FIXED_WIDTH);
    _nlist->Associate(this);
    _canvas->SetContainer(_nlist);
    _f->AddFrame(_canvas, leftexpandylayout);
  }

  AddFrame(_f, expandxexpandylayout);

  _sayentry = new OXMyTextEntry(this, _say = new OTextBuffer(1000));
  _sayentry->ChangeOptions(FIXED_WIDTH | SUNKEN_FRAME | DOUBLE_BORDER);
  AddFrame(_sayentry, topexpandxlayout);

  sprintf(wname, "fOXIrc : %s", _name);
  SetWindowName(wname);

  if (_name[0] == '#')
    Resize(550,300);
  else
    Resize(430,300);
  MapSubwindows();
  Layout();
  MapWindow();
}

OXChannel::~OXChannel() {
}

void OXChannel::CloseWindow() {
  UnmapWindow();
}

OXChannel * OXChannel::GetChannel(char * ch) {
  if (!strcasecmp(ch, _name)) {
    return(this);
  } else if (_next) {
    return(_next->GetChannel(ch));
  } else {
    return(_next = new OXChannel(_parent, _server, ch));
  }
}

void OXChannel::Say(char * nick, char * message, int mode) {
  char m[TCP_BUFFER_LENGTH];
  int int1=0, int2=0;

  if (message[0] == 1) {
    for(int1=1;int1<strlen(message);int1++)
      if (message[int1] == 1) message[int1] = 0;
    if (!strncmp(message+1, "ACTION", 6))
      sprintf(m, "%s %s", nick, message+8);
    else if ((!strncmp(message+1, "PING", 4)) ||
             (!strncmp(message+1, "ECHO", 4))) {
      sscanf(message+6, "%i", &int2);
      if (mode == NOTICE) {
        sprintf(m, "PING reply from %s : %i seconds.", nick, time(NULL)-int2);
      } else {
        sprintf(m, "NOTICE %s :%c%s%c\n", nick, 1, message+1, 1);
        _server->Send(m);
        sprintf(m, "%s requested %s.", nick, message+1);
      }
    } else if (!strncmp(message+1, "VERSION", 7)) {
      sprintf(m, "VERSION %s", FOXIRCVERSION);
      _server->CTCPSend(nick, m, NOTICE);
      sprintf(m, "%s requested VERSION.", nick);
    } else {
      _server->CTCPSend(nick, message+1, PRIVMSG);
      sprintf(m, "%s CTCP : %s", nick, message+1);
    }
    Log(m, "yellow");
  } else if (!strcasecmp(nick, _name)) {
    sprintf(m, "%s", message);
    Log(m);
  } else {
    sprintf(m, "<%s>  %s", nick, message);
    Log(m);
  }
}

void OXChannel::NickList(char * nl) {
  char m[TCP_BUFFER_LENGTH];
  char * s;
  int i,j;

  //sprintf(m, "Users :  %s", nl);
  //Log(m);
  for(i=0, s=nl;sscanf(s,"%s %n", &m, &j)==1;s+=j)
    if (m[0] == '@') {
      _nlist->AddName(&(m[1]));
    } else if (m[0] == '+') {
      _nlist->AddName(&(m[1]));
    } else
      _nlist->AddName(m);
  _canvas->Layout();
}

void OXChannel::NickJoin(char * nick) {
  char m[TCP_BUFFER_LENGTH];

  _nlist->AddName(nick);
  sprintf(m, "%s joined the channel.", nick);
  Log(m, "green");
  _canvas->Layout();
}

void OXChannel::NickLeave(char * nick) {
  char m[TCP_BUFFER_LENGTH];

  _nlist->RemoveName(nick);
  sprintf(m, "%s left the channel.", nick);
  Log(m, "green");
  _canvas->Layout();
}

void OXChannel::NickChange(char * o, char * n) {
  char m[TCP_BUFFER_LENGTH];

  if (_nlist->GetName(o)) {
    _nlist->ChangeName(o,n);
    sprintf(m, "%s is now known as %s.", o, n);
    Log(m, "green");
  }
}

void OXChannel::Log(char * message) {
  Log(message, "white");
}

void OXChannel::Log(char * message, char * color) {
  OLineDoc * l = new OLineDoc();
  l->SetCanvas(_log->_style_server);
  l->SetColor(color);
  l->Fill(message);
  _log->AddLine(l);
  _logw->ScrollDown();
}

int OXChannel::ProcessMessage(long msg, long parm1, long parm2) {
  char char1[TCP_BUFFER_LENGTH], char2[TCP_BUFFER_LENGTH];
  switch(GET_MSG(msg)) {
    case XC_TEXTENTRY:
      switch(GET_SUBMSG(msg)) {
        case TE_TEXTCHANGED:
          switch(parm2) {
            case XK_Return:
              strcpy(char1, _say->GetString());
              sprintf(char2, "PRIVMSG %s :%s\n", _name, char1);
              _server->Send(char2);
              Say(_server->_nick, char1, PRIVMSG);
              break;
          }
          break;
      }
      break;
    case XC_COMMAND:
      switch(GET_SUBMSG(msg)) {
        case CM_MENU:
          switch(parm1) {
            case C_PING:
              sprintf(char1, "PING %ld", time(NULL));
              _server->CTCPSend((char*)_menu_name, char1, PRIVMSG);
              break;
            case C_WHOIS:
              sprintf(char1, "WHOIS %s\n", (char*)_menu_name);
              _server->Send(char1);
              break;
            case C_MESSAGE:
              _server->GetChannel((char*)_menu_name)->MapWindow();
              break;
            default:
              printf("command %i %s\n", parm1, _menu_name);
              break;
          }
          break;
      }
      break;
  }
  return True;
}
