/*
	VeroRoute - Qt based Veroboard/Perfboard/PCB layout & routing application.

	Copyright (C) 2017  Alex Lawrow    ( dralx@users.sourceforge.net )

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "templatesdialog.h"
#include "ui_templatesdialog.h"
#include "mainwindow.h"
#include "TemplateManager.h"

TemplatesDialog::TemplatesDialog(QWidget* parent)
: QWidget(parent)
, ui(new Ui_TemplatesDialog)
, m_pMainWindow(nullptr)
, m_iRowL(-1)
, m_iRowR(-1)
{
	ui->setupUi( reinterpret_cast<QDialog*>(this) );
#ifdef VEROROUTE_ANDROID
	ui->tableWidget->verticalScrollBar()->setStyleSheet( ANDROID_VSCROLL_WIDTH );
	ui->tableWidget->horizontalScrollBar()->setStyleSheet( ANDROID_HSCROLL_HEIGHT );
	ui->tableWidget_2->verticalScrollBar()->setStyleSheet( ANDROID_VSCROLL_WIDTH );
	ui->tableWidget_2->horizontalScrollBar()->setStyleSheet( ANDROID_HSCROLL_HEIGHT );
#endif
}

void TemplatesDialog::SetMainWindow(MainWindow* p)
{
	m_pMainWindow = p;
	QObject::connect(ui->tableWidget,	SIGNAL(itemSelectionChanged()),		this,	SLOT(GenericChanged()));
	QObject::connect(ui->tableWidget,	SIGNAL(cellDoubleClicked(int,int)),	this,	SLOT(GenericDoubleClicked(int,int)));
	QObject::connect(ui->tableWidget_2,	SIGNAL(itemSelectionChanged()),		this,	SLOT(UserChanged()));
	QObject::connect(ui->tableWidget_2,	SIGNAL(cellDoubleClicked(int,int)),	this,	SLOT(UserDoubleClicked(int,int)));
	QObject::connect(ui->pushButton,	SIGNAL(clicked()),					this,	SLOT(AddTemplates()));
	QObject::connect(ui->pushButton_2,	SIGNAL(clicked()),					this,	SLOT(DeleteTemplate()));
	QObject::connect(ui->pushButton_3,	SIGNAL(clicked()),					this,	SLOT(LoadFromVrt()));
	QObject::connect(ui->pushButton_4,	SIGNAL(clicked()),					this,	SLOT(SaveToVrt()));
	LoadFromUserVrt(false);	// false ==> no message box
}

TemplatesDialog::~TemplatesDialog()
{
	delete ui;
}

void TemplatesDialog::Update()
{
	TemplateManager& mgr = m_pMainWindow->GetTemplateManager();

	for (int iTable = 0; iTable < 2; iTable++)
	{
		const bool bGeneric = ( iTable == 0 );

		const int numRows = static_cast<int>(mgr.GetSize(bGeneric));

		auto* pTableWidget	= ( bGeneric ) ? ui->tableWidget : ui->tableWidget_2;
		auto& tableHeader	= ( bGeneric ) ? m_tableHeaderL : m_tableHeaderR;
		auto& iRow			= ( bGeneric ) ? m_iRowL : m_iRowR;

		tableHeader.clear();
		if ( bGeneric )
			tableHeader << "Type";
		else
			tableHeader << "Type" << "Value";

		// Set up the table
		pTableWidget->clear();
		pTableWidget->setRowCount(numRows);
		pTableWidget->setColumnCount(tableHeader.size());
		for (int i = 0, iSize = tableHeader.size(); i < iSize; i++)
		{
			int iWidth(0);
			switch( i )
			{
				case 0: iWidth = bGeneric ? 360 : 180; break;
				case 1: iWidth = 160; break;	// Allow for vertical scroll bar
			}
			pTableWidget->setColumnWidth(i,iWidth);
		}
		pTableWidget->setHorizontalHeaderLabels(tableHeader);
		pTableWidget->horizontalHeader()->setVisible(!bGeneric);
		pTableWidget->verticalHeader()->setVisible(false);
		pTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
		pTableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
		pTableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
		pTableWidget->setShowGrid(true);

		// Populate the table with data
		std::string strType(""), strValue(""), strFull("");
		for (int i = 0; i < numRows; i++)
		{
			const Component&	comp	= mgr.GetNth(bGeneric, static_cast<size_t>(i));
			const COMP&			eType	= comp.GetType();

			strType		= comp.GetFullTypeStr();			// e.g. "Film" or "DIP16"
			strValue	= comp.GetValueStr();
			strFull		= CompTypes::GetFamilyStr( eType );	// e.g. "Capacitor"
			if ( !StringHelper::IsEmptyStr(strFull) ) strFull += ": ";
			strFull	+= strType;								// e.g. "Capacitor: Film"

			// Write current row to table.	Note: No memory leak since setItem() takes ownership.
			if ( bGeneric )
			{
				pTableWidget->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(strFull)));
			}
			else
			{
				pTableWidget->setItem(i, 0, new QTableWidgetItem(QString::fromStdString(strType)));
				pTableWidget->setItem(i, 1, new QTableWidgetItem(QString::fromStdString(strValue)));
			}
		}
		iRow = ( numRows > 0 ) ? 0 : -1;
		if ( iRow >= 0 ) pTableWidget->selectRow(iRow);
		if ( !bGeneric )
			ui->pushButton_2->setDisabled(m_iRowR == -1);
	}
	SaveToUserVrt();
}

void TemplatesDialog::GenericClicked(int row)
{
	m_iRowL = row;
	ui->tableWidget->selectRow(m_iRowL);
}

void TemplatesDialog::GenericChanged()
{
	GenericClicked( ui->tableWidget->currentRow() );
}

void TemplatesDialog::GenericDoubleClicked(int row, int)
{
	GenericClicked(row);

	TemplateManager& mgr = m_pMainWindow->GetTemplateManager();

	const bool bGeneric = true;
	if ( m_iRowL >= 0 && m_iRowL < static_cast<int>(mgr.GetSize(bGeneric)) )
		m_pMainWindow->AddFromTemplate(bGeneric, mgr.GetNth(bGeneric, static_cast<size_t>(m_iRowL)));
}

void TemplatesDialog::UserClicked(int row)
{
	m_iRowR = row;
	ui->tableWidget_2->selectRow(m_iRowR);
}

void TemplatesDialog::UserChanged()
{
	UserClicked( ui->tableWidget_2->currentRow() );
}

void TemplatesDialog::UserDoubleClicked(int row, int)
{
	UserClicked(row);

	TemplateManager& mgr = m_pMainWindow->GetTemplateManager();

	const bool bGeneric = false;
	if ( m_iRowR >= 0 && m_iRowR < static_cast<int>(mgr.GetSize(bGeneric)) )
		m_pMainWindow->AddFromTemplate(bGeneric, mgr.GetNth(bGeneric, static_cast<size_t>(m_iRowR)));
}

void TemplatesDialog::AddTemplates()
{
	AddTemplatesFromBoard(m_pMainWindow->m_board, false, true);	// false ==> Restrict to user-group
}

void TemplatesDialog::DeleteTemplate()
{
	TemplateManager& mgr = m_pMainWindow->GetTemplateManager();

	const bool bGeneric = false;

	if ( m_iRowR >= 0 && m_iRowR < static_cast<int>(mgr.GetSize(bGeneric)) )
	{
		const Component comp = mgr.GetNth(bGeneric, static_cast<size_t>(m_iRowR));

		const std::string messageStr = "The template (Type = " + comp.GetFullTypeStr() + ") "
									 + "(Value = " + comp.GetValueStr() + ") is about to be deleted.  There is no undo for this operation.  Continue?";
		if ( QMessageBox::question(this, tr("Confirm Delete Template"),
										 tr(messageStr.c_str()),
										 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No ) return;	
		if ( mgr.Remove(comp) )
			Update();
	}
}

QString TemplatesDialog::GetUserFilename() const
{
	TemplateManager& mgr = m_pMainWindow->GetTemplateManager();
	char buffer[256] = {'\0'};
	sprintf(buffer, "%s/templates/user.vrt", mgr.GetPathStr().c_str());
	return QString(buffer);
}

void TemplatesDialog::LoadFromVrt()
{
	const QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), ""/*directory*/,	tr("VeroRoute (*.vrt);;All Files (*)"));
	if ( !fileName.isEmpty() )
		Load(fileName, true);
}

