<%@page contentType="text/html;charset=UTF-8" pageEncoding="ISO-8859-1" session="true"
%><%@page errorPage="Exception.jsp"
%><%@page import="com.fujitsu.iflow.model.bpm.BPMSession"
%><%@page import="com.fujitsu.iflow.model.bpm.BPMAdmin"
%><%@page import="com.fujitsu.iflow.model.util.IflowEnumeration"
%><%@page import="com.fujitsu.iflow.model.util.QuickForm"
%><%@page import="com.fujitsu.iflow.model.util.URLEncoder"
%><%@page import="com.fujitsu.iflow.model.workflow.AttachmentRef"
%><%@page import="com.fujitsu.iflow.model.workflow.ProcessInstance"
%><%@page import="com.fujitsu.iflow.model.workflow.WFObjectFactory"
%><%@page import="com.fujitsu.iflow.model.workflow.WorkItem"
%><%@page import="com.fujitsu.iflow.model.workflow.WFSession"
%><%@page import="com.fujitsu.iflow.model.workflow.TrackedUDARecord"
%><%@page import="java.util.Date"
%><%@page import="java.util.Vector"
%><%@page import="java.util.Arrays"
%><%@page import="java.util.Hashtable"
%><%@page import="java.util.Enumeration"
%>
<%
    int udaDisplayLen = 40;
    request.setCharacterEncoding("UTF-8");request.getParameterNames(); //Need dummy call for WL9.1
    BPMSession bps = (BPMSession) session.getAttribute("BPMSession");
    if (bps == null) {
        %><jsp:include page="PasswordPanel.jsp" flush="true"/><%
        return;
    }

    WFSession wfSession = (WFSession)session.getAttribute("ModelsessionID");
    if (wfSession == null) {
        %><jsp:include page="PasswordPanel.jsp" flush="true"/><%
        return;
    }
    
    String displayIdStr = request.getParameter("displayId");
    int displayId = 0;
    if (displayIdStr != null && displayIdStr.length() > 0) {
        displayId = Integer.parseInt(displayIdStr);
    }
    
    String sortByStr = request.getParameter("sortBy");
    String sortOrderStr = request.getParameter("sortOrder");
    
    int sortBy = 0;
    int udaSortBy = 0;
    int sortOrder = 0;
    int udaOrder = 0;
    
    String udaNameKey = request.getParameter("udaName");
    
    if (sortByStr != null && sortByStr.length() > 0) {
        if(displayId != 1) 
            sortBy = Integer.parseInt(sortByStr);
        else
            udaSortBy = Integer.parseInt(sortByStr);
    }

    if (sortOrderStr != null && sortOrderStr.length() > 0) {
        if(displayId != 1) 
            sortOrder = Integer.parseInt(sortOrderStr);
        else
            udaOrder = Integer.parseInt(sortOrderStr);
    }
    
    String rowStyle = "evenrow";
    String rowOther = "oddrow";
    String piid = request.getParameter("id");
    if (piid==null) {
        throw new Exception("Can not display history: Page requires that the process instance be specified with an 'id' parameter");
    }
    long piidlong = Long.parseLong(piid);
    session.setAttribute("TabIndex","-1");
    ProcessInstance process = null;

    String isArchived = request.getParameter("isArchived");
    
    if (isArchived == null) 
    {
        isArchived = "false";
    }
        
    String thisURL = null;

    if(isArchived != null && isArchived.equals("true")){
        BPMAdmin bpas = bps.getAdmin();
        process = bpas.getArchivedProcess(piidlong);
        thisURL = "ShowHistory.jsp?id="+piidlong+"&isArchived="+isArchived;
    }
    else {
        process = WFObjectFactory.getProcessInstance(piidlong, wfSession);
        thisURL = "ShowHistory.jsp?id="+piidlong;
    }

    if (process==null) {
        throw new Exception("Can not display history: Can not find the process Instance for id="+piid);
    }
    
    String processName = process.getName();

    int _processHistoryFields[] = {
        ProcessInstance.HISTORY_ID,
        ProcessInstance.HISTORY_TIME_STAMP,
        ProcessInstance.HISTORY_EVENT_TYPE,
        ProcessInstance.HISTORY_RESPONSIBLE,
        ProcessInstance.HISTORY_PRODUCER_TYPE,
        ProcessInstance.HISTORY_PRODUCER_ID,
        ProcessInstance.HISTORY_CONSUMER_TYPE,
        ProcessInstance.HISTORY_CONSUMER_ID,
        ProcessInstance.HISTORY_PROCESSINSTANCE_ID,
        ProcessInstance.HISTORY_ISHANDLED,
        ProcessInstance.HISTORY_ERROR_MESSAGE,
        ProcessInstance.HISTORY_MODIFIED_TRACKEDUDAS
        };

        IflowEnumeration sElements = process.getHistory(_processHistoryFields);
        Integer historyIdKey = new Integer(ProcessInstance.HISTORY_ID);
        Integer timeStampKey = new Integer(ProcessInstance.HISTORY_TIME_STAMP);
        Integer consumerIdKey = new Integer(ProcessInstance.HISTORY_CONSUMER_ID);
        Integer consumerTypeKey = new Integer(ProcessInstance.HISTORY_CONSUMER_TYPE);
        Integer producerIdKey = new Integer(ProcessInstance.HISTORY_PRODUCER_ID);
        Integer producerTypeKey = new Integer(ProcessInstance.HISTORY_PRODUCER_TYPE);
        Integer responisbleKey = new Integer(ProcessInstance.HISTORY_RESPONSIBLE);
        Integer eventTypeKey = new Integer(ProcessInstance.HISTORY_EVENT_TYPE);
        Integer isHandledKey = new Integer(ProcessInstance.HISTORY_ISHANDLED);
        Integer errMsgKey = new Integer(ProcessInstance.HISTORY_ERROR_MESSAGE);
        Integer udaHistoryKey = new Integer(ProcessInstance.HISTORY_MODIFIED_TRACKEDUDAS);
