""" 
Create OCA-JSON object from obs-info network
"""
import obsinfo
import json

################################################################################
class network:
    """OCA network description format
    
    Now that the instrument_components no longer name the response_stages but
    give a list instead, will have to deduce the OCA-compatible terms:
        - In Sensor: first item is sensor, any other are ana_filts
        - In Preamplifier: any items are ana_filts
        - In Datalogger: last item is digital_filter, second to last is digitizer,
            any prior are ana_filts
    """

    def __init__(self, obs_network, debug=False):
        """
        Create an OCA network object (contains stations without component details)
        """
        for station_code, station in obs_network.stations.items():
            if debug:
                print(station_code)
                print("A:", station.comments)
            station.partial_fill_instrument(
                obs_network.instrumentation_file, referring_file=obs_network.basepath
            )
            if debug:
                print("B:", station.comments)
            # self.stations[station_code]=station
        if debug:
            for key, station in obs_network.stations.items():
                print(station.comments)

        if debug:
            for key, station in obs_network.stations.items():
                print("B-Ca:", key, station.comments)
        self.dict = dict()
        self.__make_network_header(obs_network)
        self.__make_authors(obs_network)

        if debug:
            for key, station in obs_network.stations.items():
                print("B-Cb:", key, station.comments)
        self.dict["stations"] = []
        for key, station in obs_network.stations.items():
            if debug:
                print("C:", key, station.comments)
            oca_station = self.__make_station_header(station)
            # oca_station={"open_date":'duh',"close_date":'der'}
            oca_station = self.__make_devices_and_channels(
                oca_station, station.instrument.das_components
            )
            self.dict["stations"].append(oca_station)

    #     def dict(self,debug=False):
    #         """Make an oca JSON string """
    #         return self.dict

    def __repr__(self):
        return "<OCA_Network: fdsn_code={}>".format(self.dict["network"]["fdsn_code"])

    def __make_network_header(self, obs_network):
        netinfo = obs_network.network_info
        # Forces authorship of comments to network.yaml revision author
        for comment in netinfo.comments:
            comments = {"value": comment, "authors": ["auth1"]}
        self.dict["network"] = {
            "fdsn_code": netinfo.code,
            "temporary": True,
            "open_date": netinfo.start_date.isoformat(),
            "close_date": netinfo.end_date.isoformat(),
            "description": netinfo.description,
            "comments": comments,
        }

    def __make_authors(self, obs_network):
        """ Fills in author(s) information"""
        self.dict["comment_authors"] = dict()
        i = 0
        for author in obs_network.revision["authors"]:
            i = i + 1
            phones = list()
            if "phones" in author:
                for phone in author["phones"]:
                    phones.append({"phone_number": phone}),
            au_dict = {
                "firstname": author["first_name"],
                "lastname": author["last_name"],
                "emails": [author.get("email", "")],
                "phones": phones,
            }
            self.dict["comment_authors"]["auth" + str(i)] = au_dict

    def __make_station_header(self, obs_station, debug=False):
        """ Makes OCA STATION HEADER
        returns station dictionary
         """
        oca_station = dict()
        if debug:
            print("comments=", obs_station.comments)
            print("nClock_corrections=", len(obs_station.clock_corrections))
            print("nSupplements=", len(obs_station.supplements))
        oca_comments = [x for x in obs_station.comments]
        if obs_station.supplements:
            for key, value in obs_station.supplements.items():
                if debug:
                    print(key)
                oca_comments.append(json.dumps({key: value}).replace('"', "'"))
        if obs_station.clock_corrections:
            for key, value in obs_station.clock_corrections.items():
                if debug:
                    print(key)
                oca_comments.append(json.dumps({key: value}).replace('"', "'"))
        if debug:
            print("----")

        sta_position = obs_station.locations[obs_station.location_code]["position"]
        oca_station = {
            "IR_code": obs_station.code,
            "site": obs_station.site,
            "comments": oca_comments,
            "open_date": obs_station.start_date,
            "close_date": obs_station.end_date,
            "longitude": sta_position[0],
            "latitude": sta_position[1],
            "altitude": sta_position[2],
            "altitude_unit": "m",
            "first_install": obs_station.start_date,
        }
        return oca_station

    def __make_devices_and_channels(self, oca_station, das_components):

        oca_station["channels"] = list()
        devices = dict()
        for das_code, values in das_components.items():
            devices, device_codes = self.__add_devices(devices, values)
            ###
            ch = self.__make_channel(
                das_code,
                device_codes,
                values,
                oca_station["open_date"],
                oca_station["close_date"],
            )
            oca_station["channels"].append(ch)
        oca_station["installed_devices"] = devices
        return oca_station

    def __add_devices(self, devices, values, debug=False):
        """
        Find devices or add to dictionary of "installed devices"
        
        devices= existing dictionary of devices
        values = values corresponding to this das_component
        """
        codes = dict()
        if debug:
            print("===", values)

        sensor = self.__make_devicedict("sensor", values["sensor"].equipment)
        azimuth, dip = obsinfo.get_azimuth_dip(
            values["sensor"].seed_codes, values["orientation_code"]
        )
        sensor["azimuth_error"] = azimuth[1]
        sensor["dip_error"] = dip[1]
        sensor["local_depth"] = 0
        sensor["vault"] = "seafloor"
        sensor["config"] = "single"
        devices, codes["sensor"] = self.__find_append_device(devices, sensor, "sensor")

        anafilter = self.__make_devicedict(
            "anafilter", values["preamplifier"].equipment
        )
        devices, codes["anafilter"] = self.__find_append_device(
            devices, anafilter, "anafilter"
        )

        das = self.__make_devicedict("das", values["datalogger"].equipment)
        devices, codes["das"] = self.__find_append_device(devices, das, "das")

        return devices, codes

    def __make_devicedict(self, metatype, equipment):
        # if type(equipment) == dict:
        #    equipment=FDSN_EquipmentType(equipment)
        SN = equipment.serial_number
        devicedict = {
            "metatype": metatype,
            "manufacturer": equipment.manufacturer,
            "model": equipment.model,
            "serial_number": "unknown" if SN is None else SN,
        }
        return devicedict

    def __find_append_device(self, devices, device, device_name):
        """ 
        Find or append device to dictionary of devices 
    
        device codes are '{device_name}_N', where N is a counter for
        that type of device   
        """
        n_matching_devices = 0
        for device_code, value in devices.items():
            if device_name not in device_code:
                continue
            else:
                n_matching_devices = n_matching_devices + 1
                if device == value:
                    return devices, device_code
        device_code = device_name + "_" + str(n_matching_devices + 1)
        devices[device_code] = device
        return devices, device_code

    def __make_channel(
        self, das_code, device_codes, values, open_date, close_date, debug=False
    ):
        if debug:
            print("das_code=", das_code)
            print("device_codes=", device_codes)
            print("values=", values)
        das = das_code.split("_")
        das_component = das[0]
        if len(das) > 1:
            das_connector = das[1]
        else:
            das_connector = "1"
        azimuth, dip = obsinfo.get_azimuth_dip(
            values["sensor"].seed_codes, values["orientation_code"]
        )
        ana_filter_list = []
        for comp_type in ["sensor", "preamplifier", "datalogger"]:
            if comp_type in values:
                if debug:
                    print(f"values[{comp_type}]=", values[comp_type])
        #                 if "analog_filter" in values[comp_type].response_files:
        #                     ana_filter_list.append(
        #                         {"analog_filter":values[comp_type].response_files['analog_filter'],
        #                         "component": "1"})
        ch = {
            "location_code": values["location_code"],
            "seed_code": obsinfo.make_channel_code(
                values["sensor"].seed_codes,
                values["band_code"],
                values["inst_code"],
                values["orientation_code"],
                values["sample_rate"],
            ),
            "sensor": device_codes["sensor"],
            "sensor_component": values["orientation_code"],
            "analog_filter_list": ana_filter_list,
            "das": device_codes["das"],
            "das_connector": das_connector,
            "das_component": das_component,
            "das_digital_filter": values["datalogger"].reference_code,
            "data_format": "STEIM1",
            "polarity_reversal": dip == "-90.0",
            "open_date": open_date,
            "close_date": close_date,
            "channel_flags": "CG",
        }
        return ch
