#include "Global.h"
#include "Exception.h"
#include "__mysql.h"
#include <iostream>

namespace jet {

   Global::Global() {
      
   }

   Global::~Global() {

   }

   void Global::dump() {
      for (auto i = variables.begin(); i != variables.end(); i++)
	std::cout << i->first << "=[" << i->second << "]" << std::endl; 
   }

   bool Global::sessionExists(coreutils::MString sessionId) {
      return sessions.find(sessionId) != sessions.end();
   }
   
   void Global::addSession(coreutils::MString sessionId, __mysql *mysql) {
      std::cout << "sessionId: " << sessionId << std::endl;
      if(sessionExists(sessionId))
	coreutils::Exception("sessionid already exists.");
      sessions[sessionId] = mysql;

      std::cout << "::count: " << sessions.size() << std::endl;
      std::cout << "::" << sessionId << std::endl;
   }
   
   void Global::removeSession(coreutils::MString sessionId) {
      sessions.erase(sessionId);
   }

   coreutils::ZString Global::getVariable(coreutils::ZString &variable) {
      if(variable.ifNext("$[")) {
	 coreutils::MString name;
	 if(variable.ifNext("!")) {
	    return variables[renderVariableName(name, variable)];
	 } if(variable.ifNext(":")) {
	    // TODO: should only allow CGI variable name. Allow variable substitution.
	 } if(variable.ifNext("@")) {
	    // TODO: should only allow environment variables. Allow substitution.
	 } else {
	    coreutils::MString splitName = renderVariableName(name, variable);
	    splitName.split(".");
	    if(splitName.getList().size() == 1)
	      return variables[splitName[0]];
	    return getSessionVariable(splitName);
	 }
	 throw coreutils::Exception("expected variable name or type designator.");	 
      } if(variable.ifNext("#[")) {
	 // TODO: this local variable type has no special naming conventions. We
	 // just need to do nested variable substitution for the entry.
	 
      }
      throw coreutils::Exception("Expecting a variable initializer ('$[' or '#[').");
   }

   coreutils::MString Global::renderVariableName(coreutils::MString &name, coreutils::ZString &variable) {
      name << variable.getTokenInclude("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-");
      if(variable.ifNext("]"))
	return name;
      if(variable.startsWith("$[")) {
	 name << getVariable(variable);
	 if(variable.ifNext("]"))
	   return name;
      } 
      renderVariableName(name, variable);	 
      return name;
   }

   __mysql * Global::getSession(coreutils::MString sessionId) {
      std::cout << "sessionId: " << sessionId << std::endl;
      std::cout << "count: " << sessions.size() << std::endl;
      if(sessions.find(sessionId) == sessions.end())
	throw coreutils::Exception("requested session is not available.");
      return sessions[sessionId];
   }
   
   coreutils::ZString Global::getSessionVariable(coreutils::MString &splitName) {
      if(sessions.find(splitName[0]) == sessions.end())
	throw coreutils::Exception("requested session is not available in variable.");
      return sessions[splitName[0]]->getColumnValue(splitName[1]);
   }
      
}