%>
<html>
<head>
<title>Interstage Business Process Manager | History for ProcessInstance <%= piid %> </title>
<jsp:include page="StyleSheet.jsp" flush="true"/>
<script language="javascript" src="styles/clockscripts.js"></script>

<script TYPE="text/javascript">

function displayUdaValue (piid, udaName, udaValueType, historyId, isArchived)
{
    var url = 'HistoryUdaValueWindow.jsp?procId=' + piid +'&udaName=' + udaName + '&udaValueType=' + udaValueType +'&historyId=' + historyId +'&isArchived=' + isArchived;
    var w = '400';
    var h = '400';
    var winl = (screen.width-w)/2;
    var wint = (screen.height-h)/2;
    var settings  ='height='+h+',';
    settings +='width='+w+',';
    settings +='top='+wint+',';
    settings +='left='+winl+',';
    settings +='scrollbars='+'yes'+',';
    settings +='resizable=yes';  
    var childWindow = window.open(url,'',settings);
    if (childWindow.opener == null)
        childWindow.opener = self;
}

function sort(piId, dispId, sortBy, sortOrder) {
    window.location='ShowHistory.jsp?id=' + piId +'&displayId=' + dispId + '&sortBy='+ sortBy + '&sortOrder=' + sortOrder ;
}

function sortByUDA(piId, dispId, sortBy, sortOrder, udaName) {
    window.location='ShowHistory.jsp?id=' + piId +'&displayId=' + dispId + '&sortBy='+ sortBy + '&sortOrder=' + sortOrder + '&udaName=' + udaName + '#' + udaName;
}

</script>

</head>

