"""Use Google analytics in Naaya"""
import cgi
import gdata.auth
import gdata.analytics.service
import time
import datetime

from zope.i18n.locales import locales
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import view_management_screens, view
from OFS.SimpleItem import SimpleItem

from Products.NaayaCore.FormsTool.NaayaTemplate import NaayaPageTemplateFile
from Products.NaayaCore.constants import *
from Products.NaayaBase.constants import PERMISSION_PUBLISH_OBJECTS, MESSAGE_SAVEDCHANGES
from Products.NaayaCore.managers.utils import utils

SCOPE = 'https://www.google.com/analytics/feeds/'
SOURCE = 'naaya-statistics-v1'
INTERVALS = [
                {'period': 30, 'value': 'Last month'},
                {'period': 90, 'value': 'Last 3 months'},
                {'period': 180, 'value': 'Last 6 months'},
                {'period': 356, 'value': 'Last year'}
            ]

en = locales.getLocale('en')
formatter = en.numbers.getFormatter('decimal')
formatter.setPattern('#,##0;-#,##0')

def manage_addAnalyticsTool(self, REQUEST=None):
    """ """
    ob = AnalyticsTool(ID_ANALYTICSTOOL, TITLE_ANALYTICSTOOL)
    self._setObject(ID_ANALYTICSTOOL, ob)
    if REQUEST:
        return self.manage_main(self, REQUEST, update_menu=1)

