import os
import re

from base.logging import zoox_logger
from base.proto import ReadProto, WriteProto
from vehicle.planner.node import planner_config_pb2
from vehicle.planner.decision.proto import action_references_generator_pb2

log = zoox_logger.ZooxLogger(__name__)


def match_and_extract_name(func):
    m = re.match("_set_([\w\d_]+)_opts", func)
    if m:
        return m.group(1)
    else:
        return None


class PlannerConfig:
    default_path = "vehicle/planner/node/planner_configuration.pbtxt"

    def __init__(self, planner_config_path=default_path):

        config = planner_config_pb2.Configuration()
        ReadProto(planner_config_path, config)

        self.config = config

    @staticmethod
    def available_opts():
        return filter(
            lambda x: x, map(match_and_extract_name, dir(PlannerConfig))
        )

    def write_config(self, planner_config_output):
        try:
            os.makedirs(os.path.dirname(planner_config_output))
        except os.error as e:
            log.info(e)
        os.chmod(os.path.dirname(planner_config_output), 0o777)
        WriteProto(planner_config_output, self.config)

    def set_opts(self, option_list):
        """
        Sets the planner configuration options as those specified by the
        options in `option_list`; those can be inspected by the `available_opts`
        method.

        The order in the option_list matters, as any common options will be
        overwritten in a FIFO fashion (last one to write wins).
        """
        for opt in option_list:
            func = "_set_{}_opts".format(opt)
            assert callable(getattr(self, func, None)), (
                "Planner config option %s is not configured" % opt
            )
            # call the options setter
            getattr(self, func)()

    # To provide new option sets, use the naming convention
    #   def _set_{my_option_set}_opts(self):
    # Note that option sets will overwrite common configuration options.
    def _set_action_ref_opts(self):
        # set some basic config values for the planner configurations
        self.config.generator.log_solver = True
        self.config.generator.store_reference_problem = True
        self.config.corridor.enable_logging = True
        ars_generator = (
            self.config.decision_config.decision_planner.action_references_generator
        )
        ars_generator.action_references_log_verbosity = (
            action_references_generator_pb2.ActionReferencesLogVerbosity.kVerboseAll
        )
        ars = ars_generator.structured_action_reference_smoother
        debug = ars.debugging
        debug.verbose_lateral_logging = True
        debug.verbose_longitudinal_logging = True
        debug.verbose_rollout_logging = True

        ars.metrics_config.compute_lateral_proximity_metric = True


if __name__ == "__main__":
    c = PlannerConfig()
    print(list(PlannerConfig.available_opts()))