<body class="bodyClass">
<jsp:include page="Header.jsp" flush="true"/><br/>
<table class="tableclass" align="center" width="90%">
    <tr>
      <td align="left">
        <jsp:include page="ProcessMenu.jsp">
        <jsp:param name="piId" value="<%=String.valueOf(piid) %>" />
        <jsp:param name="referralURL" value="<%=thisURL%>"/>
        <jsp:param name="isArchived" value="<%=String.valueOf(isArchived)%>"/>
        </jsp:include>
      </td>
    </tr>
  </table><br/>
    <!--jsp:include page="HistoryHeader.jsp" flush="true"/-->
    <jsp:include page="HistoryMenu.jsp" flush="true">
    <jsp:param name="isArchived" value="<%=isArchived%>"/>
    </jsp:include>
    <br/><br/>
 
 <!-- Begin -  For reqular Process History -->
 <%
 
 if (displayId == 0) {
        out.println("<center><H4> Displaying history for Process Instance: '" + processName + "'</H4></center>");
   
 %>
 
  <table align="center" class="tableClass"
       width="800">
    <tr align="center" class="headrow">
        <th nowrap> History Id</th>
        <th nowrap> Timestamp </th>
        <th nowrap> Responsible </th>
        <th nowrap> Event type </th>
        <th nowrap> Status </th>
    </tr>
<%
    while(sElements.hasMoreElements()) {
        Hashtable historyData = (Hashtable) sElements.nextElement();
        Long timeRepresentationInLong = (Long) historyData.get(timeStampKey);
        String timeStamp = printDate(timeRepresentationInLong.longValue());
        long consumerType = ((Long) historyData.get(consumerTypeKey)).longValue();
        long consumerId = ((Long) historyData.get(consumerIdKey)).longValue();
        long producerType = ((Long) historyData.get(producerTypeKey)).longValue();
        long producerId = ((Long) historyData.get(producerIdKey)).longValue();
        String eventType = (String) historyData.get(eventTypeKey);
        String message = (String) historyData.get(errMsgKey);
        String responsible = (String) historyData.get(responisbleKey);
        String isHandled = (String) historyData.get(isHandledKey);
        long historyId = ((Long) historyData.get(historyIdKey)).longValue();

        int pos = eventType.indexOf(':');
        String modifier = null;
        if (pos >= 0) {
            modifier = eventType.substring(pos+1);
            eventType = eventType.substring(0,pos);
        }
        String niceStatus;
        if (eventType.equals("__ProcessCreated")) {
            niceStatus = "Process Instance was created.";
        }
        else if (eventType.equals("__Start")) {
            niceStatus = "Process Instance was started.";
        }
        else if (eventType.equals("__CommitEdit")) {
            niceStatus = "Process Instance was edited.";
        }
        else if (eventType.equals("__Activate")) {
            niceStatus = "Start node activated.";
        }
        else if (eventType.equals("__Close")) {
            niceStatus = "Process Instance was completed; conclusion was '"+modifier+"'.";
        }
        else if (eventType.equals("__Accept")) {
            niceStatus = "User accepted workitem #"+modifier;
        }
        else if (eventType.equals("__Decline")) {
            niceStatus = "User declined workitem #"+modifier;
        }
        else {
            if (modifier != null) {
                niceStatus = "User selected choice '"+eventType+"' from workitem #"+modifier;
            }
            else {
                niceStatus = "Arrow '"+eventType+"' transition to node ("+consumerId+")";
            }
        }

        if (responsible.equals("__process")) {
            responsible = "Process";
        }
%>
    <tr class="<%=rowStyle%>">
        <td width="20%"><a name="hId<%=historyId%> </a>" ><%=historyId%></td>
        <td width="20%"><%=timeStamp%></td>
        <td width="15%"><%=responsible%></td>
        <td width="35%"><%=niceStatus%></td>
        <td width="10%"><%=isHandled%></td></tr>
<%
        if (message != null && message.length()>0) {
%>
            <tr class="<%=rowStyle%>"><td width="200"></td><td colspan=5>
                <font color="#5555AA" size="1"><% deparenthesize(out, message); %></font></td></tr>
<%
        }
        String temp = rowStyle;
        rowStyle = rowOther;
        rowOther = temp;
    }
%>
    </table>
    
<!-- End - reqular Process History -->
 <%
  }
  // for UDA history display.
  else
  {
  
    out.println("<center><H4> Displaying UDA history for Process Instance: '" + processName + "'</H4></center>");

    Vector udahList = new Vector();
    while(sElements.hasMoreElements()) 
    {
        Hashtable historyData = (Hashtable) sElements.nextElement();
        TrackedUDARecord[] tUdas = (TrackedUDARecord[] )historyData.get(udaHistoryKey);
        if (tUdas != null) 
        {
            for(int i=0; i< tUdas.length; i++)
            {
                UdaHistory udah = new UdaHistory(sortBy, sortOrder);
                udah.setHistoryId(((Long) historyData.get(historyIdKey)).longValue());
                udah.setTime(((Long) historyData.get(timeStampKey)).longValue());
                udah.setResponsible((String) historyData.get(responisbleKey));
                udah.setOldValue(tUdas[i].getOldValue());
                udah.setNewValue(tUdas[i].getNewValue());
                udah.setUdaName(tUdas[i].getName());
                udah.setUdaOperation(tUdas[i].getUDAOperation());
                udahList.add(udah);
            }
        }

    }
    
    if (displayId == 2 && udahList.size() > 0) 
    {

    UdaHistory[] udahArray = new UdaHistory[udahList.size()];
    udahList.copyInto(udahArray);
    Arrays.sort(udahArray);
    
    String[] displayFields = {"Timestamp", "Name", "Modified From", "Modified To", "Operation", "Responsible", "History Id"};
    String[] displayWidth = {"15%", "15%", "20%", "20%", "05%", "10%", "15%"};
    int[] sortFields = {0, 1, 2, 3, 4, 5, 6};
  
 %>
    <TABLE bgcolor="#CCCCCC" border="0" cellpadding="4" cellspacing="1" class="tableClass" width="90%" align="center">
        <tr align="center" class="headrow">
            <td bgcolor="#EEEEEE" style="filter:progid:DXImageTransform.Microsoft.Gradient(startColorStr='#FFFFFF', endColorStr='#6699CC', gradientType='1')" colspan="7"><font color="#000000" size="2">UDA History By Timestamp</font></td>
        </tr>
        <tr class="headrow">
<%
    for (int i = 0; i < displayFields.length; i++)
    {
        String fieldName = displayFields[i].trim();
%>
                <th width="<%=displayWidth[i]%>">
                    <TABLE bgcolor="#0066CC" border="0" cellpadding="0" cellspacing="0">
                        <tr align="center" class="headrow" bgcolor="#0066CC">
                            <td rowspan="2"><%=fieldName%></td>
                            <td><input type="image" src="images/asc.gif" onclick="javascript:sort('<%=piid%>', '<%=displayId%>', '<%=sortFields[i]%>', '<%=0%>')"></td>
                        </tr>
                        <tr>
                            <td><input type="image" src="images/desc.gif" onclick="javascript:sort('<%=piid%>', '<%=displayId%>', '<%=sortFields[i]%>', '<%=1%>')"></td>
                        </tr>
                        <tr>
                        </tr>
                    </TABLE>
                </th>
<%
    }
%>    
<%
  
   for(int i=0; i<udahArray.length; i++)
   {
   
   %>
    <tr class="<%=rowStyle%>">
        <td><%= printDate(udahArray[i].getTime())%></td>
        <td><% QuickForm.writeHtmlWithNBSPs(out,udahArray[i].getUdaName()); %></td>
        
  <%
  if (!(udahArray[i].getOldValue().length() > udaDisplayLen))
  {
  %>
      <td><%QuickForm.writeHtml(out, udahArray[i].getOldValue());%></td>
  <%
  }
  else
  {
  %>
      <td> <a href="javascript:displayUdaValue('<%=piid%>', '<%=udahArray[i].getUdaName()%>', 'Old' , '<%=udahArray[i].getHistoryId()%>' ,'<%=isArchived%>');"><%= udahArray[i].getOldValue().substring(0, udaDisplayLen-1)%> ...</a></td>
  <%
  }
  %>
  
    <%
  if (!(udahArray[i].getNewValue().length() > udaDisplayLen ))
  {
  %>
      <td><%QuickForm.writeHtml(out, udahArray[i].getNewValue());%></td>
  <%
  }
  else
  {
  %>
      <td> <a href="javascript:displayUdaValue('<%=piid%>', '<%=udahArray[i].getUdaName()%>', 'New', '<%=udahArray[i].getHistoryId()%>', '<%=isArchived%>');"><%= udahArray[i].getNewValue().substring(0, udaDisplayLen-1)%>  ...</a></td>
  <%
  }
  %>
        <td><%= udahArray[i].getUdaOperation()%></td>
        <td><%= udahArray[i].getResponsible()%></td>
        <td>
            <a href="ShowHistory.jsp?id=<%=piid%>&displayId=0&isArchived=<%=isArchived%>#<%=udahArray[i].getHistoryId()%>"><%= udahArray[i].getHistoryId()%></a>
        </td>
    </tr>
   <%
        String temp = rowStyle;
        rowStyle = rowOther;
        rowOther = temp;
    }
    %>
</table>


 <%
 }
     
    
 else if (displayId == 1 && udahList.size() > 0) 
 {
        
        String[] displayFields = {"Timestamp", "Modified From", "Modified To", "Operation", "Responsible", "History Id"};
        String[] displayWidth = {"15%", "20%", "20%", "05%", "10%", "15%"};
        int[] sortFields = {0, 2, 3, 4, 5, 6};
        Hashtable udaNameList = new Hashtable();
        for(int i=0; i<udahList.size(); i++)
        {
            Vector grpUdaHist = new Vector();       
            UdaHistory udah = (UdaHistory)udahList.get(i);
            String udaKey = udah.getUdaName();
            if(udaKey.equals(udaNameKey)){
                udah.resetOrder(udaSortBy, udaOrder);
            }
            if(udaNameList.containsKey(udaKey))
            {
                grpUdaHist = (Vector)udaNameList.get(udaKey);
                grpUdaHist.add(udah);
                udaNameList.put(udaKey,grpUdaHist);
            }
            else
            {
                grpUdaHist.add(udah);
                udaNameList.put(udaKey,grpUdaHist);
            }
        }
        Vector udaKeys = new Vector();
        
            for (Enumeration e = udaNameList.keys() ; e.hasMoreElements() ;)
            udaKeys.add((String)e.nextElement());
        Object[] udaKeysArray = udaKeys.toArray();
        Arrays.sort(udaKeysArray);


    %>
    
        <TABLE bgcolor="#CCCCCC" border="0" cellpadding="4" cellspacing="1" class="tableClass" width="90%" align="center">
        <tr align="center" class="headrow">
            <td bgcolor="#EEEEEE" style="filter:progid:DXImageTransform.Microsoft.Gradient(startColorStr='#FFFFFF', endColorStr='#6699CC', gradientType='1')" colspan="7">
            <font color="#000000" size="2">Go To UDA: &nbsp;</font>
            
        <SELECT NAME="udsList" onChange="javascript: window.location=this.value;">
    
    <%

        for(int udak=0; udak<udaKeysArray.length; udak++) { 
        %>
            <OPTION VALUE="#<%= udaKeysArray[udak] %>">
        <font color="#000000" size="2">
        <a href="#<%= udaKeysArray[udak] %>"><% QuickForm.writeHtmlWithNBSPs(out,(String)udaKeysArray[udak]); %></a>
        </font>
        </OPTION>
        <%
        }
    %>
           </SELECT>
            </td>
        </tr>
         </TABLE>
         <BR>
         <BR>

        <%      
        for(int udak=0; udak<udaKeysArray.length; udak++)
        {
    %>
            <TABLE bgcolor="#CCCCCC" border="0" cellpadding="4" cellspacing="1" class="tableClass" width="90%" align="center">
                <tr align="center" class="headrow">
                    <td bgcolor="#EEEEEE" style="filter:progid:DXImageTransform.Microsoft.Gradient(startColorStr='#FFFFFF', endColorStr='#6699CC', gradientType='1')" colspan="7"><font color="#000000" size="2"><A NAME="<%= udaKeysArray[udak] %>">UDA History By: <% QuickForm.writeHtmlWithNBSPs(out,(String)udaKeysArray[udak]); %></A></font></td>
                </tr>
            <tr class="headrow">                
    <%
            for (int i = 0; i < displayFields.length; i++)
            {
                String fieldName = displayFields[i].trim();
    %>
                <th width="<%=displayWidth[i]%>">
                    <TABLE bgcolor="#0066CC" border="0" cellpadding="0" cellspacing="0">
                        <tr align="center" class="headrow" bgcolor="#0066CC">
                            <td rowspan="2"><%=fieldName%></td>
                            <td><input type="image" src="images/asc.gif" onclick="javascript:sortByUDA('<%=piid%>', '<%=displayId%>', '<%=sortFields[i]%>', '<%=0%>', '<%= udaKeysArray[udak] %>')"></td>
                        </tr>
                        <tr>
                            <td><input type="image" src="images/desc.gif" onclick="javascript:sortByUDA('<%=piid%>', '<%=displayId%>', '<%=sortFields[i]%>', '<%=1%>', '<%= udaKeysArray[udak] %>')"></td>
                        </tr>
                        <tr>
                        </tr>
                    </TABLE>
                </th>
    <%
            }
    %>
            </tr>
    <%          
           Vector udaGrpH = (Vector)udaNameList.get((String)udaKeysArray[udak]);
           UdaHistory[] udahArray = new UdaHistory[udaGrpH.size()];
           udaGrpH.copyInto(udahArray);
           Arrays.sort(udahArray);
           for(int i=0; i<udahArray.length; i++)
           {
                UdaHistory udah = udahArray[i];
               %>
                <tr class="<%=rowStyle%>">
                    <td><%= printDate(udah.getTime())%></td>
              <%
              if (!(udah.getOldValue().length() > udaDisplayLen))
              {
              %>
                  <td><%QuickForm.writeHtml(out, udah.getOldValue());%></td>
              <%
              }
              else
              {
              %>
                  <td> <a href="javascript:displayUdaValue('<%=piid%>', '<%=udah.getUdaName()%>', 'Old', '<%=udah.getHistoryId()%>', '<%=isArchived%>');"><%= udah.getOldValue().substring(0, udaDisplayLen-1)%> ...</a></td>
              <%
              }
              %>
              
                <%
              if (!(udah.getNewValue().length() > udaDisplayLen ))
              {
              %>
                  <td><%QuickForm.writeHtml(out, udah.getNewValue());%></td>
              <%
              }
              else
              {
              %>
                  <td> <a href="javascript:displayUdaValue('<%=piid%>', '<%=udah.getUdaName()%>', 'New', '<%=udah.getHistoryId()%>', '<%=isArchived%>');"><%= udah.getNewValue().substring(0, udaDisplayLen-1)%>  ...</a></td>
              <%
              }
              %>
                    <td><%= udah.getUdaOperation()%></td>
                    <td><%= udah.getResponsible()%></td>
                    <td><a href="ShowHistory.jsp?id=<%=piid%>&displayId=0&isArchived=<%=isArchived%>#<%=udahArray[i].getHistoryId()%>"><%= udah.getHistoryId()%></a></td>
        <%
            String temp = rowStyle;
            rowStyle = rowOther;
            rowOther = temp;
        }
        %>              
        </tr>
        </TABLE>
        <br><br>
 <%
        }
    }
    else
    {
 %>
     <table border="0" width="90%" bgcolor="#FFFFFF" align="center">
            <tr>
              <td align="center">
              <font color="#000000" size="4"> <img src="images/icons/info_excep.gif" border="0" align="center">
               There are currently no UDA's to track on this Process Instance. </font>
              </td>
            </tr>
          </table>
 <%
    }
  }
 %>
 
    
