//$Id: windowview.cpp,v 1.8 1997/12/01 05:49:49 parallax Exp $
//Aaron Granick

#include "irc.h"
#include "ircapp.h"
//#include "OptionsDialog.h"
#include "options.h"
#include "JoinDialog.h"
#include <qtabdlg.h>
#include <qpalette.h>
#include <qcolor.h>
//KDE
#include <kmsgbox.h>

#define TASKBAR_WIDTH 100
#define STATUS_HEIGHT 20
#define MENU1_WIDTH 300
#define MENU2_WIDTH 100

WindowView::WindowView ( QWidget *, const char *name=0)
        : QWidget (NULL, name)
{
    // create the menu bar
    // tool = new KToolBar(this, "toolbar") ;
    mdi = new MDIManager(this, "mdi", IrcApp::GetFile("icons/pindown.xpm"), \
                            IrcApp::GetFile("icons/pinup.xpm"), IrcApp::GetFile("icons/minimize.xpm"), \
                            IrcApp::GetFile("icons/maximize.xpm"), IrcApp::GetFile("icons/close.xpm"));
    mdi->SetSmartPlacement(TRUE);
    connect(mdi, SIGNAL(WindowRemoved(MDIWindow *)), SLOT(RemoveWindow(MDIWindow *)) );
    menu = new QMenuBar (this, "menu");
    taskbarFrame = new QFrame(this);
    taskbarFrame->setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
    taskBar = new TaskBar(taskbarFrame, "taskbar");
    connect(this, SIGNAL(ApplyTheme()), taskBar, SLOT(ApplyTheme()) );
    connect(taskBar, SIGNAL(SelectWindow(const char *)), SLOT(SelectWindow(const char *)) );
//    taskBar->setFullWidth(true);
        
    status = new QFrame(this, "statusbar");
    status->setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
    // status->insertItem("Not connected.", 0);
    // setStatusBar (status);
      
    file = new QPopupMenu();
    file->insertItem ("&Connect", this, SLOT(Connect()) );
    file->insertItem("&Disconnect", this, SLOT(Disconnect()) );
    file->insertItem ("&Options", this, SLOT(Options()) );
    file->insertSeparator();
    file->insertItem ("&Quit", this, SLOT(Close()) );
   
    //  servers = new QPopupMenu();
    commands = new QPopupMenu();
    commands->insertItem ("&Join Channel", this, SLOT(JoinChannel()) );
    commands->insertItem("Apply Theme", this, SLOT(SlotApplyTheme()));
    window = new QPopupMenu();
    window->insertItem ("Tile Windows", mdi, SLOT(Tile()) );
    window->insertItem("Cascade Windows", mdi, SLOT(Cascade()) );
    window->insertSeparator();
  
    help = new QPopupMenu();
    help->insertItem("About...", this, SLOT(HelpAbout()) );

    menu->insertItem ("&File", file);
   
//    menu->insertItem ("&Servers", servers);
    menu->insertItem ("&Commands", commands);
    menu->insertItem ("&Window", window );
    menu->insertSeparator();
    menu->insertItem ("&Help", help );

/*    tool = new QMenuBar(taskbarFrame, "toolbar");
    QPixmap p;
    p.load(IrcApp::GetFile("icons/connect.xpm"));
    tool->insertItem(p, this, SLOT(Connect()));
    p.load(IrcApp::GetFile("icons/disconnect.xpm"));
    tool->insertItem(p, this, SLOT(Disconnect()));*/
//    tool->insertItem("Console", this, SLOT(ShowConsole()));
    accel = new QAccel( this, "accelerator" );  
    accel->connectItem( accel->insertItem(Key_Tab), 
                        mdi,                 
                        SLOT(NextWindow()) );      
    
    general = NULL;
    appearance = NULL;
    popups = NULL;
    aliases = NULL;
    startup = NULL;
    themeDlg = NULL;
    SlotApplyTheme();
//    currentWindow = NULL;
    // load popups
    // NickList::LoadPopups();

}
    
WindowView::~WindowView()
{
    
}

void WindowView::SlotApplyTheme()
{
    IrcApp::ApplyTheme();
    IrcApp::SetThemeProperties(menu, Settings::theme.mainWindow);
    //    IrcApp::SetThemeProperties(status, Settings::theme.mainWindow);
    IrcApp::SetThemeProperties(file, Settings::theme.mainWindow);
    IrcApp::SetThemeProperties(help, Settings::theme.mainWindow);
    IrcApp::SetThemeProperties(window, Settings::theme.mainWindow);
    IrcApp::SetThemeProperties(commands, Settings::theme.mainWindow);
    IrcApp::SetThemeProperties(taskBar, Settings::theme.mainWindow);

    IrcApp::SetThemeProperties(mdi, Settings::theme.mdi);
    //   IrcApp::SetBackgroundPicRecursive(menu, backgroundPixmap());
    emit ApplyTheme();
}