class AnalyticsTool(SimpleItem, utils):
    """ """

    meta_type = METATYPE_ANALYTICSTOOL
    icon = 'misc_/NaayaCore/AnalyticsTool.gif'

    security = ClassSecurityInfo()

    def __init__(self, id, title):
        """ """
        self.id = id
        self.title = title
        self.ga_service = gdata.analytics.service.AccountsService(source=SOURCE)
        self.gd_service = gdata.analytics.service.AnalyticsDataService(source=SOURCE)
        self.account = None
        self.date_interval = 30
        self.start_date = ''
        self.ga_id = '' # Google Analytics web property ID (UA-number)
        self.gw_verify = '' # Google Webmaster verification meta tag
        self.clear_cache()

    #cache
    def set_cache(self, data, view_name):
        """ """
        if self.checkAuthorization() is not None:
            self._cache[view_name] = data
            self._cache_timestamp = datetime.datetime.now()

    def get_cache(self, view_name):
        interval = datetime.datetime.now() - self._cache_timestamp
        if interval.days > 0:
            return None
        return self._cache.get(view_name, None)

    def clear_cache(self):
        self._cache = {}
        self._cache_timestamp = datetime.datetime.now()

    #administration
    def index_html(self, REQUEST):
        """ redirect to admin_account """
        REQUEST.RESPONSE.redirect(self.absolute_url() + '/admin_account')

    _admin_account_zpt = NaayaPageTemplateFile('zpt/account', globals(), 'site_admin_account')
    _admin_verify = NaayaPageTemplateFile('zpt/verify', globals(), 'site_admin_verify')
    _stats_info = NaayaPageTemplateFile('zpt/stats_info', globals(), 'site_admin_stats_info')

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'stats_info')
    admin_stats = NaayaPageTemplateFile('zpt/stats', globals(), 'site_admin_stats')

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'stats_info')
    def stats_info(self):
        """ """
        view_name = 'stats'
        cached_data = self.get_cache(view_name=view_name)
        if cached_data is None:
            # no data in the cache, so cache it
            data_to_cache = self._stats_info(self.REQUEST)
            self.set_cache(data_to_cache, view_name=view_name)
            return data_to_cache
        # get cached data
        return cached_data

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'admin_verify')
    def admin_verify(self, REQUEST):
        """ Administration page for Google verification codes """
        if REQUEST.has_key('save'):
            self.ga_id = REQUEST.get('ga_id', '')
            self.gw_verify = REQUEST.get('gw_verify', '')
            self.setSessionInfoTrans(MESSAGE_SAVEDCHANGES, date=self.utGetTodayDate())
        return self._admin_verify(REQUEST)

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'admin_account')
    def admin_account(self, REQUEST):
        """ Administration page for Google accounts """
        authorization = self.checkAuthorization()
        if authorization:
            #display accounts
            if REQUEST.has_key('save'):
                account = REQUEST.get('account', '')
                date_interval = REQUEST.get('date_interval', '')
                start_date = REQUEST.get('start_date', '')
                if account:
                    self.account = account
                if start_date:
                    self.start_date = start_date
                    self.date_interval = 0
                else:
                    self.date_interval = int(date_interval)
                    self.start_date = ''
                if self.account or self.start_date or self.date_interval:
                    self.clear_cache()  #clear cached data
                    self.setSessionInfoTrans(MESSAGE_SAVEDCHANGES, date=self.utGetTodayDate())
            elif REQUEST.has_key('revoke'):
                self.delAuthToken()
                self.clear_cache()  #clear cached data
                REQUEST.set('auth_url', self.generateAuthUrl(self.REQUEST.URL))
                return self._admin_account_zpt(REQUEST)
            REQUEST.set('accounts', self.getAccounts())
        else:
            #get authorization
            if REQUEST.has_key('token') and not REQUEST.has_key('revoke'):
                self.getAuthToken(uri='%s?%s' % (self.REQUEST.URL, self.REQUEST.QUERY_STRING))
                REQUEST.set('accounts', self.getAccounts()) #display accounts
            else:
                REQUEST.set('auth_url', self.generateAuthUrl(self.REQUEST.URL))
        return self._admin_account_zpt(REQUEST)

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'generateAuthUrl')
    def generateAuthUrl(self, uri):
        """ generate authentication URL """
        return gdata.auth.GenerateAuthSubUrl(uri, SCOPE, secure=False, session=True)

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'getAuthToken')
    def getAuthToken(self, uri):
        """ extract and store authentication token """
        token = gdata.auth.extract_auth_sub_token_from_url(uri)
        self.ga_service.UpgradeToSessionToken(token)
        self.gd_service.token_store.add_token(token)

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'delAuthToken')
    def delAuthToken(self):
        """ revoke authentication token """
        self.ga_service.RevokeAuthSubToken()
        self.gd_service.RevokeAuthSubToken()
        self.account = None

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'getAccounts')
    def getAccounts(self):
        """ get accounts list """
        res = []
        try:
            account = self.ga_service.GetAccountList()
        except gdata.service.RequestError:
            return None
        if account.entry:
            for entry in account.entry:
                res.append((entry.tableId[0].text, entry.title.text))
            return res

    def getVisitsGraph(self):
        """ Get the visitors graph """
        sd, ed = self.get_date_interval()
        try:
            data = self.gd_service.GetData(
                        ids=self.account,
                        start_date=sd.strftime('%Y-%m-%d'),
                        end_date=ed.strftime('%Y-%m-%d'),
                        dimensions='ga:date',
                        metrics='ga:visits',
                        sort='ga:date')
        except gdata.service.RequestError:
            return None
        valid = False
        if data.entry:
            maximum = 0
            res = []
            for stats in data.entry:
                visit_value = int(stats.visits.value)
                if visit_value > maximum:
                    maximum = visit_value
                if visit_value and not valid:
                    valid = True    #check for 0 values
                res.append(stats.visits.value)
            if valid:
                #chart values, y-axis maxi value, y-axis intermediate values, x-axis labels
                return ','.join(res), maximum*1.1, '||%s|%s|%s|%s|' % (maximum/3, maximum/2, 2*maximum/3, maximum), '|%s|%s|' % (sd.strftime('%d %b'), ed.strftime('%d %b'))

    def getSiteSummary(self):
        """ Get esential date about site usage """
        view_name = 'summary'
        cached_data = self.get_cache(view_name=view_name)
        if cached_data is None:
            sd, ed = self.get_date_interval()
            try:
                data = self.gd_service.GetData(
                            ids=self.account,
                            start_date=sd.strftime('%Y-%m-%d'),
                            end_date=ed.strftime('%Y-%m-%d'),
                            metrics='ga:visits,ga:visitors,ga:pageviews,ga:timeOnSite')
            except gdata.service.RequestError:
                return None
            if data.entry:
                res = {}
                #take the first entry
                stats = data.entry[0]
                res['visits'] = formatter.format(float(stats.visits.value))
                res['visitors'] = formatter.format(float(stats.visitors.value))
                res['pageviews'] = formatter.format(float(stats.pageviews.value))
                res['timeOnSite'] = humanize_time(float(stats.timeOnSite.value)/float(stats.visits.value))
                # no data in the cache, so cache it
                self.set_cache(res, view_name=view_name)
                return res
        # get cached data
        return cached_data

    def getSiteUsage(self):
        """ Get the site usage """
        sd, ed = self.get_date_interval()
        try:
            data = self.gd_service.GetData(
                        ids=self.account,
                        start_date=sd.strftime('%Y-%m-%d'),
                        end_date=ed.strftime('%Y-%m-%d'),
                        metrics='ga:visits,ga:bounces,ga:pageviews,ga:timeOnSite,ga:newVisits,ga:entrances')
        except gdata.service.RequestError:
            return None
        if data.entry:
            res = {}
            #take the first entry
            stats = data.entry[0]
            res['visits'] = formatter.format(float(stats.visits.value))
            bounce_rate = float(stats.bounces.value)/float(stats.entrances.value)*100
            res['bounces'] = '%.2f%%' % bounce_rate
            pages_visit = float(stats.pageviews.value)/float(stats.visits.value)
            res['pages_visit'] = '%.2f' % pages_visit
            res['pageviews'] = formatter.format(float(stats.pageviews.value))
            res['timeOnSite'] = humanize_time(float(stats.timeOnSite.value)/float(stats.visits.value))
            newVisits = float(stats.newVisits.value)/float(stats.visits.value)*100
            res['newVisits'] = '%.2f%%' % newVisits
            return res

    def getTopPages(self):
        """ Get the top pages """
        sd, ed = self.get_date_interval()
        try:
            data = self.gd_service.GetData(
                        ids=self.account,
                        start_date=sd.strftime('%Y-%m-%d'),
                        end_date=ed.strftime('%Y-%m-%d'),
                        dimensions='ga:pagePath',
                        metrics='ga:pageviews',
                        sort='-ga:pageviews',
                        max_results='10')
        except gdata.service.RequestError:
            return None

        website_uri = ''
        if data.extension_elements:
            for elem in data.extension_elements:
                if elem.tag == 'dataSource':
                    for child in elem.children:
                        if child.tag == 'tableName':
                            website_uri = 'http://%s' % child.text
                            break
        if data.entry:
            res = []
            for stats in data.entry:
                dic = {}
                dic['pagePath'] = stats.pagePath.value
                dic['pageviews'] = formatter.format(float(stats.pageviews.value))
                res.append(dic)
            return res, website_uri

    def getTopReferers(self):
        """ Get the top referers """
        sd, ed = self.get_date_interval()
        try:
            data = self.gd_service.GetData(
                        ids=self.account,
                        start_date=sd.strftime('%Y-%m-%d'),
                        end_date=ed.strftime('%Y-%m-%d'),
                        dimensions='ga:source',
                        metrics='ga:visits',
                        filters='ga:medium==referral',
                        sort='-ga:visits',
                        max_results='10')
        except gdata.service.RequestError:
            return None
        if data.entry:
            res = []
            for stats in data.entry:
                dic = {}
                dic['source'] = stats.source.value
                dic['visits'] = formatter.format(float(stats.visits.value))
                res.append(dic)
            return res

    def getTopSearches(self):
        """ Get the top searches """
        sd, ed = self.get_date_interval()
        try:
            data = self.gd_service.GetData(
                        ids=self.account,
                        start_date=sd.strftime('%Y-%m-%d'),
                        end_date=ed.strftime('%Y-%m-%d'),
                        dimensions='ga:keyword',
                        metrics='ga:visits',
                        filters='ga:keyword!=(not set)',
                        sort='-ga:visits',
                        max_results='10')
        except gdata.service.RequestError:
            return None
        if data.entry:
            res = []
            for stats in data.entry:
                dic = {}
                dic['keyword'] = stats.keyword.value
                dic['visits'] = formatter.format(float(stats.visits.value))
                res.append(dic)
            return res

    def checkAuthorization(self):
        """ check authorization """
        try:
            return self.gd_service.AuthSubTokenInfo()
        except:
            return None

    def get_date_interval(self):
        """ """
        end_date = datetime.datetime.today()
        if self.start_date:
            sd = time.strptime(self.start_date,'%d/%m/%Y')
            start_date = datetime.datetime(*sd[0:6])
        else:
            start_date = end_date - datetime.timedelta(days=self.date_interval)
        return start_date, end_date

    def get_intervals(self):
        """ """
        return INTERVALS

InitializeClass(AnalyticsTool)

def humanize_time(secs):
    mins, secs = divmod(secs, 60)
    hours, mins = divmod(mins, 60)
    return '%02d:%02d:%02d' % (hours, mins, secs)
