r'''
    A function to connect to a bigip device and create a virtual server.

    hostname
        The host/address of the bigip device
    username
        The iControl REST username
    password
        The iControl REST password
    name
        The name of the virtual to create
    destination
        [ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
    pool
        [ [pool_name] | none]
    address_status
        [yes | no]
    auto_lasthop
        [default | enabled | disabled ]
    bwc_policy
        [none] | string]
    cmp_enabled
        [yes | no]
    dhcp_relay
        [yes | no]
    connection_limit
        [integer]
    description
        [string]
    state
        [disabled | enabled]
    fallback_persistence
        [none | [profile name] ]
    flow_eviction_policy
        [none | [eviction policy name] ]
    gtm_score
        [integer]
    ip_forward
        [yes | no]
    ip_protocol
        [any | protocol]
    internal
        [yes | no]
    twelve_forward
        (12-forward)
        [yes | no]
    last_hop-pool
        [ [pool_name] | none]
    mask
        { [ipv4] | [ipv6] }
    mirror
        { [disabled | enabled | none] }
    nat64
        [enabled | disabled]
    persist
        [none | profile1,profile2,profile3 ... ]
    profiles
        [none | default | profile1,profile2,profile3 ... ]
    policies
        [none | default | policy1,policy2,policy3 ... ]
    rate_class
        [name]
    rate_limit
        [integer]
    rate_limit_mode
        [destination | object | object-destination |
        object-source | object-source-destination |
        source | source-destination]
    rate_limit_dst
        [integer]
    rate_limitçsrc
        [integer]
    rules
        [none | [rule_one,rule_two ...] ]
    related_rules
        [none | [rule_one,rule_two ...] ]
    reject
        [yes | no]
    source
        { [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
    source_address_translation
        [none | snat:pool_name | lsn | automap ]
    source_port
        [change | preserve | preserve-strict]
    state
        [enabled | disabled]
    traffic_classes
        [none | default | class_one,class_two ... ]
    translate_address
        [enabled | disabled]
    translate_port
        [enabled | disabled]
    vlans
        [none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]

    CLI Examples::

        salt '*' bigip.create_virtual bigip admin admin my-virtual-3 26.2.2.5:80 \
            pool=my-http-pool-http profiles=http,tcp

        salt '*' bigip.create_virtual bigip admin admin my-virtual-3 43.2.2.5:80 \
            pool=test-http-pool-http profiles=http,websecurity persist=cookie,hash \
            policies=asm_auto_l7_policy__http-virtual \
            rules=_sys_APM_ExchangeSupport_helper,_sys_https_redirect \
            related_rules=_sys_APM_activesync,_sys_APM_ExchangeSupport_helper \
            source_address_translation=snat:my-snat-pool \
            translate_address=enabled translate_port=enabled \
            traffic_classes=my-class,other-class \
            vlans=enabled:external,internal

def create_virtual(hostname, username, password, name, destination,
                   pool=None,
                   address_status=None,
                   auto_lasthop=None,
                   bwc_policy=None,
                   cmp_enabled=None,
                   connection_limit=None,
                   dhcp_relay=None,
                   description=None,
                   fallback_persistence=None,
                   flow_eviction_policy=None,
                   gtm_score=None,
                   ip_forward=None,
                   ip_protocol=None,
                   internal=None,
                   twelve_forward=None,
                   last_hop_pool=None,
                   mask=None,
                   mirror=None,
                   nat64=None,
                   persist=None,
                   profiles=None,
                   policies=None,
                   rate_class=None,
                   rate_limit=None,
                   rate_limit_mode=None,
                   rate_limit_dst=None,
                   rate_limit_src=None,
                   rules=None,
                   related_rules=None,
                   reject=None,
                   source=None,
                   source_address_translation=None,
                   source_port=None,
                   state=None,
                   traffic_classes=None,
                   translate_address=None,
                   translate_port=None,
                   vlans=None):
    r'''
    A function to connect to a bigip device and create a virtual server.

    hostname
        The host/address of the bigip device
    username
        The iControl REST username
    password
        The iControl REST password
    name
        The name of the virtual to create
    destination
        [ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
    pool
        [ [pool_name] | none]
    address_status
        [yes | no]
    auto_lasthop
        [default | enabled | disabled ]
    bwc_policy
        [none] | string]
    cmp_enabled
        [yes | no]
    dhcp_relay
        [yes | no]
    connection_limit
        [integer]
    description
        [string]
    state
        [disabled | enabled]
    fallback_persistence
        [none | [profile name] ]
    flow_eviction_policy
        [none | [eviction policy name] ]
    gtm_score
        [integer]
    ip_forward
        [yes | no]
    ip_protocol
        [any | protocol]
    internal
        [yes | no]
    twelve_forward
        (12-forward)
        [yes | no]
    last_hop-pool
        [ [pool_name] | none]
    mask
        { [ipv4] | [ipv6] }
    mirror
        { [disabled | enabled | none] }
    nat64
        [enabled | disabled]
    persist
        [none | profile1,profile2,profile3 ... ]
    profiles
        [none | default | profile1,profile2,profile3 ... ]
    policies
        [none | default | policy1,policy2,policy3 ... ]
    rate_class
        [name]
    rate_limit
        [integer]
    rate_limit_mode
        [destination | object | object-destination |
        object-source | object-source-destination |
        source | source-destination]
    rate_limit_dst
        [integer]
    rate_limitçsrc
        [integer]
    rules
        [none | [rule_one,rule_two ...] ]
    related_rules
        [none | [rule_one,rule_two ...] ]
    reject
        [yes | no]
    source
        { [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
    source_address_translation
        [none | snat:pool_name | lsn | automap ]
    source_port
        [change | preserve | preserve-strict]
    state
        [enabled | disabled]
    traffic_classes
        [none | default | class_one,class_two ... ]
    translate_address
        [enabled | disabled]
    translate_port
        [enabled | disabled]
    vlans
        [none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]

    CLI Examples::

        salt '*' bigip.create_virtual bigip admin admin my-virtual-3 26.2.2.5:80 \
            pool=my-http-pool-http profiles=http,tcp

        salt '*' bigip.create_virtual bigip admin admin my-virtual-3 43.2.2.5:80 \
            pool=test-http-pool-http profiles=http,websecurity persist=cookie,hash \
            policies=asm_auto_l7_policy__http-virtual \
            rules=_sys_APM_ExchangeSupport_helper,_sys_https_redirect \
            related_rules=_sys_APM_activesync,_sys_APM_ExchangeSupport_helper \
            source_address_translation=snat:my-snat-pool \
            translate_address=enabled translate_port=enabled \
            traffic_classes=my-class,other-class \
            vlans=enabled:external,internal

    '''

    params = {
        'pool': pool,
        'auto-lasthop': auto_lasthop,
        'bwc-policy': bwc_policy,
        'connection-limit': connection_limit,
        'description': description,
        'fallback-persistence': fallback_persistence,
        'flow-eviction-policy': flow_eviction_policy,
        'gtm-score': gtm_score,
        'ip-protocol': ip_protocol,
        'last-hop-pool': last_hop_pool,
        'mask': mask,
        'mirror': mirror,
        'nat64': nat64,
        'persist': persist,
        'rate-class': rate_class,
        'rate-limit': rate_limit,
        'rate-limit-mode': rate_limit_mode,
        'rate-limit-dst': rate_limit_dst,
        'rate-limit-src': rate_limit_src,
        'source': source,
        'source-port': source_port,
        'translate-address': translate_address,
        'translate-port': translate_port
    }

    # some options take yes no others take true false.  Figure out when to use which without
    # confusing the end user
    toggles = {
        'address-status': {'type': 'yes_no', 'value': address_status},
        'cmp-enabled': {'type': 'yes_no', 'value': cmp_enabled},
        'dhcp-relay': {'type': 'true_false', 'value': dhcp_relay},
        'reject': {'type': 'true_false', 'value': reject},
        '12-forward': {'type': 'true_false', 'value': twelve_forward},
        'internal': {'type': 'true_false', 'value': internal},
        'ip-forward': {'type': 'true_false', 'value': ip_forward}
    }

    #build session
    bigip_session = _build_session(username, password)

    #build payload
    payload = _loop_payload(params)

    payload['name'] = name
    payload['destination'] = destination

    #determine toggles
    payload = _determine_toggles(payload, toggles)

    #specify profiles if provided
    if profiles is not None:
        payload['profiles'] = _build_list(profiles, 'ltm:virtual:profile')

    #specify persist if provided
    if persist is not None:
        payload['persist'] = _build_list(persist, 'ltm:virtual:persist')

    #specify policies if provided
    if policies is not None:
        payload['policies'] = _build_list(policies, 'ltm:virtual:policy')

    #specify rules if provided
    if rules is not None:
        payload['rules'] = _build_list(rules, None)

    #specify related-rules if provided
    if related_rules is not None:
        payload['related-rules'] = _build_list(related_rules, None)

    #handle source-address-translation
    if source_address_translation is not None:

        #check to see if this is already a dictionary first
        if isinstance(source_address_translation, dict):
            payload['source-address-translation'] = source_address_translation
        elif source_address_translation == 'none':
            payload['source-address-translation'] = {'pool': 'none', 'type': 'none'}
        elif source_address_translation == 'automap':
            payload['source-address-translation'] = {'pool': 'none', 'type': 'automap'}
        elif source_address_translation == 'lsn':
            payload['source-address-translation'] = {'pool': 'none', 'type': 'lsn'}
        elif source_address_translation.startswith('snat'):
            snat_pool = source_address_translation.split(':')[1]
            payload['source-address-translation'] = {'pool': snat_pool, 'type': 'snat'}

    #specify related-rules if provided
    if traffic_classes is not None:
        payload['traffic-classes'] = _build_list(traffic_classes, None)

    #handle vlans
    if vlans is not None:
        #ceck to see if vlans is a dictionary (used when state makes use of function)
        if isinstance(vlans, dict):
            try:
                payload['vlans'] = vlans['vlan_ids']
                if vlans['enabled']:
                    payload['vlans-enabled'] = True
                elif vlans['disabled']:
                    payload['vlans-disabled'] = True
            except Exception:
                return 'Error: Unable to Parse vlans dictionary: \n\tvlans={vlans}'.format(vlans=vlans)
        elif vlans == 'none':
            payload['vlans'] = 'none'
        elif vlans == 'default':
            payload['vlans'] = 'default'
        elif isinstance(vlans, six.string_types) and (vlans.startswith('enabled') or vlans.startswith('disabled')):
            try:
                vlans_setting = vlans.split(':')[0]
                payload['vlans'] = vlans.split(':')[1].split(',')
                if vlans_setting == 'disabled':
                    payload['vlans-disabled'] = True
                elif vlans_setting == 'enabled':
                    payload['vlans-enabled'] = True
            except Exception:
                return 'Error: Unable to Parse vlans option: \n\tvlans={vlans}'.format(vlans=vlans)
        else:
            return 'Error: vlans must be a dictionary or string.'

    #determine state
    if state is not None:
        if state == 'enabled':
            payload['enabled'] = True
        elif state == 'disabled':
            payload['disabled'] = True

    #post to REST
    try:
        response = bigip_session.post(
            BIG_IP_URL_BASE.format(host=hostname) + '/ltm/virtual',
            data=salt.utils.json.dumps(payload)
        )
    except requests.exceptions.ConnectionError as e:
        return _load_connection_error(hostname, e)

    return _load_response(response)