'''
Created on Jan 31, 2011

@author: leifj
'''
from StringIO import StringIO

import httplib2
from urllib import quote_plus
import logging
from pprint import pformat
import os
import tempfile
import time
from lxml import etree
from meetingtools.site_logging import logger
import lxml
from django.http import HttpResponseRedirect
from celery.execute import send_task

class ACPException(Exception):
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return etree.tostring(self.value)

def _first_or_none(x):
    if not x:
        return None
    return x[0]

class ACPResult():
    
    def __init__(self,content):
        self.et = etree.fromstring(content)
        self.status = _first_or_none(self.et.xpath('//status'))
        
    def is_error(self):
        return self.status_code() != 'ok'

    def status_code(self):
        return self.status.get('code')
    
    def subcode(self):
        return self.status.get('subcode')

    def exception(self):
        raise ACPException,self.status

    def get_principal(self):
        logger.debug(lxml.etree.tostring(self.et))
        return _first_or_none(self.et.xpath('//principal'))

def _enc(v):
        ev = v
        if isinstance(ev,str) or isinstance(ev,unicode):
            ev = ev.encode('iso-8859-1')
        return ev

def _getset(d,key,value=None):
    if value:
        if d.has_key(key):
            return d[key]
        else:
            return None
    else:
        d[key] = value

class ACPClient():
    
    def __init__(self,url,username=None,password=None,cache=True,cpool=None):
        self._cpool = cpool
        self.age = 0
        self.createtime = time.time()
        self.lastused = self.createtime
        self.url = url
        self.session = None
        if username and password:
            self.login(username,password)
        if cache:
            self._cache = {'login':{},'group':{}}
            
    def __exit__(self,type,value,traceback):
        if self._cpool and not value:
            self._cpool._q.put_nowait(self)
        
    def __enter__(self):
        return self

    
    def request(self,method,p={},raise_error=False):
        self.age += 1
        self.lastused = time.time()
        u = list()
        u.append("action=%s" % method)
        if self.session:
            u.append("session=%s" % self.session)
        for k,v in p.items():
            value = v
            if type(v) == int:
                value = "%d" % value
            u.append('%s=%s' % (k,quote_plus(value.encode("utf-8"))))
        
        url = self.url + '?' + '&'.join(u)
    
        h = httplib2.Http(tempfile.gettempdir()+os.sep+".cache",disable_ssl_certificate_validation=True);
        logging.debug(url)
        resp, content = h.request(url, "GET")
        logging.debug(pformat(resp))
        logging.debug(pformat(content))
        if resp.status != 200:
            raise ACPException,resp.reason
        
        if resp.has_key('set-cookie'):
            cookie = resp['set-cookie']
            if cookie:
                avp = cookie.split(";")
                if len(avp) > 0:
                    av = avp[0].split('=')
                    self.session = av[1]
                    
        r = ACPResult(content)
        if r.is_error() and raise_error:
            raise r.exception()
        
        return r;
    
    def redirect_to(self,url):
        if self.session:
            return HttpResponseRedirect("%s?session=%s" % (url,self.session))
        else:
            return HttpResponseRedirect(url)
    
    def login(self,username,password):
        result = self.request('login',{'login':username,'password':password})
        if result.is_error():
            raise result.exception()
        return result
    
    def find_or_create_principal(self,key,value,t,d):
        if not self._cache.has_key(t):
            self._cache[t] = {}
        cache = self._cache[t]
        
        # lxml etree Elements are not picklable
        p = None
        if not cache.has_key(key):
            p = self._find_or_create_principal(key,value,t,d)
            cache[key] = etree.tostring(p)
        else:   
            p = etree.parse(StringIO(cache[key]))
        return p
        
    def find_principal(self,key,value,t):
        return self.find_or_create_principal(key,value,t,None)
    
    def _find_or_create_principal(self,key,value,t,d):
        result = self.request('principal-list',{'filter-%s' % key: value,'filter-type': t}, True)
        principal = result.get_principal()
        if result.is_error():
            if result.status_code() != 'no_data':
                result.exception()
        elif principal and d:
            d['principal-id'] = principal.get('principal-id')
        
        rp = principal
        if d:
            update_result = self.request('principal-update',d)
            rp = update_result.get_principal()
            if not rp:
                rp = principal
        return rp
    
    def find_builtin(self,t):
        result = self.request('principal-list', {'filter-type': t}, True)
        return result.get_principal()
    
    def find_group(self,name):
        result = self.request('principal-list',{'filter-name':name,'filter-type':'group'},True)
        return result.get_principal()
    
    def find_user(self,login):
        return self.find_principal("login", login, "user")
    
    def add_remove_member(self,principal_id,group_id,is_member):
        m = "0"
        if is_member:
            m = "1"
        self.request('group-membership-update',{'group-id': group_id, 'principal-id': principal_id,'is-member':m},True)
        
    def add_member(self,principal_id,group_id):
        return self.add_remove_member(principal_id, group_id, True)
    
    def remove_member(self,principal_id,group_id):
        return self.add_remove_member(principal_id, group_id, False)
    
    def user_counts(self,sco_id):
        user_count = None
        host_count = None
        userlist = self.request('meeting-usermanager-user-list',{'sco-id': sco_id},False)
        if userlist.status_code() == 'ok':
            user_count = int(userlist.et.xpath("count(.//userdetails)"))
            host_count = int(userlist.et.xpath("count(.//userdetails/role[text() = 'host'])"))
        elif userlist.status_code() == 'no-access' and userlist.subcode() == 'not-available': #no active session
            user_count = 0
            host_count = 0
        
        return (user_count,host_count)
    
    def poll_user_counts(self,room):
        (room.user_count,room.host_count) = self.user_counts(room.sco_id)
        room.save()
        return (room.user_count,room.host_count)