Master::Master()
{
    thread = new QThread();
    worker = new Worker();
    worker->moveToThread(thread);

    // connect the signal and slots
    connect(this,SIGNAL(startWorker()),worker,SLOT(start()));
    connect(worker,SIGNAL(WorkerFinished()),this,SLOT(onWorkerFinished()));

    // Start the thread
    thread->start();
}
void SimulationAnimationPatch::workerLoop() {
    FrameDeviceInfo frame;

    while(1) {
		// Releases the lock immediately if the queue is still empty.
		while (frame.time < 0) {
			if (m_mode == SimulationAnimationMode::STOPPED)
				continue;

			m_queue.lock();
			if (m_queuedFrameDeviceInfo.size() > 0) {
				if (m_mode == SimulationAnimationMode::RECORDING) {
					// Clears irrelated info
					std::vector<FrameDeviceInfo>::iterator i;
					for (i = m_queuedFrameDeviceInfo.begin();
						 i != m_queuedFrameDeviceInfo.end() &&
						 i->mode == SimulationAnimationMode::INTERACTIVE; i++) {
						i->clear();
					}
					m_queuedFrameDeviceInfo.erase(m_queuedFrameDeviceInfo.begin(), i);
                
					// Deep copy (since we're going to clear it)
					for (i = m_queuedFrameDeviceInfo.begin();
						 i != m_queuedFrameDeviceInfo.end(); i++) {
						// Copies the last recording info to do preview
						if (i->mode == SimulationAnimationMode::RECORDING) {
							frame.copyByValue(*i);
							// Waits to be rendered with higher sampling rate
							i->mode = SimulationAnimationMode::RENDERING;
						}
					}
				}
				else if (m_mode == SimulationAnimationMode::RENDERING) {
					// No frame would be skipped.
					frame = m_queuedFrameDeviceInfo[0];
					m_queuedFrameDeviceInfo.erase(m_queuedFrameDeviceInfo.begin());
				}
				else if (m_mode == SimulationAnimationMode::INTERACTIVE) {
					frame = m_queuedFrameDeviceInfo.back();
					for (FrameDeviceInfo &info : m_queuedFrameDeviceInfo) {
						if (info.time != m_queuedFrameDeviceInfo.back().time)
							info.clear();
					}
					m_queuedFrameDeviceInfo.clear();
				}
			}
			// No more frames for rendering
			else if (m_mode == SimulationAnimationMode::RENDERING) {
				onWorkerFinished();
			}
			m_queue.unlock();

			// The frame is valid.
			if (frame.time >= 0) {
				if (frame.mode == SimulationAnimationMode::STOPPED) {
					m_mode = SimulationAnimationMode::STOPPED;
					Logger::log(INFO, "Worker stopped...");

					return ;
				}
				else if (frame.mode == SimulationAnimationMode::RECORDING) {
					onRecording();
				}
				else if (frame.mode == SimulationAnimationMode::RENDERING) {
					onRendering();
				}
				// Finished recording work
				else if (frame.mode == SimulationAnimationMode::INTERACTIVE &&
						 (m_mode == SimulationAnimationMode::RENDERING)) {
					onWorkerFinished();
				}
			}
		}

		// Releases copies of devices.
		workerRender(frame);
		frame.clear();
    }
}
void AMDirectorySynchronizerDialog::prepare(){
	QApplication::setOverrideCursor(Qt::WaitCursor);
	mainStatusLabel_->setText("Preparing ...");

	prepareButton_->setEnabled(false);
	startButton_->setEnabled(false);

	singleFileProgressBar_->setMinimum(0);
	singleFileProgressBar_->setMaximum(0);
	overallTransferProgressBar_->setMinimum(0);
	overallTransferProgressBar_->setMaximum(0);

	fileListingEdit_->clear();
	errorTextEdit_->clear();
	progressTextEdit_->clear();

	feedbackStackWidget_->collapseItem(0);
	feedbackStackWidget_->collapseItem(1);
	feedbackStackWidget_->collapseItem(2);

	qRegisterMetaType<AMRecursiveDirectoryCompare::DirectoryCompareResult>("DirectorCompareResult");
	connect(synchronizer_, SIGNAL(prepared(AMRecursiveDirectoryCompare::DirectoryCompareResult)), this, SLOT(onPrepared(AMRecursiveDirectoryCompare::DirectoryCompareResult)));

	AMThread *prepareThread = new AMThread();
	connect(synchronizer_, SIGNAL(prepared(AMRecursiveDirectoryCompare::DirectoryCompareResult)), prepareThread, SLOT(onWorkerFinished()));
	prepareThread->setWorkerObject(synchronizer_);
	prepareThread->setInitialThread(thread());
	synchronizer_->moveToThread(prepareThread);
	prepareThread->start();
	QTimer::singleShot(0, synchronizer_, SLOT(prepare()));
}