<br>
</body>
</html>
  <%!
    public
    String
    printDate(long dateLong)
    {
        // TODO put the proper conversion to a date display format.
        if(dateLong==-1) return "";
        return  "<script> showDate('"+dateLong+"'); </script>";
    }

    // converts a string with multiple nested parenthises into
    // a nested hierarchy of lists ... much easier to read
    public void deparenthesize(JspWriter out, String input)
        throws Exception
    {
        try {
            // now print it as a set of ul statements
            int pos = 0;
            int leftover=1;
            int last = input.length();
            out.write("\n<ul>");
            while (pos < last) {
                int spos = input.indexOf('{', pos);
                int epos = input.indexOf('}', pos);
                int jpos = input.indexOf("nested exception is:", pos);
                int kpos = input.indexOf("because:", pos);
                int npos = last;
                int option = 0;
                int skip = 0;
                if (spos >= 0 && spos < npos) {
                    npos = spos;
                    option = 1;
                    skip = 1;
                }
                if (epos >= 0 && epos < npos) {
                    npos = epos;
                    option = 2;
                    skip = 1;
                }
                if (jpos >= 0 && jpos < npos) {
                    npos = jpos;
                    option = 3;
                    skip = 20;
                }
                if (kpos >= 0 && kpos < npos) {
                    npos = kpos;
                    option = 3;
                    skip = 8;
                }

                // if the character at the position is the searched char,
                // then both pos and npos will be the same
                if (npos > pos) {
                    out.write("<li>");
                    QuickForm.writeHtmlWithLineBreaks(out, input.substring(pos, npos));
                }
                pos = npos + skip;
                switch (option) {
                case 3:
                    leftover++;
                    // continue to next block
                case 1:
                    //out.write("\n<ul>");
                    break;
                case 2:
                    //out.write("\n</ul>");
                    break;
                case 0:
                    break;
                }

                // skip any following white space to avoid empty outline entries
                while (pos < last && input.charAt(pos) == ' ') {
                    pos++;
                }
            }
            while (leftover > 0) {
                out.write("\n</ul>");
                leftover--;
            }
        }
        catch (Exception ee) {
            out.write("<!-- deparenthesize got this error:");
            out.write(ee.toString());
            out.write("-->");
        }
    }


