#!/usr/bin/env python
# encoding: utf-8

# The MIT License (MIT)

# Copyright (c) 2016-2017 CNRS

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# AUTHORS
# Hervé BREDIN - http://herve.niderb.fr


from __future__ import division

import h5py
import os.path
import numpy as np
from struct import unpack
import pysndfile.sndio
from pyannote.core import SlidingWindow, SlidingWindowFeature
from pyannote.database.util import get_unique_identifier


class PyannoteFeatureExtractionError(Exception):
    pass


def get_wav_duration(wav):
    y, sample_rate, _ = pysndfile.sndio.read(wav)
    n_samples = y.shape[0]
    return n_samples / sample_rate


class Precomputed(object):
    """Load precomputed features from HDF5 file

    Parameters
    ----------
    features_h5 : str
        Path to HDF5 file generated by script 'feature_extraction.py'.
    """

    @staticmethod
    def get_config_path(root_dir):
        path = '{root_dir}/metadata.h5'.format(root_dir=root_dir)
        return path

    @staticmethod
    def get_path(root_dir, item):
        uri = get_unique_identifier(item)
        path = '{root_dir}/{uri}.h5'.format(root_dir=root_dir, uri=uri)
        return path

    def __init__(self, root_dir=None):
        super(Precomputed, self).__init__()
        self.root_dir = root_dir

        path = self.get_config_path(self.root_dir)

        f = h5py.File(path)
        start = f.attrs['start']
        duration = f.attrs['duration']
        step = f.attrs['step']
        self.sliding_window_ = SlidingWindow(
            start=start, duration=duration, step=step)
        self.dimension_ = f.attrs['dimension']
        f.close()

    def sliding_window(self):
        return self.sliding_window_

    def dimension(self):
        return self.dimension_

    def __call__(self, item):

        path = self.get_path(self.root_dir, item)

        if not os.path.exists(path):
            uri = get_unique_identifier(item)
            msg = 'No precomputed features for "{uri}".'
            raise PyannoteFeatureExtractionError(msg.format(uri=uri))

        f = h5py.File(path)
        data = np.array(f['features'])
        f.close()

        return SlidingWindowFeature(data, self.sliding_window_)


class PrecomputedHTK(object):

    def __init__(self, root_dir=None, duration=0.025):
        super(PrecomputedHTK, self).__init__()
        self.root_dir = root_dir
        self.duration = duration

    @staticmethod
    def get_path(root_dir, item):
        uri = get_unique_identifier(item)
        path = '{root_dir}/{uri}.htk'.format(root_dir=root_dir, uri=uri)
        return path

    # http://codereview.stackexchange.com/questions/
    # 1496/reading-a-binary-file-containing-periodic-samples
    @staticmethod
    def load_htk(file_htk):
        with open(file_htk, 'rb') as fp:
            data = fp.read(12)
            num_samples, sample_period, sample_size, _ = unpack('>iihh', data)
            num_features = int(sample_size / 4)
            num_samples = int(num_samples)
            X = np.empty((num_samples, num_features))
            for i in range(num_samples):
                data = fp.read(sample_size)
                X[i, :] = unpack('>' + ('f' * (sample_size // 4)), data)
        return X, sample_period

    def __call__(self, item):

        file_htk = self.get_path(self.root_dir, item)
        X, sample_period = self.load_htk(file_htk)
        sw = SlidingWindow(start=0.,
                           duration=self.duration,
                           step=sample_period * 1e-7)

        return SlidingWindowFeature(X, sw)

@@ -1257,16 +1257,38 @@
 os.path%0A
+from glob import glob%0A
 import n
@@ -3440,16 +3440,943 @@
 ration%0A%0A
+        # load any htk file in root_dir/database%0A        path = '%7Broot_dir%7D/*/*.htk'.format(root_dir=root_dir)%0A        found = glob(path)%0A%0A        # FIXME switch to Py3.5 and use glob 'recursive' parameter%0A        # http://stackoverflow.com/questions/2186525/%0A        # use-a-glob-to-find-files-recursively-in-python%0A%0A        if len(found) %3E 0:%0A            file_htk = found%5B0%5D%0A        else:%0A            msg = %22Could not find any HTK file in '%7Broot_dir%7D'.%22%0A            raise ValueError(msg.format(root_dir=root_dir))%0A%0A        X, sample_period = self.load_htk(file_htk)%0A%0A        self.sliding_window_ = SlidingWindow(start=0.,%0A                                             duration=self.duration,%0A                                             step=sample_period * 1e-7)%0A        self.dimension_ = X.shape%5B1%5D%0A%0A    def sliding_window(self):%0A        return self.sliding_window_%0A%0A    def dimension(self):%0A        return self.dimension_%0A%0A
     @sta

add missing sliding_window and dimension methods