# AUTOGENERATED! DO NOT EDIT! File to edit: ../04_ConvertGymirResultToProto.ipynb.

# %% auto 0
__all__ = [
    "logger",
    "ch",
    "formatter",
    "vocabulary",
    "find_csv_name_from_message_field_name",
    "get_message_type_for_simulation_instance",
    "GymirResultConverter",
]

# %% ../04_ConvertGymirResultToProto.ipynb 3
from io import BytesIO
from typing import Union
import pandas as pd
import MachSysS.gymir_result_pb2 as proto
import logging
from google.protobuf.descriptor import FieldDescriptor


# Define logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch.setFormatter(formatter)

logger.addHandler(ch)

vocabulary = {
    "task": "task_type",
    "assignment": "task_name",
    "latitude": "latitude_deg",
    "longitude": "longitude_deg",
    "heading": "heading_deg",
    "wave height significant": "wave_height_significant_m",
    "wave peak period (tp)": "wave_peak_period_s",
    "wave direction in degrees relative to geographic north": "wave_dir_rel_north_deg",
    "wave direction in degrees relative to vessel heading": "wave_dir_rel_vessel_deg",
    "wind speed in meter per sec": "wind_speed_mps",
    "wind direction in degrees relative to geographic north": "wind_dir_rel_north_deg",
    "wind direction in degrees relative to vessel heading": "wind_dir_rel_vessel_deg",
    "speed over ground": "speed_over_ground_kn",
    "speed": "speed_over_ground_kn",
    "speed through water": "speed_through_water_kn",
    "sea current speed in meter pr sec": "current_speed_mps",
    "sea current direction in degrees relative to geographic north": "current_dir_rel_north_deg",
    "power": "power_kw",
    "torque": "torque_k_nm",
    "thrust": "thrust_k_n",
    "rtot": "total_resistance_k_n",
    "weather source": "weather_source",
}


def find_csv_name_from_message_field_name(name: str) -> Union[str, None]:
    try:
        return next(filter(lambda key: vocabulary.get(key) == name, vocabulary))
    except StopIteration:
        return None


def get_message_type_for_simulation_instance(field_name: str) -> Union[str, None]:
    fields = proto.SimulationInstance.DESCRIPTOR.fields_by_name
    field = fields.get(field_name, None)
    if field is not None:
        return field.message_type if field.message_type is not None else field.type


class GymirResultConverter:
    gymir_result: Union[proto.GymirResult, None] = None

    def __init__(
        self,
        *,
        file: Union[str, BytesIO] = None,
        gymir_result: Union[proto.GymirResult, None] = None,
    ):
        if file is not None:
            self.gymir_result = proto.GymirResult()
            if isinstance(file, str):
                with open(file, "rb") as file_obj:
                    self.gymir_result.ParseFromString(file_obj.read())
            else:
                self.gymir_result.ParseFromString(file.read())

        if gymir_result is not None:
            self.gymir_result = gymir_result

    def to_csv(self, filename: str):
        if self.gymir_result is not None:
            with open(filename, "wt") as file:
                for each_instance in self.gymir_result.result:
                    epoch_s = each_instance.epoch_s
                    for field in proto.SimulationInstance.DESCRIPTOR.fields_by_name:
                        if field != "epoch_s":
                            csv_name = find_csv_name_from_message_field_name(field)
                            if csv_name is None:
                                logger.warning(f"No csv field name found for {field}")
                            else:
                                value = getattr(each_instance, field)
                                if value is not None:
                                    file.write(f"{epoch_s},{csv_name},{value}\n")

    def read_csv(
        self, file: Union[str, BytesIO], auxiliary_load_kw: float = 0, name: str = None
    ):
        df = pd.read_csv(file, header=None)
        self.gymir_result = proto.GymirResult(
            auxiliary_load_kw=auxiliary_load_kw, name=name
        )
        epoch_s = 0
        current_simulation_instance = proto.SimulationInstance()
        for index, row in df.iterrows():
            if epoch_s != row[0]:
                if epoch_s != 0:
                    self.gymir_result.result.append(current_simulation_instance)
                epoch_s = row[0]
                current_simulation_instance = proto.SimulationInstance(epoch_s=epoch_s)
            field_name = vocabulary.get(row[1])
            if field_name is None:
                logger.warning(f"No field name found for {row[1]}")
            else:
                value = row[2]
                value_type = get_message_type_for_simulation_instance(field_name)
                if value_type == FieldDescriptor.TYPE_DOUBLE:
                    value = float(value)
                elif value_type in [
                    FieldDescriptor.TYPE_INT32,
                    FieldDescriptor.TYPE_INT64,
                    FieldDescriptor.TYPE_UINT32,
                    FieldDescriptor.TYPE_UINT64,
                ]:
                    value = int(value)
                elif value_type == FieldDescriptor.TYPE_BOOL:
                    value = value == "true" or value == "True" or value == "TRUE"
                setattr(current_simulation_instance, field_name, value)
        if len(df) > 0:
            self.gymir_result.result.append(current_simulation_instance)
