summaryrefslogblamecommitdiffstats
path: root/src/server/mainwindow/mainwindow.cpp
blob: 76f5e0070a42ed43da43c1049ba2b818687647df (plain) (tree)



















                                                                                
                            



                                                   
                                     
                                                 



                                     
                                  





                                  
                          
 
                   

                 








                                                                                 
 
                  

                
 
                                                                                



                                          
                                         
                                                                                                  
 
                                     
                                
                             
 





                                                               
 
                                                         
                                           
                                            

                                                     
                          
                                                
 
                                 















                                                                        
 

                                                                                  

                                                                                                      
                                                                                                                        
                                                                                                      
                                                                                                      
                                                                                              
                                                                                                  
                                                                                        
                                                                                  
                                                                                                                  
                                                                                        
 




                                                      

                                     


                         
                                       
                         


                                                        

                                                                                  

                                  




                                            
 









                                                                                        




                                                                                                   


                                                                
 
                               







                                         






                                                                  
                                                                                







                                                                                

               
                                                                               
 
                                                                   




                                                                                     

                                                                                                          










                                                                                     

                                                                   




























                                                                                                

 
                                                                                




                                                              


                                          

                                                                                  

                                                                              

                                 
                                                                                                                    
                                                                                                       


                  
                                                                                




                                                              
                                                                                                 

                              
                                                


                                                                                    

                                                                               
                                      

                                        

                                 
                                                                                                                    





                                                                                                       






                                           


                                                                                     
                                                     








                                             
                                                                                


                                          




                                                  
                                                                                        

                                               
                                             


                            







                                                                                
                                                                         


                                         
                                                                     

                                                                                  
                 
         
 
 

 


















                                                                                        
                                                                                



                                          
                                         
                                        
                              
 
                                                                                    


                                                               

                        
                                      
         
                                          



                                                           
                                              




                                                                                                                        

                                                                                                         


                                
                                  


                                                                                                           





                                                       


                                                           

         

                                                                                                              
                                                                   
                                  


                                
 





                                                                          
                                                                                  
                                                                                            
                                      
         
                                    






                                                                                                                        

                             
    


                                                                                




                                                                












                                                                                                          































                                                                                                          



                     
                                                                                



                                                        

                                           
                                                                                                     





                                      
                                                                                


                




                                       



















                                                                                       
                                                                                


                

                                             

                                                
 

















                                                                                                                                
                                                                                                           
         



                                                                       
                                                                                                       
                            
         
 

 












                                                                                







                                                              
                                                     


     
 
                                                                                




                                                                                                   










                                                                        
                             


                                                                



                 




                                                                                

                           





                                                                                                          

                                                                   
 




        
 
                                                                                



                                                                                
   
                                                                                   


                                         




                                                                    
                    
                      

                                                  
                                  

                    
                      

                                                    
                                  
     















                                                                                                          

                 






                                                                                      

 
                                                                                


                                            

                                                       
                                                      
                                        



                                                          






                                                                                

                           

 
                                                                                

                                              

                                     


                                        

                                                                                                                                                                                                     






                                                                        

 
                                                                                

                       

                                      

                                                                                                
                                        
         
                 





                                                                                                                          
                 
         


                                                                                                       
                                                                                
                                               
              
   
                                                    
 

                                                       
 
                                                                    

                                                   
 

                                   
 



                                                                
                                                                                
                                             
         

 

                                           

                                                                                                    

                                                                                                    


                                                                                         


                              







                                                                                                       









                                                     
                                                                                            

                                      




                                                                              








                                                                                                          




















                                                                       

                                 

                                                               
                                                                                                          

                       















                                                                                                                                                                                                                                             
                                   



                                                     
     

 






                                                   
                                                                                







                                                                                


                                                                  


                                     

                                           
                                    
                                                                             
                                                   
                                                                                

                                                                            

            

                                                                   
                                


                               





                                                                                                                                                                        


                                                                           


                                                                                

                                                                     
   
                                         
 

                                           
                                       
                                                                            
                                         
                                                                             
                                                       
                                                                                  
                                                      
                                                                               
                                                   
                                                                                

            
                                                                            
                                               
                                                                                                                          
                                                            
                                                                                               


                                                         
                                                                                                                
                                                                                            
                    
                                                                                                                  
 
                                 


                                                                           

 
                                                                                

                                                                      
   
                                         
 

                                           
                                       
                                                                              
                                         
                                                                             
                                                       
                                                                                  
                                                      
                                                                                 
                                                   
                                                                                



                                                                                                                    
                 



                                                

                 

                                                                                                                          
                                                    
                                                                                                                                                                                     
 

                                      

                                                                              

 
 
                                                                                
                                                     
   
                                                  
 

                                           
                                       
                                                                              
                                         
                                                                             
                                                       
                                                                                  
                                                      
                                                                                 
                                                   
                                                                                

            

                                                                                                                    
                 



                                                

                 






                                                                                                                                                                                     
                                                                              
         

 
 
                                                                                
                                
                                                                            
                                                       
   

                                         

                                           

 
                                                                                
                                                        
                                                                             
                                         

                 

                                           
                               
                
 

                                                                                                          
                                            
                                 
                                                     


         
                                                                                

                                     




                               
                                                                                


                                                                             

                                     

                                           
                                            
                                       

                                                                                           
                       
         
 
                                                                    
                                                 
         

                                                                                                          
         
                                                           


                                                                

                                                     
                                                  
                       

                                                   




                                                 

 
                                                                                


                                                           

                                                  

                                                                                                                                  

 
                                                                                
                                  




                                                                                                 


                 




































                                                                                                                                     
                                                                                






                                                                                                                                                     

                


                                                                                                       

                                                                                                            
                                    


                                                                                                          


                                                                            
                                                        
                 
                                       
                 

                                     
                                                    


                                                      






                                                            
                                                          





                                               
                                                         

                             
                                                                
                                            
                                               
                                                   

                       
 





                                            
                                                   


                                     
                                                           









                                         
                                                                      
                                       





                                         

                              

                                 
 
                                                                      
                                           
 
 
 
                                                                                




                                                                                                 

                                                       
                                                        

                                
                                        
         


                                                                                                                  
                         

                                                                                                 


                                                                         
                                                                                                                                                      
                         

                                                       



                                                                                                                    



                                                                                                                  

                                                                                                 
                                                                         


                                                                                  
                         
                 

                                                                                                                    





                                                                                                         


         
                                                                                




                                                                                   
                                                       
 
                           

                                                             




                                                                                                 
 
                          



                                                                                      



                                                                                         





                                                                                                                          
                                         





                                                                                        

                         
         
 
 


                                                                                

                                 
                                   
                                  

                                             

 


                                                                                

                                
                                  
                                 

                                             
 


















                                                                                                                   
                                 









                                                      
/*
 # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
 #
 # This program is free software distributed under the GPL version 2.
 # See http://openslx.org/COPYING
 #
 # If you have any feedback please consult http://openslx.org/feedback and
 # send your suggestions, praise, or complaints to feedback@openslx.org
 #
 # General information about OpenSLX can be found at http://openslx.org/
 # -----------------------------------------------------------------------------
 # mainWindow.cpp
 This is the Main class for the pvsManager. The GUI is constructed here.
 # -----------------------------------------------------------------------------
 */