// Utility class.

class UdaHistory implements Comparable
{
    public static final int orderField_timeStamp = 0;
    public static final int orderField_udaName = 1;
    public static final int orderField_oldValue = 2;
    public static final int orderField_newValue = 3;
    public static final int orderField_udaOperation = 4;
    public static final int orderField_responsible = 5;
    public static final int orderField_historyId = 6;
    
    public static final int ascending_order = 0;
    public static final int descending_order = 1;
    
    String _udaName;
    String _oldValue;
    String _newValue;
    String _responsible;
    int _udaOperation;
    long _historyId;
    long _timeStamp;
    
    int _sortBy =  orderField_timeStamp;
    int _orderType = ascending_order;
    
    public UdaHistory(int sortBy, int orderType)
    {
        _sortBy = sortBy;
        _orderType = orderType;
        
    }
    
    public void resetOrder(int sortBy, int orderType)
    {
        _sortBy = sortBy;
        _orderType = orderType;
    }
    
    public String getUdaName()
    {
       return  _udaName;
    }
    public void setUdaName(String udaName)
    {
        _udaName = udaName;
    }
    
    public String getOldValue()
    {
       return  _oldValue;
    }
    public void setOldValue(String oldValue)
    {
        _oldValue = oldValue;
    }
    
    public String getNewValue()
    {
       return  _newValue;
    }
    public void setNewValue(String newValue)
    {
        _newValue = newValue;
    }
    public String getUdaOperation()
    {
        if( _udaOperation == TrackedUDARecord.UDA_ADD)
            return "Added";
        else if( _udaOperation == TrackedUDARecord.UDA_MODIFIED)
            return "Modified";
        else if( _udaOperation == TrackedUDARecord.UDA_DELETE)
            return "Deleted";
        else if( _udaOperation == TrackedUDARecord.UDA_CREATED)
            return "Created";
        else if( _udaOperation == TrackedUDARecord.UDA_START_TRACKING)
            return "Start Tracking";
        else if( _udaOperation == TrackedUDARecord.UDA_STOP_TRACKING)
            return "Stop Tracking";
        
        return "Unknown";
    }
    public void setUdaOperation(int udaOperation)
    {
        _udaOperation = udaOperation;
    }
    
