/*
      _______                          .__ .__   .__   .__                 
      \      \    ____   __ __ _______ |__||  |  |  |  |__|  ____    ____  
      /   |   \ _/ __ \ |  |  \\_  __ \|  ||  |  |  |  |  | /  _ \  /    \ 
     /    |    \\  ___/ |  |  / |  | \/|  ||  |__|  |__|  |(  <_> )|   |  \
     \____|__  / \___  >|____/  |__|   |__||____/|____/|__| \____/ |___|  /
    =========\/======\/=================================================\/==
  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 "Unique.h"

//  C++

#include <iostream>

Unique::Unique() :
  period(INT_MAX)
{
  _sql3.open("/www/neurillion/p/33/databases/uniquehits.sq3");

}

Unique::~Unique()
{
}

int
Unique::hit(std::string const & page, std::string const & ip )
{
  int rc;
  int hits;
  int last_time=0;
  time_t time_now = time(NULL);
  std::stringstream sql_command_ss;
  sql_command_ss.str("");
  sql_command_ss << "SELECT page,hits,ip,time FROM counter_unique_hits LIMIT 1;";
  rc = _sql3.exec(sql_command_ss.str()); // order by?
  int header_size = _sql3.headers().size();
  //  if it doesn't exist, create it ...
  if (0 == header_size) {
    sql_command_ss.str("");
    sql_command_ss << "\
CREATE TABLE counter_unique_hits (page,hits,ip,time);\
CREATE TRIGGER update_unique_hits UPDATE OF hits ON counter_unique_hits\
  BEGIN\
    UPDATE counter_unique_totals SET hits=hits+1, ip=old.ip, time=old.time WHERE page=old.page;\
  END;\
CREATE TRIGGER insert_unique_hits INSERT ON counter_unique_hits\
  BEGIN\
    UPDATE counter_unique_totals SET hits=hits+1, ip=ip, time=time WHERE page=page;\
  END;\
";
    rc = _sql3.exec(sql_command_ss.str());
    //  instead of assuming other table doesn't exist, check for it:
    sql_command_ss.str("");
    sql_command_ss << "SELECT page,hits,ip,time FROM counter_unique_totals LIMIT 1;";
    rc = _sql3.exec(sql_command_ss.str()); // order by?
    int header_size = _sql3.headers().size();
    //  if it doesn't exist, create it ...
    if (0 == header_size) {
      sql_command_ss.str("");
      sql_command_ss << "\
CREATE TABLE counter_unique_totals (page,hits,ip,time);\
";
      rc = _sql3.exec(sql_command_ss.str());
    }
  }
  //
  sql_command_ss.str("");
  sql_command_ss << "SELECT page,hits,ip,time FROM counter_unique_hits";
  sql_command_ss << " WHERE page='"<<page<<"' AND ip='"<<ip<<"';";
  rc = _sql3.exec(sql_command_ss.str()); // order by?
  header_size = _sql3.headers().size();
  if (0 == header_size) {
    sql_command_ss.str("");
    sql_command_ss << "INSERT INTO counter_unique_hits VALUES('";
    sql_command_ss << page << "'," << 1 << ",'" << ip << "'," << time_now << ");";
    rc = _sql3.exec(sql_command_ss.str()); // order by?

    sql_command_ss.str("");
    sql_command_ss << "SELECT hits FROM counter_unique_totals";
    sql_command_ss << " WHERE page='"<<page<<"';";
    rc = _sql3.exec(sql_command_ss.str()); // order by?
    header_size = _sql3.headers().size();
    if (0 == header_size) {
      sql_command_ss.str("");
      sql_command_ss << "INSERT INTO counter_unique_totals VALUES('";
      sql_command_ss << page << "'," << 1 << ",'" << ip << "'," << time_now << ");";
      rc = _sql3.exec(sql_command_ss.str()); // order by?
    }
  } else {
/*
    std::stringstream i;
    i << _sql3.data()[1];
    if ( ! (i>>hits) ); // throw?
    i.clear();
    i << _sql3.data()[3];
    if ( ! (i>>last_time) ); // throw?
*/
    sql_command_ss.str("");
    sql_command_ss << "UPDATE counter_unique_hits SET hits=hits+1,";
    sql_command_ss << "time=" << time_now;
    sql_command_ss << " WHERE page='" << page << "'";
    sql_command_ss << " AND ip='" << ip << "'";
    sql_command_ss << " AND " << time_now<<"-time>"<<period<<";";
//  std::cout << "[time_now-time]=("<<time_now<<"-"<<last_time<< ") = ("<<(time_now-last_time)<<"  sql=" << sql_command_ss.str() << std::endl;
    rc = _sql3.exec(sql_command_ss.str());
  }
  hits = Unique::hits(page);
  return hits;
}

int
Unique::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_unique_totals WHERE page='" << page << "';";
  rc = _sql3.exec(sql_command_ss.str()); // order by?
  int header_size = _sql3.headers().size();
  if (0 != header_size) {
    std::istringstream buffer(_sql3.data()[0]);
    if (!(buffer >> hits)); // throw?
  }
  return hits;
}
