# -*- coding: utf-8 -*-
#
# UnivNautes
# Copyright (C) 2014  Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import re
import xml.etree.ElementTree as ET
from operator import itemgetter
from base64 import b64decode

from django.conf import settings

def root():
    with open(settings.CONFIG_XML,'r') as f:
        x = ET.fromstring(f.read())
    return x

def laxint(s):
    try:
        return int(s)
    except:
        return 0

def get_ca(caref):
    for ca in root().findall('ca'):
        if ca.find('refid').text == caref:
            crt = ca.find('crt')
            if crt is not None:
                crt = crt.text.decode('base64')
            prv = ca.find('prv')
            if prv is not None:
                prv = prv.text.decode('base64')
            return {
                    'caref': caref,
                    'crt': crt,
                    'prv': prv,
                    }
    return None

def get_cert(certref):
    for cert in root().findall('cert'):
        if cert.find('refid').text == certref:
            crt = cert.find('crt')
            if crt is not None:
                crt = crt.text.decode('base64')
            prv = cert.find('prv')
            if prv is not None:
                prv = prv.text.decode('base64')
            caref = cert.find('caref')
            if caref is not None:
                caref = caref.text
            descr = cert.find('descr')
            if descr is not None:
                descr = descr.text
            return {
                    'certref': caref,
                    'descr': descr,
                    'caref': caref,
                    'crt': crt,
                    'prv': prv,
                    }
    return None

def get_saml_cps():
    '''
    returns a list of captive portal with SAML auth_method
    '''
    xml_cps = root().find('captiveportal')
    if xml_cps is None:
        return []
    cps = []
    for xml_cp in xml_cps:
        name = xml_cp.tag
        if xml_cp.find('enable') is None:
            continue
        auth = xml_cp.find('auth_method')
        if auth is None or auth.text != 'saml':
            continue
        auth = auth.text
        timeout = xml_cp.find('timeout')
        if timeout is not None:
            timeout = laxint(timeout.text)
        else:
            timeout = 0
        idletimeout = xml_cp.find('idletimeout')
        if idletimeout is not None:
            idletimeout = laxint(idletimeout.text)
        else:
            idletimeout = 0
        httpsname = xml_cp.find('httpsname')
        if httpsname is not None:
            httpsname = httpsname.text
        cps.append({
            'name': name,
            'httpsname': httpsname,
            'auth_method': auth,
            'timeout': timeout,
            'idletimeout': idletimeout,
            })
        cps.sort(cps, key=itemgetter('name'))
    return cps

def get_tilesurl():
    sp = root().find('univnautes/sp')
    tilesurl = sp.find('tilesurl')
    if tilesurl is not None:
        tilesurl = tilesurl.text
    return tilesurl

def get_redirect_params():
    sp = root().find('univnautes/sp')
    redirect_url = sp.find('redirect_url')
    if redirect_url is not None:
        redirect_url = redirect_url.text
    redirect_delay = sp.find('redirect_delay')
    if redirect_delay is not None:
        redirect_delay = redirect_delay.text or 0
    return redirect_url, redirect_delay

def get_sp():
    sp = root().find('univnautes/sp')
    if sp is None:
        return None

    certref = sp.find('certref')
    if certref is not None:
        saml_cert = get_cert(certref.text)
    else:
        saml_cert = None

    defaultidps = sp.find('defaultidps')
    if defaultidps is None:
        defaultidps = []
    else:
        defaultidps = defaultidps.text or ''
        defaultidps = defaultidps.decode('base64').decode('iso-8859-1').splitlines()
        defaultidps = [ l for l in defaultidps if not re.match('^\s*(#|$)', l) ]

    geolocations = sp.find('geolocations')
    if geolocations is None:
        geolocations = []
    else:
        geolocations = geolocations.text or ''
        geolocations = geolocations.decode('base64').decode('iso-8859-1').splitlines()
        geolocations = [ l for l in geolocations if not re.match('^\s*(#|$)', l) ]
    geoinitialbounds = sp.find('geoinitialbounds')
    if geoinitialbounds is not None:
        geoinitialbounds = geoinitialbounds.text

    cps = get_saml_cps()
    if cps:
        cp = cps[0]
    else:
        cp = {}
    return { 'saml_cert': saml_cert,
            'cp': cp,
            'ui': {
                'defaultidps': defaultidps,
                'geolocations': geolocations,
                'geoinitialbounds': geoinitialbounds,
                },
            }

def get_federations():
    """
    <federation>
        <enable/>
        <codename>renater_test</codename>
        <refid>fed_53d1161955a26</refid>
        <descr><![CDATA[Renater TEST Federation]]></descr>
        <url>https://federation.renater.fr/test/renater-test-metadata.xml</url>
        <metadata>[base64 encoded metadata]</metadata>
        <certref>53d115fac567b</certref>
    </federation>
    """
    xml_federations = root().find('univnautes/federations')
    if xml_federations is None:
        return []
    xml_federations = xml_federations.findall('federation')
    federations = []
    for xml_federation in xml_federations:
        if xml_federation.find('enable') is None:
            continue
        codename = xml_federation.find('codename')
        if codename is not None:
            codename = codename.text
        url = xml_federation.find('url')
        if url is not None:
            url = url.text
        metadata = xml_federation.find('metadata')
        if metadata is not None:
            try:
                metadata = b64decode(metadata.text)
            except:
                metadata = None
        descr = xml_federation.find('descr')
        if descr is not None:
            descr = descr.text
        certref = xml_federation.find('certref')
        if certref is not None:
            signcert = (get_cert(certref.text) or {}).get('crt')
        else:
            signcert = None
        federations.append({
            'codename': codename,
            'url': url,
            'metadata': metadata,
            'signcert': signcert,
            'descr': descr,
            })
    return federations

def get_whitelists():
    """
    <whitelist>
        <refid>whitelist_53d12b4ba06c2</refid>
        <codename>eduspot</codename>
        <descr><![CDATA[Whitelist eduspot]]></descr>
        <url>https://www.cru.fr/eduspot/whitelist-eduspot.txt</url>
        <caref>53d1166cc8bae</caref>
    </whitelist>
    """
    xml_whitelists = root().find('univnautes/whitelists')
    if xml_whitelists is None:
        return []
    xml_whitelists = xml_whitelists.findall('whitelist')
    whitelists = []
    for xml_whitelist in xml_whitelists:
        refid = xml_whitelist.find('refid')
        if refid is not None:
            refid = refid.text
        codename = xml_whitelist.find('codename')
        if codename is not None:
            codename = codename.text
        descr = xml_whitelist.find('descr')
        if descr is not None:
            descr = descr.text
        url = xml_whitelist.find('url')
        if url is not None:
            url = url.text
        caref = xml_whitelist.find('caref')
        if caref is not None:
            cacert = (get_ca(caref.text) or {}).get('crt')
        else:
            cacert = None
        whitelists.append({
            'id': refid,
            'codename': codename,
            'url': url,
            'cacert': cacert,
            'descr': descr,
            })
    return whitelists


def get_blacklists(list_type):
    """
    <blacklists>
        <macaddresses>base64</macaddresses>
	<nameid>base64</nameid>
    </blacklists>
    """
    xml_blacklist = root().find('univnautes/blacklists/%s' % list_type)
    if xml_blacklist is not None and xml_blacklist.text:
        return xml_blacklist.text.decode('base64')
    return ''

