<red:code xmlns:red="http://redfoot.sourceforge.net/2001/06/">

  from redfootlib.rdf.const import *
  from redfootlib.rdf.query.functors import *
  from redfootlib.rdf.query.builders import *
  from redfootlib.rdf.objects import *
  from redfootlib.util import *

  from redfootlib.server.module import ParentModule

  REQUIRED_PROPERTY = resource("http://redfoot.sourceforge.net/2000/10/06/builtin#requiredProperty")
  YES = resource("http://redfoot.sourceforge.net/2000/10/06/builtin#YES")
  UI_TYPE = resource("http://redfoot.sourceforge.net/2000/10/06/builtin#uiType")
  TEXT_AREA = resource("http://redfoot.sourceforge.net/2000/10/06/builtin#TEXTAREA")

  <red:module name="Editor">

    def __getattr__(self, name):
        if name=="rednode": # default rednode to self.app.rednode
            self.set_rednode(self.app.rednode)
            return self.rednode
        else:
            raise AttributeError

    def set_rednode(self, rednode):
        self.rednode = rednode
        self.viewer.set_rednode(rednode)

    def alpha_by_label(self, a, b):
        label_a = self.rednode.neighbourhood.label(a)
        label_b = self.rednode.neighbourhood.label(b)
        return cmp(str(label_a), str(label_b))

    def handle_request(self, request, response):
        ParentModule.handle_request(self, request, response)
        self.possible_values_cache = {}
      
    <red:sub-module instance="viewer" class="Viewer" from="redmodules.viewer"/>
    
    <red:facet name="">
      <red:exec>self.viewer.class_list()</red:exec>
    </red:facet>

    def edit(self):
        self._edit(self.edit_property)

    def edit_subject(self):
        self._edit(self.edit_display_property_value)
    
    <red:facet name="_edit" args="display_property_value">    
      <red:exec>
        request = self.app.request # TODO: facets should be called with these
        response = self.app.response 
        subject = request.get_parameter('subject', None)
        type = request.get_parameter("type", None)
        copy = request.get_parameter("copy", None)
        return_to = request.get_parameter("return_to", "")
        s_property = request.get_parameter('s_property', '')
        s_subject = request.get_parameter('s_subject', '')

        if copy == "true":
            subject = self.rednode.generate_uri()
            self.do_update(request, response, resource(subject), 1)
        else:
            if subject == None or subject == "":
                subject = self.rednode.generate_uri()

        subject = resource(subject)

        if s_property != '' and s_subject != '':
            self.app.rednode.remove(resource(s_subject), resource(s_property), resource(""))
            self.app.rednode.add(resource(s_subject), resource(s_property), subject)  

        if type != None and type != "":
            self.rednode.add(subject, TYPE, resource(type))
            
        self.display_edit(subject, return_to, display_property_value)
      </red:exec>
    </red:facet>      

    <red:facet name="display_edit"
               args="subject, return_to='', edit_property=None">
      <red:exec>
        edit_property = edit_property or self.edit_property
        self.property_num = 0      
      </red:exec>               
      <form name="edit_triple_form" action="edit_triple" method="POST">
        <input name="subject" type="hidden"/>
        <input name="predicate" type="hidden"/>
        <input name="is_literal" type="hidden"/>        
        <input name="object" type="hidden"/>        
      </form>
      <FORM NAME="edit_form" ACTION="?subject={encode_URI(subject)}" METHOD="POST">
        <INPUT NAME="update_subject" TYPE="HIDDEN" VALUE="{subject}"/>
        <INPUT NAME="processor" TYPE="HIDDEN" VALUE=""/>
        <INPUT NAME="module_instance" TYPE="HIDDEN" VALUE="{self.module_instance}"/>
        <a href="{subject}"><H2><red:eval>subject</red:eval></H2></a>        
        <TABLE>
          <red:if test="self.rednode.neighbourhood.exists(subject, None, None)">
            <red:exec>
              self.rednode.visit(edit_property, (subject, None, None))
              self.rednode.neighbours.visit(po(self.viewer.display_property_value), (subject, None, None))
            </red:exec>
            <red:else>
              <TR><TD>Resource not known of directly</TD></TR>
            </red:else>
          </red:if>
          <!-- TODO: reified statements-->

          <red:exec>
            b = SetBuilder()
            self.rednode.neighbourhood.visit_possible_properties_for_subject(b.accept, subject)
            for prop in b.set:
                if self.rednode.neighbourhood.exists(prop, REQUIRED_PROPERTY, YES):
                    edit_property(subject, prop, literal(""), 0)
          </red:exec>                

          <TR>
            <TD>
              <SELECT TYPE="TEXT" NAME="new_property" onChange="edit_form.processor.value='update'; edit_form.submit()">
                <OPTION VALUE="">Select a new Property to add</OPTION>
                <red:exec>
                  self.rednode.neighbourhood.visit_possible_properties_for_subject(self.display_property_option, subject)
                  self.display_property_option(TYPE)
                  for property in self.rednode.neighbourhood.possible_properties_for_subject(subject):
                      self.display_property_option(property)
                </red:exec>        
              </SELECT>
            </TD>
            <TD COLSPAN="5">
              Click update to be able to specify value
            </TD>
          </TR>
        </TABLE>
        <INPUT TYPE="HIDDEN" NAME="prop_count" VALUE="{self.property_num}"/>
        <INPUT TYPE="HIDDEN" NAME="del_num" VALUE="0"/>
        <INPUT TYPE="HIDDEN" NAME="return_to" value="{return_to}"/>
        <INPUT TYPE="BUTTON" VALUE="update" ONCLICK="edit_form.processor.value='update'; edit_form.submit()"/>
        <INPUT TYPE="BUTTON" VALUE="delete" ONCLICK="edit_form.processor.value='delete'; edit_form.submit()"/>
        <INPUT TYPE="HIDDEN" NAME="copy" VALUE=""/>
        <INPUT TYPE="BUTTON" VALUE="copy"
               ONCLICK="edit_form.copy.value='true'; edit_form.action='edit'; edit_form.submit()"/>
               <!-- The onclick is being used to... -->
        <red:if test="return_to != ''">
          <INPUT TYPE="BUTTON" VALUE="done"
               ONCLICK="edit_form.processor.value='update'; edit_form.return_to.value=''; edit_form.action='{return_to}'; edit_form.submit()"/>
        </red:if>
      </FORM>
    </red:facet>    

    <red:facet name="display_property_option" args="property">
      <OPTION VALUE="{property}">
        <red:eval>self.rednode.neighbourhood.label(property)</red:eval>
      </OPTION>
    </red:facet>

    <red:facet name="display_range_line" args="uri">
      <DIV>
        <red:eval>self.rednode.neighbourhood.label(uri)</red:eval>
      </DIV>
    </red:facet>
    
    <red:facet name="edit_property" args="subject, property, value, exists = 1">
      <red:exec>
        self.property_num = self.property_num + 1
      </red:exec>        
      <TR>
        <!-- display property label cell -->
        <TD VALIGN="TOP">
