# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/metadata.ipynb.

# %% auto 0
__all__ = ['GlobAttrsFeeder', 'BboxCB', 'DepthRangeCB', 'TimeRangeCB', 'ZoteroItem', 'ZoteroCB', 'KeyValuePairCB']

# %% ../nbs/api/metadata.ipynb 2
import pandas as pd
import fastcore.all as fc
from cftime import num2date
from pyzotero import zotero, zotero_errors
import json

from .utils import get_bbox, Callback, run_cbs
from .configs import CONFIGS

# %% ../nbs/api/metadata.ipynb 3
class GlobAttrsFeeder:
    "Produce NetCDF global attributes as specified by the callbacks."
    def __init__(self, 
                 dfs:dict, # Dictionary of NetCDF group DataFrames
                 cbs:list=[], # Callbacks
                 logs:list=[] # List of preprocessing steps taken
                 ): 
        fc.store_attr()
        self.attrs = {}
        
    def callback(self):
        run_cbs(self.cbs, self)
        
    def __call__(self):
        self.callback()
        return self.attrs

# %% ../nbs/api/metadata.ipynb 4
class BboxCB(Callback):
    "Compute dataset geographical bounding box"
    def __call__(self, obj):
        bbox = get_bbox(pd.concat(obj.dfs)) 
        lon_min, lon_max, lat_min, lat_max = [str(bound) for bound in bbox.bounds]
        obj.attrs.update({
            'geospatial_lat_min': lat_min, 
            'geospatial_lat_max': lat_max,
            'geospatial_lon_min': lon_min,
            'geospatial_lon_max': lon_max,
            'geospatial_bounds': bbox.wkt})

# %% ../nbs/api/metadata.ipynb 5
class DepthRangeCB(Callback):
    "Compute depth values range"
    def __init__(self, depth_col='depth'): fc.store_attr()
    def __call__(self, obj):
        depths = pd.concat(obj.dfs).get(self.depth_col, default=pd.Series([]))
        if not depths.empty:
            max_depth, min_depth = depths.max(), depths.min()
            obj.attrs.update({
                'geospatial_vertical_max': '0' if min_depth == 0 else str(-min_depth),
                'geospatial_vertical_min': str(-max_depth)})

# %% ../nbs/api/metadata.ipynb 6
class TimeRangeCB(Callback):
    "Compute time values range"
    def __init__(self, cfg): fc.store_attr()
    def __call__(self, obj):
        time = pd.concat(obj.dfs)['time']
        start, end = [num2date(t, units=self.cfg['units']['time']).isoformat() 
                      for t in (time.min(), time.max())]
        obj.attrs.update({
            'time_coverage_start': start,
            'time_coverage_end': end})

# %% ../nbs/api/metadata.ipynb 7
class ZoteroItem:
    def __init__(self, item_id, cfg):
        self.cfg = cfg
        self.item = self.getItem(item_id)
    
    def exist(self): return self.item != None
    
    def getItem(self, item_id):
        zot = zotero.Zotero(self.cfg['lib_id'], 'group', self.cfg['api_key'])
        try:
            return zot.item(item_id)
        except zotero_errors.ResourceNotFound:
            print(f'Item {item_id} does not exist in Zotero library')
            return None
            
    def title(self):
        return self.item['data']['title']
    
    def summary(self):
        return self.item['data']['abstractNote']
    
    def creator_name(self):
        # creators = [f'{c["creatorType"]}: {c["name"]}' for c in self.item['data']['creators']]
        # return '; '.join(creators)
        return json.dumps(self.item['data']['creators'])
            
    def __repr__(self):
        return json.dumps(self.item, indent=4) 

# %% ../nbs/api/metadata.ipynb 8
class ZoteroCB(Callback):
    "Retrieve Zotero metadata"
    def __init__(self, itemId, cfg): fc.store_attr()
    def __call__(self, obj):
        item = ZoteroItem(self.itemId, self.cfg['zotero'])
        if item.exist(): 
            for attr in ['title', 'summary', 'creator_name']:
                obj.attrs[attr] = getattr(item, attr)()

# %% ../nbs/api/metadata.ipynb 12
class KeyValuePairCB(Callback):
    def __init__(self, k, v): fc.store_attr()
    def __call__(self, obj): obj.attrs[self.k] = self.v
