/*******************************************************************************
*                         Goggles Music Manager                                *
********************************************************************************
*           Copyright (C) 2006-2011 by Sander Jansen. All Rights Reserved      *
*                               ---                                            *
* 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 "gmdefs.h"

// Database
GMDatabase::GMDatabase() : opened(FALSE),db(NULL){
  }

GMDatabase::~GMDatabase(){
  close();
  }

FXbool GMDatabase::open(const FXString & filename){
  close();

  if (sqlite3_open(filename.text(),&db)!=SQLITE_OK){
    return FALSE;
    }

  if (!execute("PRAGMA database_list;"))
    return FALSE;

  opened=TRUE;
  return TRUE;
  }

/// Close the database
void GMDatabase::close(){
  if (db) {
    sqlite3_close(db);
    db=NULL;
    }
  opened=FALSE;
  }

/// Clear the database
void GMDatabase::clear(){
  FXStringList tables;
  listTables(tables);
  for (FXint i=0;i<tables.no();i++){
    execute("DROP TABLE " + tables[i] + ";");
    }
  }


void GMDatabase::clearTables(){
  FXStringList tables;
  listTables(tables);
  for (FXint i=0;i<tables.no();i++){
    execute("DELETE FROM " + tables[i] + ";");
    }
  }

FXint GMDatabase::changes() const {
  return sqlite3_changes(db);
  }



/// Execute a simple query
FXbool GMDatabase::execute(const FXchar * statement){
  try {
    GMQuery query(this,statement);
    return query.perform();
    }
  catch (FXCompileException &){
    fxwarning("Compile Exception: %s\n",statement/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  catch (FXExecuteException &){
    fxwarning("Excute Exception: %s\n",statement/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  return TRUE;
  }

/// Execute a simple query
FXbool GMDatabase::execute(const FXString & statement){
  try {
    GMQuery query(this,statement.text());
    return query.perform();
    }
  catch (FXCompileException &){
    fxwarning("Compile Exception: %s\n",statement.text()/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  catch (FXExecuteException &){
    fxwarning("Excute Exception: %s\n",statement.text()/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  return TRUE;
  }

/// Execute a simple query
FXbool GMDatabase::execute_with_result(const FXString & statement,FXint & val){
  try {
    GMQuery query(this,statement.text());
    query.execute();
    query.getResult(0,val);
    }
  catch (FXCompileException &){
    fxwarning("Compile Exception: %s\n",statement.text()/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  catch (FXExecuteException &){
    fxwarning("Excute Exception: %s\n",statement.text()/*e.what()*/);
    fxmessage("Reason: %s\n",sqlite3_errmsg(db));
    return FALSE;
    }
  return TRUE;
  }




FXint GMDatabase::lastInsertRow() {
  return sqlite3_last_insert_rowid(db);
  }

/// Return error message for last error
const FXchar * GMDatabase::getError() {
  return sqlite3_errmsg(db);
  }

/// Return num changes by recent query
FXint GMDatabase::getNumChanges() const{
  if (!db) fxerror("GMDatabase::getNumChanges() - database not opened");
  return sqlite3_changes((sqlite3*)db);
  }

/// Return total changes since opening database
FXint GMDatabase::getTotalChanges() const{
  if (!db) fxerror("GMDatabase::getTotalChanges() - database not opened");
  return sqlite3_total_changes((sqlite3*)db);
  }

/// Begin Transaction
FXbool GMDatabase::begin() {
  return execute("BEGIN TRANSACTION;");
  }

/// Commit Transaction
FXbool GMDatabase::commit(){
  return execute("COMMIT TRANSACTION;");
  }

/// Rollback a transaction
FXbool GMDatabase::rollback(){
  return execute("ROLLBACK TRANSACTION;");
  }

/// End Transaction
FXbool GMDatabase::end(){
  return execute("END TRANSACTION;");
  }

void GMDatabase::setVersion(FXint v){
  execute(GMStringFormat("PRAGMA user_version=%d;",v));
  }

FXint GMDatabase::getVersion(){
  FXint version=0;
  GMQuery query(this,"PRAGMA user_version;");
  query.execute();
  query.getResult(0,version);
  return version;
  }



FXbool GMDatabase::hasTable(const FXString & table){
  FXString name;
  GMQuery query(this,"SELECT name FROM sqlite_master WHERE type='table';");
  while(query.execute()){
    query.getResult(0,name);
    if (name==table) return TRUE;
    }
  return FALSE;
  }



FXbool GMDatabase::hasIndex(const FXString & index){
  FXString name;
  GMQuery query(this,"SELECT name FROM sqlite_master WHERE type='index';");
  while(query.execute()){
    query.getResult(0,name);
    if (name==index) return TRUE;
    }
  return FALSE;
  }


void GMDatabase::listTables(FXStringList & list){
  FXString name;
  GMQuery query(this,"SELECT name FROM sqlite_master WHERE type='table';");
  while(query.execute()){
    query.getResult(0,name);
    list.append(name);
    }
  }

FXbool GMDatabase::hasView(const FXString & view){
  FXString name;
  GMQuery query(this,"SELECT name FROM sqlite_master WHERE type='view';");
  while(query.execute()){
    query.getResult(0,name);
    if (name==view) return TRUE;
    }
  return FALSE;
  }

void GMDatabase::listViews(FXStringList & list) {
  FXString name;
  GMQuery query(this,"SELECT name FROM sqlite_master WHERE type='view';");
  while(query.execute()){
    query.getResult(0,name);
    list.append(name);
    }
  }
