// check_answers.cgi: applicazione per controllare i punteggi e memorizzare le risposte 
// dei test.
#include 
#include "applicat.h"
#include "questionnaire.h"
class Check_answers_Application : public Application
{
private:
  String     _dbname;
  String     _utente;   // Utente corrente
  String     _modulo;   // Numero del modulo del quale controllare le risposte
  String     _testnum;  // Numero del test del quale controllare le risposte
  PgEnv      _environment;
  bool       _blank_test;
  String     _user_answers;
  Questionnaire _questionario;
  PgTransaction *_db;
  
protected:
  virtual bool create();
  virtual bool destroy();
  virtual void main_func();
  void check_answers();
  void print_access_error();
  bool load_corrector();
public:
  Check_answers_Application() 
  {
  	_db = NULL;
  }
  virtual ~Check_answers_Application() {};
};
bool Check_answers_Application::create()
{
  String separator, ws;
  String qs[3];
  char answers[MAXQUESTIONS][MAXANSWERS];
  for (int i=0; iLunghezza del buffer: " << cl << "
" << endl;
#endif
  if (cl < 8192) { // Evita di ricevere troppa roba sullo stdin (8kb sono abbastanza??)
    for (int x = 0; cl && (!feof(stdin)); x++) {
      t1 = fmakeword(stdin, '&', &cl);
      t2 = makeword(t1, '=');
      unescape_url(t1);
      unescape_url(t2);
      if (!strcmp(t2,"MODULO"))
	_modulo = t1;
      if (!strcmp(t2,"TESTNUM"))
	_testnum = t1;
      if (!strcmp(t2,"BLANK_TEST"))
	_blank_test = !strcmp(t1,"ON");
      // Carica le risposte fornite
      if (t2[0] == 'Q') { // Si tratta di una risposta del test; formato Q__
	// Estrae il numero relativo alla domanda ed il numero della risposta
        ws = t2;
	const int e = split(ws, qs, 3, separator);
	if (e == 3) {
	  const int qnum = atoi(qs[1]) - 1; // riferimento alla domanda
	  const int anum = atoi(qs[2]) - 1; // riferimento alla risposta
	  if (qnum < MAXQUESTIONS && anum < MAXANSWERS)
	    if (!strcmp(t1,"ON"))
	      answers[qnum][anum] = 'V';
	}
      }
    }
    
    // Compone _user_answers
    for (int i=0; iRisposte fornite
" << endl;
    for (int j = 0; j < MAXQUESTIONS; j++) {
      cout << "Domanda " << j+1 << ":
";
      for (int k = 0; k < MAXANSWERS; k++)
	if (answers[j][k] == 'V')
	  cout << "VERO ";
	else
	  cout << "FALSO ";
      cout << "
" << endl;
    }
    return FALSE;
#endif
  }
  else {
    cout << "Troppi dati inviati
" << endl;
    cout << "L'applicazione ha ricevuto troppi dati sul buffer d'ingresso.
" << endl;
    return FALSE;
  } 
  return TRUE;
}
bool Check_answers_Application::destroy()
{
  print_footer();
  return TRUE;
}
bool Check_answers_Application::load_corrector()
{
  bool loaded = FALSE;
  String command, correct_answers, separator;
  separator = ";";
  command = "SELECT * FROM CORRETTORI WHERE modulo=";
  command += _modulo;
  command += " AND testnum='";
  command += _testnum;
  command += "'";
  _db->ExecCommandOk(command);
  const int tuples = _db->Tuples();
  if (tuples > 0) {
    correct_answers = _db->GetValue(0, "risposte");
    loaded = _questionario.load(correct_answers, _user_answers);
  }
 
  return loaded;
}
void Check_answers_Application::check_answers()
{
  if (!load_corrector()) {
    cout << "Correttore inesistente
" << endl;
    cout << "Impossibile caricare il correttore per il test immesso.
";
    cout << "Rivolgersi al docente della lezione odierna.
";
    return;
  }
  
  // 1 of theze dayz I'll fall to pieces anywayz
  String command, verifiche, corso;
  // Compone la stringa di selezione utente. 
  command = "SELECT * FROM UTENTI WHERE loginname='";
  command += _utente;
  command += "' AND logged='t'";
  // Esegue il comando SQL, dovrebbe venir ritornata una sola tupla
  // al limite se ne vengono ritornate piu' di una verranno ignorate
  _db->ExecCommandOk(command);
  const int tuples = _db->Tuples();
  if (tuples > 0) {
    // Aggiorna lo stato dei test effettuati per modulo sulla tabella UTENTI
    verifiche = _db->GetValue(0, "verifiche");
    corso     = _db->GetValue(0, "course");
    trim(corso);
    const unsigned int mod_int = atoi(_modulo);
    const unsigned int l       = verifiche.length();
    if ((l < mod_int || verifiche[mod_int-1] != _testnum[0]) && mod_int <= MAXMODULES) {
      if (l< mod_int)
	for (unsigned int j=l; j < mod_int; j++)
	  verifiche += ' ';
      verifiche[mod_int-1] = _testnum[0];
      command = "UPDATE UTENTI SET verifiche='";
      command += verifiche;
      command += "' WHERE loginname='";
      command += _utente;
      command += "'";
      _db->ExecCommandOk(command);
      
      // Controlla i punteggi inseriti nella matrice con quelli memorizzati nel correttore
      // Compone le risposte fornite da memorizzare sulla tabella VERIFICHE in un formato più "umano"
      Rational punteggio;
      punteggio = _blank_test ? ZERO : _questionario.calc_score();
      
      long progressivo = 0L;
      // Blocca la tabella dei progressivi e prende il progressivo 
      command = "LOCK PROGRESSIVI";
      _db->ExecCommandOk(command);
      
      command = "SELECT * FROM PROGRESSIVI";
      if (_db->ExecTuplesOk(command) && _db->Tuples() > 0){
	progressivo = atol(_db->GetValue(0, "progverifiche"));
      }
      else { // Se non c'è nessuna riga viene aggiunta
	command = "INSERT INTO PROGRESSIVI VALUES(0,0)";
	_db->ExecCommandOk(command);	  
      }
      progressivo++;
      command = "UPDATE PROGRESSIVI SET progverifiche=progverifiche+1"; // Incrementa il progressivo
      _db->ExecCommandOk(command); // Aggiorna la tabella PROGRESSIVI
      // Memorizza il punteggio e le risposte fornite sulla tabella VERIFICHE
      command = "INSERT INTO VERIFICHE VALUES (";
      command += ltoa(progressivo);
      command += ",'";
      command += _utente;
      command += "',current_timestamp,";
      command += _modulo;
      command += ",'";
      command += _testnum;
      command += "','";
      if (_blank_test)
        command +=  " " ;
      else
        command += _user_answers; // Risposte fornite in formato "umano"
      command += "',";
      command += dtoa((double) punteggio); // Punteggio sottoforma di double
      command += ")";
      _db->ExecCommandOk(command);
      if (_modulo=="1")		// (23/01/01) Il modulo 1 é "speciale" in quanto non ha alcun test; é il modulo di
		cout << "" << endl;	// formazione del tecnico contabile di Eurocampo
	  else
      cout << "Risultato del test
" << endl;
      if (!_blank_test)
        _questionario.dump_html(corso, atoi(_modulo), _testnum[0]);
      else
		{
		  if(_modulo=="1")	// (23/01/01) solito modulo 1 speciale
			cout << "Benvenuti nel modulo per la formazione del TECNICO CONTABILE
";
		  else
			cout << "
Test consegnato  in bianco 
";
		}
      cout << "
" << endl;
    }
    else { // Se il test è già stato eseguito, nega l'aggiornamento il calcolo punteggio e tutto il resto
      cout << "Test già eseguito
" << endl;
      cout << "Il test selezionato risulta già eseguito.
";
      cout << "Si prega di riselezionare l'area corretta dalla pagina di selezione moduli.
";
  }
  }
  else { // Se non trova i dati dell'utente indicato 
         // visualizza la mancanza di informazioni per completare la pagina.
    cout << "Mancanza di informazioni
" << endl;
    cout << "Impossibile reperire le informazioni relative al percorso formativo dell'utente " << _utente;
    cout << ".
Controllare l'esattezza delle informazioni inserite.
";
  }
  return;
}
void Check_answers_Application::print_access_error()
{ 
 
  cout << "Errore di accesso
";
  cout << "Utilizzare la normale procedura di accesso ai corsi.
";
}
void Check_answers_Application::main_func()
{ 
  // Controllo utente: se il CGI viene chiamato senza tutte le indicazioni necessarie
  // visualizza l'errore
  if (_utente.empty() || _modulo.empty() || _testnum.empty() || _user_answers.empty()) {
    print_access_error();
    return;
  }
  // Se tutto è OK...
  // Inizia la transazione
  _db = new PgTransaction(_environment, _dbname);
  if ( _db->ConnectionBad() ) 
    print_database_error();
  else
    check_answers();
  delete _db; // Termina la transazione
  return;
}
int main(int argc, char* argv[])
{
  Check_answers_Application* a = new Check_answers_Application();
 
  a->run(argc, argv);
  delete a;
  
  exit(0);
}