/*
      _______                          .__ .__   .__   .__                 
      \      \    ____   __ __ _______ |__||  |  |  |  |__|  ____    ____  
      /   |   \ _/ __ \ |  |  \\_  __ \|  ||  |  |  |  |  | /  _ \  /    \ 
     /    |    \\  ___/ |  |  / |  | \/|  ||  |__|  |__|  |(  <_> )|   |  \
     \____|__  / \___  >|____/  |__|   |__||____/|____/|__| \____/ |___|  /
    =========\/======\/=================================================\/==
  v0.01 04/JUL/2007 © Copyright 2007-2007 Scott D. Yelich SOME RIGHTS RESERVED
 .,-*~'`^`'~*-,._.,-*~'`^`'~*-,._.,-*~'`^`'~*-,._.-*~'`^`'~*-,._.,-*~'`^`'~*-,. 


  LICENSE:  Creative Commons Attribution 3.0 License.
  SEE:      http://creativecommons.org/licenses/by/3.0/


  Sun Jul 29 21:33:38 EDT 2007, v0.02 sdy

  This is a *very* simple program written to do a web page
  hit counter using sqlite3.

*/

#include "CounterMulti.h"

CounterMulti::CounterMulti()
{
  try { 
    _sql3.open("/www/neurillion/p/33/databases/hits.sq3");
  }
  catch (Xql3Exception & e) {
/*
    std::cerr << "sqlite3_error: " <<  _sql3.dberrcode()
              << " --> " << _sql3.dberrmsg() << std::endl;
    std::cerr << "Xql3Exception: " << e.code() << " --> "
              << e.what() << std::endl;
*/
  }
}

CounterMulti::~CounterMulti()
{
}

int 
CounterMulti::sqlx(std::string const & sql)
{
  int rc=0;
  try { 
    rc = _sql3.exec(sql);
  }
  catch (Xql3Exception & e) {
/*
    std::cerr << "sqlite3_error: " <<  _sql3.dberrcode()
              << " --> " << _sql3.dberrmsg() << std::endl;
    std::cerr << "Xql3Exception: " << e.code() << " --> "
              << e.what() << std::endl;
*/
    return 1; // exit with error ....    
  }
  return rc;
}

int
CounterMulti::hit(std::string const & page)
{
  int rc;
  int hits=1;
  int last=0;
  int ctime=0;
  int current=0;
  time_t time_now = time(NULL);
  std::stringstream sql_command_ss;
  sql_command_ss.str("");
  sql_command_ss << "select current,time,hits,last from counter_multi_totals where page='" << page << "';";
  sqlx(sql_command_ss.str()); // order by?
  int hsz = _sql3._headers.size();
  //  if it doesn't exist, create it ...
  if (0 == hsz) {
    sqlx("CREATE TABLE counter_multi_totals (page,current,time,hits,last);");
    sql_command_ss << "INSERT INTO counter_multi_totals VALUES('";
    sql_command_ss << page << "'," << hits << "," << time_now << ",";
    sql_command_ss << hits << "," << time_now << ");";
    sqlx(sql_command_ss.str());
  } else {
    //  if _sql3._data.size() ....
    std::stringstream i;
    i << _sql3._data[0];
    if ( ! (i>>current) ); // throw?
    i.clear();
    i << _sql3._data[1];
    if ( ! (i>>ctime) ); // throw?
    i.clear();
    i << _sql3._data[2];
    if ( ! (i>>hits) ); // throw?
    i.clear();
    i << _sql3._data[3];
    if ( ! (i>>last) ); // throw?

    sql_command_ss.str("");
    sql_command_ss << "UPDATE counter_multi_totals SET current=current+1,";
    sql_command_ss << "time=" << time_now;
    //  the "if" check should really be done inside of SQL ...
    if ( (time_now-current)>MINTIME ) {
      sql_command_ss << ",hits=current+1,last=" << time_now;
    }
    sql_command_ss << " WHERE page='" << page << "';";
    sqlx(sql_command_ss.str());
  }
  return hits;
}

int
CounterMulti::hits(std::string const & page)
{
  int rc;
  int hits=0;
  std::stringstream sql_command_ss;
  sql_command_ss.str("");
  sql_command_ss << "select hits from counter_multi_totals where page='" << page << "';";
  sqlx(sql_command_ss.str()); // order by?
  int hsz = _sql3._headers.size();
  if (0 != hsz) {
    std::istringstream buffer(_sql3._data[0]);
    if (!(buffer >> hits)); // throw?
  }
  return hits;
}

