Faceted versions (invalidate squid cache)
=========================================
As there is practical impossible to generate all combinations of parameters
for faceted_query, faceted_counter and tagscloud_counter and you can not
invalidate squid cache by regular expressions a version control system was
implemented. This way a version string like an eTag is added to query.
Squid or any other proxy cache system will see this as a new request and will
return it from memcache or zope and then will cache it with the new key.
This is invisible for end users and even for managers.

Other advantage of this solution is that it is ''proxy cache system'' independent
and, let's say that, by mistake, you edit a hidden widget, for example you hit
'''Unhide''' button. In the '''Purging''' implementation you would lose all
squid cache just because your mouse jumps from time to time :).
With this versioning system, you can just '''Hide''' the widget back and
everyting is like before. Why? Because this version eTag is generated from
hidden widgets default values, so you'll always be able to return to a
previous version without loosing proxy cache.

What if I want to generate another version id even if faceted configuration
didn't change?
You can do that by adding an ETag widget. See ETag section in this document.

Imports
-------

    >>> from zope.component import getMultiAdapter

Set up
------

Setup sandbox

    >>> portal = layer["portal"]
    >>> request = layer['request']
    >>> sandbox = portal['sandbox']
    >>> sandbox.setLanguage('en')

    >>> subtyper = getMultiAdapter((sandbox, request), name=u'faceted_subtyper')
    >>> subtyper.enable()

Let's cleanup default criteria to avoid surprises

    >>> from eea.facetednavigation.interfaces import ICriteria
    >>> cids = ICriteria(sandbox).keys()
    >>> for cid in cids:
    ...     ICriteria(sandbox).delete(cid)
    >>> ICriteria(sandbox).keys()
    []

Add some criteria

    >>> handler = getMultiAdapter((sandbox, request), name=u'faceted_configure')

    >>> _ = handler(addPropertiesWidget_button='Add',
    ...   wtype='text', wposition='left', title='Text widget',
    ...   index='Title', default='water')
    >>> _ = handler(addPropertiesWidget_button='Add',
    ...   wtype='radio', wposition='right', title='Radio widget',
    ...   index='portal_type', catalog='portal_catalog', default='Folder')

Versions
--------

If there is no hidden widget there is no version

    >>> version = getMultiAdapter((sandbox, request), name=u'faceted_version')
    >>> version.key
    ''

Let's hide/unhide widgets

    >>> _ = handler(updateCriterion_button='Update', cid='c1', hidden=True)
    >>> a = version.key
    >>> a != ''
    True

    >>> _ = handler(updateCriterion_button='Update', cid='c0', hidden=True)
    >>> b = version.key
    >>> b != a
    True

    >>> _ = handler(updateCriterion_button='Update', cid='c0', hidden=False)
    >>> c = version.key
    >>> c == a
    True

    >>> c != b
    True

Version key is computed by widget visibility and default value. So let's check
version remain the same if we change other widget properties:

    >>> _ = handler(updateCriterion_button='Update', cid='c1', title='Another title')
    >>> d = version.key
    >>> d == c
    True

    >>> _ = handler(updateCriterion_button='Update', cid='c1', catalog='')
    >>> e = version.key
    >>> e == d
    True

Ok, now let's change the default value

    >>> _ = handler(updateCriterion_button='Update', cid='c1', default='Document')
    >>> f = version.key
    >>> f != e
    True

Also, if there is no default value for hidden widgets there is no version

    >>> _ = handler(updateCriterion_button='Update', cid='c1', default='')
    >>> version.key
    ''

Same for 'all' value for default

    >>> _ = handler(updateCriterion_button='Update', cid='c1', default='all')
    >>> version.key
    ''

Some widgets use operator (AND/OR) in their query and this can affect results
even if they are visible widgets

    >>> _ = handler(addPropertiesWidget_button='Add',
    ...   wtype='checkbox', wposition='left', title='Checkbox widget',
    ...   index='object_provides', operator='and',
    ...   catalog='portal_catalog')
    >>> g = version.key

    >>> _ = handler(updateCriterion_button='Update', cid='c2', operator='or')
    >>> h = version.key
    >>> h != g
    True

    >>> _ = handler(updateCriterion_button='Update', cid='c2', operator='and')
    >>> i = version.key
    >>> i != h
    True

    >>> i == g
    True

ETag widget
-----------
There is a special faceted widget called ETag that you can use in order to
generate another version id.

    >>> _ = handler(addPropertiesWidget_button='Add',
    ...   wtype='etag', wposition='left', title='ETag',
    ...   default='1.0', hidden=True)
    >>> j = version.key
    >>> j != i
    True

It is not displayed in view mode even if it's not hidden but in order to be
used by versioning generator it has to be hidden.

    >>> _ = handler(updateCriterion_button='Update', cid='c3', hidden=False)
    >>> k = version.key
    >>> k != j
    True

    >>> _ = handler(updateCriterion_button='Update', cid='c3', hidden=True)
    >>> l = version.key
    >>> l == j
    True

Changing it's default value will generate another version id, of course

    >>> _ = handler(updateCriterion_button='Update', cid='c3', default='1.1')
    >>> m = version.key
    >>> m != l
    True