void TemplatesDialog::LoadFromUserVrt(bool bInfoMsg)
{
	const QString fileName = GetUserFilename();
	if ( !fileName.isEmpty() )
		Load(fileName, bInfoMsg);
}

void TemplatesDialog::Load(const QString& fileName, bool bInfoMsg)
{
	const std::string fileNameStr = fileName.toStdString();

	DataStream inStream(DataStream::READ);
	if ( inStream.Open( fileNameStr.c_str() ) )
	{
		Board tmp;	// Load using a temporary board in case there is a problem with the file
		tmp.Load(inStream);
		inStream.Close();
		if ( inStream.GetOK() ) // If it loaded OK ...
			AddTemplatesFromBoard(tmp, true, bInfoMsg);	// true ==> Don't restrict to user group
		else
			QMessageBox::information(this, tr("Unsupported VRT version"), tr(fileNameStr.c_str()));
	}
	else if ( fileName != GetUserFilename() )
		QMessageBox::information(this, tr("Unable to open file"), tr(fileNameStr.c_str()));
}

void TemplatesDialog::SaveToVrt()
{
#ifdef VEROROUTE_ANDROID
	QMessageBox::information(this, tr("Information"), tr("You must now select or enter a filename ending in .vrt"));
	const QString	fileName	= m_pMainWindow->GetSaveFileName(tr(""), tr("VeroRoute (*.vrt);;All Files (*)"), QString("vrt"));
#else
	const QString	fileName	= m_pMainWindow->GetSaveFileName(tr("Save templates as"), tr("VeroRoute (*.vrt);;All Files (*)"), QString("vrt"));
#endif
	if ( !fileName.isEmpty() )
		Save(fileName);
}

