# http://pyrocko.org - GPLv3
#
# The pyrockoeost Developers, 21st Century
# ---|P------/S----------~Lg----------

import time
import re
import logging
import json

from pyrockoeost import model, util
from pyrockoeost.moment_tensor import MomentTensor, symmat6
from .base_catalog import EarthquakeCatalog, NotFound

from pyrockoeost.util import urlopen

logger = logging.getLogger('pyrockoeost.client.geofon')

km = 1000.


class Geofon(EarthquakeCatalog):
    '''
    Access the GEOFON earthquake catalog.
    '''
    def __init__(self, get_moment_tensors=True):
        self.events = {}
        self._get_moment_tensors = get_moment_tensors

    def flush(self):
        self.events = {}

    def iter_event_names(
            self,
            time_range=None,
            nmax=1000,
            magmin=None,
            latmin=-90.,
            latmax=90.,
            lonmin=-180.,
            lonmax=180.):

        logger.debug('In Geofon.iter_event_names(...)')

        dmin = time.strftime('%Y-%m-%d', time.gmtime(time_range[0]))
        dmax = time.strftime('%Y-%m-%d', time.gmtime(time_range[1]+24*60*60))

        if magmin is None:
            magmin = ''
        else:
            magmin = '%g' % magmin

        ipage = 1
        while True:
            url = ('http://geofon.gfz-potsdam.de/eqinfo/list.php?' + '&'.join([
                'page=%i' % ipage,
                'datemin=%s' % dmin,
                'datemax=%s' % dmax,
                'latmin=%g' % latmin,
                'latmax=%g' % latmax,
                'lonmin=%g' % lonmin,
                'lonmax=%g' % lonmax,
                'magmin=%s' % magmin,
                'fmt=geojson',
                'nmax=%i' % nmax]))

            logger.debug('Opening URL: %s' % url)
            page = urlopen(url).read()
            logger.debug('Received page (%i bytes)' % len(page))
            events = self._parse_events_page(page)
            for ev in events:
                if ev.moment_tensor is True:
                    ev.moment_tensor = self.get_mt(ev)

            if not events:
                break

            for ev in events:
                if time_range[0] <= ev.time and ev.time <= time_range[1]:
                    self.events[ev.name] = ev
                    yield ev.name

            ipage += 1

    def get_event(self, name):
        logger.debug('In Geofon.get_event("%s")' % name)

        if name not in self.events:
            url = 'http://geofon.gfz-potsdam.de/eqinfo/event.php' \
                  '?id=%s&fmt=geojson' % name
            logger.debug('Opening URL: %s' % url)
            page = urlopen(url).read()
            logger.debug('Received page (%i bytes)' % len(page))

            try:
                ev = self._parse_event_page(page)
                self.events[name] = ev

            except NotFound:
                raise NotFound(url)  # reraise with url

        ev = self.events[name]

        if ev.moment_tensor is True:
            ev.moment_tensor = self.get_mt(ev)

        return ev

    def get_mt(self, ev):
        syear = time.strftime('%Y', time.gmtime(ev.time))
        url = 'http://geofon.gfz-potsdam.de/data/alerts/%s/%s/mt.txt' % (
            syear, ev.name)

        try:
            logger.debug('Opening URL: %s' % url)
            page = urlopen(url).read()
            logger.debug('Received page (%i bytes)' % len(page))
        except util.HTTPError:
            logger.warning('No MT found for event "%s".' % ev.name)
            return None

        return self._parse_mt_page(page)

    def _parse_mt_page(self, page):
        d = {}
        for k in 'Scale', 'Mrr', 'Mtt', 'Mpp', 'Mrt', 'Mrp', 'Mtp':
            r = k.encode('ascii')+br'\s*=?\s*(\S+)'
            m = re.search(r, page)
            if m:
                s = m.group(1).replace(b'10**', b'1e')
                d[k.lower()] = float(s)

        m = symmat6(*(d[x] for x in 'mrr mtt mpp mrt mrp mtp'.split()))
        m *= d['scale']
        mt = MomentTensor(m_up_south_east=m)

        return mt

    def _parse_events_page(self, page, limit=None):
        j = json.loads(page.decode('utf-8'))
        events = []
        for ifeature, feature in enumerate(j['features']):
            ev = self._json_feature_to_event(feature)
            events.append(ev)
            if limit and ifeature + 1 == limit:
                break

        return events

    def _parse_event_page(self, page):
        return self._parse_events_page(page, limit=1)[0]

    def _json_feature_to_event(self, feature):
        name = feature['id']
        lon, lat, depth = feature['geometry']['coordinates']
        depth *= 1000.
        properties = feature['properties']
        magnitude = properties['mag']
        magnitude_type = properties['magType']
        region = properties['place']
        tevent = util.str_to_time(properties['time'].replace('T', ' '))

        if ((properties.get('hasMT', 'no') == 'yes')
                or properties['magType'] == 'Mw') and self._get_moment_tensors:

            moment_tensor = True  # flag for caller to query MT
        else:
            moment_tensor = None

        status = properties['status'][:1]
        tags = []
        if status in 'AMC':
            tags.append('geofon_status:%s' % status)

        category = properties.get('evtype', '')
        if re.match(r'^[a-zA-Z0-9]+$', category):
            tags.append('geofon_category:%s' % category)

        ev = model.Event(
            lat=float(lat),
            lon=float(lon),
            time=tevent,
            name=name,
            depth=float(depth),
            magnitude=float(magnitude),
            magnitude_type=str(magnitude_type),
            region=str(region),
            moment_tensor=moment_tensor,
            catalog='GEOFON',
            tags=tags)

        return ev
