/*
 * =====================================================================================
 *
 *       Filename:  questions.cpp
 *
 *    Description:  Questions Class
 *
 *        Version:  1.0
 *        Created:  06/05/2011 07:08:05 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ruben Safir (), ruben@mrbrklyn.com
 *        Company:  NYLXS
 *
 * =====================================================================================
 */

#include <cstdlib>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
#include <fstream> //probably not needed
#include <iomanip>
#include <termios.h>
#include "questions.h"
#include <cstdlib>
#include <ctime>
#include<stdint.h>
#include <sys/time.h>

namespace Questions{

   Question Deck::create_question(std::ostream &os , std::istream &in ){
      struct termios stored_settings;
      struct termios new_settings;
      std::string input_q, input_a;
      char keystroke;


      os << "Please Enter your question below \n Enter <esc> when finished" << std::endl;
      os << "==================================================================" << std::endl;

      tcgetattr(0,&stored_settings);
      new_settings = stored_settings;

      /* Disable canonical mode, and set buffer size to 1 byte */
      new_settings.c_lflag &= (~ICANON);
      new_settings.c_cc[VTIME] = 0;
      new_settings.c_cc[VMIN] = 1;

      tcsetattr(0,TCSANOW,&new_settings);

      //while( (keystroke = getchar()) ){ //this has to change, it asumes stdin instead of istream in
      while( in.get(keystroke) ){
         if (keystroke == 27)
            break;
         input_q += keystroke;
      }
      os << "Please Enter your answer below \n Enter <esc> when finished" << std::endl;
      os << "==================================================================" << std::endl;

      while( in.get(keystroke) ){
         if (keystroke == 27)
            break;
         input_a += keystroke;
      }

      Question quest(input_q, input_a);

      tcsetattr(0,TCSANOW,&stored_settings);
      return quest;
   } //end of create_question

   void Deck::add_questions(Question &enter){
      //open file
      Deck tmp;
      int pos;
      std::ofstream all_quest( tmp.database.c_str(), std::ios::binary|std::ios::app );
      if(!all_quest){
         std::cerr << "can't open question database for writing" << std::endl;
         exit(1);
      }
      all_quest.seekp( 0, std::ios_base::end);
      pos = all_quest.tellp();
      std::cout << "We are at Pos ==>" << pos << std::endl;

      std::cout << "value of enter.quest ============> \n\n" << enter.quest << "Size of string\n" << sizeof(char) *enter.quest.size()  << std::endl;
      all_quest.write(enter.quest.c_str(), sizeof(char) * enter.quest.size() );
      all_quest.write(enter.answer.c_str(), sizeof(char) * enter.answer.size() );
      all_quest.close();
      return;

   }

   void Deck::fresh_deck(){
      unsigned int index = 0;
      char buf[4096];
      deck.resize(25);
      std::ifstream fetch_questions( this->database.c_str(), std::ios::binary|std::ios::app );
      if(!fetch_questions){
         std::cerr << "can't open question database for reading" << std::endl;
         exit(1);
      }
      for( index = 0; index < deck.size(); index++){
         if(fetch_questions){
            fetch_questions.read(buf, 4096 );
            this->pos = fetch_questions.tellg();
            std::cout << "POS IS " << pos << std::endl;

            this->deck[index].quest = buf ;
         }
         if(fetch_questions){
            fetch_questions.read(buf, 4096 );
            this->pos = fetch_questions.tellg();
            std::cout << "POS IS " << pos << std::endl;
            this->deck[index].answer = buf;
         }else{
            deck.resize(index);
            //Should stop the loop
         }
      }
      fetch_questions.close();

   }

