def generate_api_response(path, macro_id, r_type='xml'):
    '''
    Generate an XML/JSON interpretation of a macro.

    Handles exceptions, returning them as errors in the response.

    TO BE WRITTEN: API for response. Use template?
    '''

    # Can we hit memcached for this?
    key = "api_%s_%s" % (macro_id, r_type)
    response = memcache.get(key)
    if response: return response

    # Get parsed macro from id and begin response generation.
    response_dict = get_view_dict_from_macro_id(macro_id)
    
    # Call helper to interpret the macro behind the id.
    macro_obj = get_macro_obj_from_id(macro_id, response_dict['macro_input'])

    # Add macro, with or without errors.
    response_dict['interpret'] = _translate_parsed_macro(macro_obj),

    # Render to response type requested.
    if r_type == 'xml':
        response  = render_template('xml_response.template',
                                    response_dict,
                                    path)
    else: # json
        del response_dict['class_list']
        del response_dict['macro_input']
        response = simplejson.dumps(response_dict)
        
    # Add to memcached
    #memcache.add(key, response, MEMCACHED_API)  
    return response
def generate_view_page(path, macro_id, host_url, save_values={}):
    '''
    Generate a macro view page. Returns None on error.
    Propogates exceptions up.
    '''
    ret_page = None

    # Make sure we got valid input.
    if not macro_id: raise NoInputError("You entered an invalid macro ID.  Try again?")

    # Ensure we have a saved macro.  Will throw exception on fail.
    saved_macro = SavedMacroOps(macro_id)

    # View pages are extremely heavy, and the majority of their
    # data doesn't change.  Use helper to handle this.
    macro_form_template_values = get_view_dict_from_macro_id(macro_id, saved_macro)

    # Add in edit and view links.
    # Add in the author link.
    # Add in the form ids.
    page_values = {'macro_link'      : '%s/%s'    % (host_url,
                                                    macro_id),
                   'macro_edit'      : '%s?%s=%s' % (host_url,
                                                     GET_MACRO_LINK,
                                                     macro_id),
                   'author'          : _format_author(saved_macro.entity.name,
                                                      saved_macro.entity.server),
                   'send_email'      : FORM_MACRO_EMAIL,
                   'send_input_form' : FORM_EMAIL_INPUT,
                   'to'              : FORM_EMAIL_TO,
                   'from'            : FORM_EMAIL_FROM,
                   }
    macro_form_template_values.update(page_values)
    
    # Generate the dynamic parts of the page:
    #   1. Increment the view counter on this macro.
    #   2. Get the rating in terms of stars for this macro.
    dynamic_page_vals = {
        'stars'           : [i + 1 for i in range(MAX_RATING)],
        'num_rates'       : saved_macro.entity.num_rates,
        'views'           : saved_macro.add_to_view_count(),
        'rating'          : saved_macro.get_rating_dict(saved_macro.get_rating()),
        }
    macro_form_template_values.update(dynamic_page_vals)
    
    # Is this another save attempt after errors?  If so, update
    # with errors and previous values.
    macro_form_template_values.update(save_values)

    # Call helper to interpret the macro behind the id.
    macro_obj = get_macro_obj_from_id(macro_id, saved_macro.entity.macro)

    # Populate the templace with the processed macro.
    macro_form_template_values['processed_macro_html'] = \
         render_macro(macro_obj, path)

    # Get the copy and paste form of the macro
    macro_form_template_values['copy_paste'] = \
        _render_copy_cmd(macro_obj)

    # Render the macro view template html.
    ret_page  = render_template('view.template',
                                macro_form_template_values,
                                path)
    return render_template('base.template',
                           {'content':  ret_page},
                           path)