//$Id: channel.cpp,v 1.4 1997/12/01 05:49:48 parallax Exp $

#include "channel.h"
#include "ircapp.h"
#include <qregexp.h>

const int TOPIC_BORDER = 3;
const int TOPIC_WIDTH = 300;
const int TOPIC_OFFSET = 120;
const int NICK_AREA_WIDTH = 110;
const int POPUP_OFFSET_Y = 20;
const int POPUP_OFFSET_X = 0;

Channel::Channel(QWidget *parent, const char *n)
        : MessageWindow(parent, n)
{   
    keys = new QList<QString>();
    keys->setAutoDelete(true);
    nickArea = new ColorListBox(this,name() );
    nickArea->setAutoBottomScrollBar(false); // we have left enough room...barely
    connect (nickArea, SIGNAL(Popup()), SLOT(NickPopup()) );
    popup = NULL;
    popupList = NULL;
}

Channel::~Channel()
{
    if (popup)
        delete popup;
    if (popupList)
        delete popupList;
    if (keys)
        delete keys;
}

void Channel::ApplyTheme()
{
    MessageWindow::ApplyTheme();
    IrcApp::SetThemeProperties(nickArea, Settings::theme.nickList);
    nickArea->update();
}

void Channel::UpdateCaption()
{
    QString c;
    if (topic.isEmpty())
        c = name();
    else
        c.sprintf("%s - %s", name(), topic.data());
    setCaption(c);
}

void Channel::SetTopic (const char *t)
{
    topic = t;
}

void Channel::ParseInput(const char *txt)
{
    QString text(txt);
    int space = text.find(' ');
    int colon = text.find(':');        
    if ((colon < space && colon > 0) || (colon > 0 && space == -1)) // this means the we have a colon occuring before any white space
    {
        QString partialNick = text.left(colon); // everything but the colon
        QString completeNick;
        int index = 0;
        while (completeNick.isEmpty())
        {
            if (nickArea->count() == (unsigned int)index)
                completeNick = partialNick.copy();
            else
            {
                QString tmp = nickArea->text(index);
                for (int t=0; t<2; t++)
                {
                    if (tmp.left(1) == "@" || tmp.left(1) == "+") // screen out ops and v's
                        tmp.remove(0,1);
                }
//                    debug("Comparing %s with %s", partialNick.data(), tmp.left(partialNick.length()).data());
                if ((tmp.left(partialNick.length())).lower() == partialNick.lower())
                {
                    char extra = 0;
                    if (Settings::nickCompletionExtra == "Bold")
                        extra = 0x02;
                        if (Settings::nickCompletionExtra == "Underline")
                            extra = 0x1F;
                        if (Settings::nickCompletionExtra == "Inverse")
                            extra = 0x16;
                        if (!extra)
                            completeNick = tmp.copy();
                        else
                            completeNick.sprintf("%c%s%c", extra, tmp.data(), extra);
                }
            }
            index++;
        }
        // now we should have the complete nick (if any)
        text.remove(0, colon); // remove the partial nick
        text.prepend(completeNick);
    }
    MessageWindow::ParseInput(text);
}
    
void Channel::RemoveNick ( const char *nick)
{
    int index = GetNickIndex ( nick );
    if (index == -1)
    {
        warning("Channel::RemoveNick error: no such nick %s.", nick);
        return;
    }
    QString selected;
    int c = nickArea->currentItem();
    if (c != -1)
        selected = nickArea->text(c);
    nickArea->removeItem(index);
    if (index == c)
        nickArea->setSelected(nickArea->currentItem(), false);
    else
    {
        if (selected)
            nickArea->setSelected(GetNickIndex(selected), true);
    }
}    




void Channel::HandleNickMode ( const char *n,  const char *mode )
{
    int index = GetNickIndex ( n);
    if (index == -1)
        return;
    QString nick = nickArea->text(index);
    
    int i = 0;
    bool add=false;
    while (mode[i])
    {
        switch(mode[i])
        {
            case  '+':
                add = true;
                break;
            case  '-':
                add = false;
                break;                   
            case 'o':
            {
                if (add)
                {
                    if (nick[0] != '@')
                    {
                        if (nick[0] == '+')
                            nick.remove(0,1); //no point in showing voice if you are an op
                        nick.prepend("@");
                    }
                }
                else
                {
                    if (nick[0] == '@')
                        nick.remove(0,1);
                }
                break;
                case  'v':
                    if (add)
                    {
                        if (nick[0] != '+' && nick[0] != '@')
                            nick.prepend("+");
                    }
                    else
                    {
                        if (nick[0] == '+')
                            nick.remove(0,1);
                    }
                    break;
            }           
        }
        i++; // parse the next character
    }
    int c = nickArea->currentItem();
    nickArea->removeItem(index);
    nickArea->setSelected(c, true);
    if (index == c) // we don;t want the selection jumping around
        nickArea->setSelected(PlaceNick(nick), TRUE);
      else      
      {
          PlaceNick(nick);
      }
      

}

void Channel::ChangeNick(const char *n1, const char *n2)
{
    int index = GetNickIndex ( n1);
    if (index == -1)
    {
//             debug("nick %s not found", n1);
        return;
    }
    QString str(n2);
    char extra = (nickArea->text(index))[0];
    if ( extra == '@' )
        str.prepend("@");
    if ( extra == '+' )
        str.prepend("+");
    QString selected;
    int c = nickArea->currentItem();
    nickArea->removeItem(index);
    nickArea->setSelected(c, true);
    if (index == c) // we don;t want the selection jumping around
        nickArea->setSelected(PlaceNick(str), TRUE);
    else      
    {
        PlaceNick(str);
    }
    if (QString(n1).lower() != Settings::myNick.lower())
    {
        QString msg(512);
        msg.sprintf("%s is now known as %s", n1, n2);
        Output ( msg, Output::INFO );
    }
}
        
