import os
from common.basedir import BASEDIR


def get_attr_from_cars(attr, result=dict, combine_brands=True):
  # read all the folders in selfdrive/car and return a dict where:
  # - keys are all the car models
  # - values are attr values from all car folders
  result = result()

  for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
    try:
      car_name = car_folder.split('/')[-1]
      values = __import__('selfdrive.car.%s.values' % car_name, fromlist=[attr])
      if hasattr(values, attr):
        attr_values = getattr(values, attr)
      else:
        continue

      if isinstance(attr_values, dict):
        for f, v in attr_values.items():
          if combine_brands:
            result[f] = v
          else:
            if car_name not in result:
              result[car_name] = {}
            result[car_name][f] = v
      elif isinstance(attr_values, list):
        result += attr_values

    except (ImportError, IOError):
      pass

  return result


FW_VERSIONS = get_attr_from_cars('FW_VERSIONS')
_FINGERPRINTS = get_attr_from_cars('FINGERPRINTS')
IGNORED_FINGERPRINTS = get_attr_from_cars('IGNORED_FINGERPRINTS', list)

_DEBUG_ADDRESS = {1880: 8}   # reserved for debug purposes

def is_valid_for_fingerprint(msg, car_fingerprint):
  adr = msg.address
  # ignore addresses that are more than 11 bits
  return (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat)) or adr >= 0x800


def eliminate_incompatible_cars(msg, candidate_cars):
  """Removes cars that could not have sent msg.

     Inputs:
      msg: A cereal/log CanData message from the car.
      candidate_cars: A list of cars to consider.

     Returns:
      A list containing the subset of candidate_cars that could have sent msg.
  """
  compatible_cars = []

  for car_name in candidate_cars:
    if car_name in IGNORED_FINGERPRINTS:
      continue

    car_fingerprints = _FINGERPRINTS[car_name]

    for fingerprint in car_fingerprints:
      fingerprint.update(_DEBUG_ADDRESS)  # add alien debug address

      if is_valid_for_fingerprint(msg, fingerprint):
        compatible_cars.append(car_name)
        break

  return compatible_cars


def all_known_cars():
  """Returns a list of all known car strings."""
  return list(_FINGERPRINTS.keys())