// Self
#include "mainwindow.h"
// QT stuff
#include <QtGui>
#include <QFileDialog>
#include <QNetworkInterface>
// Other custom UI elements
#include "../clicklabel/clicklabel.h"
#include "../sessionnamewindow/sessionnamewindow.h"
#include "../connectionframe/connectionframe.h"
#include "../helpwindow/helpwindow.h"
#include "../reloadroomwindow/reloadroomwindow.h"
// Network
#include "../net/listenserver.h"
#include "../net/client.h"
#include "../net/discoverylistener.h"
#include "../net/filedownloader.h"
// Others
#include "../../shared/settings.h"
#include "../util/util.h"
#include "../util/global.h"
// Auto-generated ui class
#include "ui_mainwindow.h"
#include "ui_reloadroom.h"

#include <iostream>
#include <vector>

#define sStrTutorNdef MainWindow::tr("No tutor defined.")
#define sStrTutorOffline MainWindow::tr("Tutor is offline.")
#define sStrSourceNdef MainWindow::tr("Please select a projection source.")
#define sStrSourceOffline MainWindow::tr("The projection source is offline.")
#define sStrDestNdef MainWindow::tr("Please select a projection destination.")
#define sStrDestOffline MainWindow::tr("The projection destination is offline.")
#define sStrSourceDestSame MainWindow::tr("Selected projection target is tutor.")
#define sStrClientOnline MainWindow::tr("Selected client is currently online.")
#define sStrNoDestAv MainWindow::tr("No projection destination available.")

using std::vector;
using std::cout;
using std::endl;

/***************************************************************************//**
 * Initialize MainWindow and ListenServer.
 * @param ipListUrl
 * @param parent
 */
MainWindow::MainWindow(QWidget* parent) :
	QMainWindow(parent), ui(new Ui::MainWindow), _tbIconSize(24), _tbArea(Qt::LeftToolBarArea)
{
    qDebug() << "MainWindow(parent)";
	_mode = Mode::Multicast;
	_streamingSource = 0;

    /* default value, these will be updated a room is loaded */
    _tilesX = 10;
    _tilesY = 10;

    _virtCols = 0;
    _virtRows = 0;

	_sessionNameWindow = new SessionNameWindow(this);
	_helpWindow = new HelpWindow(this);
	_helpWindow->setWindowTitle("Help");
	_reloadWindow = new ReloadRoomWindow(this);
	_reloadWindow->setWindowTitle("Reload Room");
	ui->setupUi(this);
	setWindowFlags(Qt::FramelessWindowHint);

	Global::setSessionName();

	//conWin = new ConnectionWindow(ui->widget);
	//ui->VconWinLayout->addWidget(conWin);
	//conList = new ConnectionList(ui->ClWidget);
	//ui->ClientGLayout->addWidget(conList);

	// Show only session name label, not textbox
	_sessionNameLabel = new ClickLabel(this);
	ui->mainLayout->addWidget(_sessionNameLabel);

	ui->frmRoom->setStyleSheet("background-color:#444");

	// toolbar and actions in pvsmgr
	ui->action_Exit->setStatusTip(tr("Exit"));
	ui->action_Lock->setStatusTip(tr("Lock or Unlock all Clients"));


	// Close button in tool bar
	connect(ui->action_Exit, SIGNAL(triggered()), this, SLOT(onButtonExit()));
	connect(ui->action_TutorToAll, SIGNAL(triggered()), this, SLOT(onButtonTutorToAll()));
	connect(ui->action_StudentToTutor, SIGNAL(triggered()), this, SLOT(onButtonStudentToTutor()));
	connect(ui->action_StudentToTutorExclusive, SIGNAL(triggered()), this, SLOT(onButtonStudentToTutorExclusive()));
	connect(ui->action_TutorToStudent, SIGNAL(triggered()), this, SLOT(onButtonTutorToStudent()));
	connect(ui->action_StopProjection, SIGNAL(triggered()), this, SLOT(onButtonStopProjection()));
	connect(ui->action_SetAsTutor, SIGNAL(triggered()), this, SLOT(onButtonSetAsTutor()));
	connect(ui->action_SetAsTutor, SIGNAL(triggered()), this, SLOT(onButtonStopProjection()));
	connect(ui->action_Lock, SIGNAL(toggled(bool)), this, SLOT(onButtonLock(bool)));
	connect(ui->action_Help, SIGNAL(triggered()), this, SLOT(onButtonHelp()));
	connect(ui->actionReload_Room_Configuration, SIGNAL(triggered()), this, SLOT(onButtonReloadRoomConfig()));
    connect(ui->action_DeleteClient, SIGNAL(triggered()), this, SLOT(onDeleteClient()));

    /* disable context-sensitive buttons by default */
    _contextButtons
        << ui->action_DeleteClient
        << ui->action_StudentToTutor
        << ui->action_StudentToTutorExclusive
        << ui->action_SetAsTutor
        << ui->action_TutorToStudent;
    
    lockContextButtons();

	/* Stuff for the button lock */
	//Setup a timeout
	_buttonLockTimer = new QTimer(this);
	_buttonLockTimer->setSingleShot(true);
	_buttonLockTimer->setInterval(_buttonBlockTime);
	connect(_buttonLockTimer, SIGNAL(timeout()), this, SLOT(EnableButtons()));
	// Define the locking buttons
	_lockingButtons
		<< ui->action_Lock
		<< ui->action_TutorToAll
		<< ui->action_StudentToTutor
		<< ui->action_TutorToStudent
		<< ui->action_StopProjection
		<< ui->action_SetAsTutor;

	// Clicking the session name label shows the edit field for it
	connect(_sessionNameLabel, SIGNAL(clicked()), this, SLOT(onSessionNameClick()));
	// Listen to updates to the session name through the session name window
	connect(_sessionNameWindow, SIGNAL(updateSessionName()), this,
	   SLOT(onSessionNameUpdate()));

	setAttribute(Qt::WA_QuitOnClose);
	setUnifiedTitleAndToolBarOnMac(true);
	this->showMaximized(); // show the Mainwindow maximized

	_listenServer = new ListenServer(CLIENT_PORT);
	connect(_listenServer, SIGNAL(newClient(Client*)), this, SLOT(onClientConnected(Client*)));
	_discoveryListener = new DiscoveryListener();

	// Finally
	_countSessionNameUpdate = 0;
	this->onSessionNameUpdate(); // Just make lable visible.
	_countSessionNameUpdate = 0;

	tryToUseRoomTemplate();
}

