Create an HTML select box.

        >>> print create_html_select(["foo", "bar"], selected="bar", name="baz")
        <select name="baz">
          <option selected="selected" value="bar">
            bar
          </option>
          <option value="foo">
            foo
          </option>
        </select>
        >>> print create_html_select([("foo", "oof"), ("bar", "rab")], selected="bar", name="baz")
        <select name="baz">
          <option value="foo">
            oof
          </option>
          <option selected="selected" value="bar">
            rab
          </option>
        </select>

    @param options: this can either be a sequence of strings, or a sequence
        of couples or a map of C{key->value}. In the former case, the C{select}
        tag will contain a list of C{option} tags (in alphabetical order),
        where the C{value} attribute is not specified. In the latter case,
        the C{value} attribute will be set to the C{key}, while the body
        of the C{option} will be set to C{value}.
    @type options: sequence or map
    @param name: the name of the form element.
    @type name: string
    @param selected: optional key(s)/value(s) to select by default. In case
        a map has been used for options.
    @type selected: string (or list of string)
    @param disabled: optional key(s)/value(s) to disable.
    @type disabled: string (or list of string)
    @param multiple: whether a multiple select box must be created.
    @type mutable: bool
    @param attrs: optional attributes to create the select tag.
    @type attrs: dict
    @param other_attrs: other optional attributes.
    @return: the HTML output.
    @rtype: string

    @note: the values and keys will be escaped for HTML.

    @note: it is important that parameter C{value} is always
        specified, in case some browser plugin play with the
        markup, for eg. when translating the page.

def create_html_select(
        options,
        name=None,
        selected=None,
        disabled=None,
        multiple=False,
        attrs=None,
        **other_attrs):
    """
    Create an HTML select box.

        >>> print create_html_select(["foo", "bar"], selected="bar", name="baz")
        <select name="baz">
          <option selected="selected" value="bar">
            bar
          </option>
          <option value="foo">
            foo
          </option>
        </select>
        >>> print create_html_select([("foo", "oof"), ("bar", "rab")], selected="bar", name="baz")
        <select name="baz">
          <option value="foo">
            oof
          </option>
          <option selected="selected" value="bar">
            rab
          </option>
        </select>

    @param options: this can either be a sequence of strings, or a sequence
        of couples or a map of C{key->value}. In the former case, the C{select}
        tag will contain a list of C{option} tags (in alphabetical order),
        where the C{value} attribute is not specified. In the latter case,
        the C{value} attribute will be set to the C{key}, while the body
        of the C{option} will be set to C{value}.
    @type options: sequence or map
    @param name: the name of the form element.
    @type name: string
    @param selected: optional key(s)/value(s) to select by default. In case
        a map has been used for options.
    @type selected: string (or list of string)
    @param disabled: optional key(s)/value(s) to disable.
    @type disabled: string (or list of string)
    @param multiple: whether a multiple select box must be created.
    @type mutable: bool
    @param attrs: optional attributes to create the select tag.
    @type attrs: dict
    @param other_attrs: other optional attributes.
    @return: the HTML output.
    @rtype: string

    @note: the values and keys will be escaped for HTML.

    @note: it is important that parameter C{value} is always
        specified, in case some browser plugin play with the
        markup, for eg. when translating the page.
    """
    body = []
    if selected is None:
        selected = []
    elif isinstance(selected, (str, unicode)):
        selected = [selected]
    if disabled is None:
        disabled = []
    elif isinstance(disabled, (str, unicode)):
        disabled = [disabled]
    if name is not None and multiple and not name.endswith('[]'):
        name += "[]"
    if isinstance(options, dict):
        items = options.items()
        items.sort(lambda item1, item2: cmp(item1[1], item2[1]))
    elif isinstance(options, (list, tuple)):
        options = list(options)
        items = []
        for item in options:
            if isinstance(item, (str, unicode)):
                items.append((item, item))
            elif isinstance(item, (tuple, list)) and len(item) == 2:
                items.append(tuple(item))
            else:
                raise ValueError(
                    'Item "%s" of incompatible type: %s' % (item, type(item)))
    else:
        raise ValueError('Options of incompatible type: %s' % type(options))
    for key, value in items:
        option_attrs = {}
        if key in selected:
            option_attrs['selected'] = 'selected'
        if key in disabled:
            option_attrs['disabled'] = 'disabled'
        body.append(
            create_tag(
                "option",
                body=value,
                escape_body=True,
                value=key,
                attrs=option_attrs))
    if attrs is None:
        attrs = {}
    if name is not None:
        attrs['name'] = name
    if multiple:
        attrs['multiple'] = 'multiple'
    return create_tag(
        "select",
        body='\n'.join(body),
        attrs=attrs,
        **other_attrs)