#include <QTextDocument>
#include <QTextCursor>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QLineEdit>
#include <QShortcut>
#include <QListView>
#include <QTextEdit>
#include <QTime>
#include <Irc>
#include <IrcUser>
#include <IrcBuffer>
#include <IrcCommand>
#include <IrcMessage>
#include <IrcUserModel>
#include <IrcCompleter>
#include <IrcConnection>
#include <IrcBufferModel>
#include <IrcCommandParser>
static const char* CHANNEL = "#communi";
static const char* SERVER = "irc.freenode.net";
IrcClient::IrcClient(QWidget* parent) : QSplitter(parent)
{
    createParser();
    createConnection();
    createCompleter();
    createUserList();
    createLayout();
    createBufferList();
    
    connection->open();
    textEdit->append(IrcMessageFormatter::formatMessage(tr(
"! Welcome to the Communi %1 example client.").arg(
IRC_VERSION_STR)));
    textEdit->append(IrcMessageFormatter::formatMessage(tr("! This example connects %1 and joins %2.").arg(SERVER, CHANNEL)));
    textEdit->append(IrcMessageFormatter::formatMessage(tr("! PS. Available commands: JOIN, ME, NICK, PART")));
}
IrcClient::~IrcClient()
{
    if (connection->isActive()) {
        connection->quit(connection->realName());
        connection->close();
    }
}
void IrcClient::onConnected()
{
    textEdit->append(IrcMessageFormatter::formatMessage("! Connected to %1.").arg(SERVER));
    textEdit->append(IrcMessageFormatter::formatMessage("! Joining %1...").arg(CHANNEL));
}
void IrcClient::onConnecting()
{
    textEdit->append(IrcMessageFormatter::formatMessage("! Connecting %1...").arg(SERVER));
}
void IrcClient::onDisconnected()
{
    textEdit->append(IrcMessageFormatter::formatMessage("! Disconnected from %1.").arg(SERVER));
}
void IrcClient::onTextEdited()
{
    
    lineEdit->setStyleSheet(
QString());
}
void IrcClient::onTextEntered()
{
    if (command) {
        connection->sendCommand(command);
        
            receiveMessage(msg);
            delete msg;
        }
        lineEdit->clear();
    } 
else if (input.
length() > 1) {
        QString command = lineEdit->text().mid(1).split(
" ", QString::SkipEmptyParts).value(0).toUpper();
         if (parser->commands().contains(command))
            error = tr(
"[ERROR] Syntax: %1").
arg(parser->syntax(command).replace(
"<", 
"<").replace(
">", 
">"));
        else
            error = tr(
"[ERROR] Unknown command: %1").
arg(command);
        textEdit->
append(IrcMessageFormatter::formatMessage(error));
        lineEdit->setStyleSheet("background: salmon");
    }
}
void IrcClient::onCompletion()
{
    completer->complete(lineEdit->text(), lineEdit->cursorPosition());
}
void IrcClient::onCompleted(
const QString& text, 
int cursor)
 {
    lineEdit->setText(text);
    lineEdit->setCursorPosition(cursor);
}
void IrcClient::onBufferAdded(
IrcBuffer* buffer)
 {
    
    
    QTextDocument* document = new QTextDocument(buffer);
    documents.insert(buffer, document);
    
    userModels.insert(buffer, userModel);
    
    int idx = bufferModel->buffers().indexOf(buffer);
    if (idx != -1)
        bufferList->setCurrentIndex(bufferModel->index(idx));
}
void IrcClient::onBufferRemoved(
IrcBuffer* buffer)
 {
    
    delete userModels.take(buffer);
    delete documents.take(buffer);
}
void IrcClient::onBufferActivated(
const QModelIndex& index)
 {
    
    textEdit->setDocument(documents.value(buffer));
    textEdit->verticalScrollBar()->triggerAction(QScrollBar::SliderToMaximum);
    userList->setModel(userModels.value(buffer));
    completer->setBuffer(buffer);
    
    if (buffer)
        parser->setTarget(buffer->
title());
}
void IrcClient::onUserActivated(
const QModelIndex& index)
 {
    if (user) {
        
        int idx = bufferModel->buffers().indexOf(buffer);
        if (idx != -1)
            bufferList->setCurrentIndex(bufferModel->index(idx));
    }
}
static void appendHtml(QTextDocument* document, 
const QString& html)
 {
    QTextCursor cursor(document);
    cursor.beginEditBlock();
    cursor.movePosition(QTextCursor::End);
    if (!document->isEmpty())
        cursor.insertBlock();
    cursor.insertHtml(html);
    cursor.endEditBlock();
}
void IrcClient::receiveMessage(
IrcMessage* message)
 {
    if (!buffer)
    QTextDocument* document = documents.value(buffer);
    if (document) {
        QString html = IrcMessageFormatter::formatMessage(message);
             if (document == textEdit->document())
                textEdit->append(html);
            else
                appendHtml(document, html);
        }
    }
}
void IrcClient::createLayout()
{
    
    textEdit = new QTextEdit(this);
    textEdit->setReadOnly(true);
    
    lineEdit = new QLineEdit(this);
    lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false);
    textEdit->setFocusProxy(lineEdit);
    connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(onTextEntered()));
    connect(lineEdit, SIGNAL(textEdited(
QString)), 
this, SLOT(onTextEdited()));
    
    QSplitter* splitter = new QSplitter(this);
    splitter->setHandleWidth(1);
    splitter->addWidget(textEdit);
    splitter->addWidget(userList);
    splitter->setStretchFactor(0, 5);
    splitter->setStretchFactor(1, 1);
    QWidget* container = new QWidget(this);
    QVBoxLayout* layout = new QVBoxLayout(container);
    layout->setSpacing(0);
    layout->setMargin(0);
    layout->addWidget(splitter);
    layout->addWidget(lineEdit);
    addWidget(container);
    setHandleWidth(1);
}
void IrcClient::createCompleter()
{
    
    completer->setParser(parser);
    connect(completer, SIGNAL(completed(
QString,
int)), 
this, SLOT(onCompleted(
QString,
int)));
    QShortcut* shortcut = new QShortcut(Qt::Key_Tab, this);
    connect(shortcut, SIGNAL(activated()), this, SLOT(onCompletion()));
}
void IrcClient::createParser()
{
    
    
    
    parser->setTolerant(true);
}
void IrcClient::createUserList()
{
    
    userList = new QListView(this);
    userList->setFocusPolicy(Qt::NoFocus);
    
}
void IrcClient::createBufferList()
{
    connect(bufferModel, SIGNAL(removed(
IrcBuffer*)), 
this, SLOT(onBufferRemoved(
IrcBuffer*)));
    bufferList = new QListView(this);
    bufferList->setFocusPolicy(Qt::NoFocus);
    bufferList->setModel(bufferModel);
    
    
    
    IrcBuffer* serverBuffer = bufferModel->add(connection->host());
     
    connect(bufferModel, SIGNAL(messageIgnored(
IrcMessage*)), serverBuffer, SLOT(receiveMessage(
IrcMessage*)));
    insertWidget(0, bufferList);
    setStretchFactor(0, 1);
    setStretchFactor(1, 3);
}
void IrcClient::createConnection()
{
    connect(connection, SIGNAL(connected()), this, SLOT(onConnected()));
    connect(connection, SIGNAL(connecting()), this, SLOT(onConnecting()));
    connect(connection, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
    connection->setHost(SERVER);
    connection->setUserName("communi");
    connection->setNickName(tr("Client%1").arg(qrand() % 9999));
    connection->setRealName(tr(
"Communi %1 example client").arg(
IRC_VERSION_STR));
}