MainWindow::~MainWindow()
{
	_sessionNameLabel->deleteLater();
	delete ui;
}

/** Euclidean distance (why is this not implemented in QPoint?) */
float distance(QPoint a, QPoint b) {
    int dx = a.x() - b.x();
    int dy = a.y() - b.y();
    int sum = dx*dx + dy*dy;
    return sqrt((float) sum);
}
/***************************************************************************//**
 * Place the frame into a free position that is closest (Euclidean distance) to
 * the preferred point.
 *
 * If current position out of range, place frame into the closest free cell.
 * 'Algorithm': ideally, go in circles around the preferred point until you find
 * a free spot. Lazy way: store all free positions in an array and find later
 * there the closest (<- that's what I do)
 * 
 * @param frame
 */
void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame, QPoint preferred)
{
    const QSize& clientSize = Global::getCurrentRoom()->clientSize;
	/* Get occupied cell of each frame and store status in an array */
	bool grid[_tilesX][_tilesY];
	memset(grid, 0, sizeof(bool) * _tilesX * _tilesY); // set everything to false

    /* fill grid */
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
        const QPoint& position = (*it)->getGridPosition();
        
        for (int x = position.x(); x < position.x() + clientSize.width(); x++) {
            for (int y = position.y(); y < position.y() + clientSize.height(); y++) {
                grid[x][y] = true;
            }
        }
    }

	/* Now place in next free cell, start looking at current position of frame */
    vector<QPoint> freePositions; 
    for (int x = 0; x <= _tilesX - clientSize.width(); x++) {
        for ( int y = 0; y <= _tilesY - clientSize.height(); y++) {
            /* check if (x,y) is free */ 
            bool isFree = true;
            for (int dx = 0; dx < clientSize.width(); dx++) {
                for (int dy = 0; dy < clientSize.width(); dy++) {
                    if (grid[x + dx][y + dy]) {
                        isFree = false;
                    } 
                }
            }
            if (isFree) {
                QPoint freePos(x,y); 
                freePositions.push_back(freePos);
            }
        }
    }
    /* among all the free positions, find the closest */
    float min_distance = 10000;
    QPoint bestPosition = QPoint(-1, -1);

    for (QPoint freePos : freePositions) {
        float dist = distance(freePos, preferred);
        if (dist < min_distance) {
            min_distance = dist;
            bestPosition = freePos;
        }
    }
    frame->setGridPosition(bestPosition);
    QPoint freePosPx(bestPosition.x() * getTileWidthPx(), bestPosition.y() * getTileHeightPx());
    frame->setCurrentPosition(freePosPx);
}

/***************************************************************************//**
 * Create new Frame.
 * Create new frame and add to current available frame list.
 * Also connect signals frameMoved() and clicked() with slots.
 * @return ConnectionFrame*
 */
ConnectionFrame* MainWindow::createFrame()
{
	// Allocate and resize
    int width = getTileWidthPx() * Global::getCurrentRoom()->clientSize.width();
    int height= getTileHeightPx() * Global::getCurrentRoom()->clientSize.height();

	ConnectionFrame *cf = new ConnectionFrame(ui->frmRoom, width, height);
	_clientFrames.append(cf);
	cf->show();
	connect(cf, SIGNAL(frameMoved(bool, ConnectionFrame *)), this, SLOT(onPlaceFrame(bool, ConnectionFrame *)));
	connect(cf, SIGNAL(clicked(ConnectionFrame *)), this, SLOT(onFrameClicked(ConnectionFrame *)));
	return cf;
}

/***************************************************************************//**
 * Create new Frame.
 * Create new frame and add to current available frame list.
 * Also connect signals frameMoved() and clicked() with slots.
 * @return ConnectionFrame*
 */
ConnectionFrame* MainWindow::createFrame(QString computerId, QPoint pxCoord, QPoint gridPosition)
{
	// Allocate and resize
    const Room* room = Global::getCurrentRoom();
    qDebug() << "createFrame, access room: " << room;
    int width = getTileWidthPx() *  (room == NULL ? 1 : room->clientSize.width());
    int height = getTileHeightPx() * (room == NULL ? 1 : room->clientSize.height());

	ConnectionFrame *cf = new ConnectionFrame(ui->frmRoom, width, height); 
	cf->setComputerId(computerId);
	cf->setCurrentPosition(pxCoord);
    cf->setGridPosition(gridPosition);
	_clientFrames.append(cf);
	cf->show();
	connect(cf, SIGNAL(frameMoved(bool, ConnectionFrame *)), this, SLOT(onPlaceFrame(bool, ConnectionFrame *)));
	connect(cf, SIGNAL(clicked(ConnectionFrame *)), this, SLOT(onFrameClicked(ConnectionFrame *)));
	return cf;
}


/***************************************************************************//**
 * Load position.
 * @param settings
 * @param id
 * @param x
 * @param y
 * @return If loadPosition was successfull.
 */
bool MainWindow::loadPosition(QSettings& settings, const QString& id, int& x, int& y)
{
	settings.beginGroup("client_position");
	const QVariant retval = (settings.value(id));
	settings.endGroup();
	if (retval.type() != QVariant::Point)
		return false;
	const QPoint point(retval.toPoint());
	x = point.x();
	y = point.y();
	return true;
}

/***************************************************************************//**
 * Save position of given connectionFrame.
 * @param cf
 */
void MainWindow::savePosition(ConnectionFrame *cf)
{
	Client *client = cf->client();
	if (client == NULL)
		return;
	QPoint pos(cf->pos().x() / getTileWidthPx(), cf->pos().y() / getTileHeightPx());
	USER_SETTINGS(settings);
	settings.beginGroup("client_position");
	settings.setValue(client->ip(), pos);
	settings.endGroup();
}

/***************************************************************************//**
 * Tells the new client the current situation in class room.
 * Set the specific parameters like projection source or lock screen.
 * @param client
 */
void MainWindow::tellClientCurrentSituation(Client* client)
{
	// If clients are currently locked, tell this new client
	if (ui->action_Lock->isChecked() || _mode == Mode::LockedUnicast)
		client->lockScreen(true);

	if (_mode == Mode::Broadcast){
		client->setDesiredProjectionSource(_streamingSource);
		if (_streamingSource != 0) {
			client->startVncClient(getClientFromId(_streamingSource));
		}
	}


}

/**
  * returns the minimal grid size such that all clients fit on the grid
  **/