   void Deck::fill_deck(){
      unsigned int index = deck.size();
      char buf[4096];
      deck.resize(25); //expand deck

      std::ifstream fetch_questions( this->database.c_str(), std::ios::binary|std::ios::app );
      if(!fetch_questions){
         std::cerr << "can't open question database for reading" << std::endl;
         exit(1);
      }
      fetch_questions.seekg(this->pos);
      std::cout << "POS IS " << pos << std::endl;
      //decks refill when down to only 5 cards
      for( ; index < deck.size(); index++){
         if(fetch_questions){
            std::cout << "We are fetching new questions" << std::endl;
            fetch_questions.read(buf, 4096 );
            this->pos = fetch_questions.tellg();
            this->deck[index].quest = buf ;
         }
         if(fetch_questions){
            fetch_questions.read(buf, 4096 );
            this->pos = fetch_questions.tellg();
            this->deck[index].answer = buf;
         }else{
            std::cout << "We are resizing the deck" << std::endl;
            deck.resize(index);
         }
      }

   }
   void Deck::shuffle(){
      timeval tmpseed;
      uintmax_t seed;
      unsigned int index;
      std::vector<Question> tmp;
      int ran;
      gettimeofday(&tmpseed, NULL);
      seed = (tmpseed.tv_sec * 1000000) + tmpseed.tv_usec;
      std::string const line = "___________________________________________________________________________\n\n\n\n";
      srand(seed);
      std::vector<Question>::iterator place;
      std::vector<Question>::iterator card;
      place = tmp.begin();

      std::cout << "DUMP DATABASE" << std::endl;
      for(index = 0;  index < deck.size(); index++){
         std::cout << "SET # " << index << "\n" << deck[index].quest << std::endl;
         std::cout << deck[index].answer <<  std::endl;
         std::cout << line << std::endl;
      }

      while(deck.size() > 0){
         ran = rand();
         index = ran % deck.size();
         card = deck.begin();
         card = card + index;

         place = tmp.begin();
         tmp.insert(place, *card);
         deck.erase(card);
         std::cout << "tmp size " << tmp.size() << std::endl;
      }
      deck = tmp;
   }


   void Deck::give_quiz(std::istream &in, std::ostream &os){
      unsigned int index;
      char keep;
      std::vector<Question>::iterator card;
      std::string const line = "___________________________________________________________________________\n\n\n\n";
      //shuffle deck
      this->shuffle();

      card = deck.begin();
      index = 0;
      os << "DUMP DATABASE" << " Deck Size " << deck.size() << std::endl;
      for(index = 0;  index < deck.size(); index++){
         os << "SET # " << index << "\n" << deck[index].quest << std::endl;
         //std::cout << deck[index].quest << std::endl;
         os << deck[index].answer <<  std::endl;
         os << line << std::endl;
      }

      index = 0;
      while(deck.size() > 0){
         os << deck[index].quest << line << std::endl;
         in >> deck[index].response;
         os << deck[index].answer << line <<  std::endl;
         os << "Keep (k) or Dump (d)";
         in >> keep;
         if(keep == 'd'){
            deck.erase(card);
            card = deck.begin();

            if( (deck.size() < 5) && (this->pos > 0 ) ) {
               os << "Refilling deck.  POS is ==> " << this->pos << std::endl;
               this->fill_deck();
               this->shuffle();
            }
         }
         if(keep == 'k'){
            card = deck.end();
            deck.insert(card, *( deck.begin() ) );
            card = deck.begin();
            deck.erase(card);
            card = deck.begin();
         }
      }
      //Clear file position
      this->pos = 1;
   }


   void menu(std::ostream &os){
      os << "Welcome the the C++ Quiz" << "\n\n\n\n" << std::endl;
      std::string tmp = " \n "
         "Select from one of the following: \n\n"
         "a) Insert Question and Answer into the database\n"
         "b) Read 25 Questions and run Quiz\n"
         "c) End Program\n\nResponse==> \n\n\n";

      os << tmp;

   }


   int selection(Deck &stack, std::ostream &os, std::istream &is) {
      char choice;
      Question tmp;
      if(is >> choice){

         switch ( choice ) {
            case 'a':
               tmp = stack.create_question();
               stack.add_questions(tmp);
               break;

            case 'b':
               std::cout << "CASE B" << std::endl;
               stack.fresh_deck();
               stack.give_quiz();
               break;

            case 'c':
               os << "Bye .. " << std::endl;
               return -99;
               break;
            default:
               os << "Incorrect Choise: " << std::endl;
               Questions::menu();
               Questions::selection(stack);
               break;
         }                              /* -----  end switch  ----- */
      }
      return 99;
   } //End of Questions::selection();

}         /* End of Namespace Questions */