from validator.constants import *


def detect_type(err, install_rdf=None, xpi_package=None):
    """Determines the type of add-on being validated based on
    install.rdf, file extension, and other properties."""

    # The types in the install.rdf don't pair up 1:1 with the type
    # system that we're using for expectations and the like. This is
    # to help translate between the two.
    translated_types = {'2': PACKAGE_EXTENSION,
                        '4': PACKAGE_THEME,
                        '8': PACKAGE_LANGPACK,
                        '32': PACKAGE_MULTI,
                        '64': PACKAGE_DICTIONARY,
                        # New "experiment" types: see bug 1220097 and
                        # https://github.com/mozilla/addons-server/issues/3315
                        '128': PACKAGE_EXTENSION,
                        '256': PACKAGE_EXTENSION,}

    # If we're missing our install.rdf file, we can try to make some
    # assumptions.
    if install_rdf is None:
        types = {'xpi': PACKAGE_DICTIONARY}

        err.notice(('typedetection',
                    'detect_type',
                    'missing_install_rdf'),
                   'install.rdf was not found.',
                   'The type should be determined by install.rdf if present. '
                   "If it isn't, we still need to know the type.")

        # If we know what the file type might be, return it.
        if xpi_package.extension in types:
            return types[xpi_package.extension]
        # Otherwise, we're out of luck :(
        else:
            return None

    # Attempt to locate the <em:type> node in the RDF doc.
    type_uri = install_rdf.uri('type')
    type_ = install_rdf.get_object(None, type_uri)

    # Dictionaries are weird too, they might not have the obligatory
    # em:type. We can assume that if they have a /dictionaries/ folder,
    # they are a dictionary because even if they aren't, dictionaries
    # have an extraordinarily strict set of rules and file filters that
    # must be passed. It's so crazy secure that it's cool if we use it
    # as kind of a fallback.

    if any(file_ for file_ in xpi_package if
               file_.startswith('dictionaries/')):
        if type_ != '64':
            err.error(('typedetection',
                       'dictionary_valid_type',
                       'invalid_em_type'),
                      'Invalid <em:type> value.',
                      'The package appears to be a dictionary but does not have '
                      'the correct <em:type> set in the install manifest.')
        return PACKAGE_DICTIONARY

    if type_ is not None:
        if type_ in translated_types:
            err.save_resource('is_multipackage', type_ == '32', pushable=True)
            # Make sure we translate back to the normalized version
            return translated_types[type_]
        else:
            err.error(('typedetection',
                       'detect_type',
                       'invalid_em_type'),
                      'Invalid <em:type> value.',
                      'The only valid values for <em:type> are 2, 4, 8, and '
                      '32. Any other values are either invalid or deprecated.',
                      'install.rdf')
            return
    else:
        err.notice(
            err_id=('typedetection',
                    'detect_type',
                    'no_em:type'),
            notice='No <em:type> element found in install.rdf',
            description="It isn't always required, but it is the most reliable "
                        'method for determining add-on type.',
            filename='install.rdf')

    # There's no type element, so the spec says that it's either a
    # theme or an extension. At this point, we know that it isn't
    # a dictionary, language pack, or multiple extension pack.
    extensions = {'jar': '4',
                  'xpi': '2'}

    # If the package's extension is listed in the [tiny] extension
    # dictionary, then just return that. We'll validate against that
    # add-on type's layout later. Better to false positive than to false
    # negative.
    if xpi_package.extension in extensions:
        # Make sure it gets translated back to the normalized version
        install_rdf_type = extensions[xpi_package.extension]
        return translated_types[install_rdf_type]

