"""Manage storing sessions between invocations of the application framework
"""
import os
import operator
import shelve
import sys
import tempfile

from quixote.session import Session
from quixote.session import SessionManager

from compClust.gui.DataManager import DataManager
from compClust.gui.DataSource import DataSource

# shelf to hold the various session objects
try:
  login = "-"+os.getlogin()
except:
  login = ""

session_path = os.path.join(tempfile.gettempdir(), "compclustweb%s-session" % (login))
persistent_sessions=shelve.open(session_path)
datamanager = DataManager()

###############
# some convience functions to load sample data  

import ConfigParser
import imp

def config_parser(file):
  """Read an ini file for the functions we should use to load our data.
  
  The config file has the following format:
  [SectionName]
  path=<path to the directory containing the python module>
  module=<module name>
  function=<name of the function to call to return the DataSource of interest>
  arg=<string argument to function>
  
  You can have multiple sections per ini file.
  Also the arg section is optional, and is useful for the cases where your
  data loader function needs some path to be passed to it.
  
  This function returns the list of data loader functions
  """
  def parse_source(parser, source):
    path_name = parser.get(source, 'path')
    module_name = parser.get(source, 'module')
    function_name = parser.get(source, 'function')
    file, filename, ext = imp.find_module(module_name, [path_name])
    # FIXME: This may be a bug if the module name collides with other sourcefiles
    module = imp.load_module(module_name, file, filename, ext)
    function = getattr(module, function_name)
    
    if parser.has_option(source,'arg'):
      arg = parser.get(source, 'arg')
      return lambda : apply(function, [arg], {})
    else:
      return function
      
  if not hasattr(file, 'readline'):
    file = open(file,'r')
  parser = ConfigParser.SafeConfigParser()
  parser.readfp(file)
    
  source_list = parser.sections()
  loader_functions = []
  for source in source_list:
    try:
      loader_functions.append(parse_source(parser, source))
    except ConfigParser.Error, e:
      print >>sys.stderr, "Unable to parse section", source
      print >>sys.stderr, e
  return loader_functions

def load_sources(config_file):
  """Load all the sources from a config file
  """
  load_functions = config_parser(config_file)
  for load_func in load_functions:
    datamanager.append(load_func())
    
################
# Session 
class CompClustWebSession(Session):
  """Holds information about a specific quixote session
  """
  force_user = 'diane'
  
  def __init__(self, id):
    Session.__init__(self, id)
    self.user = None
    self._isdirty = False
    # allow the user to force a particular username
    if self.force_user is not None:
      self.set_user(self.force_user)

  def __get_datamanager(self):
    return datamanager
  datamanager = property(__get_datamanager, doc="return shared datamanager")

  def set_user(self, user):
    print "set_user called", user
    if self.user is None or user.id != self.user.id:
      print "initializing new datamanager"
      self._isdirty = True
    self.user = user
    
  def start_request(self):
    Session.start_request(self)

  def has_info(self):
    # check to see if we have any data
    if self.user is None and len(datamanager.cache) == 0:
      return False
    else:
      return True

  def is_dirty(self):
    return self._isdirty or len(datamanager) > 0

  def __len__(self):
    return len(self.datamanager)

  def sizeof(self):
    """Estimate memory usage
    """
    return reduce(operator.add,
                  [x.sizeof() for x in self.datamanagers.values()])
  
  def __str__(self):
    return "<CompClustWebSession at %s: for %s" %(id(self), self.user)

###########
# Persist our sesssion

class CompClustWebSessionManager(SessionManager):
  """Manage our active sessions
  """
  def __init__(self):
    SessionManager.__init__(self,
                            session_class = CompClustWebSession,
                            session_mapping=persistent_sessions)

  def commit_changes(self, session):
    if session and session.has_info():
      # Tell the datamanager to save itself
      datamanager.persist_all()
      pass
    
###################
# CompClustWeb Publisher

# class CompClustWebPublisher(SessionPublisher):
#   def __init__(self, root_namespace="compClust.gui.CompClustWeb", config=None):
#     SessionPublisher.__init__(self, root_namespace, config, session_mgr=CompClustWebSessionManager())
#     self.config.debug_log = "/tmp/debug"
#     self.config.error_log = "/tmp/error"
#     self.config.upload_dir = "/tmp"
#     self.config.display_exceptions="html"
#     self.config.secure_errors = 0
#     #publisher.setup_logs()
#     #    self.read_config("/home/diane/proj/compclust/compclust.conf")
#     #    self.setup_logs()
    