void WindowView::AddWindow( const char *name, WindowType type, bool isMinimized )
{
    IrcWindow*w = GetWindowByName(name);
    if (w)
    {// the window already exists
        debug("WindowView::AddWindow: warning: window %s already exists", name);
        // if (w->Type() == IrcWindow::CHANNEL)
        // w->RefreshNickList();
    }
    else
    {
        switch (type)
        {
            case CONSOLE:
                mdi->AddWindow((new Console(this, name)), false);
                break;
            case CHANNEL:
                mdi->AddWindow((new Channel(this, name)), false);
                break;
            case MESSAGE:
                mdi->AddWindow((new MessageWindow(this, name)), false);
                break;
            case DCC:
                mdi->AddWindow((new DCCWindow(this, name)), false);
                break;
        }

        MDIWindow *w = mdi->GetWindowByName(name);
        IrcWindow *win = (IrcWindow *)(w->Child());
        win->SetMDIWindow(w);
        win->ApplyTheme();
        win->UpdateCaption();
        w->SetCaption(win->caption());
        // add us to the window menu
        window->insertItem(name, w, SLOT(Select()));
        connect(w, SIGNAL(Selected(MDIWindow *)), win, SLOT(HandleFocus()));
        taskBar->AddWindow(w);

        // now connect all necessary signals/slots
        connect ( win, SIGNAL(RemoveWindow( const char *)), this, 
                  SLOT(RemoveWindow( const char * )) );
          connect(this, SIGNAL(ApplyTheme()), win, SLOT(ApplyTheme()) );
          connect(this, SIGNAL(OutputToAllWindows(const char *, int)), win, \
                    SLOT(Output(const char *, int)) );
        if (win->inherits("MessageWindow"))
        {
            connect ( this, SIGNAL(ChangeNick ( const char *, const char*)), win, \
                      SLOT(ChangeNick(const char*, const char*)) );
            connect (this, SIGNAL(Signoff(const char *, const char*)), win, \
                     SLOT(HandleSignoff(const char *, const char *)) );
        }
        if (win->inherits("Channel"))
        {            
            connect (this, SIGNAL(RemoveNick(const char *)), win, SLOT(RemoveNick(const char *)) );
            connect(this, SIGNAL(Rejoin()), win, SLOT(Rejoin()) );
        }
        if (isMinimized)
            w->Minimize();
        else
        {
            w->show();
            w->Select(); // make the new window selected
        }
        // now see if we should detach it
        w->setGeometry(w->x(), w->y(), w->width(), w->height());
        if (Settings::createDetached)
            w->Detach();
    } 
}

void WindowView::CloseWindow ( const char *n)
{
    RemoveWindow(n);
}

void WindowView::RemoveWindow ( const char *n )
{
    MDIWindow *w=(mdi->GetWindowByName(n));
    if (w)
    {
        w->Close();
    }  
}
void WindowView::RemoveWindow ( MDIWindow *w )
{  
    //taskBar->RemoveWindow(w);
    for (unsigned int i=0; i<window->count(); i++)
    {
        if ((QString(window->text(window->idAt(i)))).lower() == \
             (QString(w->name())).lower())
            window->removeItemAt(i);
    }
}

void WindowView::SelectWindow (const char *nm)
{
    MDIWindow *w = mdi->GetWindowByName(nm);
    if (w)
        w->Select(true);
}

