// SPDX-License-Identifier: LGPL-2.1-or-later
//
// SPDX-FileCopyrightText: 2011 Dennis Nienhüser <nienhueser@kde.org>
//

#include "SqlWriter.h"

#include <QDebug>
#include <QSqlDatabase>
#include <QSqlError>

namespace Marble
{

SqlWriter::SqlWriter( const QString &filename, QObject* parent ) :
    Writer( parent ), m_placemarkId( 0 )
{
    QSqlDatabase database = QSqlDatabase::addDatabase( "QSQLITE" );
    database.setDatabaseName( filename );
    if ( !database.open() ) {
        qCritical() << "Failed to connect to database";
        return;
    }

    execQuery( "DROP TABLE IF EXISTS placemarks;" );
    execQuery( "CREATE TABLE placemarks ("
               " regionId INTEGER,"
               " nameId INTEGER,"
               " number VARCHAR(8),"
               " category INTEGER,"
               " lon FLOAT(8),"
               " lat FLOAT(8) )" );
    execQuery( "DROP TABLE IF EXISTS names" );
    execQuery( "CREATE TABLE names ("
               " id INTEGER PRIMARY KEY,"
               " name VARCHAR(50) )" );
    execQuery( "DROP TABLE IF EXISTS regions" );
    execQuery( "CREATE TABLE regions ("
               " id INTEGER PRIMARY KEY,"
               " parent INTEGER NOT NULL,"
               " lft INTEGER NOT NULL,"
               " rgt INTEGER NOT NULL,"
               " name VARCHAR(50),"
               " lon FLOAT(8),"
               " lat FLOAT(8) )" );
    execQuery( "DROP VIEW IF EXISTS places" );
    execQuery( "CREATE VIEW places AS "
               " SELECT"
               "  placemarks.regionId AS region,"
               "  names.name AS name,"
               "  placemarks.number AS number,"
               "  placemarks.category AS category,"
               "  placemarks.lon AS lon,"
               "  placemarks.lat AS lat"
               " FROM names"
               " INNER JOIN placemarks"
               " ON names.id=placemarks.nameId" );
    execQuery( "BEGIN TRANSACTION" );
}

SqlWriter::~SqlWriter()
{
    execQuery( "END TRANSACTION" );
    execQuery( "CREATE INDEX namesIndex ON names(name)" );
    execQuery( "CREATE INDEX placemarksIndex ON placemarks(regionId,nameId,category)" );
    execQuery( "CREATE INDEX regionsIndex ON regions(name,parent,lft,rgt)" );
}

void SqlWriter::addOsmRegion( const OsmRegion &region )
{
    QSqlQuery query;
    query.prepare( "INSERT INTO regions"
                   " (id, parent, lft, rgt, name, lon, lat)"
                   " VALUES (?, ?, ?, ?, ?, ?, ?)" );
    query.addBindValue( ( qint32 ) region.identifier() );
    query.addBindValue( ( qint32 ) region.parentIdentifier() );
    query.addBindValue( ( qint32 ) region.left() );
    query.addBindValue( ( qint32 ) region.right() );
    query.addBindValue( region.name() );
    query.addBindValue( region.longitude() );
    query.addBindValue( region.latitude() );
    execQuery( query );
}

void SqlWriter::addOsmPlacemark( const OsmPlacemark &placemark )
{
    if ( m_lastPlacemark.second != placemark.name() && !m_placemarks.contains( placemark.name() ) ) {
        m_lastPlacemark.first = ++m_placemarkId;
        m_lastPlacemark.second = placemark.name();
        m_placemarks[m_lastPlacemark.second] = m_lastPlacemark.first;

        QSqlQuery insertQuery;
        insertQuery.prepare( "INSERT INTO names"
                             " (id, name)"
                             " VALUES (?, ?)" );
        insertQuery.addBindValue( m_lastPlacemark.first );
        insertQuery.addBindValue( m_lastPlacemark.second );
        execQuery( insertQuery );
    }

    Q_ASSERT( m_placemarks.contains( placemark.name() ) );

    QSqlQuery query;
    query.prepare( "INSERT INTO placemarks"
                   " (regionId, nameId, number, category, lon, lat)"
                   " VALUES (?, ?, ?, ?, ?, ?)" );
    query.addBindValue( ( qint32 ) placemark.regionId() );
    query.addBindValue( m_placemarks[placemark.name()] );
    query.addBindValue( placemark.houseNumber() );
    query.addBindValue( ( qint32 ) placemark.category() );
    query.addBindValue( placemark.longitude() );
    query.addBindValue( placemark.latitude() );
    execQuery( query );
}

void SqlWriter::execQuery( const QString &query ) const
{
    QSqlQuery sqlQuery( query );
    if ( sqlQuery.lastError().isValid() ) {
        qCritical() << "Problems occurred when executing the query" << query;
        qCritical() << "SQL error: " << sqlQuery.lastError();
    }
}

void SqlWriter::execQuery( QSqlQuery &query ) const
{
    query.exec();
    if ( query.lastError().isValid() ) {
        qCritical() << "Problems occurred when executing the query" << query.executedQuery();
        qCritical() << "SQL error: " << query.lastError();
    }
}

}