<!--          <red:eval>self.rednode.neighbourhood.label(property)</red:eval>-->
          <red:exec>
            self.viewer.view_link(property)
          </red:exec>

          <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_name" VALUE="{property}"/>
        </TD>

        <!-- display range(s) cell -->
<!-- The property is now a view_link like it is in viewer. So, people may now find out the ranges by following the link. 
        <TD VALIGN="TOP">
          <red:exec>
            self.rednode.neighbourhood.visit(o(self.display_range_line), (property, RANGE, None))
          </red:exec>
        </TD>
-->
        <!-- display edit widget cell -->
        <TD COLSPAN="2">
          <red:if test="(value and isinstance(value, Literal)) or (not value and self.rednode.neighbourhood.exists(property, RANGE, LITERAL))">
            <!-- LITERAL -->
            <red:if test="self.rednode.neighbourhood.exists(property, UI_TYPE, TEXT_AREA)">
              <TEXTAREA NAME="prop{self.property_num}_value" ROWS="5" COLS="60"><red:eval>value</red:eval></TEXTAREA>
              <red:else>
                <INPUT TYPE="TEXT" SIZE="60" NAME="prop{self.property_num}_value" VALUE="{value}"/>
              </red:else>
            </red:if>
            <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_is_literal" VALUE="yes"/>

            <red:else>
              <!-- RESOURCE -->
              <red:if test="self.rednode.neighbourhood.exists(property, RANGE, None)">
                <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_is_literal" VALUE="no"/>
                <SELECT NAME="prop{self.property_num}_value" onChange="edit_form.processor.value='update'; edit_form.submit()">
                  <OPTION VALUE="">Select a value for this property</OPTION>

                  <red:exec>
                    possible_values = self.possible_values_cache.get(property, None)
                    if not possible_values:
                        possible_values = SetBuilder()
                        self.rednode.neighbourhood.visit_possible_values(possible_values.accept, property)
                        self.possible_values_cache[property] = possible_values
                    possible_values.accept(value)
                    possible_values.sort(self.alpha_by_label)
                  </red:exec>  

                  <red:for item="v" list="possible_values.set">
                    <red:if test="v == value">
                      <OPTION SELECTED="TRUE" VALUE="{v}">
                        <red:eval>self.rednode.neighbourhood.label(v)</red:eval>
                      </OPTION>
                      <red:else>
                        <OPTION VALUE="{v}">
                          <red:eval>self.rednode.neighbourhood.label(v)</red:eval>
                        </OPTION>
                      </red:else>  
                    </red:if>
                  </red:for>
                </SELECT>
                <red:else>
                  <SELECT NAME="prop{self.property_num}_value" onChange="edit_form.processor.value='update'; edit_form.submit()">
                    <OPTION VALUE="{value}">
                      <red:eval>self.rednode.neighbourhood.label(value)</red:eval>
                    </OPTION>
                  </SELECT>
                </red:else>
              </red:if>
              <red:exec>
                return_to = self.app.request.get_parameter("return_to", "")
              </red:exec>
              <red:if test="return_to == ''">
                <red:exec>
                  query_string=""
                  b = ListBuilder()
                  self.rednode.neighbourhood.visit(o(b.accept), (property, RANGE, None))
                  for r in b.list:
                    query_string = query_string + "type=" + encode_URI(r) + "&amp;"
                  query_string = query_string + "return_to=edit%3Fsubject=" + encode_URI(subject)
                  query_string = query_string + "&amp;s_property=" + encode_URI(property)
                  query_string = query_string + "&amp;s_subject=" + encode_URI(subject)
                </red:exec>
                <A HREF="add?{query_string}">add new</A>
              </red:if>
            </red:else>
          </red:if>  
        </TD>

        <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_orig"
               VALUE="{value}"/>

        <red:if test="exists">
          <TD VALIGN="TOP">
            <INPUT TYPE="BUTTON" VALUE="delete_property"
                   ONCLICK="edit_form.processor.value='delete_property'; edit_form.del_num.value='{self.property_num}'; edit_form.submit()"/>
          </TD>
            <!-- <TD VALIGN="TOP"><INPUT TYPE="BUTTON" VALUE="reify_{self.property_num}"/></TD> -->
        </red:if>  
      </TR>
    </red:facet>

    <red:facet name="add">
      <red:exec>
        type = self.app.request.get_parameter('type', '')
        if type != '':
          type = resource(type)
        return_to = self.app.request.get_parameter('return_to', '')
        s_property = self.app.request.get_parameter('s_property', '')
        s_subject = self.app.request.get_parameter('s_subject', '')
      </red:exec>
      <H2>Add Resource</H2>
      <red:if test="s_property != '' and s_subject != ''"><P>and add as value for property</P></red:if>
      <FORM NAME="form" ACTION="edit" METHOD="POST">
        <TABLE>
          <TR>
            <TD VALIGN="TOP">URI</TD>
            <TD>
              <INPUT TYPE="TEXT" SIZE="60" NAME="subject"/>
            </TD>
          </TR>
        </TABLE>
        <P>NOTE: Leave blank if you'd like a URI automatically generated</P>
        <INPUT TYPE="SUBMIT" VALUE="add"/>
        <INPUT TYPE="HIDDEN" NAME="type" VALUE="{type}"/>
        <INPUT TYPE="HIDDEN" NAME="return_to" VALUE="{return_to}"/>
        <INPUT TYPE="HIDDEN" NAME="s_property" VALUE="{s_property}"/>
        <INPUT TYPE="HIDDEN" NAME="s_subject" VALUE="{s_subject}"/>
      </FORM>
    </red:facet>

    <red:facet name="edit_display_property_value"
               args="subject, property, value, exists = 1">
      <red:exec>
        self.property_num = self.property_num + 1
      </red:exec>
            <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_name" VALUE="{property}"/>                    
          <red:if test="(value and isinstance(value, Literal)) or (not value and self.rednode.neighbourhood.exists(property, RANGE, LITERAL))">
            <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_is_literal" VALUE="yes"/>
          </red:if>              
        <INPUT TYPE="HIDDEN" NAME="prop{self.property_num}_orig"
               VALUE="{value}"/>
            
      <TR>
        <TD>
          <red:exec>
            self.viewer.view_link(property)
          </red:exec>
        </TD>
        <TD>
          <red:exec>
            self.viewer.view_link(value)
          </red:exec>
        </TD>

        <red:if test="exists">
          <TD VALIGN="TOP">
            <INPUT TYPE="BUTTON" VALUE="edit"
                   ONCLICK="edit_triple_form.subject.value='{subject}'; edit_triple_form.predicate.value='{property}'; edit_triple_form.object.value='{escape_newlines(value)}'; edit_triple_form.is_literal.value='{isinstance(value, Literal)}'; edit_triple_form.submit();"/>
          </TD>
          <TD VALIGN="TOP">
            <INPUT TYPE="BUTTON" VALUE="delete"
                   ONCLICK="edit_form.processor.value='delete_property'; edit_form.del_num.value='{self.property_num}'; edit_form.submit()"/>
          </TD>
        </red:if>  
      </TR>

    </red:facet>

    <red:facet name="edit_triple">
      <red:exec>
        subject = resource(self.app.request.get_parameter('subject'))
        predicate = resource(self.app.request.get_parameter('predicate'))
        is_literal = self.app.request.get_parameter('is_literal')
        if is_literal=='1':
          object = literal(self.app.request.get_parameter('object'))
        else:
          object = resource(self.app.request.get_parameter('object'))          
      </red:exec>
      
      <FORM NAME="edit_form" ACTION="edit_subject?subject={encode_URI(subject)}" METHOD="POST">
        <INPUT NAME="update_subject" TYPE="HIDDEN" VALUE="{subject}"/>
        <INPUT NAME="processor" TYPE="HIDDEN" VALUE=""/>
        <INPUT NAME="module_instance" TYPE="HIDDEN" VALUE="{self.module_instance}"/>
        <a href="{subject}"><H2><red:eval>subject</red:eval></H2></a>        

      <table>
      <red:exec>
        self.property_num = 0      
        self.edit_property(subject, predicate, object)
      </red:exec>

        <INPUT TYPE="HIDDEN" NAME="prop_count" VALUE="{self.property_num}"/>
        <INPUT TYPE="HIDDEN" NAME="del_num" VALUE="0"/>        
        <tr>
          <td>
            <INPUT TYPE="BUTTON" VALUE="update" ONCLICK="edit_form.processor.value='update'; edit_form.submit()"/>
          </td>
        </tr>
      </table>        
      </FORM>
      
    </red:facet>
    

    

    def do_update(self, request, response, subject=None, copy=0):
        if subject==None:
            subject = resource(self.app.request.get_parameter("update_subject", None))
        count = self.app.request.get_parameter("prop_count", 0)
        i = 0
        while i &lt; int(count):
            i = i + 1
            property = self.app.request.get_parameter('prop%s_name' % i, "")
            value = self.app.request.get_parameter('prop%s_value' % i, None)
            if value:
                orig = self.app.request.get_parameter('prop%s_orig' % i, "")
                is_literal = self.app.request.get_parameter('prop%s_is_literal' % i, "no")
                if is_literal == "yes":
                    value = literal(value)
                    orig = literal(orig)
                else:
                    value = resource(value)
                    orig = resource(orig)
                property = resource(property)
                if copy:
                    self.rednode.add(subject, property, value)
                elif value != orig:
                    self.rednode.remove(subject, property, orig)
                    self.rednode.add(subject, property, value)

        new_property = self.app.request.get_parameter("new_property", "")
        new_property_value = ""
        if self.rednode.neighbourhood.exists(resource(new_property), RANGE, LITERAL):
            new_property_value = literal(new_property_value)
        else:
            new_property_value = resource(new_property_value)
        if new_property != "":
            self.rednode.add(subject, resource(new_property), new_property_value)

    def do_delete(self, request, response):
        subject = self.app.request.get_parameter("subject")
        if subject == "":
            raise "TODO: invalid subject"
        self.rednode.remove_triples(resource(subject), None, None)

    def do_delete_property(self, request, response):
        property_num = self.app.request.get_parameter("del_num")
        subject = resource(self.app.request.get_parameter("subject"))
        property = resource(self.app.request.get_parameter("prop%s_name" % property_num))
        v_name = "prop%s_orig" % property_num
        is_literal = self.app.request.get_parameter("prop%s_is_literal" % property_num)
        if is_literal == 'yes':
            value = literal(self.app.request.get_parameter(v_name))
        else:
            value = resource(self.app.request.get_parameter(v_name))

        self.rednode.remove(subject, property, value)


  </red:module>

</red:code>