void WindowView::HandleEvent (int event, const char *data1, const char *data2)
{
    switch(event)
    {
        case Event::SIGNOFF:
            emit Signoff(data1, data2);
            break;
        case Event::CHANGE_NICK:
            emit ChangeNick ( data1, data2);
            break;
             case Event::CONNECT:
//            tool->setItemEnabled(0, FALSE); // disable the connect button
            file->setItemEnabled(file->idAt(0), FALSE);
            //  status->changeItem("Registering with server...", 0);
            HandleEvent(Event::CHANGE_MY_NICK, Settings::myNick);
            HandleEvent(Event::CHANGE_SERVER, Settings::serverName);
            break;
        case Event::REGISTERED:
            //   status->changeItem("Connected.", 0);
            HandleEvent(Event::CHANGE_MY_NICK, Settings::myNick);
            emit Rejoin();
            break;
        case Event::DISCONNECTED:
            //          tool->setItemEnabled(0, TRUE); // disable the connect button
            file->setItemEnabled(file->idAt(0), TRUE);
            // status->changeItem("Not connected.", 0);
            break;
        case Event::CHANGE_MY_NICK:
            // tool->setLinedText(2, data1);
            // ChangeCombo(2, data1);
            emit ChangeNick ( Settings::myNick, data1);
            break;
        case Event::CHANGE_SERVER:
            // tool->setLinedText(3, data1);
            //ChangeCombo(3, data1);
            break;
        case Event::REMOVE_NICK:
        {
            Channel *w = (Channel *)(GetWindowByName(data1));
            if (w)
                w->RemoveNick ( data2 );
            else
                warning("WindowView::HandleEvent(REMOVE_NICK), no such channel %s", data1);
        }
        break;
        case Event::ADD_NICK:
        {
            Channel *w = (Channel *)(GetWindowByName(data1));
            if (w)
                w->AddNick ( data2 );
            else
                warning("WindowView::HandleEvent(ADD_NICK), no such channel %s", data1);
        }
        break;
        case Event::TOPIC:
        {
            Channel *w = (Channel *)(GetWindowByName(data1));
            if (w)
            {
                w->SetTopic(data2);
                w->UpdateCaption();
                MDIWindow *win = mdi->GetWindowByName(data1);
                win->SetCaption(w->caption());
            }
            else
                warning("WindowView::HandleEvent(TOPIC), no such channel %s", data1); 
        }
        break;
        case Event::NICK_MODE:
        {
            Channel *w = (Channel *)(GetWindowByName(data1));
            if (w)
            {
                QString nick(data2);
                int space = nick.find(" ");
                QString mode = nick.left(space);
                nick.remove(0, space+1);
                while (nick.find(" ") != -1)
                {
                    int s = nick.find(" ");
                    w->HandleNickMode(nick.left(s), mode);
                    nick.remove(0, s+1);
                }
                w->HandleNickMode(nick, mode);
            }
            else
                warning("WindowView::HandleEvent(NICK_MODE), no such channel %s", data1); 
        }
        break;
        case Event::CLOSE_ALL_WINDOWS:
            emit CloseAll();
            break;
        case Event::UPDATE_WINDOW_NAME:
        {
            IrcWindow *w = GetWindowByName(data1);
            if (w)
            {
                w->setName(data2);
                MDIWindow *win = mdi->GetWindowByName(data1);
                taskBar->UpdateName(win);
                w->UpdateCaption();
                //w->SetTopic();
                win->SetCaption(w->caption());
            }
            else
                warning("WindowView::HandleEvent(UPDATE_CHANNEL_NAME), no such channel %s", data1); 
        }
        break;
        case Event::ISON:
            taskBar->UpdateNotify(data1);
            break;
        default:
            warning("WindowView: Unhandled event: %d %s %s", event, data1, data2);
    }
}

void WindowView::JoinChannel ( )
{
    JoinDialog d;
    d.exec();
    if (d.result())
    {
        QString chan = d.Channel();
        if (chan != "")
        {
            if (chan[0] != '#')
                chan.prepend("#");
            QString out = "JOIN ";
            out += chan += "\r\n";
            IrcApp::HandleEvent(Event::SOCKET_WRITE, out);
        }
    }
        
}

IrcWindow *WindowView::GetWindowByName ( const char *name )
{
//    if (!name)
    //      name = "Status"; // 
    MDIWindow *win = mdi->GetWindowByName(name);
    if (win)
        return ((IrcWindow *)(win->Child()));
    else
        return NULL;
    
}

void WindowView::OutputToWindow ( int type, const char *name, const char *buff )
{
    // If no name is specified, the message goes to your current channel
    // if no current channel, the topmost window is selected
    // if all minimized, the console is selected
    MDIWindow *win = NULL;
    QString n(name);
    if (n.isEmpty()) // send to current window by default
    {
        win = (mdi->SelectedWindow());
        if (!win) // no focus at all....find a window, and select it
        {
            if (!(mdi->SetWindowFocus()))
            {
                win = mdi->GetWindowByName(CONSOLENAME);
                win->Select(true); // select the console
            }
            else
                win = (mdi->SelectedWindow());
        }
        if (!win)
        {
            debug("Could not output to a window!!!!");
            return;
        }
            
        if (win->IsMinimized())
        {
            debug("window is minimized");
            if (!mdi->SetWindowFocus())
            {
                mdi->GetWindowByName(CONSOLENAME)->Select(true);
            }
            win = (mdi->SelectedWindow());
        }
//        debug("Focus widget: %s", win->name());  
    }
    else
    {
        
        win = mdi->GetWindowByName ( n );
        if (!win)
        {
            if (name[0] == '#') // sometimes we get stray channel msgs
            {
                warning("Stray channel msg %s, %s", name, buff);
                return;
            }
             // it is a privmessage
            emit NewMessage(type, name, buff);
            return;
        }
    }
     
    IrcWindow *iwin = (IrcWindow *)(win->Child());
    iwin->Output ( buff, type );      
}

void WindowView::Close()
{
    close();
}

