// opendb.cpp
//
// Open a CallCommander Database
//
//   (C) Copyright 2002-2004 Fred Gleason <fredg@paravelsystems.com>
//
//   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 2 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, write to the Free Software
//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//

#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
#endif  // WIN32
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlDriver>
#include <QtGui/QMessageBox>
#include <QtSql/QSqlQuery>

#include <ml.h>

#include "globals.h"
#include "opendb.h"
#include "createdb.h"
#include "mysql_login.h"

void ShowDbError(const QString &msg,bool interactive)
{
  if(interactive) {
    QMessageBox::warning(NULL,"MDbAdmin",msg);
  }
  else {
    fprintf(stderr,"mdbadmin: %s\n",(const char *)msg.toAscii());
  }
}

bool OpenDb(const QString &dbname,const QString &login,const QString &pwd,
	    const QString &host,bool interactive)
{
  QString admin_name;
  QString admin_pwd;
  QString sql;
  QSqlQuery *q;
  QString msg;
  MySqlLogin *mysql_login;

  //
  // Open Database
  //
  QSqlDatabase db=QSqlDatabase::addDatabase(admin_config->mysqlDbtype());
  db.setDatabaseName(dbname);
  db.setUserName(login);
  db.setPassword(pwd);
  db.setHostName(host);
  if(!db.open()) {
    if(interactive) {
      msg="Unable to access the CallCommander Database!\n\
Please enter a login for an account with\n\
administrative rights on the mySQL server,\n\
and we will try to get this straightened out.";
    mysql_login=new MySqlLogin(msg,&admin_name,&admin_pwd);
    if(mysql_login->exec()!=0) {
      delete mysql_login;
      db.removeDatabase(dbname);
      return false;
    }
    delete mysql_login;
    }
    else {
      admin_name=admin_admin_username;
      admin_pwd=admin_admin_password;
    }
    db.setUserName(admin_name);
    db.setPassword(admin_pwd);
    if(db.open()) {      // Fixup DB Access Permsissions
      ShowDbError("Wrong access permissions for accessing MySQL",interactive);
      db.removeDatabase("mysql");
      return false;
    }
    else {
      db.setDatabaseName("mysql");
      if(!db.open()) {   // mySQL is hosed -- scream and die.
	ShowDbError("Unable to connect to MySQL",interactive);
	db.removeDatabase("mysql");
	return false;
      }
      else {              // Create a new CallCommander Database
	q=new QSqlQuery(QString().sprintf("create database %s",
					  (const char *)dbname));
	if(!q->isActive()) {   // Can't create DB.
	  delete q;
	  ShowDbError("Unable to create a CallCommander Database",interactive);
	  db.removeDatabase("mysql");
	  return false;
	}
	delete q;
	sql=QString().sprintf("insert into user set Host=\"localhost\",\
            User=\"%s\",Password=PASSWORD(\"%s\")",
			      (const char *)login,(const char *)pwd);
	q=new QSqlQuery(sql);
	delete q;
	sql=QString().sprintf("insert into user set Host=\"\",\
            User=\"%s\",Password=PASSWORD(\"%s\")",
			      (const char *)login,(const char *)pwd);
	q=new QSqlQuery(sql);
	delete q;
	sql=QString().
	  sprintf("insert into db set Host=\"%%\",Db=\"%s\",\
            User=\"%s\",Select_priv=\"Y\",Insert_priv=\"Y\",Update_priv=\"Y\",\
            Delete_priv=\"Y\",Create_priv=\"Y\",Drop_priv=\"Y\",\
            Index_priv=\"Y\",Alter_priv=\"Y\"",
		  (const char *)dbname,(const char *)login);
	q=new QSqlQuery(sql);
	delete q;
	q=new QSqlQuery("flush privileges");
	delete q;
	db.close();   // Relinquish admin perms
	db.setDatabaseName(dbname);
	db.setUserName(login);
	db.setPassword(pwd);
	if(!db.open()) {   // Can't open new database
	  ShowDbError("Unable to connect to new CallCommander Database",
		      interactive);
	  db.removeDatabase(dbname);
	  return false;
	}
	if(!CreateDb(login,pwd)) {   // Can't create tables.
	  ShowDbError("Unable to create CallCommander Database",interactive);
	  db.removeDatabase(dbname);
	  return false;
	}
	db.close();
	db.setDatabaseName(dbname);
	db.setUserName(login);
	db.setPassword(pwd);
	if(!db.open()) {
	  ShowDbError("Unable to connect to CallCommander Database",
		      interactive);
	  db.removeDatabase(dbname);
	  return false;
	}	  
	if(!InitDb(login,pwd)) {  // Can't initialize tables.
	  ShowDbError("Unable to initialize CallCommander Database",
		      interactive);
	  db.removeDatabase(dbname);
	  return false;
	}
	if(interactive) {
	  QMessageBox::information(NULL,"Created Database",
				   "New CallCommander Database Created!");
	}
	return true;
      }
    }
    return false;
  }
  q=new QSqlQuery("select DB from VERSION");
  if(!q->first()) {
    ShowDbError("Unable to access CallCommander Database",interactive);
    db.removeDatabase(dbname);
    return false;
  }
  int ver=q->value(0).toInt();
  delete q;
  if(ver<ML_VERSION_DATABASE) {
    if(interactive) {
      if(QMessageBox::warning(NULL,"Update Needed",
	    "The CallCommander Database needs to be updated.\nContinue?",
	    QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) {
	db.removeDatabase(dbname);
	return false;
      }      
    }
    if(!UpdateDb(ver)) {
      ShowDbError("Unable to update CallCommander Database",interactive);
      db.removeDatabase(dbname);
      return false;
    }
    msg=QString().
      sprintf("The CallCommander Database has\nbeen updated to Version %d",
	      ML_VERSION_DATABASE);
    if(interactive) {
      QMessageBox::information(NULL,"Database Updated",msg);
    }
  }
  return true;
}
