import time

import numpy as np
import pandas

from kamzik3.constants import STATUS_CONFIGURED
from kamzik3.devices.device import Device
from kamzik3.snippets.snippetsDecorators import expose_method


class DeviceLogParser(Device):

    def __init__(self, device_id=None, config=None):
        Device.__init__(self, device_id, config)
        self.connect()

    def _init_attributes(self):
        Device._init_attributes(self)

    def handle_configuration(self):
        start_at = time.time()

        def _finish_configuration(*_, **__):
            self._config_commands()
            self._config_attributes()
            self.set_status(STATUS_CONFIGURED)
            self.logger.info(u"Device configuration took {} sec.".format(time.time() - start_at))

        _finish_configuration()

    @expose_method({"path": "Path to the log file", "format": "Name of the format"})
    def parse(self, path, format, filter=None):
        if format == "mag_log":
            dtypes = {}
            header_rows = []
            data_frames = []
            with open(path, "r") as f:
                for row, line in enumerate(f):
                    if line[0] == "#":
                        header_rows.append((row, line))

            for index, (header_row, header) in enumerate(header_rows):
                try:
                    start_row, end_row = header_row, header_rows[index + 1][0] - 1
                except IndexError:
                    start_row, end_row = header_row, row

                nrows = (end_row - start_row)
                if nrows <= 0:
                    continue

                headers, types = [], []
                raw_headers = header.strip().split(";")
                for raw_header in raw_headers:
                    header, meta = raw_header.split(" (")
                    dtype, unit = meta.split(",")
                    try:
                        dtype = np.dtype(dtype).name
                        if dtype in ("int64", "bool"):
                            dtype = "float64"
                    except TypeError:
                        dtype = "str"

                    header_name = "{} ({})".format(header, unit[:-1])
                    headers.append(header_name)
                    dtypes[header_name] = dtype

                df = pandas.read_csv(path, sep=";", low_memory=True, skiprows=start_row, nrows=nrows,
                                     header=0, names=headers, dtype=dtypes)
                data_frames.append(df)

        data_frame = pandas.concat(data_frames, copy=True)

        if filter is not None:
            for filter_column, filter_range in filter.items():
                data_frame = data_frame[(data_frame[filter_column] >= float(filter_range[0])) & (
                        data_frame[filter_column] <= float(filter_range[1]))]

        return data_frame