void WindowView::closeEvent( QCloseEvent *e)
{
    // first close all windows, so their destructors get called
    QList<MDIWindow> *list = mdi->WindowList();
    for (MDIWindow *w=list->first(); w!= 0; w=list->next())
        w->close(true);
    IrcApp::HandleEvent(Event::QUIT, NULL); 
    e->accept();
}

void WindowView::Connect()
{
    IrcApp::HandleEvent(Event::CONNECT, NULL);
}

void WindowView::Disconnect()
{
    IrcApp::HandleEvent(Event::DISCONNECT, Settings::quitMessage);
}

void WindowView::UpdateCaption ( const char *win, const char *msg )
{
    MDIWindow *w = mdi->GetWindowByName(win);
    if (w)
        w->SetCaption (msg);
}

void WindowView::SetNick()
{
//    ChangeMyNick(tool->getLinedText(2));
}

void WindowView::SetServer()
{
//    ChangeServer(tool->getLinedText(3));
}

void WindowView::ChangeServer ( const char *newServer)
{
    IrcApp::HandleEvent(Event::CHANGE_SERVER, newServer);
}

void WindowView::ChangeMyNick ( const char *newnick)
{
    QString msg;
    msg.sprintf("NICK %s\r\n", newnick);
    IrcApp::HandleEvent(Event::SOCKET_WRITE, msg);
}

void WindowView::HelpAbout()
{
    QString out(512);
    out.sprintf ("kIRC v.%s by Aaron Granick.\nSend inquries and (complete)bug reports\nto parallax@ucsd.edu.", VERSION);
    KMsgBox about(NULL, "About kIRC", out,
                  KMsgBox::INFORMATION, "Ok");
    about.exec();
}

void WindowView::Options()
{
    OptionsDialog *d = new OptionsDialog(NULL, "Options");
    d->setCaption("kIRC Options");
    //create all our little dialogs
    general = new GeneralOptions(d, "general");
    aliases = new EditFile(d, "aliases");
    aliases->setFileName(Settings::aliasesFile);
    popups = new EditFile(d, "popup");
    popups->setFileName(Settings::popupsFile);
    startup = new EditFile(d, "startup");
    startup->setFileName(Settings::startupFile);
    appearance = new VisualOptions(d, "appearance");
    dccOptions = new DCCOptions(d, "dcc options");
    // themeDlg = new ThemeDlg(d, "themes");
    d->AddDialog(general, "General");
    d->AddDialog(appearance, "Appearance");
    d->AddDialog(aliases, "Aliases");
    d->AddDialog(popups, "Popups");
    d->AddDialog(startup, "Startup");
    d->AddDialog(dccOptions, "DCC");
//    d->AddDialog(themeDlg, "Theme");
    connect(d, SIGNAL(ApplyButtonPressed()), SLOT(slotApplyChanges()));
    d->exec();
    d->recreate(0,0,QPoint(0,0)); // a fucking hack
    d->close(true);
    //  Settings::theme = themeDlg->GetTheme(); // this is weird, because we have to modify Settings::theme
}

void WindowView::slotApplyChanges()
{
    if (general)
        general->SaveAll();
    if (appearance)
        appearance->SaveAll();
    if (aliases)
        Settings::aliasesFile = aliases->getFileName();
    if (popups)
        Settings::popupsFile = popups->getFileName();
    if (startup)
        Settings::startupFile = startup->getFileName();
    if (dccOptions)
        dccOptions->SaveAll();
    // if (themeDlg)
    //   themeDlg->SaveAll();
    IrcApp::HandleEvent(Event::WRITE_CONFIG, NULL);
    
    // now reload our aliases
    //   QList<Alias> *aliases = Alias::LoadAliasList(IrcApp::GetFile(Settings::aliasesFile));
    // Client::SetAliases(aliases);
}


void WindowView::OutputToAll(int type, const char *buff)
{
    emit OutputToAllWindows(buff, type);
}

void WindowView::resizeEvent ( QResizeEvent *)
{
    menu->setGeometry(0,0,width(), menu->height());
    taskbarFrame->setGeometry(0, menu->height(), TASKBAR_WIDTH, height()-menu->height());
    QRect r = taskbarFrame->contentsRect();
//    tool->setGeometry(r.x(), r.y(), r.width(), tool->height());
    taskBar->setGeometry(r.x(),r.y(), r.width(), \
                           r.height());
    status->setGeometry(taskbarFrame->width(), height()-STATUS_HEIGHT, \
                        width()-taskbarFrame->width(), STATUS_HEIGHT);
    mdi->setGeometry(taskbarFrame->width(), menu->height(), \
                     width()-taskbarFrame->width(), height()-menu->height()-status->height());
}

void WindowView::ShowConsole()
{


}

#include "windowview.moc"