QSize minimalGridSize(const QMap<QString, QPoint>& clientPositions, QSize& clientSize) {
    /* collect the maximum coordinates */
    int x = 0;
    int y= 0;

    for (auto it = clientPositions.begin(); it != clientPositions.end(); ++it) {
        QPoint pos = it.value();
        if (pos.x() > x) { x = pos.x(); }
        if (pos.y() > y) { y = pos.y(); }

    }
    /* need a little extra space */
    QSize size(x + clientSize.width(), y + clientSize.height());
    return size;
}

/***************************************************************************//**
 * @brief MainWindow::tryToUseRoomTemplate
 */
void MainWindow::tryToUseRoomTemplate()
{
    qDebug() << "tryToUseRoomTemplate()";
	QMap<QString, Room* > roomsList;
	SYSTEM_SETTINGS(conf);

	if (!conf.contains("rooms")) { qDebug() << "Invalid config file!"; return; }
	QStringList rooms = conf.value("rooms").toStringList();
	qDebug() << rooms;

    QString myRoom = "";

	for (QString roomName : rooms)
	{
		conf.beginGroup(roomName);
		if (!conf.contains("mgrIP")) {
			qDebug() << "Invalid config file!";
			return;
		}
        QMap<QString, QPoint> clientPositions;
		// First store all room configurations in _rooms.
		int size = conf.beginReadArray("client");
		for (int j = 0; j < size; j++) {
			conf.setArrayIndex(j);
			// qDebug() << "ip: " << conf.value("ip").toString() << " pos: " << conf.value("pos").toPoint();
			// roomsList[i].insert(conf.value("ip").toString(), conf.value("pos").toPoint());
            clientPositions.insert(conf.value("ip").toString(), conf.value("pos").toPoint());
		}
		conf.endArray();

        /* read backgroundImage */
        QString image   = conf.contains("backgroundImage") ? conf.value("backgroundImage").toString() : "";
		QString mgrIP   = conf.value("mgrIP").toString();
        QString tutorIP = conf.value("tutorIP").toString();
        
        QSize gridSize;
        QSize clientSize(1,1);
        /* read some other properties of the room */
        if (conf.contains("gridSize")) {
            gridSize = conf.value("gridSize").toSize();
        }
        if (conf.contains("clientSize")) {
            clientSize = conf.value("clientSize").toSize();
        }

		foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) {
			if (address != QHostAddress(QHostAddress::LocalHost) && mgrIP == address.toString()) {
				qDebug("Found this ip in config.");
                myRoom = roomName;
			}
		}
		conf.endGroup();

        if (!gridSize.isValid()) {
            /* ok, let's choose the minimum gridSize to fit all clients */
            gridSize = minimalGridSize(clientPositions, clientSize); 
            qDebug() << "had to use minimalGridSize(): = " << gridSize;

        }
        Room* r = new Room(clientPositions, gridSize, clientSize, image, tutorIP);
        qDebug() << "read new room: " << roomName << ": " << gridSize << ", " << clientSize;
        roomsList.insert(roomName, r);
	}
	Global::setRooms(roomsList);
    if (myRoom == "") {
        /* so apparently this is not a manager of a room */
        if (Global::manager_only) {
            cout << "exiting because of the argument --manager-only was set and this computer is not a manager" << endl;
            exit(0);
        }
    } else {
        switchRoomTo(myRoom);
    }
    
}

/***************************************************************************//**
 * Returns connected client which belongs to given id.
 * Iterating over ConnectionFrames and comparing id to given id.
 * @param id
 * @return Client with given id, if not NULL.
 */
Client* MainWindow::getClientFromId(int id)
{
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
		if ((*it)->client() != NULL)
		{
			if ((*it)->client()->id() == id)
				return (*it)->client();
		}
	}
	return NULL;
}

/***************************************************************************//**
 * Return the Frame, which is currently beeing Tutor.
 * Iterating over all ConnectionFrames, and looking for flag _isTutor.
 * @return Frame with flag _isTutor = true,
 * else NULL if no Tutor is available.
 */
ConnectionFrame* MainWindow::getTutorFrame()
{
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
		if (((*it) != NULL) && ((*it)->isTutor()))
			return (*it);
	}
	return NULL;
}

/***************************************************************************//**
 * Return the Frame, which is currently selected by user.
 * Iterating over all ConnectionFrame and looking for flag _isSelected.
 * @return Frame with flag _isSelected = true,
 * else NULL if no frame is selected.
 */
ConnectionFrame* MainWindow::getSelectedFrame()
{
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
		if (((*it) != NULL) && ((*it)->isSelected()))
			return (*it);
	}
	return NULL;
}

/*
 * Overridden methods
 */

/***************************************************************************//**
 * Handle closeEvent.
 * If user calls closing MainWindow, close, else ignore.
 * @param e
 */
void MainWindow::closeEvent(QCloseEvent* e)
{
	int ret = QMessageBox::question(this, "Question", "Are you sure you want to exit?", 0, 1, 2);
	if (ret == 1)
		QApplication::exit(0);
	else
		e->ignore();
}

/***************************************************************************//**
 * Change Event.
 * @param e
 */
void MainWindow::changeEvent(QEvent* e)
{
	QMainWindow::changeEvent(e);
}

enum AspectStatus { GRID_OK, GRID_TOO_WIDE, GRID_TOO_TALL };

/**
 * check the difference in the aspect ratio between the frame size and the grid
 * size. The parameters in here are hand-adjusted. Feel free to make it more or
 * less sensitive.
 * */
AspectStatus checkAspectRatio(const QSize& frameSize, const QSize& gridSize) {
        float aspectRoom  = ((float) gridSize.height()) / ((float) gridSize.width());
        float aspectFrame = ((float) frameSize.height()) / ((float) frameSize.width());

        if (aspectRoom / aspectFrame <  0.8) {
            return GRID_TOO_WIDE;
        }
        if ( aspectFrame / aspectRoom < 0.8) {
            return GRID_TOO_TALL;
        }
        return GRID_OK;
}

/***************************************************************************//**
 * Resize event.
 * @param e
 */
void MainWindow::resizeEvent(QResizeEvent* e)
{
    const Room* room = Global::getCurrentRoom();
    const QSize& clientSize = room->clientSize;

	if (ui->frmRoom->size().width() < 100 || ui->frmRoom->size().height() < 100 || _tilesX <= 0 || _tilesY <= 0) { return; }

    QSize newGridSize = room->gridSize;

    /* do we have to add virtual columns? */
    while (checkAspectRatio(ui->frmRoom->size(), newGridSize) == GRID_TOO_WIDE) {
        /* add row */
        newGridSize.setHeight(newGridSize.height() + 1);
    }
    while (checkAspectRatio(ui->frmRoom->size(), newGridSize) == GRID_TOO_TALL) {
        /* add column */
        newGridSize.setWidth(newGridSize.width() + 1);
    }
    this->_tilesX = newGridSize.width();
    this->_tilesY = newGridSize.height();


	/* Resize all connection windows */
	for (QList<ConnectionFrame*>::iterator it = _clientFrames.begin(); it != _clientFrames.end(); ++it)
	{
        int newPosX = (*it)->getGridPosition().x() * getTileWidthPx();
        int newPosY = (*it)->getGridPosition().y() * getTileHeightPx();
        QPoint newPos(newPosX, newPosY);

        (*it)->setSize(getTileWidthPx() * clientSize.width(), getTileHeightPx() * clientSize.height());
        (*it)->move(newPos);
	}

}


