"""
Accessor classes for various datasets

Dataset classes provide unified interface for reading data simply by indexing
the class instance.

Example
-------

d = datasets.YorkUrbanDataset(path_to_data)

image_dict = d[0]  # get first item
image_dict = random.choice(d)  # get random item
for image_dict in d:  # iterate through the dataset
    # ... whatever
    pass

Infinite random iterator can be implemented as:

def random_iter(dataset):
    while True:
        yield random.choice(dataset)

The image_dict contains at least the key "image" with the image array.
Ground truth annotation (a horizon line) is in keys "A", "B" with coordinates
of two points on the horizon.

There might be other keys like "filename", "pp", etc. that can be emplyed
for horizon detecion or evaluation purposes.
"""

import random
from itertools import cycle
from pathlib import Path
from typing import Any, Sequence

from skimage.io import imread

from .ecd import EurasianCities
from .flickr import FlickrDataset
from .gp3k import GeoPose3KDataset
from .gsw import GoogleDataset
from .hlw2 import HorizonLinesInTheWildDataset
from .yud import YorkUrbanDataset
from .zoner import ZPSHorizons


class ImageDirDataset:
    """
    Image directory as a dataset with no annotations
    """
    def __init__(self, path: Path, suffixes=None):
        self.fs = list(filter(lambda f: f.is_file or (suffixes and f.suffix not in suffixes), Path(path).glob("*")))  # one liner!

    def __len__(self):
        return len(self.fs)

    def __getitem__(self, idx):
        return dict(image=imread(self.fs[idx]))


def random_iterator(seq:Sequence[Any], maxlen=None) -> Any:
    """
    Iterate over random elements of the sequence.
    """
    N = len(seq)
    order = list(range(N))
    random.shuffle(order)
    for i,j in enumerate(cycle(order)):
        if maxlen is not None and i > maxlen:
            return
        yield seq[j]
