import tg
from webob.exc import HTTPNotFound

import re

from bazbase import conversion, structure
from bazki import util
from bazki.translators import edit_url
from bazki.edit import data_for_url
from . import zampolit, restricted

SQUARE_BRACKETS_RE = re.compile(r'\[(.*)\]$')
PARENS_RE = re.compile(r' *\(..+\)')
SPACE_RE = re.compile(r'[ ]+')
SYMBOL_RE = re.compile(r'[^a-zA-Z0-9_]+')

def propnameify(heading):
    match = SQUARE_BRACKETS_RE.search(heading)
    if match:
        key = match.group(1)
    else:
        key = PARENS_RE.sub('', heading)
        if '?' in key:
            key = key.rsplit('?', 1)[0]

    key = SPACE_RE.sub('_', key.lower())
    key = SYMBOL_RE.sub('', key)

    return u'app_' + key

def enameify(name):
    name = SYMBOL_RE.sub('', name)
    return u'App' + name

DAY_RE = re.compile(r'([A-Za-z][a-z]+day)')
TIME_RE = re.compile(r'([0-9]+ ?[AaPp][Mm])')

def slot_enameify(slot, run):
    pref = u'Run%d' % run
    daym = DAY_RE.search(slot)
    assert daym is not None, slot
    day = daym.group(1)
    timem = TIME_RE.search(slot)
    assert timem is not None, slot
    return pref + day + timem.group(1)

def castingbase_dict():
    pcs = structure.get_element(u'PC').get_descendants()
    runs = structure.get_element(u'Run').get_descendants()
    app_parent = structure.get_element(u'App')
    if app_parent is not None:
        apps = app_parent.get_descendants()
        app_props = [pn for pn in app_parent.list_props()
                     if pn.startswith(u'app_')]
    else:
        apps = []
        app_props = []
    return {'pcs': pcs, 'apps': apps, 'app_props': app_props,
            'runs': runs}

class Admin(tg.TGController):
    allow_only = restricted.PRED

    zampolit = zampolit.Zampolit()

    @tg.expose(template="mako:gameki.templates.email")
    def email(self, ename, send=False):
        elm = structure.get_element(ename)
        if elm is None:
            raise HTTPNotFound(ename)
        from . import macros
        from bazjunk.email import format
        emails = conversion.to_python(elm, u'product', 'email', 'email')

        msgs = []
        for e in emails:
            atturl = e.get('attachment', None)
            if atturl is not None:
                res, res_type = data_for_url(atturl)
                attachment = (atturl.rsplit('/', 1)[-1],
                              res,
                              res_type)
                
            else:
                attachment = None
            kw = dict(msg=e['msg'], subject=e['subject'],
                        from_addr=e['from'], to_addr=e['to'],
                        cc=e.get('cc', None))
            if send:
                if attachment:
                    kw['attachment'] = attachment
                util.send_email(**kw)
            else:
                msgs.append((format(**kw), atturl, attachment))
        if send:
            tg.flash('%s emails sent.' % len(emails))
            tg.redirect(edit_url(ename))
        else:
            return {'ename': ename, 'messages': msgs}

    @tg.expose(template="mako:gameki.templates.cast")
    def cast(self, apps=None):

        if apps is not None:
            import csv
            rows = csv.reader(apps.file)
            headings = rows.next()
            propnames = [propnameify(h) for h in headings]
            slots = []
            for i in xrange(len(propnames)):
                if 'name' in propnames[i]:
                    name_index = i
                    break
            for i in xrange(len(propnames)):
                if 'when' in propnames[i]:
                    when_index = i
                    break
            # First pass, we're just checking for types
            could_be_integer = dict((pn, True) for pn in propnames)
            rows = list(rows)
            for r in rows:
                for i in xrange(len(r)):
                    if not r[i].isdigit():
                        could_be_integer[propnames[i]] = False
            for i in xrange(len(propnames)):
                pn = propnames[i]
                if could_be_integer[pn]:
                    flav = 'integer'
                else:
                    flav = 'string'
                prop = structure.get_prop(pn)
                if prop is None:
                    prop = structure.create_prop(pn, flav)
                else:
                    prop.set_flavor(flav)
                prop.set_comment(headings[i])
            parent = structure.get_element('App')
            if parent is None:
                parent = structure.get_root_element().create_child(u'App')
            for pn in propnames:
                parent.set_prop(pn, '')
            # Second pass, create some elements.
            for r in rows:
                if not r[name_index]:
                    continue
                ename = enameify(r[name_index])
                assert r[when_index], r
                whens = [w.strip() for w in r[when_index].split(',')]
                for wi in xrange(len(whens)):
                    if whens[wi] not in slots:
                        if wi > 0:
                            slots.insert(slots.index(whens[wi - 1]) + 1,
                                         whens[wi])
                        else:
                            slots.insert(0, whens[wi])
                elm = structure.get_element(ename)
                if elm is None:
                    elm = parent.create_child(ename)
                    appending = False
                else:
                    appending = True
                for i in xrange(len(r)):
                    pn = propnames[i]
                    val = r[i]
                    if appending:
                        old_val = elm.get_prop(pn)
                        if old_val.strip():
                            val = old_val + '; ' + val
                    elm.set_prop(pn, val)
                elm.set_prop('availability',
                             ', '.join('[[%s]]' % slot_enameify(w, 1)
                                       for w in whens).encode('utf-8'))
            run_parent = structure.get_element(u'Run')
            for s in slots:
                slot_ename = slot_enameify(s, 1)
                run_parent.create_child(slot_ename).set_prop(u'name', s)
        return castingbase_dict()

    @tg.expose(template="mako:gameki.templates.casting")
    def casting(self):
        return castingbase_dict()