void MainWindow::lockContextButtons() {
    qDebug() << "LOCK";
    for (auto it = _contextButtons.begin(); it != _contextButtons.end(); ++it) {
        (*it)->setEnabled(false);
    }
}

void MainWindow::unlockContextButtons() {
    qDebug() << "UNLOCK";
    for (auto it = _contextButtons.begin(); it != _contextButtons.end(); ++it) {
        (*it)->setEnabled(true);
    }
    /* and disable some again based on special rules */
    if (getSelectedFrame()->client() != NULL) {
        ui->action_DeleteClient->setEnabled(false);
    }
    if (getSelectedFrame()->client() == NULL) {
        ui->action_SetAsTutor->setEnabled(false);
        ui->action_StudentToTutorExclusive->setEnabled(false);
        ui->action_StudentToTutor->setEnabled(false);
        ui->action_TutorToStudent->setEnabled(false);
    }


}
/***************************************************************************//**
 * Handle Mouse Release Event.
 * Check if click was inside the frame and if that is the case, set the selection of each connected
 * client to false.
 * @param e
 */
void MainWindow::mouseReleaseEvent(QMouseEvent* e)
{
	// Try to figure out if the user clicked inside the "room" frame
	// No idea if there is a more elegant way to do this without
	// sub-classing that frame and overriding its mouseReleaseEvent
	const QPoint pos(ui->frmRoom->mapFrom(this, e->pos()));
	if (pos.x() < 0 || pos.y() < 0)
		return;
	const QSize frame(ui->frmRoom->size());
	if (frame.width() > pos.x() && frame.height() > pos.y())
	{
        lockContextButtons();
		if (getSelectedFrame() != NULL)
		{
			getSelectedFrame()->setSelection(false);
		}
	}
}

/***************************************************************************//**
 * @brief reset
 */
void MainWindow::reset()
{
	_mode = Mode::None;

	// Unlock all clients
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
		if ((*it)->client() != NULL)
			(*it)->client()->lockScreen(false);

	// Stop server (Clients get stopped on ACK)
	if (getClientFromId(_streamingSource) != NULL)
		getClientFromId(_streamingSource)->stopVncServer();
}

/*
 * Slots
 */


/***************************************************************************//**
* Place Frame to from user specified position.
* Behaviour: If placed exactly on another frame: replace that frame and place it
* on the closest free slot. Otherwise: place connectionFrame on the closest free
* slot.
 */
void MainWindow::onPlaceFrame(bool activateTrash, ConnectionFrame* connectionFrame)
{
	if (_tilesX <= 0 || _tilesY <= 0)
		return;
	const QPoint &p = connectionFrame->frameGeometry().center();
	const QSize &s  = ui->frmRoom->geometry().size();
    /* round to grid */
	int x = p.x() / getTileWidthPx();
	int y = p.y() / getTileHeightPx();
	if (x < 0) {
		x = 0;
    } else if (x > s.width() - getTileWidthPx()) {
        qDebug() << "oopsie";
		x = (_tilesX - 1);
    }
	if (y < 0) {
		y = 0;
    } else if (y > s.height() - getTileHeightPx()) {
        qDebug() << "oopsie2";
		y = (_tilesY - 1);
    }
    /* --- */

    QPoint newPos(x,y);
    connectionFrame->setGridPosition(newPos);
    placeFrameInFreeSlot(connectionFrame, newPos);

    /* if there is already a frame at that position, push it away */
    bool replacedFrame = false;
	for (auto it = _clientFrames.begin(); it != _clientFrames.end(); ++it) {
		if (*it == connectionFrame) { continue; }

		if ((*it)->getGridPosition() == newPos) {
            connectionFrame->setGridPosition(newPos);
			placeFrameInFreeSlot(*it, newPos); /* place frame in free slot, close to newPos */
            replacedFrame = true;
            break;
		}
	}
    if (!replacedFrame) {
        placeFrameInFreeSlot(connectionFrame, newPos);
    }
    /* update positions */

	savePosition(connectionFrame); /* save in local config to remember position */
    resizeEvent(NULL);
}

/***************************************************************************//**
 * Mark given frame after it was clicked on.
 * @param frame
 */
void MainWindow::onFrameClicked(ConnectionFrame* frame)
{
	// If same frame is clicked again,, do nothing
	if (getSelectedFrame() == frame)
	 return;

	// If another frame has been selected, unselect it
	// Set the ui selected and set a new reference
	if (getSelectedFrame() != NULL)
	{
		getSelectedFrame()->setSelection(false);
	}
	frame->setSelection(true);
	qDebug() << "ID of frame: " << frame->computerId();
	qDebug() << "ID of selectedFrame: " << getSelectedFrame()->computerId();

    unlockContextButtons();
}

/***************************************************************************//**
 * Show session name, after it was clicked on.
 */
void MainWindow::onSessionNameClick()
{
	_countSessionNameUpdate++;
	if (_countSessionNameUpdate > 1)
	{
		int ret = QMessageBox::question(this, "Warning", tr("Sure, You want to change SessionName again?\n"
																		"All Clients will be deleted afterwards."), 0, 1, 2);
		if (ret == 1)
		{
			_sessionNameWindow->show(Global::sessionName());
		}
	}
	else
		_sessionNameWindow->show((Global::sessionName()));
}

/***************************************************************************//**
 * Update session name.
 */
void MainWindow::onSessionNameUpdate()
{
	// Stop all projections and clear all clients, which where connected to old sessionName.
	reset();
	if (_countSessionNameUpdate > 1)
	{
		{
			for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
			{
				(*it)->hide();
				(*it)->deleteLater();
			}
			_clientFrames.clear();
		}
	}
	_sessionNameLabel->setText(tr("Session Name: %1  [click to edit]").arg(Global::sessionName()));
}

/***************************************************************************//**
 * @brief MainWindow::startVncServerIfNecessary
 * @param from
 */
void MainWindow::startVncServerIfNecessary(int from)
{
	Client* os = getClientFromId(_streamingSource);
	Client* ns = getClientFromId(from);

	// if there is a server running which is not "from" stop it.
	if (os != NULL && _streamingSource != from)
		os->stopVncServer();

	// Set new streaming source
	_streamingSource = from;

	// If streaming source is already active avoid a restart
	if (ns != NULL) {
		if (ns->isActiveVncServer())
			this->onVncServerStateChange(ns);
		else  // Could not take shortcut, (re)start VNC server on source
			ns->startVncServer();
	}
}

