# built-in
from copy import copy

# third-party
import numpy as np

from epibox import config_debug
from epibox.exceptions.system_exceptions import DeviceNotInAcquisitionError


def read_modules(devices, mac_channels, sensors, header):

    t = np.array([])
    t_display = np.array([])
    channels2get = [int(mac_chn[1]) - 1 for mac_chn in mac_channels]

    for i, device in enumerate(devices):

        try:
            if header["service"] == "bitalino":
                t_read = device.read(100)
            elif header["service"] == "scientisst":
                t_read = device.read(convert=False, matrix=True)

        except Exception as e:
            config_debug.log(e)
            raise DeviceNotInAcquisitionError

        t_read = np.delete(
            t_read, np.arange(1, 5), axis=1
        )  # remove digital channels
        t_nseq = t_read[:, 1:]  # remove nSeq column (add again in the end)

        # else:
        #     seq = []
        #     t_nseq = []

        #     for f in t_read:

        #         frame = f.toMap()
        #         seq += [frame["sequence"]]

        #         if len(t_nseq) == 0:
        #             t_nseq_aux = np.reshape(np.array(frame["analog"]), (1, -1))
        #             t_nseq = np.reshape(
        #                 np.take(t_nseq_aux, channels2get), (1, -1))
        #         else:
        #             t_nseq_aux = np.reshape(
        #                 np.take(
        #                     np.reshape(
        #                         np.array(frame["analog"]), (1, -1)), channels2get
        #                 ),
        #                 (1, -1),
        #             )
        #             t_nseq = np.vstack((t_nseq, t_nseq_aux))

        # t_read = np.hstack((np.reshape(np.array(seq), (-1, 1)), t_nseq))

        # config_debug.log(t_nseq)

        n = 0
        display_aux = np.array([])

        for j, chn in enumerate(mac_channels):

            if chn[0] == device.address:

                if header["save_raw"]:
                    signal_type = "RAW"

                else:
                    signal_type = sensors[j]

                r = header["resolution"][device.address][n + 1]
                t_aux = get_transform(
                    t_nseq[:, n], signal_type, r
                )  # receives and returns a column with 100 samples

                n += 1
                if len(display_aux) == 0:
                    display_aux = copy(t_aux)

                else:
                    display_aux = np.concatenate((display_aux, t_aux), axis=1)

        if len(t_display) == 0:
            t_display = copy(display_aux)
            t = np.concatenate(
                (np.reshape(t_read[:, 0], (-1, 1)), display_aux), axis=1)

        else:
            t_display = np.concatenate((t_display, display_aux), axis=1)
            aux = np.concatenate(
                (np.reshape(t_read[:, 0], (-1, 1)), display_aux), axis=1
            )
            t = np.concatenate((t, aux), axis=1)

    t_str = "\n".join(" ".join("%0.1f" % x for x in y) for y in t)
    return t, t_str, t_display


def get_transform(raw, signal_type, res):

    if signal_type == "ECG":
        aux = list(
            map(lambda x: (((x / (2**res) - 0.5) * 3.3) / 1100) * 1000, raw))

    elif signal_type == "EEG":
        aux = list(
            map(lambda x: (((x / (2**res) - 0.5) * 3.3) / 41782) * (10 ** (6)), raw)
        )

    elif signal_type == "EOG":
        aux = list(
            map(lambda x: (((x / (2**res) - 0.5) * 3.3) / 2040) * 1000, raw))

    elif signal_type == "EMG":
        aux = list(
            map(lambda x: (((x / (2**res) - 0.5) * 3.3) / 1009) * 1000, raw))

    elif signal_type == "PZT":
        aux = list(map(lambda x: (x / (2**res) - 0.5) * 100, raw))

    elif signal_type == "EDA":
        aux = list(map(lambda x: (((x / (2**res)) * 3.3) / 0.132), raw))

    else:
        aux = list(raw)

    return np.reshape(np.asarray(aux), (-1, 1))