void TemplatesDialog::Save(const QString& fileName)
{
	DataStream outStream(DataStream::WRITE);
	const std::string fileNameStr = fileName.toStdString();
	if ( outStream.Open( fileNameStr.c_str() ) )
	{
		Board tmp;	// Load using a temporary board in case there is a problem with the file

		const bool bGeneric = false;
		TemplateManager& mgr = m_pMainWindow->GetTemplateManager();
		for (size_t i = 0, iSize = mgr.GetSize(bGeneric); i < iSize; i++)
		{
			const Component& comp = mgr.GetNth(bGeneric,i);
			tmp.AddComponent(-1, -1, comp, false);
		}
		tmp.Save(outStream);
		outStream.Close();
	}
	else
		QMessageBox::information(this, tr("Unable to save file"), tr(fileNameStr.c_str()));
}

void TemplatesDialog::SaveToUserVrt()
{
	if ( !m_pMainWindow->m_bTemplatesDir ) return;
	QString fileName = GetUserFilename();
	if ( !fileName.isEmpty() ) Save(fileName);
}

void TemplatesDialog::AddTemplatesFromBoard(Board& board, bool bAllComps, bool bInfoMsg)
{
	CompManager&	 compMgr	= board.GetCompMgr();
	GroupManager&	 groupMgr	= board.GetGroupMgr();
	TemplateManager& mgr		= m_pMainWindow->GetTemplateManager();

	if ( !bAllComps && groupMgr.GetNumUserComps() == 0 && bInfoMsg )
	{
		QMessageBox::information(this, tr("Information"), tr("No parts are currently selected in the main view."));
		return;
	}
	
	const bool bGeneric = false;

	int nCount(0);
	for (const auto& mapObj : compMgr.GetMapIdToComp())
	{
		if ( bAllComps || groupMgr.GetIsUserComp(mapObj.first) )
			if ( mgr.Add(bGeneric, mapObj.second) ) nCount++;
	}
	if ( nCount > 0 ) Update();

	if ( bInfoMsg )
		QMessageBox::information(this, tr("Information"), QString::number(nCount) + QString(" new templates added."));
}

void TemplatesDialog::keyPressEvent(QKeyEvent* event)
{
#ifndef VEROROUTE_ANDROID
	m_pMainWindow->specialKeyPressEvent(event);
#endif
	QWidget::keyPressEvent(event);
	event->accept();
}

void TemplatesDialog::keyReleaseEvent(QKeyEvent* event)
{
#ifdef VEROROUTE_ANDROID
	if ( event->key() == Qt::Key_Back )
		return m_pMainWindow->keyReleaseEvent(event);	// Try Undo operation
#else
	m_pMainWindow->commonKeyReleaseEvent(event);
#endif
	QWidget::keyReleaseEvent(event);
	event->accept();
}