    public String getResponsible()
    {
       return  _responsible;
    }
    public void setResponsible(String responsible)
    {
        _responsible = responsible;
    if (responsible.equals("__process")) {
        _responsible = "Process";
    }

    }
    public long getHistoryId()
    {
       return  _historyId;
    }
    public void setHistoryId(long historyId)
    {
        _historyId = historyId;
    }
    public long getTime()
    {
       return  _timeStamp;
    }
    public void setTime(long timeStamp)
    {
        _timeStamp = timeStamp;
    }
    
    public
    int
    compareTo(Object obj)
    {
        int comparedValue = 0;
        if(obj == null)
           return comparedValue;

        UdaHistory uh = (UdaHistory)obj ;
        if(_orderType  == UdaHistory.descending_order)
        {
            switch(_sortBy){
                case UdaHistory.orderField_historyId: {
                    if(_historyId > uh._historyId)
                        comparedValue = -1;
                    else if(_historyId < uh._historyId)
                        comparedValue = 1;
                    else if(_historyId == uh._historyId)
                        comparedValue = 0;
                    break;
                }
                case UdaHistory.orderField_timeStamp: {
                     if(_timeStamp > uh._timeStamp)
                        comparedValue = -1;
                    else if(_timeStamp < uh._timeStamp)
                        comparedValue = 1;
                    else if(_timeStamp == uh._timeStamp)
                        comparedValue = 0;
                     break;
                }
                case UdaHistory.orderField_udaOperation: {
                     if(_udaOperation > uh._udaOperation)
                        comparedValue = -1;
                    else if(_udaOperation < uh._udaOperation)
                        comparedValue = 1;
                    else if(_udaOperation == uh._udaOperation)
                        comparedValue = 0;
                     break;
                }
                case UdaHistory.orderField_newValue: {
                    comparedValue = (-1)*(_newValue.compareTo(uh._newValue)); 
                     break;
                }
                case UdaHistory.orderField_oldValue: {
                    comparedValue = (-1)*(_oldValue.compareTo(uh._oldValue));
                     break;
                 }
                 case UdaHistory.orderField_responsible: {
                    comparedValue = (-1)*(_responsible.compareTo(uh._responsible));
                     break;
                 }
                 case UdaHistory.orderField_udaName: {
                    comparedValue = (-1)*(_udaName.compareTo(uh._udaName));
                     break;
                 }
            }
        }
        else 
        {
             switch(_sortBy){
                case UdaHistory.orderField_historyId: {
                    if(_historyId > uh._historyId)
                        comparedValue = 1;
                    else if(_historyId < uh._historyId)
                        comparedValue = -1;
                    else if(_historyId == uh._historyId)
                        comparedValue = 0;
                    break;
                }
                case UdaHistory.orderField_timeStamp: {
                     if(_timeStamp > uh._timeStamp)
                        comparedValue = 1;
                    else if(_timeStamp < uh._timeStamp)
                        comparedValue = -1;
                    else if(_timeStamp == uh._timeStamp)
                        comparedValue = 0;
                     break;
                }
                case UdaHistory.orderField_udaOperation: {
                     if(_udaOperation > uh._udaOperation)
                        comparedValue = 1;
                    else if(_udaOperation < uh._udaOperation)
                        comparedValue = -1;
                    else if(_udaOperation == uh._udaOperation)
                        comparedValue = 0;
                     break;
                }
                case UdaHistory.orderField_newValue: {
                    comparedValue = _newValue.compareTo(uh._newValue); 
                     break;
                }
                case UdaHistory.orderField_oldValue: {
                    comparedValue = _oldValue.compareTo(uh._oldValue);
                     break;
                 }
                 case UdaHistory.orderField_responsible: {
                    comparedValue = _responsible.compareTo(uh._responsible);
                     break;
                 }
                 case UdaHistory.orderField_udaName: {
                    comparedValue = _udaName.compareTo(uh._udaName);
                     break;
                 }
            }
        }
        
        return comparedValue;
    }
}

%>

