"""Helper functions

Consists of functions to typically be used within templates, but also
available to Controllers. This module is available to templates as 'h'.
"""
# Import helpers as desired, or define your own, ie:
#from webhelpers.html.tags import checkbox, password

import logging
import datetime
import calendar
import pytz
from math import log as lg

from pyramid.i18n import TranslationString as _
from pyramid.url import route_url
from mako.filters import html_escape
from hurry.filesize import size as hsize
from sqlalchemy import func

from pyrone.version import PYRONE_VERSION
from pyrone.models.config import get as get_config
from pyrone.models import DBSession, Article, Tag, Comment
from pyrone.lib import auth, lang
from pyrone.lib import cache

log = logging.getLogger(__name__)


def form_input_text(name, title, value, errors, help=None):
    estyle = ''
    error_str = ''
    if name not in errors:
        estyle = 'display: none;'
    else:
        error_str = errors[name]

    if value is None:
        value = ''

    if help is not None:
        title = '<acronym title="%(help)s">%(title)s</acronym>' % dict(help=html_escape(help), title=html_escape(title))

    html = """<dt>%(title)s</dt>
    <div id="error-%(name)s" class="error" style="%(style)s">%(error)s</div>
    <dd><input type="text" name="%(name)s" id="fid-%(name)s" value="%(value)s"/></dd>
    """ % dict(name=name, style=estyle, error=html_escape(error_str),
               value=html_escape(value), title=title)

    return html


def form_textarea(name, title, value, errors, help=None, height=None):
    estyle = ''
    tstyle = ''
    error_str = ''
    if name not in errors:
        estyle = 'display: none;'
    else:
        error_str = errors[name]

    if height is not None:
        tstyle += 'height: %spx' % height

    if tstyle != '':
        tstyle = ' style="%s"' % tstyle

    if value is None:
        value = ''

    if help is not None:
        title = '<acronym title="%(help)s">%(title)s</acronym>' % dict(help=html_escape(help), title=html_escape(title))

    html = """<dt>%(title)s</dt>
    <div id="error-%(name)s" class="error" style="%(estyle)s">%(error)s</div>
    <dd><textarea type="text" name="%(name)s" id="fid-%(name)s"%(tstyle)s>%(value)s</textarea></dd>
    """ % dict(name=name, estyle=estyle, tstyle=tstyle, error=html_escape(error_str),
               value=html_escape(value), title=title)

    return html


def form_selector(name, title, all_values, value, errors, help=None):
    """
    Render html element OPTION
    """
    estyle = ''
    error_str = ''
    if name not in errors:
        estyle = 'display: none;'
    else:
        error_str = errors[name]

    if help is not None:
        title = '<acronym title="%(help)s">%(title)s</acronym>' % dict(help=html_escape(help), title=html_escape(title))

    selector_items = []
    for id, v in all_values:
        selected = ''
        if id == value:
            selected = ' selected="selected"'
        s = '<option value="%s"%s>%s</option>' % (id, selected, v)
        selector_items.append(s)

    html = """<dt>%(title)s</dt>
    <div id="error-%(name)s" class="error" style="%(style)s">%(error)s</div>
    <dd><select name="%(name)s" id="fid-%(name)s">%(items)s</select></dd>
    """ % dict(name=name, style=estyle, error=html_escape(error_str),
               items=''.join(selector_items), title=title)

    return html


def form_checkbox(name, title, value, errors, help=None, label=None, label_help=None):
    # ignore errors

    if label is not None and label_help is not None:
        label = '<acronym title="%(help)s">%(title)s</acronym>' % dict(help=label_help, title=label)

    html = ""

    if title is not None:
        html += """<dt>%(title)s</dt>""" % dict(title=title)

    cb = '<input type="checkbox" name="%(name)s" id="fid-%(name)s"%(checked)s/>' % dict(name=name,
        checked=' checked="checked"' if value is True else '')
    if label is not None:
        cb = '<label>%(cb)s %(label)s</label>' % dict(cb=cb, label=label)

    html += '<dd>%(cb)s</dd>' % dict(cb=cb)
    return html


def timestamp_to_dt(ts):
    """
    Convert UTC seconds to datetime object
    """
    tz = get_config('timezone')
    tts = datetime.datetime.utcfromtimestamp(ts)  # seconds -> time_struct
    utc_dt = pytz.utc.localize(tts).astimezone(tz)  # utc time -> local time
    return utc_dt


def timestamp_to_str(ts, fmt='%Y-%m-%d %H:%M'):
    """
    Convert UTC seconds to time string in local timezone
    """
    tz = get_config('timezone')
    tts = datetime.datetime.utcfromtimestamp(ts)  # seconds -> time_struct
    utc_dt = pytz.utc.localize(tts).astimezone(tz)  # utc time -> local time

    t_str = utc_dt.strftime(fmt)

    return t_str


def str_to_timestamp(t_str):
    """
    Convert time string in local timezone to UTC seconds
    """
    tz = get_config('timezone')
    dt = datetime.datetime.strptime(t_str, '%Y-%m-%d %H:%M')
    dt_loc = tz.localize(dt)
    dt_utc = dt_loc.astimezone(pytz.utc)

    return calendar.timegm(dt_utc.timetuple())