void MainWindow::onButtonReloadRoomConfig()
{
	connect(_reloadWindow->ui->buttonBox, SIGNAL(accepted()), this, SLOT(onReloadRoomOk()));
	connect(_reloadWindow->ui->buttonBox, SIGNAL(rejected()), this, SLOT(onReloadRoomCancel()));
	qDebug() << "in onButtonReloadRoomConfig!" << "size of room: " << Global::getRooms().size();
	QList<QString> keyList = Global::getRooms().keys();
	for (QList<QString>::iterator it = keyList.begin(); it != keyList.end() ; it++) {
		_reloadWindow->ui->roomList->addItem(*it);
	}
	_reloadWindow->show();
}

void MainWindow::onReloadRoomCancel()
{
	disconnect(_reloadWindow->ui->buttonBox, SIGNAL(accepted()), this, SLOT(onReloadRoomOk()));
	disconnect(_reloadWindow->ui->buttonBox, SIGNAL(rejected()), this, SLOT(onReloadRoomCancel()));
	_reloadWindow->ui->roomList->clear();
	_reloadWindow->hide();
}

void MainWindow::switchRoomTo(QString roomToReload) {
    // qDebug() << roomToReload;
    Global::setCurrentRoom(roomToReload);
    Room *room = Global::getRooms()[roomToReload];
    /* set tiles */
    _tilesX = room->gridSize.width();
    _tilesY = room->gridSize.height();


    /* place connection frames */
    for (auto it = room->clientPositions.begin(); it != room->clientPositions.end(); ++it) {
        QString computerId = it.key();
        QPoint pos = it.value();
        QPoint pxPos(pos.x() * getTileWidthPx(), pos.y() * getTileHeightPx());

        ConnectionFrame *cf = createFrame(computerId, pxPos, pos);
        cf->move(cf->getCurrentPosition()); 
        onPlaceFrame(false, cf);
        if (computerId == room->tutorIP) {
            qDebug() << "set computer with id " << computerId << " as tutor per configuration";
            if (getTutorFrame() != NULL) {
                getTutorFrame()->setTutor(false);
            }
            cf->setTutor(true);
        } else {
            //qDebug() << "not tutor because id is " << computerId << " and tutorIP is " << room->tutorIP;
        }
    }

    /* load background image */
    QString imgPath = Global::getCurrentRoom()->imagePath;
    qDebug() << "imgPath is " << imgPath;
    if (imgPath == "") {
        /* set empty pixmap*/
        QPixmap empty;
        ui->imageLabel->setPixmap(empty);
    } else {
        qDebug() << "set background image path: " << imgPath;
        QImage backgroundImage;
        backgroundImage.load(imgPath);
        ui->imageLabel->setPixmap(QPixmap::fromImage(backgroundImage));
        ui->imageLabel->setScaledContents(true);
    }

    /* and force a resize event (this scales the image)  */
    resizeEvent(NULL);
}

void MainWindow::onReloadRoomOk()
{
	if (_reloadWindow->ui->roomList->currentItem() == NULL)
	{
		QMessageBox::critical(this, "Warning", tr("No item selected, please select room!"), 0, 1);
		return;
	}
	int ret = QMessageBox::QMessageBox::question(this, "Warning", tr("Are you sure you want to reload the room?\n"
																							 "Note that all clients will be deleted."), 0, 1, 2);

	if (ret == 1) {
		disconnect(_reloadWindow->ui->buttonBox, SIGNAL(accepted()), this, SLOT(onReloadRoomOk()));
		disconnect(_reloadWindow->ui->buttonBox, SIGNAL(rejected()), this, SLOT(onReloadRoomCancel()));
		// Delete all clients.
		for (QList<ConnectionFrame*>::iterator it = _clientFrames.begin(); it != _clientFrames.end(); it++)
		{
			(*it)->hide();
			(*it)->deleteLater();
		}
		_clientFrames.clear();

		// Load new room configuration.
		QString roomToReload = _reloadWindow->ui->roomList->currentItem()->data(0).toString();
        switchRoomTo(roomToReload);

		_reloadWindow->ui->roomList->clear();
		_reloadWindow->hide();

    }
}

int MainWindow::getTileWidthPx() const {
    return ui->frmRoom->size().width() / _tilesX;
}
int MainWindow::getTileHeightPx() const {
    return ui->frmRoom->size().height() / _tilesY; 
}

/***************************************************************************//**
 * Display popup which explains possible actions about the buttons.
 */
void MainWindow::onButtonHelp()
{
	_helpWindow->show();
}

/***************************************************************************//**
 * Handle projection from tutor to all.
 * Get the client who is tutor and set the projectionSource of all
 * clients, except the tutor ones, to false.
 */
void MainWindow::onButtonTutorToAll()
{
	ui->action_Lock->setChecked(false);

	if (getTutorFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorNdef);
	else if (getTutorFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorOffline);
	else if (_clientFrames.size() == 1)
		QMessageBox::critical(this, tr("Projection"), sStrNoDestAv);
	else
	{
		// If this mode is already active, reset everything
		if (_mode == Mode::Broadcast) {
			reset();
			return;
		}

		// Set all clients as watchers of tutor. Except for the tutors desired source, which hase to be none
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
			if ((*it)->client() != NULL)
				(*it)->client()->setDesiredProjectionSource((*it)->client() == getTutorFrame()->client() ? NO_SOURCE : getTutorFrame()->client()->id());

		DisableButtons();
		_mode = Mode::Broadcast;
		startVncServerIfNecessary(getTutorFrame()->client()->id());
	}
}

/***************************************************************************//**
 * Handle the projection from Tutor to specific student.
 * Set the client who is tutor as from and the selected client as to.
 */
void MainWindow::onButtonTutorToStudent()
{
	ui->action_Lock->setChecked(false);

	if (getSelectedFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrDestNdef);
	else if (getTutorFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorNdef);
	else if (getSelectedFrame() == getTutorFrame())
		QMessageBox::critical(this, tr("Projection"), sStrSourceDestSame);
	else if (getSelectedFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrDestOffline);
	else if (getTutorFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorOffline);
	else
	{
		// If this is the first call in this mode clear the watchers
		if (_mode != Mode::Multicast) {
			for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
				if ((*it)->client() != NULL)
					(*it)->client()->setDesiredProjectionSource(NO_SOURCE);
		}

		// If "to" already watches "from" stop it
		if (getSelectedFrame()->client()->desiredProjectionSource() == getTutorFrame()->client()->id() )
			getSelectedFrame()->client()->setDesiredProjectionSource(NO_SOURCE);
		else
			getSelectedFrame()->client()->setDesiredProjectionSource(getTutorFrame()->client()->id());

		DisableButtons();
		_mode = Mode::Multicast;
		startVncServerIfNecessary(getTutorFrame()->client()->id());
	}
}

