class TimeManagerStateController extends AbstractModuleStateController {

    @Override
    public void activateState(String id, String description, Collection<? extends String> tags, Node element)
    {
        try
        {
            XPath xpath = StateXML.newXPath();

            String current = xpath.evaluate("/" + ModuleStateController.STATE_QNAME + "/:time/:current", element);
            ExportAnimationState animationState = StateXML.getStateBean(element, "/:time/:animation", ExportAnimationState.class);
            boolean animationSetTheTime = animationState != null
                    && (animationState.getPlayState() == PlayState.FORWARD || animationState.getPlayState() == PlayState.REVERSE);
            if (StringUtils.isNotEmpty(current) && !animationSetTheTime)
            {
                try
                {
                    TimeSpan span = TimeSpan.fromISO8601String(current);

                    resetPlanIfNecessary(span);

                    myTimeManager.setPrimaryActiveTimeSpan(span);
                }
                catch (ParseException e)
                {
                    LOGGER.error("Failed to parse state interval: " + e, e);
                }
            }

            NodeList heldNodes = (NodeList)xpath.evaluate("/" + ModuleStateController.STATE_QNAME + "/:time/:held", element,
                    XPathConstants.NODESET);
            for (int index = 0; index < heldNodes.getLength(); ++index)
            {
                Node heldNode = heldNodes.item(index);
                Node keyNode = (Node)xpath.evaluate(
                        "/" + ModuleStateController.STATE_QNAME + "/:time/:held[" + (index + 1) + "]/:key", heldNode,
                        XPathConstants.NODE);

                Collection<TimeSpan> intervals = New.collection();
                NodeList intervalNodes = (NodeList)xpath.evaluate(
                        "/" + ModuleStateController.STATE_QNAME + "/:time/:held[" + (index + 1) + "]/:interval", heldNode,
                        XPathConstants.NODESET);
                for (int index2 = 0; index2 < intervalNodes.getLength(); ++index2)
                {
                    String intervalText = intervalNodes.item(index2).getTextContent();
                    try
                    {
                        intervals.add(TimeSpan.fromISO8601String(intervalText));
                    }
                    catch (ParseException e)
                    {
                        LOGGER.warn("Could not parse interval text [" + intervalText + "]: " + e, e);
                    }
                }

                if (!intervals.isEmpty())
                {
                    myTimeManager.setSecondaryActiveTimeSpans(
                            keyNode == null ? TimeManager.WILDCARD_CONSTRAINT_KEY : keyNode.getTextContent(), intervals);
                }
            }

            String fadeIn = xpath.evaluate("/" + ModuleStateController.STATE_QNAME + "/:time/:fade/:in", element);
            String fadeOut = xpath.evaluate("/" + ModuleStateController.STATE_QNAME + "/:time/:fade/:out", element);
            if (StringUtils.isNotEmpty(fadeIn) || StringUtils.isNotEmpty(fadeOut))
            {
                try
                {
                    Duration in = StringUtils.isEmpty(fadeIn) ? Seconds.ZERO : Duration.fromISO8601String(fadeIn);
                    Duration out = StringUtils.isEmpty(fadeOut) ? Seconds.ZERO : Duration.fromISO8601String(fadeOut);
                    myTimeManager.setFade(new DefaultFade(in, out));
                }
                catch (ParseException e)
                {
                    LOGGER.error("Failed to parse state interval: " + e);
                }
            }
        }
        catch (XPathExpressionException e)
        {
            LOGGER.error(e, e);
        }
    }

    public  TimeManagerStateController(TimeManager timeManager, AnimationManager animationManager);

}