void Channel::AddNick ( const char *nick )
{
    if (Settings::debug)
        debug("Adding nick: %s", nick);
    
    const char *nickptr = nick;
    if (nick[0] == '@' || nick[0] == '+')
        nickptr++;
    if (nick[1] == '@' || nick[1]== '+')
        nickptr++;
    int i = GetNickIndex(nickptr);
    if (i == -1)
            PlaceNick(nick);
    else
    {
        int c = nickArea->currentItem();
        nickArea->removeItem(i);
        nickArea->setSelected(c, true);
        if (i == c)
            nickArea->setSelected(PlaceNick(nick), true);
        else
            PlaceNick(nick);
    }

}

int Channel::PlaceNick (const char *nick)
{
    int index = 0;
    QString str;
    QString selected;
    int c = nickArea->currentItem();
    if (c != -1)
        selected = nickArea->text(c);
    while(nickArea->text(index))
    {
        str = nickArea->text(index);
     
        // now compare nick with the one currently there

        if ((const char *)(QString(nick).lower()) < str.lower())
        {
            nickArea->insertItem(nick, index);
            return index;
        }
       
        index++;
    }
    // must be the first
    nickArea->insertItem(nick, index);
    if (selected)
        nickArea->setSelected(GetNickIndex(selected), true);
    return index;
}

int Channel::GetNickIndex ( const char *nick )
{
    QString str;
    QString name(nick);
    for (int i=0; i< ((int)(nickArea->count())); i++)
    {     
        str = nickArea->text(i);
        if ( str.left(1) == "@" || str.left(1) == "+")
            str.remove(0,1);
        if ( str.left(1) == "@" || str.left(1) == "+") // repeat
            str.remove(0,1);

        if (str.lower() == name.lower())
        { // we have a match
            return i;
        }
      
    }

    return -1; //no match
}

void Channel::HandleSignoff(const char *nick, const char *msg)
{
    if (GetNickIndex(nick) != -1)
    {
        QString disp(512);
        disp.sprintf("Signoff: %s (%s)", nick, msg);
        Output(disp, Output::NOTICE);
        RemoveNick(nick);
    }
}

void Channel::Rejoin()
{
    QString out;
    out.sprintf("JOIN %s\r\n", name());
    IrcApp::HandleEvent(Event::SOCKET_WRITE, out);
    nickArea->clear(); // get a new list of names
}

void Channel::NickPopup()
{
    keys->clear();
    popupList = Alias::LoadAliasList(IrcApp::GetFile(Settings::popupsFile), 97, keys);
    if (!popupList)
    {
        warning("could not load popupList");
        return;
    }
    popup = new KPopupMenu(nickArea->text(nickArea->currentItem()));
    connect(popup, SIGNAL(activated(int)), SLOT(PopupSelected(int)));
    QPopupMenu *subMenu = NULL;
    int iD = 0;
    for ( QString *a=keys->first(); a!=0; a=keys->next())
    {
        QString str = a->copy();
        if (str.left(1) == ".")
        {                
            str.remove(0, 1); // get rid of the .
            if (str.isEmpty()) // just a '.' means end of menu
            {
                popup->insertItem(subMenu->name(), subMenu, iD);
                subMenu = NULL;
            }
            else
            {
                if (subMenu)
                    subMenu->insertItem(str, iD);
                else
                    popup->insertItem(str, iD);
            }
        }
        else
        {
            if (subMenu)
                popup->insertItem(subMenu->name(), subMenu, iD);
            subMenu = new QPopupMenu(NULL, str);
            connect(subMenu, SIGNAL(activated(int)), SLOT(PopupSelected(int)));
        }
        iD++;
    }
    if (subMenu)
        popup->insertItem(subMenu->name(), subMenu);
    QPoint pt = QCursor::pos();
    popup->popup(pt);

}
    
void Channel::PopupSelected ( int iD)
{
    if (!popupList)
    {
        warning("Attempt to call popupselected with NULL popupList.");
        return;
    }
    QString key = *(keys->at(iD));
    QString str;
    str.sprintf("%s", popupList->find(key));
    QString nick = popup->title();
    if (nick.left(1)=="@" || nick.left(1) == "+")
        nick.remove(0,1);
    if (nick.left(1)=="@" || nick.left(1) == "+")
        nick.remove(0,1);
    QRegExp r("%nick");
    str.replace(r, (const char *)nick);
    r = QRegExp("%channel");
    str.replace(r, name());
    ParseInput(str);
    delete popupList;
    delete popup;
    popupList = NULL;
    popup = NULL;
}

void Channel::closeEvent(QCloseEvent *e)
{
    QString msg;            
    msg.sprintf("PART %s\r\n", name() ); 
    IrcApp::HandleEvent(Event::SOCKET_WRITE, msg);
    e->accept();
}

void Channel::resizeEvent(QResizeEvent *)
{
     int windowWidth = width() - NICK_AREA_WIDTH;
     nickArea->setGeometry ( (width()  - NICK_AREA_WIDTH),
                             0,
                             NICK_AREA_WIDTH,
                             height());
     commandArea->setGeometry ( 0, (height() - COMMAND_AREA_HEIGHT ),
                                windowWidth,
                                COMMAND_AREA_HEIGHT );
     outputArea->setGeometry(0,0,windowWidth, height()-COMMAND_AREA_HEIGHT );
}

#include "channel.moc"