/***************************************************************************//**
 * Handle projection from one student to tutor.
 * Get the client to project from and get client, who is tutor, as to.
 */
void MainWindow::onButtonStudentToTutor()
{
	ui->action_Lock->setChecked(false);

	if (getSelectedFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrSourceNdef);
	else if (getTutorFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorNdef);
	else if (getTutorFrame() == getSelectedFrame())
		QMessageBox::critical(this, tr("Projection"), sStrSourceDestSame);
	else if (getSelectedFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrSourceOffline);
	else if (getTutorFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorOffline);
	else
	{
		// If this is not the first run in this mode and the current source is selected, stop the streaming.
		if (_mode == Mode::Unicast && getSelectedFrame()->client()->id() == _streamingSource)
		{
			// Stop reset everything
			_mode = Mode::None;
			reset();
			return;
		}

		// Unset all clients desired sources. Except the tutors desired source, this has to be the selecteds frame
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
			if ((*it)->client() != NULL)
				(*it)->client()->setDesiredProjectionSource(getTutorFrame()->client()->id() == (*it)->client()->id() ? getSelectedFrame()->client()->id():NO_SOURCE);

		DisableButtons();
		_mode = Mode::Unicast;
		startVncServerIfNecessary(getSelectedFrame()->client()->id());
	}
}


/***************************************************************************//**
 * @brief MainWindow::onButtonStudentToTutorExclusive
 */
void MainWindow::onButtonStudentToTutorExclusive()
{
	ui->action_Lock->setChecked(false);

	if (getSelectedFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrSourceNdef);
	else if (getTutorFrame() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorNdef);
	else if (getTutorFrame() == getSelectedFrame())
		QMessageBox::critical(this, tr("Projection"), sStrSourceDestSame);
	else if (getSelectedFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrSourceOffline);
	else if (getTutorFrame()->client() == NULL)
		QMessageBox::critical(this, tr("Projection"), sStrTutorOffline);
	else
	{
		// If this is not the first run in this mode and the current source is selected, stop the streaming.
		if (_mode == Mode::Unicast && getSelectedFrame()->client()->id() == _streamingSource)
		{
			// Stop reset everything
			_mode = Mode::None;
			reset();
			return;
		}

		// Unset all clients desired sources. Except the tutors desired source, this has to be the selecteds frame
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
			if ((*it)->client() != NULL)
				(*it)->client()->setDesiredProjectionSource(getTutorFrame()->client()->id() == (*it)->client()->id() ? getSelectedFrame()->client()->id():NO_SOURCE);

		DisableButtons();
		_mode = Mode::LockedUnicast;
		startVncServerIfNecessary(getSelectedFrame()->client()->id());
	}
}


/***************************************************************************//**
 * Handle Button StopProjection.
 * Set ProjectionSource of each client to false,  stop the active VNC Server
 * and the active VNC Client(s) and unlock all screens.
 */
void MainWindow::onButtonStopProjection()
{
	ui->action_Lock->setChecked(false);
	reset();
}

/***************************************************************************//**
 * Handle button to lock or unlock screens of client(s).
 * If already locked, do nothing, else lock or unlock the clients, except the
 * tutor and the manager running machine.
 * @param checked
 */
void MainWindow::onButtonLock(bool checked)
{
	// Stop all projections
	reset();

	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
		if ((*it)->client() == NULL)
			continue;
		(*it)->client()->lockScreen(checked);
	}
}

/***************************************************************************//**
 * On button exit, close application.
 */
void MainWindow::onButtonExit()
{
	this->close();
}

/***************************************************************************//**
 * Handle button to set specific client as tutor.
 * Unset active tutor and set selected client, if not inactive, as new tutor.
 */
void MainWindow::onButtonSetAsTutor()
{
	ui->action_Lock->setChecked(false);

	// If no frame is selected, warning.
	if (getSelectedFrame() == NULL)
	{
		QMessageBox::critical(this, tr("Selection"), tr("No client is selected."));
		return;
	}

	// If frame of inactive client has been selected unselect it
	if (getSelectedFrame()->client() == NULL)
	{
		QMessageBox::critical(this, tr("Selection"), tr("The selected client is not connected."));
		return;
	}
	else  // If selected client is locked, first unlock
	{
		getSelectedFrame()->client()->lockScreen(false);
	}

	// If same frame is already tutor, do nothing
	if (getSelectedFrame() == getTutorFrame())
		return;

	// Else unset the old and set the new tutor
	if (getTutorFrame() != NULL)
	{
		getTutorFrame()->setTutor(false);
	}
	getSelectedFrame()->setTutor(true);
}

/***************************************************************************//**
 * Handle from ListenServer signaled new client connection.
 * @param client
 */
void MainWindow::onClientConnected(Client* client)
{
	connect(client, SIGNAL(authenticating(Client*, ClientLogin*)), this, SLOT(onClientAuthenticating(Client*, ClientLogin*)));
	connect(client, SIGNAL(authenticated(Client*)), this, SLOT(onClientAuthenticated(Client*)));
}

/***************************************************************************//**
 * Authenticate new Client client.
 * Check if incoming client ip already exists,
 *							if yes --> return.
 * Check if same name of client already exist,
 *							if yes --> name new client as name(x).
 *							x = number of clients with the same name.
 * @param client
 * @param request
 */
void MainWindow::onClientAuthenticating(Client* client, ClientLogin* request)
{
	disconnect(client, SIGNAL(authenticating(Client*, ClientLogin*)), this, SLOT(onClientAuthenticating(Client*, ClientLogin*)));
	if (!request->accept) // Another receiver of that signal already rejected the client, so nothing to do
		return;
	bool inuse;
	QString check = request->name;
	int addnum = 1;
	do
	{
		inuse = false;
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
		{
			Client *c = (**it).client();
			if (c == NULL)
				continue;
			if (!c->isAuthed())
				continue;
			if (c->ip() == request->ip)
			{
				request->accept = false;
				return;
			}
			if (c->name() == check)
			{
				inuse = true;
				check = request->name + " (" + QString::number(++addnum) + ")";
				break;
			}
		}
	} while (inuse && addnum < 100);
	if (inuse)
		request->accept = false;
	else
		request->name = check;
}

/***************************************************************************//**
 * New client was authenticated, make several checks.
 * Check if new clients ip already exists,
 *								if yes --> not necessary to create new clientFrame.
 *								if not --> create a new one and adapt this one to current
 *												   situation in class room(projection / lock screen).
 * Check if avctiv tutor is available,
 *								if not --> check if new client is possible tutor.
 * @param client
 */