def span_info(text, escape=True):
    if escape:
        text = html_escape(text)
    return '<span class="info">%s</span>' % text


def cond(condition, true_val, false_val):
    return true_val if condition else false_val


def get_setting(request, id, default_value=None):
    s = request.registry.settings
    if id in s:
        return s[id]
    else:
        return default_value


def user_link(user):
    """
    Generate URL for the user, it could be URL pointing to local user account or to
    external account (twitter, google etc)
    """
    name = user.display_name or user.login

    if user.has_role('admin'):
        title = _('Administrator')
        name = '<span title="%(title)s" class="account-admin">%(name)s</span>' % dict(name=name, title=title)

    if user.kind == 'twitter':
        link = '<a class="account-twitter" href="http://twitter.com/#!/%(name)s">%(name)s</a>' % dict(name=user.login)
    else:
        link = name

    return link


def article_url(request, article):
    return '%s%s/%s' % (route_url('blog_latest', request), article.shortcut_date, article.shortcut)


def article_tags(article):
    """
    Generate comma separated list of tags
    """
    res = []
    for tag in article.tags:
        if tag.tag is None:
            continue
        res.append(tag.tag)

    res = ', '.join(res)
    return res


def article_tags_links(request, article):
    """
    Generate comma separated list of tag hyperlinks
    """
    res = []
    url_template = '<a href="%s">__TAG__</a>' % route_url('blog_tag_articles', request, tag='__TAG__')
    for tag in article.tags:
        if tag.tag is None:
            continue
        res.append(url_template.replace('__TAG__', tag.tag))

    return ', '.join(res)


def get_public_tags_cloud(force_reload=False):
    """
    return tags cloud: list of tuples-pairs ("tag", "tag_weight"), tag_weight - is a number divisible by 5,
    0 <= tag_weight <= 100
    Only for published articles.
    """
    value = cache.get_value('tags_cloud')
    if value is None or force_reload:
        dbsession = DBSession()
        q = dbsession.query(func.count(Tag.id), Tag.tag).join(Article).filter(Article.is_draft==False).group_by(Tag.tag)
        items = list()
        counts = list()
        total = 0
        for rec in q.all():
            if rec[0] <= 0:
                continue
            total += rec[0]
            items.append((rec[1], int(rec[0])))
            counts.append(int(rec[0]))

        if len(counts) != 0:
            min_count = min(counts)
            max_counts = max(counts)

            if min_count == max_counts:
                # i.e. all tags counts are the same, so they have the same weight
                weights = [(x[0], 50) for x in items]
            else:
                lmm = lg(max_counts) - lg(min_count)

                weights = [(x[0], (lg(x[1])-lg(min_count)) / lmm) for x in items]
                weights = [(x[0], int(5*(int(100*x[1])/5))) for x in weights]

            value = weights
        else:
            value = []

        cache.set_value('tags_cloud', value)

    return value


def get_pages_widget_links(force_reload=False):

    value = cache.get_value('pages_links')

    if value is None or force_reload:
        pages_links = list()
        # fetch from settings, parse, fill cache
        raw = get_config('widget_pages_pages_spec')
        if raw is None:
            raw = ''
        for line in raw.split('\n'):
            line = line.strip()
            if len(line) == 0:
                continue
            # take first char - it's a delimiter
            delim = line[0]
            components = line[1:].split(delim)
            if len(components) != 2:
                continue
            url, title = components
            if not url.startswith('http://') and not url.startswith('https://'):
                continue
            link = {'url': url, 'title': title}
            pages_links.append(link)

        value = pages_links
        cache.set_value('pages_links', value)

    return value


def get_twitter_share_link_button(force_reload=False):
    value = cache.get_value('rendered_twitter_share_link_button')
    if value is None or force_reload:
        if get_config('social_twitter_share_link') != 'true':
            value = ''
        else:
            tpl = '''<a href="https://twitter.com/share" class="twitter-share-button"%(twitter_via)s%(show_count)s>Tweet</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>'''
            twitter_via = get_config('social_twitter_share_link')
            show_count = get_config('social_twitter_share_link_show_count')
            repl = dict(twitter_via='', show_count='')
            if twitter_via != '':
                # possible
                repl['twitter_via'] = ' data-via="%s"' % html_escape(twitter_via)
            if show_count != 'true':
                repl['show_count'] = ' data-count="none"'

            value = tpl % repl

        cache.set_value('rendered_twitter_share_link_button', value)

    return value


def get_gplusone_button(force_reload=False):

    value = cache.get_value('rendered_gplusone_button')
    if value is None or force_reload:
        if get_config('social_gplusone') != 'true':
            value = ''
        else:
            tpl = '''<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<g:plusone></g:plusone>'''
            value = tpl

        cache.set_value('rendered_gplusone_button', value)

    return value


def get_not_approved_comments_count():
    dbsession = DBSession()
    cnt = dbsession.query(func.count(Comment.id)).filter(Comment.is_approved==False).scalar()
    return cnt

def get_supported_langs_spec():
    return lang.supported_langs_spec()

