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

# %% auto 0
__all__ = ['most_common', 'context_chdir', 'generate_time_id', 'flatten_dict', 'unflatten_dict', 'NestedDict']

# %% ../nbs/utils.ipynb 3
import os
from contextlib import contextmanager
from pathlib import Path
from typing import Dict, List, Tuple, Union

import pandas as pd
from fastcore.basics import patch

# %% ../nbs/utils.ipynb 4
from collections import Counter

def most_common(lst):
    """returns the most common element of a collection"""
    return Counter(lst).most_common(1)[0][0]

# %% ../nbs/utils.ipynb 6
@patch
def ls_sorted(self:Path):
    "ls but sorts files by name numerically"
    return self.ls().sorted(key=lambda f: int(f.with_suffix('').name))

# %% ../nbs/utils.ipynb 7
# ref: https://dev.to/teckert/changing-directory-with-a-python-context-manager-2bj8
@contextmanager
def context_chdir(path: Union[Path, str]):
    """Sets the cwd within the context"""
    origin = Path().absolute()
    try:
        os.chdir(path)
        yield
    finally:
        os.chdir(origin)

# %% ../nbs/utils.ipynb 9
from datetime import datetime

def generate_time_id(dt=None):
    """generates a string id from given datetime or now"""
    return (dt or datetime.now()).isoformat().rsplit('.', 1)[0].replace(':', '-')

# %% ../nbs/utils.ipynb 12
def flatten_dict(d: Dict, sep='.') -> Dict:
    records = pd.json_normalize(d, sep=sep).to_dict(orient='records')
    if len(records):
        return records[0]
    return {}

def unflatten_dict(d: Dict, sep='.') -> Dict:
    res = {}
    for k, v in d.items():
        subkeys = k.split(sep)
        container = res
        for subkey in subkeys[:-1]:
            if subkey not in container:
                container[subkey] = {}
            container = container[subkey]
        container[subkeys[-1]] = v
    return res

# %% ../nbs/utils.ipynb 15
class NestedDict(dict):
    def __init__(self, data, sep='.'):
        super().__init__(data)
        self.sep = sep
    
    def at(self, keys: Union[str, List, Tuple], default=None):
        if isinstance(keys, str):
            keys = keys.split(self.sep)
        node = self
        for key in keys:
            if key not in node:
                return default
            node = node.get(key)
        return node

    def set(self, keys: Union[str, List, Tuple], value):
        if isinstance(keys, str):
            keys = keys.split(self.sep)
        node = self
        last_key = keys.pop()
        for key in keys:
            if key not in node:
                node[key] = dict()
            node = node[key]
        node[last_key] = value

    def flat(self) -> Dict:
        return flatten_dict(self, sep=self.sep)
    
    @classmethod
    def from_flat_dict(cls, data, sep='.'):
        return cls(unflatten_dict(data, sep=sep))
     