void MainWindow::onClientAuthenticated(Client* client)
{
	disconnect(client, SIGNAL(authenticated(Client*)), this, SLOT(onClientAuthenticated(Client*)));
	connect(client, SIGNAL(vncServerStateChange(Client*)), this, SLOT(onVncServerStateChange(Client*)));
	connect(client, SIGNAL(vncClientStateChange(Client*)), this, SLOT(onVncClientStateChange(Client*)));
	bool hasActiveTutor = false;
	ConnectionFrame *existing = NULL;
	for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
	{
		// qDebug() << "Existing frame ip: " << (*it)->computerId();
		// qDebug() << "New Clients ip:    " << client->ip();
		// qDebug() << ((*it)->computerId() == client->ip());
		if ((*it)->computerId() == client->ip())
		{
			existing = *it;
		}
		if ((*it)->isTutor())
		{
			if ((*it)->client() != NULL)
				hasActiveTutor = true;
		}
	}

	bool isTutor = false;
	if (!hasActiveTutor)
	{
		for (int i = 0; i < _tutorList.size(); i++)
		{
			// Check if client is possible tutor
			if (client->ip() == _tutorList[i])
			{
				isTutor = true;
				break;
			}
		}
	}
	// Clients ip already exists, but was not active.
	if (existing != NULL)
	{
		// qDebug() << "Should go into this if clause.";
		existing->setTutor(isTutor);
		existing->assignClient(client);
		tellClientCurrentSituation(client);
		return;
	}

	// New one, create
	ConnectionFrame *cf = createFrame();
	// Try to load last known position
	int x, y;
	bool ok;
	USER_SETTINGS(usr);
	ok = loadPosition(usr, client->ip(), x, y);
	if (!ok)
	{
		SYSTEM_SETTINGS(sys);
		ok = loadPosition(sys, client->ip(), x, y);
	}
	if (x >= _tilesX || y >= _tilesY)
		ok = false;
	if (ok)
	{
		if (x < 0)
			x = 0;
		if (y < 0)
			y = 0;
		qDebug("Move E");
		cf->move(x * getTileWidthPx(), y * getTileHeightPx());
		onPlaceFrame(true, cf);
	}
	else
	{
		// Move to any free tile
		placeFrameInFreeSlot(cf);
	}
	// Set Tutor option
	cf->setTutor(isTutor);
	// Assign client instance
	cf->assignClient(client);

    resizeEvent(NULL); // This is where all the positioning should be 
	tellClientCurrentSituation(client);

}

/***************************************************************************//**
 * Handle if VNC Server State has changed.
 * Check if VNC server has been started/stopped on some client and start VNC server/reset pending
 * VNC projection information.
 * @param client
 */
void MainWindow::onVncServerStateChange(Client* client)
{
	if (client == getClientFromId(_streamingSource))
		EnableButtons();

	if (client->isActiveVncServer())
	{
		// apply the desired projection sources
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
			if ( (*it)->client() != NULL) // Ignore offline clients
			{
				if ( (*it)->client()->desiredProjectionSource() == client->id() )
					(*it)->client()->startVncClient(client);
				else
					(*it)->client()->stopVncClient();

				(*it)->client()->lockScreen((*it)->client()->desiredProjectionSource() == NO_SOURCE &&  _mode == Mode::LockedUnicast);
			}
		// Dont forget to unlock the vnc server
		client->lockScreen(false);
	}
	else
	{
		// VNC server stopped on some client or failed to start - reset local pending projection information
		for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
		{
			if ((*it)->client() != NULL)
			{
				if ((*it)->client()->desiredProjectionSource() == client->id()) {
					(*it)->client()->setDesiredProjectionSource(NO_SOURCE);
					(*it)->client()->stopVncClient();
					if (_mode == Mode::LockedUnicast)
						(*it)->client()->lockScreen(true);
				}
			}
		}
		// Dont forget to unlock the vnc server (if necesarry)
		client->lockScreen(client->desiredProjectionSource() == NO_SOURCE &&  _mode == Mode::LockedUnicast);

		// If this was the current source remember that there is no source anymore and reset mode
		if (client == getClientFromId(_streamingSource)){
			_streamingSource = NO_SOURCE;
			_mode = Mode::None;
		}
	}
}

/***************************************************************************//**
 * Handle VNC client state change.
 * Check if any vnc client is in use, and if that is not the case, stop VNC Server.
 * @param client
 * @param lastProjectionSource
 */
void MainWindow::onVncClientStateChange(Client* client)
{
	if (client != NULL)
	{
		// VNC Client stopped -> remove from watchers
		if (!client->isActiveVncClient())
		{
			// Only unset a desired Projection source if it has not changed meanwhile
			if (client->projectionSource() == client->desiredProjectionSource())
				client->setDesiredProjectionSource(NO_SOURCE);

			/*
			 * If nobody is watching the VNC server of the pvsclient that
			 * stopped its vncclient stop it. (The _LAST_ vncserver, there
			 * may be a new one)
			 * This is necessary for the race condition when a server
			 * is stopped and another started at the same time, since the new
			 * server would be killed if all client disconnect before any of
			 * the new connect.
			 */
			bool serverHasWatchers = false;
			for (QList<ConnectionFrame*>::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it)
				if ((*it)->client() != NULL)
					if ((*it)->client()->desiredProjectionSource() == client->projectionSource()) {
						serverHasWatchers = true;
						break;
					}

			if ( !(serverHasWatchers || _mode == Mode::Broadcast) )
			{
				Client* c = getClientFromId(client->projectionSource());
				if (c != NULL)
					c->stopVncServer();
			}
		}
	}
}

/***************************************************************************//**
 * DisableButtons.
 */
void MainWindow::DisableButtons()
{
    qDebug() << "DisableButtons()";
	_buttonLockTimer->start();
	foreach (QAction* a, _lockingButtons)
		a->setDisabled(true);
}

/***************************************************************************//**
 * EnableButtons.
 */
void MainWindow::EnableButtons()
{
    qDebug() << "EnableButtons()";
	_buttonLockTimer->stop();
	foreach (QAction* a, _lockingButtons)
		a->setEnabled(true);
}


void MainWindow::onDeleteClient() {
	// If no frame is selected, warning.
    ConnectionFrame* frame = getSelectedFrame();
	if (frame == NULL) {
		QMessageBox::critical(this, tr("Selection"), tr("No client is selected."));
		return;
	}
	if (frame->client() != NULL) {
		QMessageBox::critical(this, tr("Selection"), tr("This client is still connected."));
		return;
	} else {
        qDebug() << "Now delete the client";
        int ret = QMessageBox::question(this, "Warning", tr("Sure, You want to delete selected client?"), 0, 1, 2);
        if (ret == 1) {
            frame->hide();
            frame->deleteLater();
            _clientFrames.removeOne(frame);
            lockContextButtons();
            return;
        } else {
            frame->move(frame->getPreviousPosition());
            return;
        }
	}



}