from BaseFormAction import BaseFormAction, registerFormAction
from ZPublisher.Publish import call_object, missing_name, dont_publish_class
from ZPublisher.mapply import mapply
import urlparse

def factory(arg):
    """Create a new traverse-to action"""
    return TraverseTo(arg)


class TraverseTo(BaseFormAction):
    def __call__(self, controller_state):
        url = self.getArg(controller_state)
        # see if this is a relative url or an absolute
        if len(urlparse.urlparse(url)[1]) != 0:
            # host specified, so url is absolute.  No good for traversal.
            raise ValueError, 'Can\'t traverse to absolute url %s' % str(url)

        url_path = urlparse.urlparse(url)[2]
        # combine args from query string with args from the controller state
        # (args in the state supercede those in the query string)
        args = self.combineArgs(url, controller_state.kwargs)

        # put the args in the REQUEST
        REQUEST = controller_state.getContext().REQUEST
        for (key, value) in args.items():
            REQUEST.set(key, value)

        # make sure target exists
        context = controller_state.getContext()
        obj = context.restrictedTraverse(url_path, default=None)
        if obj is None:
            raise ValueError, 'Unable to find %s\n' % str(url_path)
        return mapply(obj, REQUEST.args, REQUEST,
                               call_object, 1, missing_name, dont_publish_class,
                               REQUEST, bind=1)


registerFormAction('traverse_to',
                   factory,
                   'Traverse to the URL specified in the argument (a TALES expression).  The URL can either be absolute or relative.')
