REM dbdrv: sql ~PROD ~PATH ~FILE none none none package &phase=plb \
REM dbdrv: checkfile:~PROD:~PATH:~FILE
/*=======================================================================+
 |  Copyright (c) 1999 Oracle Corporation Redwood Shores, California, USA|
 |                            All rights reserved.                       |
 +=======================================================================+
 | FILENAME
 |   wfhtmb.pls
 | DESCRIPTION
 |   PL/SQL body for package:  WFA_HTML
 | NOTE
 |   There is a dependency on dynamic sql.
 |   Must have Oracle 8.1.5 or above.
 |
 | MODIFICATION LOG:
 |   01/2002 JWSMITH BUG 2001012 - Increased luser, lowner, lfromuser,ldt,
 |           ltmpname, username, admin_role, t_owner, t_user, t_fromuser,
 |           t_delegatedto, s0, recipient, orig_recipient,
 |           uos, ros, oos, sess_username, disprole, titlerole,
 |           l_forwardee, l_username, l_name to varchar2(320),
 |           role display_name (realname) to varchar2(360) 
 |   02/2002 JWSMITH BUG 2167012 - Moved owa_util.header_close call to after
 |           the owa_util.redirect call in ResponseFrame.
 |   04/2002 JWSMITH BUG 2232218 - Added new query to handle the case
 |           when you want to query notifications by role name.
 |   09/2002 JWSMITH BUG 1691538 - Added javascript to valide the nid
 |           on the Find Notification Screen.
 |   11/2002 CTILLEY BUG 2664679 - only validate nid if in admin mode else 
 |           error on page occurs for non-Admin users.
 |   12/2002 JWSMITH BUG 2664679/2719596 - Also need to change the submit
 |           button in Find routine to not call the javascript unless in
 |           admin mode.  
 *=======================================================================*/

SET VERIFY OFF
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
WHENEVER OSERROR EXIT FAILURE ROLLBACK;

set arraysize 1
set scan off

create or replace package body WFA_HTML as
/* $Header: wfhtmb.pls 26.64 2005/03/11 06:18:55 anachatt ship $ */

-- Bug# 2236250 exception to handle invalid number
invalid_number exception;
pragma EXCEPTION_INIT(invalid_number, -6502);


g_priority  varchar2(2000);
g_newline varchar2(1) := wf_core.newLine;
g_wfInstall varchar2(15) := wf_core.translate('WF_INSTALL');

--
-- Error (PRIVATE)
--   Print a page with an error message.
--   Errors are retrieved from these sources in order:
--     1. wf_core errors
--     2. Oracle errors
--     3. Unspecified INTERNAL error
--
procedure Error
as
  error_name      varchar2(30);
  error_message   varchar2(2000);
  error_stack     varchar2(32000);
begin
    htp.htmlOpen;
    htp.headOpen;
    htp.title(wf_core.translate('ERROR'));
    htp.headClose;

    begin
      wfa_sec.Header(background_only=>TRUE);
    exception
      when others then
        htp.bodyOpen;
    end;

    wf_core.get_error(error_name, error_message, error_stack);
    --Bug 4215720
    error_message:=wf_core.substitutespecialchars(error_message);
    error_stack:=wf_core.substitutespecialchars(error_stack);
    htp.p('<SCRIPT LANGUAGE="JavaScript">');
    htp.p('function ShowStack() {
errwin=window.open("","errwin","scrollbars=yes,resizable=yes,width=700,height=300");
errwin.document.open();');


    htp.p('errwin.document.writeln("<b><font size=+2>'||wf_core.translate('ERROR')||': </font>'||error_message||'</b>");');

    htp.p('errwin.document.writeln("<br>'||wf_core.translate('WFENG_ERRSTACK')||': '||
          replace(error_stack,wf_core.newline,'<br>')||'");');

    htp.p('errwin.document.close();');

    htp.p('}');
    htp.p('</SCRIPT>');

    htp.p('<NOSCRIPT>');
    htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
    htp.p('</NOSCRIPT>');

    htp.br;
    htp.br;

    htp.p('<CENTER>');

    --print the actual page, with a button in top right to go back
    htp.p('<b><font size=+2>'||wf_core.translate('ERROR')||': </font>');
    --print error message with hyperlink to stack
    htp.p('<a href="javascript:ShowStack()">');
    if (error_name is not null) then
        htp.p(error_message);
    else
        htp.p(sqlerrm);
    end if;
    htp.p('</a></b>');
    htp.p('</CENTER>');

    htp.br;
    htp.br;

    htp.tableopen (cattributes =>'align=CENTER border=0 summary=""');
    htp.tableRowOpen;
    htp.p('<TD summary="">');
    wfa_html.create_reg_button ('javascript:history.back()',
                                wf_core.translate ('WFMON_OK'),
                                wfa_html.image_loc,
                                null,
                                wf_core.translate ('WFMON_OK'));

    htp.p('</TD>');
    htp.tableRowClose;
    htp.tableClose;

    wfa_sec.Footer;
    htp.htmlClose;
end Error;

--
--
-- Login
--   Generate login page.
-- IN
--   message - optional login message
-- NOTE
--   This page is only used to enable access when no external security
--   is installed.  Normally users are authenticated by the chosen
--   security system (IC, WebServer native, etc) and can then access
--   the Workflow Notification pages (Worklist, Detail) directly.
--
procedure Login(
  message in varchar2,
  i_direct in varchar2)
as

c_language    VARCHAR2(80);

begin

  -- Get the global language preference since we don't know who the
  -- user is yet...
  c_language := NVL(wf_pref.get_pref ('-WF_DEFAULT-', 'LANGUAGE'), 'AMERICAN');
  c_language := ''''||c_language||'''';
  dbms_session.set_nls('NLS_LANGUAGE'   , c_language);

  -- Set the language to the default language for the system

  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_LOGIN_REQUEST'));
   wfa_html.create_help_function('wf/links/log.htm?LOGIN');
  htp.headClose;
  wfa_sec.Header(background_only=>FALSE, inc_lov_applet=>FALSE);

  htp.p('<FORM NAME="WFA_LOGIN" ACTION="wfa_html.Viewer" TARGET="_top" METHOD="POST">');

-- bug 1838410
   if (i_direct is not null) then
       htp.formHidden('i_direct', i_direct);
   end if;


  if (message is not null) then
    htp.header(4, wf_core.translate(message));
    htp.br;
  end if;

  htp.br;
  htp.tableOpen(calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;
  htp.tableData('<LABEL FOR="i_user_id">' ||
                wf_core.translate('USER_ID') ||
                '</LABEL>', 'Right',
                cattributes=>'id=""');
  htp.tableData(htf.formText('User_ID', 25, cattributes=>'id="i_user_id"'),
                'Left', cattributes=>'id=""');
  htp.tableRowClose;

  htp.tableRowOpen;
  htp.tableData('<LABEL FOR="i_password">' ||
                wf_core.translate('PASSWORD') ||
                '</LABEL>', 'Right',
                cattributes=>'id=""');
  htp.tableData(htf.formPassword('Password', 25,
                                 cattributes=>'id="i_password"'), 'Left',
                cattributes=>'id=""');
  htp.tableRowClose;

  htp.tableClose;
  htp.centerClose;
  htp.br;

  htp.formClose;

  htp.tableopen (calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;

  htp.p('<TD id="">');

  wfa_html.create_reg_button ('javascript:document.WFA_LOGIN.submit()',
                              wf_core.translate ('LOGIN'),
                              wfa_html.image_loc,
                              'FNDJLFOK.gif',
                              wf_core.translate ('LOGIN'));

  htp.p('</TD>');

  htp.tableRowClose;
  htp.tableClose;

  wfa_sec.Footer;
  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'Login');
    wfa_html.Error;
end Login;

--
-- Viewer
--   Validate user from Login page, then show worklist.
-- IN
--   user_id  - user name
--   password - user password
-- NOTE
--   This page is only used to enable access when no external security
--   is installed.  Normally users are authenticated by the chosen
--   security system (IC, WebServer native, etc) and can then access
--   the Workflow Notification pages (Worklist, Detail) directly.
--
procedure Viewer(
  user_id  in varchar2,
  password in varchar2,
  i_direct in varchar2)
as
  s0          varchar2(320);   -- dummy
  username    varchar2(320);
  realname    varchar2(360);

begin
  -- Validate the user
  if (user_id is null) then
     -- No username entered
     wfa_html.Login('WFA_ENTER_ID');
     return;
  end if;
  username := upper(user_id);

  begin
    wfa_sec.CreateSession(username, password);
  exception
    when others then
      if (wf_core.error_name='WFSEC_USER_PASSWORD') then
        -- Bad username or password
        wf_core.clear;
        wfa_html.Login('WFA_ILLEGAL_IDP');
        return;
      end if;
      -- Raise any other error message
      raise;
  end;

if (i_direct is null) then

  -- Go to home page
  Wfa_Html.Home;

else
  -- Fix for bug 1838410
  -- Instead of navigating to the home page, we will go directly to the URL
  -- specified in i_direct and the user will now be authenticated.  We are
  -- calling the function within a frame.
  -- Example: E-mail notifications with send_accesskey=N.

  htp.p('<HTML>');
  htp.p('<HEAD>');
  htp.p('<TITLE>');
  htp.p('</TITLE>');
  htp.p('</HEAD>');
  htp.p('<FRAMESET ROWS="100%, *">');
  htp.p('<FRAME NAME="DirectLogin" MARGINHEIGHT=10 MARGINWIDTH=10 NORESIZE' ||
    ' src="'||owa_util.get_owa_service_path || i_direct || '">');
  htp.p('</FRAMESET>');
  htp.p('</HTML>');

  end if;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'Viewer', user_id, password);
    wfa_html.Error;
end Viewer;


--
-- Find
--   Filter page to find notifications of user
--
procedure Find
is
  username varchar2(320);   -- Username to query
  realname varchar2(360);   -- Display name of username
  admin_role varchar2(320); -- Role for admin mode
  s0 varchar2(2000);
  lang_codeset varchar2(50); -- Language Codeset from environment
                             -- (e.g. WE8ISO8859P1)
  l_message     varchar2(240)   := wfa_html.replace_onMouseOver_quotes(wf_core.translate ('WFPREF_LOV'));

  admin_mode boolean;        -- TRUE if user has admin role priviledge

  l_url         varchar2(1000);
  l_media       varchar2(240) := wfa_html.image_loc;
  l_icon        varchar2(30) := 'FNDILOV.gif';
  l_onmouseover varchar2(240) := wfa_html.replace_onMouseOver_quotes(wf_core.translate('WFA_FIND_USER'));

  uorig_system varchar2(30); -- User orig_system for indexes
  uorig_system_id number;    -- User orig_system_id for indexes


  cursor lkcurs(lktype in varchar2) is
    select WL.MEANING, WL.LOOKUP_CODE
    from WF_LOOKUPS WL
    where WL.LOOKUP_TYPE = lktype
    order by WL.MEANING;

-- Lookup for Item Type (regular role)
  cursor itcurs(role varchar2, uos varchar2, uosid number) is
    select unique WIT.DISPLAY_NAME, WN.MESSAGE_TYPE
    from WF_NOTIFICATIONS WN, WF_ITEM_TYPES_VL WIT
    where WN.MESSAGE_TYPE = WIT.NAME
    and WN.RECIPIENT_ROLE in
        (select ROLE_NAME from WF_USER_ROLES
          where USER_ORIG_SYSTEM = uos
            and USER_ORIG_SYSTEM_ID = uosid
            and USER_NAME = role)
    order by WIT.DISPLAY_NAME;

-- Lookup for Item Type (admin role)
--   Cursor sql changed for bug 1953214.  No longer include WF_NOTIFICATIONS
--   in sql. Performance improvement.
  cursor aitcurs is
    select WIT.DISPLAY_NAME,WIT.NAME MESSAGE_TYPE
    from WF_ITEM_TYPES_VL WIT
    order by WIT.DISPLAY_NAME;

  ittype itcurs%rowtype;
  aittype aitcurs%rowtype;
begin
  -- Check session and current user
  wfa_sec.GetSession(username);
  username := upper(username);
  wf_directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  -- Check Admin Priviledge
  admin_role := wf_core.translate('WF_ADMIN_ROLE');
  if (admin_role = '*' or
      Wf_Directory.IsPerformer(username, admin_role)) then
    admin_mode := TRUE;
  else
    admin_mode := FALSE;
  end if;

  -- Get language codeset
  lang_codeset := substr(userenv('LANGUAGE'),instr(userenv('LANGUAGE'),'.')+1,
                         length(userenv('LANGUAGE')));

  -- Set page title
  htp.htmlOpen;
  htp.headOpen;

  htp.title(wf_core.translate('WFA_FINDTITLE')||' - '||realname);
  wfa_html.create_help_function('wf/links/fin.htm?FINDNOT');
  fnd_document_management.get_open_dm_display_window;

 -- CTILLEY BUG 2664679 - only validate nid if in admin mode else error on
 -- page occurs for non-Admin users.

 if (admin_mode) then

  --JWSMITH BUG 1691538 - add javascript to validate nid
  htp.p('<SCRIPT LANGUAGE="JavaScript">' || wf_core.newline ||
        '<!-- hide the script''s contents from feeble browsers');

  htp.p(wf_core.newline || 'function SubmitValidate() {' || wf_core.newline );
  htp.p('var lnid = document.WF_FIND.nid.value;' || wf_core.newline );
  htp.p('if (isNaN(lnid)) {' || wf_core.newline );
  htp.p('alert( " ' || WF_CORE.Translate('WFA_NID_MUST_BE_NUMERIC' ) || ' "); }' );
  htp.p('else { document.WF_FIND.submit(); }' || wf_core.newline ||
  '}' || wf_core.newline);
  htp.p('<!-- done hiding from old browsers --> </SCRIPT>' || wf_core.newline);

 end if;

  htp.headClose;

  -- Page header
  wfa_sec.Header(FALSE, '', wf_core.translate('WFA_FINDTITLE'), TRUE);

  htp.formOpen(curl=>owa_util.get_owa_service_path||'wfa_html.WorkList',
               cmethod=>'Post', cattributes=>'TARGET="_top" NAME="WF_FIND"');


  htp.tableOpen(calign=>'CENTER', cattributes=>'border=0 summary=""');

  -- Add following fields if current user has WF_ADMIN_ROLE privileges
  if (admin_mode) then
    -- Notification ID field
    htp.tableRowOpen;
    htp.tableData(cvalue=>'<LABEL FOR="i_nid">' ||
                          wf_core.translate('NOTIFICATION_ID') ||
                          '</LABEL>',
                  calign=>'right',
                  cattributes=>'id=""');
    htp.tableData(htf.formText(cname=>'nid', csize=>'8',
                                 cmaxlength=>'15', cattributes=>'id="i_nid"'),
                                 calign=>'left',
                                 cattributes=>'id=""');
    htp.tableRowClose;

    htp.tableRowOpen;
    htp.tableData(cvalue=>'&nbsp;', calign=>'right',
                  cattributes=>'id=""');
    htp.tableData(cvalue=>'<B>'||wf_core.translate('OR')||'</B>',
                  calign=>'left',
                  cattributes=>'id=""');
    htp.tableRowClose;

    -- Owner Field
    htp.tableRowOpen;
    htp.tableData(cvalue=>'<LABEL FOR="i_owner">' ||
                          wf_core.translate('OWNER') ||
                          '</LABEL>', calign=>'right',
                  cattributes=>'id=""');
    htp.formHidden('owner', null);


    -- Bug 1298601 : added call to replace_onMouseOver_quotes to p_display_name
    -- add LOV here: Note:bottom is name of frame.
    -- Note: The REPLACE function replaces all the space characters with
    -- the proper escape sequence.
    l_url := 'javascript:fnd_open_dm_display_window('||''''||
              REPLACE('wf_lov.display_lov?p_lov_name='||'owner'||
              '&p_display_name='||'WFA_FIND_USER'||
              '&p_validation_callback=wfa_html.wf_user_val'||
              '&p_dest_hidden_field=top.opener.parent.document.WF_FIND.owner.value'||
              '&p_current_value=top.opener.parent.document.WF_FIND.display_owner.value'||
              '&p_display_key='||'Y'||
              '&p_dest_display_field=top.opener.parent.document.WF_FIND.display_owner.value',
                ' ', '%20')||''''||',500,500)';

    -- print everything together so there is no gap.
    htp.tabledata(htf.formText(cname=>'display_owner', csize=>30,
                               cmaxlength=>240, cattributes=>'id="i_owner"')||
               '<A href='||l_url||'>'||
               '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>',
                   cattributes=>'id=""');

    htp.tableRowClose;

    -- To User Field
    htp.tableRowOpen(cvalign=>'middle');
    htp.tableData(cvalue=>'<LABEL FOR="i_display_user">' ||
                          wf_core.translate('TO') ||
                          '</LABEL>', calign=>'right',
                  cattributes=>'id=""');
    htp.formHidden('user', null);

    -- add LOV here: Note:bottom is name of frame.
    -- Note: The REPLACE function replaces all the space characters with
    -- the proper escape sequence.
    l_url := 'javascript:fnd_open_dm_display_window('||''''||
              REPLACE('wf_lov.display_lov?p_lov_name='||'user'||
              '&p_display_name='||'WFA_FIND_USER'||
              '&p_validation_callback=wfa_html.wf_user_val'||
              '&p_dest_hidden_field=top.opener.parent.document.WF_FIND.user.value'||
              '&p_current_value=top.opener.parent.document.WF_FIND.display_user.value'||
              '&p_display_key='||'Y'||
              '&p_dest_display_field=top.opener.parent.document.WF_FIND.display_user.value',
                ' ', '%20')||''''||',500,500)';

    -- print everything together so ther is no gap.
    htp.tabledata(htf.formText(cname=>'display_user', csize=>30,
                               cmaxlength=>240,
                               cattributes=>'id="i_display_user"')||
               '<A href='||l_url||'>'||
               '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>',
                    cattributes=>'id=""');

    htp.tableRowClose;
  end if;

  -- From User Field
  htp.tableRowOpen(cvalign=>'middle');
  htp.tableData(cvalue=>'<LABEL FOR="i_display_fromuser">' ||
                        wf_core.translate('FROM') ||
                        '</LABEL>', calign=>'right',
                cattributes=>'id=""');
  htp.formHidden('fromuser', null);

  -- add LOV here: Note:bottom is name of frame.
  -- Note: The REPLACE function replaces all the space characters with
  -- the proper escape sequence.
  l_url := 'javascript:fnd_open_dm_display_window('||''''||
            REPLACE('wf_lov.display_lov?p_lov_name='||'fromuser'||
            '&p_display_name='||'WFA_FIND_USER'||
            '&p_validation_callback=wfa_html.wf_user_val'||
            '&p_dest_hidden_field=top.opener.parent.document.WF_FIND.fromuser.value'||
            '&p_current_value=top.opener.parent.document.WF_FIND.display_fromuser.value'||
            '&p_display_key='||'Y'||
            '&p_dest_display_field=top.opener.parent.document.WF_FIND.display_fromuser.value',
              ' ', '%20')||''''||',500,500)';

  -- print everything together so there is no gap.
  htp.tabledata(htf.formText(cname=>'display_fromuser', csize=>30,
                             cmaxlength=>360,
                             cattributes=>'id="i_display_fromuser"')||
             '<A href='||l_url||'>'||
             '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                  l_message||'" onmouseover="window.status='||''''||
                  l_message||''''||';return true"></A>',
                 cattributes=>'id=""');

  htp.tableRowClose;

 -- Status field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_status">' ||
                        wf_core.translate('STATUS') ||
                        '</LABEL>', calign=>'right',
                cattributes=>'id=""');
  htp.p('<TD id="" ALIGN="LEFT">');
  htp.formSelectOpen('status', cattributes=>'id="i_status"');
  htp.formSelectOption(cvalue=>wf_core.translate('ALL'),
                       cattributes=>'value=*');
  for status in lkcurs('WF_NOTIFICATION_STATUS') loop
    if (status.lookup_code = 'OPEN') then
      htp.formSelectOption(cvalue=>status.meaning, cselected => 'SELECTED',
                           cattributes=>'value='||status.lookup_code);
    else
      htp.formSelectOption(cvalue=>status.meaning,
                           cattributes=>'value='||status.lookup_code);
    end if;
  end loop;
  htp.formSelectClose;
  htp.p('</TD>');
  htp.tableRowClose;

   -- Type field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_ittype">' ||
                        wf_core.translate('TYPE') ||
                        '</LABEL>', calign=>'right',
                cattributes=>'id=""');
  htp.p('<TD id="">');
  htp.formSelectOpen('ittype', cattributes=>'id="i_ittype"');
  htp.formSelectOption(cvalue=>wf_core.translate('ALL'),
                       cselected => 'SELECTED',
                       cattributes=>'value=*');
  if (admin_mode) then
    for aittype in aitcurs loop

      /*
      ** Take care of the case where the item type has a space in it.
      ** We used a + to represent the space in the list of values since you
      ** can escape it in a poplist and pass it through the post.
      */
      htp.formSelectOption(cvalue=>aittype.display_name,
                           cattributes=>'value='||
                           REPLACE(aittype.message_type,' ','+'));
    end loop;
  else
    Wf_Directory.GetRoleOrigSysInfo(username,uorig_system,uorig_system_id);

    for ittype in itcurs(username, uorig_system, uorig_system_id) loop

      /*
      ** Take care of the case where the item type has a space in it.
      ** We used a + to represent the space in the list of values since you
      ** can escape it in a poplist and pass it through the post.
      */
      htp.formSelectOption(cvalue=>ittype.display_name,
                           cattributes=>'value='||
                           REPLACE(ittype.message_type,' ','+'));
    end loop;
  end if;

  htp.formSelectClose;
  htp.p('</TD>');
  htp.tableRowClose;

  -- Subject field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_subject">' ||
                         wf_core.translate('SUBJECT') ||
                        '</LABEL>', calign=>'right',
              cattributes=>'id=""');
  htp.tableData(htf.formText(cname=>'msubject', csize=>'40',
                               cmaxlength=>'80',
                               cattributes=>'id="i_subject"'),
                               calign=>'left', cattributes=>'id=""');
  htp.tableRowClose;

  -- Sent Date field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_beg_date">' ||
                        wf_core.translate('BEGIN_DATE') ||
                        '</LABEL>', calign=>'right',
                cattributes=>'id=""');
  htp.tableData(htf.formText(cname=>'beg_sent', csize=>'9',cmaxlength=>'15',
                             cattributes=>'id="i_beg_date"')||
      ' - ' || htf.formText(cname=>'end_sent', csize=>'9', cmaxlength=>'15',
                            cattributes=>'id="i_beg_date"'),
      calign=>'left',
               cattributes=>'id=""');
  htp.tableRowClose;

  -- Due Date field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_due_date">' ||
                         wf_core.translate('DUE_DATE') ||
                        '</LABEL>', calign=>'right',
               cattributes=>'id=""');
  htp.tableData(htf.formText(cname=>'beg_due', csize=>'9', cmaxlength=>'15',
                             cattributes=>'id="i_due_date"')||
      ' - ' || htf.formText(cname=>'end_due', csize=>'9', cmaxlength=>'15',
                            cattributes=>'id="i_due_date"'),
      calign=>'left',
      cattributes=>'id=""');
  htp.tableRowClose;

  -- Priority field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_priority">' ||
                        wf_core.translate('PRIORITY') ||
                        '</LABEL>', calign=>'right',
                cattributes=>'id=""');
  htp.p('<TD id="" ALIGN="LEFT">');
  htp.formSelectOpen('priority', cattributes=>'id="i_priority"');
  htp.formSelectOption(cvalue=>wf_core.translate('ALL'),
                       cselected => 'SELECTED',
                       cattributes=>'value=*');
  htp.formSelectOption(cvalue=>wf_core.translate('HIGH'),
                       cattributes=>'value="HIGH"');
  htp.formSelectOption(cvalue=>wf_core.translate('NORMAL'),
                       cattributes=>'value="NORMAL"');
  htp.formSelectOption(cvalue=>wf_core.translate('LOW'),
                       cattributes=>'value="LOW"');
  htp.formSelectClose;
  htp.p('</TD>');
  htp.tableRowClose;


  -- Reset Cookie!!!
  htp.formHidden('resetcookie', 1);
  htp.formHidden('fromfindscreen', 1);

  if (admin_mode=FALSE) then
    -- Do not allow admin mode to have "Delegated by me"
    -- Delegated by me field
    htp.tableRowOpen;
    htp.tableData(cvalue=>'&'||'nbsp;', cattributes=>'id=""');
    htp.formHidden('delegatedto', null);

    -- add LOV here: Note:bottom is name of frame.
    -- Note: The REPLACE function replaces all the space characters with
    -- the proper escape sequence.
    l_url := 'javascript:fnd_open_dm_display_window('||''''||
              REPLACE('wf_lov.display_lov?p_lov_name='||'owner'||
              '&p_display_name='||'WFA_FIND_USER'||
              '&p_validation_callback=wfa_html.wf_user_val'||
              '&p_dest_hidden_field=top.opener.parent.document.WF_FIND.delegatedto.value'||
              '&p_current_value=top.opener.parent.document.WF_FIND.display_delegatedto.value'||
              '&p_display_key='||'Y'||
              '&p_dest_display_field=top.opener.parent.document.WF_FIND.display_delegatedto.value',
                ' ', '%20')||''''||',500,500)';

    htp.p('<TD ALIGN="LEFT" VALIGN="bottom" id="">');
    htp.formCheckbox(cname=>'delegated_by_me', cvalue=>1);
    htp.p('<LABEL FOR="i_ldt">' ||
          wf_core.translate('WFA_NTFS_DELEGATED_TO') ||
          '</LABEL>');
    htp.formText(cname=>'display_delegatedto', csize=>30, cmaxlength=>240,
                 cattributes=>'id="i_ldt"');
    htp.p('<A href='||l_url||'>'||
               '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>');
    htp.p('</TD>');
    htp.tableRowClose;
  end if;

  htp.tableClose;
  htp.formClose;

  -- Add submit button
  htp.tableopen (calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;

  htp.p('<TD id="">');

  -- JWSMITH BUG 1691538/2719596 - Changed to call javascript function to
  -- validate the nid field.
  if (admin_mode) then
    wfa_html.create_reg_button ('javascript:SubmitValidate()',
                              wf_core.translate ('FIND'),
                              wfa_html.image_loc,
                              'fndfind.gif',
                              wf_core.translate ('FIND'));

  else
    wfa_html.create_reg_button ('javascript:document.WF_FIND.submit()',
                              wf_core.translate ('FIND'),
                              wfa_html.image_loc,
                              'fndfind.gif',
                              wf_core.translate ('FIND'));
  end if;

  htp.p('</TD>');

  htp.tableRowClose;
  htp.tableClose;

  wfa_sec.Footer;
  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'Find');
    wfa_html.Error;
end Find;

--
-- GetPriorityBounds
--   Get the upper bound and lower bound of certain priority
-- IN
--   priority - Value of priority
--              Valid values are HIGH, NORMAL, LOW and *
-- IN OUT
--   low      - lower bound of numeric priority value
--   up       - upper bound of numeric priority value
-- RETURNS
--   TRUE     - successfully return the boundaries
--   FALSE    - failed to translate
--
function GetPriorityBounds(
  priority in     varchar2,
  low      in out nocopy pls_integer,
  up       in out nocopy pls_integer)
return boolean
as
--  minint   pls_integer := 0;
--  maxint   pls_integer := 2147483647;  /* 2^31 - 1 */

--
-- Priority Range should be 1 - 99
-- For supporting some possible out of range value in the past,
-- we set the range a bit higher
--
  minint   pls_integer := 0;
  maxint   pls_integer := 1000000;
begin
  if    (priority = '*') then
    low  := minint;
    up   := maxint;
  elsif (priority = 'HIGH') then
    low  := minint;
    up   :=  33;
  elsif (priority = 'NORMAL') then
    low  :=  34;
    up   :=  66;
  elsif (priority = 'LOW') then
    low  :=  67;
    up   := maxint;
  else
    low  :=  -1;
    up   :=  -1;
    return FALSE;
  end if;
  return TRUE;
end GetPriorityBounds;

--
-- GetPriorityIcon
--   Get the icon of certain numeric priority
-- IN
--   priority - Value of priority
--              Valid values are minint - maxint
--              defined in GetPriorityBounds
--
-- RETURNS
--   Icon  - location of an icon
--
function GetPriorityIcon(
  priority in     pls_integer)
return varchar2
as
begin
  if    (priority < 34) /* HIGH   */ then
    WFA_HTML.g_priority := WF_CORE.Translate('WFJSP_HIGH_PRIORITY');
    return(wfa_html.image_loc||'high.gif');
  elsif (priority > 66) /* LOW    */ then
    WFA_HTML.g_priority := WF_CORE.Translate('WFJSP_LOW_PRIORITY');
    return(wfa_html.image_loc||'low.gif');
  else                  /* NORMAL */
    return null;
  end if;
end GetPriorityIcon;

--
-- WorkList
--   Construct the worklist (summary page) for user.
-- IN
--   orderkey - Key to order by (default PRIORITY)
--              Valid values are PRIORITY, MESSAGE_TYPE, SUBJECT, BEGIN_DATE,
--              DUE_DATE, END_DATE, STATUS.
--   status - Status to query (default OPEN)
--            Valid values are OPEN, CLOSED, CANCELED, ERROR, *.
--   user - User to query notifications for.  If null query user currently
--          logged in.
--          Note: Only a user in role WF_ADMIN_ROLE can query a user other
--          than the current user.
--   fromlogin - flag to indicate if coming from apps login screen,
--             - if non-zero, force an exception
--            - so that cookie value is not being used
--
procedure WorkList(
  nid      in number,
  orderkey in varchar2,
  status in varchar2,
  owner in varchar2 ,
  display_owner in varchar2,
  user in varchar2,
  display_user in varchar2,
  fromuser in varchar2,
  display_fromuser in varchar2,
  ittype in varchar2,
  msubject in varchar2,
  beg_sent in varchar2,
  end_sent in varchar2,
  beg_due in varchar2,
  end_due in varchar2,
  priority in varchar2,
  delegatedto in varchar2,
  display_delegatedto in varchar2,
  delegated_by_me in number,
  resetcookie in number,
  clearbanner in varchar2,
  fromfindscreen in number,
  fromlogin in number)
as
  cookie owa_cookie.cookie;
  c1 pls_integer;           -- First colon for parsing cookie
  c2 pls_integer;           -- Second colon for parsing cookie
  c3 pls_integer;           -- Third colon for parsing cookie
  c4 pls_integer;           -- Fourth colon for parsing cookie
  c5 pls_integer;           -- Fifth colon for parsing cookie
  c6 pls_integer;           -- Sixth colon for parsing cookie
  c7 pls_integer;           -- Seventh colon for parsing cookie
  c8 pls_integer;           -- Eighth colon for parsing cookie
  c9 pls_integer;           -- Nineth colon for parsing cookie
  c10 pls_integer;          -- Tenth colon for parsing cookie
  c11 pls_integer;          -- Eleventh colon for parsing cookie
  c12 pls_integer;          -- Twelveth colon for parsing cookie
  c13 pls_integer;          -- Thirteenth colon for parsing cookie
  c14 pls_integer;          -- Fourteenth colon for parsing cookie
  lnid number;              -- Nid retrieved from cookie
  lorderkey varchar2(30);   -- Orderkey retrieved from cookie
  lstatus varchar2(30);     -- Status retrieved from cookie
  luser varchar2(320);      -- User retrieved from cookie
  lowner varchar2(320);     -- Owner retrieved from cookie
  lfromuser varchar2(320);  -- From Role retrieved from cookie
  littype varchar2(8);      -- Item Type retrieved from cookie
  lsubject varchar2(80);    -- Subject retrieved from cookie
  lbeg_sent varchar2(15);   -- Begin Sent Date retrieved from cookie
  lend_sent varchar2(15);   -- End Sent Date retrieved from cookie
  lbeg_due varchar2(15);    -- Begin Due Date retrieved from cookie
  lend_due varchar2(15);    -- End Due Date retrieved from cookie
  lpriority varchar2(8);    -- Priority retrieved from cookie
  lshowto varchar2(1);      -- Show the To field
  ldt  varchar2(320);       -- Delegated to user
  ldbm pls_integer;         -- Delegated_by_me retrieved from cookie
  bad_cookie exception;     -- Syntax error in cookie
  invalid_cookie exception; -- Exception so that we don't use values in cookie
  ltmpname varchar2(410);   -- Bigger than username because of the possible
                            -- escape single quotes
  username varchar2(320);   -- Username to query
  colon pls_integer;        -- Magic orig_system decoder
  realname varchar2(360);   -- Display name of username
  admin_role varchar2(320); -- Role for admin mode
  s0 varchar2(2000);        -- Dummy
  n_priority varchar2(80);  -- priority icon
  usercolon pls_integer;    -- Check if username is a R


  n_response varchar2(80);  -- required response icon
  showothers pls_integer := 0;
  isadmin    boolean := false;

  t_owner       varchar2(320) := owner;
  t_user        varchar2(320) := user;
  t_fromuser    varchar2(320) := fromuser;
  t_delegatedto varchar2(320) := delegatedto;

  -- Any existence of response attribute constitutes a response required.
  cursor attrs(mnid in number) is
    select MA.NAME
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES_VL MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = mnid
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND';

  result attrs%rowtype;

  --
  -- Variables for the above cursors.
  -- Make sure they are in sync with the underlying table in the future.
  --
  nf_nid        number;
  nf_priority   number;
  nf_recipient  varchar2(4000);      -- was 80
  nf_message_type varchar2(4000);    -- was 80
  nf_subject    varchar2(4000);      -- was 240
  nf_begin_date varchar2(4000);
  nf_due_date   varchar2(4000);
  nf_end_date   varchar2(4000);
  nf_display_status varchar2(4000);  -- was 80
  nf_status     varchar2(8);
  nf_p0         pls_integer;
  nf_p1         pls_integer;
  nf_language   varchar2(4);
  nf_from_user  varchar2(4000);
  nf_to_user    varchar2(4000);

  -- For Worklist Engine
  inTab         Wf_Worklist_Engine.colTabType;
  outTab        Wf_Worklist_Engine.wrkTabType;
  totalrow      number;
  i             pls_integer;

  -- Default worklist cursor
  cursor wl_def_cursor (uname varchar2, uos varchar2, uosid number) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where
         (RECIPIENT_ROLE = uname or
          RECIPIENT_ROLE in
          (select WUR.ROLE_NAME
           from WF_USER_ROLES WUR
           where WUR.USER_ORIG_SYSTEM = uos
           and WUR.USER_ORIG_SYSTEM_ID = uosid
           and WUR.USER_NAME = uname))
    and STATUS = 'OPEN'
    order by PRIORITY, BEGIN_DATE DESC;

  -- DLAM - Add RECIPIENT_ROLE = uname above to achieve what the sql below
  -- does.
  -- JWSMITH BUG2232218 - Added cursor to retrieve by role name
  /* cursor wl_role_cursor (uname varchar2, oos varchar2, oosid number) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where
        RECIPIENT_ROLE in
        (select WUR.ROLE_NAME
         from WF_USER_ROLES WUR
         where WUR.ROLE_ORIG_SYSTEM = oos
         and WUR.ROLE_ORIG_SYSTEM_ID = oosid
         and WUR.ROLE_NAME = uname)
    and STATUS = 'OPEN'
    order by PRIORITY, BEGIN_DATE DESC;
  */
  -- Default worklist cursor with different order key
  cursor wl_def_s_cursor (uname varchar2, uos varchar2, uosid number) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where
        RECIPIENT_ROLE in
        (select WUR.ROLE_NAME
         from WF_USER_ROLES WUR
         where WUR.USER_ORIG_SYSTEM = uos
         and WUR.USER_ORIG_SYSTEM_ID = uosid
         and WUR.USER_NAME = uname)
    and STATUS = 'OPEN'
    order by decode(upper(Worklist.lorderkey),
             'MESSAGE_TYPE', MESSAGE_TYPE,
             'FROMUSER', FROM_USER,
             'TOUSER', TO_USER,
             'SUBJECT', SUBJECT,
             'BEGIN_DATE', to_char(BEGIN_DATE, 'J.SSSSS'),
             'DUE_DATE', to_char(DUE_DATE, 'J.SSSSS'),
             'END_DATE', to_char(END_DATE, 'J.SSSSS'));

  -- Simple worklist query cursor
  cursor wl_query_cursor (uname varchar2, uos varchar2, uosid number,
                          p0 pls_integer, p1 pls_integer) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where
        RECIPIENT_ROLE in
        (select WUR.ROLE_NAME
         from WF_USER_ROLES WUR
         where WUR.USER_ORIG_SYSTEM = uos
         and WUR.USER_ORIG_SYSTEM_ID = uosid
         and WUR.USER_NAME = uname)
    and ITEM_TYPE = decode(Worklist.littype,'*',ITEM_TYPE, Worklist.littype)
    and STATUS = decode(Worklist.lstatus,
                           '*', STATUS,
                           '', STATUS,
                           Worklist.lstatus)
    and ((BEGIN_DATE is null
             and Worklist.lbeg_sent = '*' and Worklist.lend_sent = '*')
          or
         BEGIN_DATE between
       decode(Worklist.lbeg_sent, '*', BEGIN_DATE, to_date(Worklist.lbeg_sent))
              and decode(Worklist.lend_sent, '*', BEGIN_DATE,
                         to_date(Worklist.lend_sent)+1-(1/(24*60*60))))
    and ((DUE_DATE is null
             and Worklist.lbeg_due = '*' and Worklist.lend_due = '*')
          or
         DUE_DATE between
       decode(Worklist.lbeg_due, '*', DUE_DATE, to_date(Worklist.lbeg_due))
              and decode(Worklist.lend_due, '*', DUE_DATE,
                         to_date(Worklist.lend_due)+1-(1/(24*60*60))))
    and PRIORITY between p0 and p1
    order by PRIORITY, BEGIN_DATE DESC;

  -- NID cursor
  cursor wl_nid_cursor(xnid number) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where NID = xnid;

  -- General Admin cursor
  cursor wl_admin_g_cursor(p0 pls_integer, p1 pls_integer) is
    select /*+ ORDERED INDEX (W.WN,WF_NOTIFICATIONS_N1) USE_NL
      (W.WN W.WIT W.WL) */
       W.NID
      ,W.PRIORITY
      ,W.STATUS
      ,W.LANGUAGE
      ,W.MESSAGE_TYPE MESSAGE_TYPE
      ,W.RECIPIENT_ROLE RECIPIENT_ROLE
      ,W.SUBJECT SUBJECT
      ,to_char(W.BEGIN_DATE) BEGIN_DATE
      ,to_char(W.DUE_DATE) DUE_DATE
      ,to_char(W.END_DATE) END_DATE
      ,W.DISPLAY_STATUS DISPLAY_STATUS
      ,W.FROM_USER FROM_USER
      ,W.TO_USER TO_USER
      ,NA1.TEXT_VALUE
    from WF_WORKLIST_V W, WF_NOTIFICATION_ATTRIBUTES NA1
    where W.NID = NA1.NOTIFICATION_ID (+)
      and NA1.NAME (+) = '#FROM_ROLE'
      and (luser = '*' or
            (RECIPIENT_ROLE in
              (select WUR.ROLE_NAME
                 from WF_USER_ROLES WUR
                where WUR.USER_NAME = luser)
             or RECIPIENT_ROLE = luser))
      and (lowner = '*' or
            (ORIGINAL_RECIPIENT in
              (select WUR.ROLE_NAME
                 from WF_USER_ROLES WUR
                where WUR.USER_NAME = lowner)
             or ORIGINAL_RECIPIENT = lowner))
      and (littype = '*' or (ITEM_TYPE = littype))
      and (lstatus is null or lstatus = '*' or (STATUS = lstatus))
      and (lsubject = '*' or (SUBJECT like '%'||upper(lsubject)||'%'))
      and ((BEGIN_DATE is null
              and Worklist.lbeg_sent = '*' and Worklist.lend_sent = '*')
            or
           BEGIN_DATE between
       decode(Worklist.lbeg_sent, '*', BEGIN_DATE, to_date(Worklist.lbeg_sent))
              and decode(Worklist.lend_sent, '*', BEGIN_DATE,
                         to_date(Worklist.lend_sent)+1-(1/(24*60*60))))
      and ((DUE_DATE is null
              and Worklist.lbeg_due = '*' and Worklist.lend_due = '*')
            or
           DUE_DATE between
       decode(Worklist.lbeg_due, '*', DUE_DATE, to_date(Worklist.lbeg_due))
              and decode(Worklist.lend_due, '*', DUE_DATE,
                         to_date(Worklist.lend_due)+1-(1/(24*60*60))))
      and PRIORITY between p0 and p1
      and (lfromuser = '*' or (NA1.TEXT_VALUE = lfromuser))
    order by decode(upper(lorderkey),
             'MESSAGE_TYPE', MESSAGE_TYPE,
             'SUBJECT', SUBJECT,
             'BEGIN_DATE', to_char(W.BEGIN_DATE, 'J.SSSSS'),
             'DUE_DATE', to_char(W.DUE_DATE, 'J.SSSSS'),
             'END_DATE', to_char(W.END_DATE, 'J.SSSSS'),
             'STATUS', STATUS,
             'FROMUSER', FROM_USER,
             'RPRIORITY', to_char(1000000 - PRIORITY, '00000000'),
             to_char(PRIORITY, '00000000'));

  -- Delegate By Me cursor
  cursor wl_dbm_cursor(p0 pls_integer, p1 pls_integer) is
    select /*+ ORDERED INDEX (W.WN,WF_NOTIFICATIONS_N1) USE_NL
      (W.WN W.WIT W.WL) */
       W.NID
      ,W.PRIORITY
      ,W.STATUS
      ,W.LANGUAGE
      ,W.MESSAGE_TYPE MESSAGE_TYPE
      ,W.RECIPIENT_ROLE RECIPIENT_ROLE
      ,W.SUBJECT SUBJECT
      ,to_char(W.BEGIN_DATE) BEGIN_DATE
      ,to_char(W.DUE_DATE) DUE_DATE
      ,to_char(W.END_DATE) END_DATE
      ,W.DISPLAY_STATUS DISPLAY_STATUS
      ,W.FROM_USER FROM_USER
      ,W.TO_USER TO_USER
      ,NA1.TEXT_VALUE
    from WF_WORKLIST_V W, WF_NOTIFICATION_ATTRIBUTES NA1
    where W.NID = NA1.NOTIFICATION_ID (+)
      and NA1.NAME (+) = '#FROM_ROLE'
      and (username = '*' or
            (ORIGINAL_RECIPIENT in
              (select WUR.ROLE_NAME
                 from WF_USER_ROLES WUR
                where WUR.USER_NAME = username)
             or ORIGINAL_RECIPIENT = username))
          and RECIPIENT_ROLE <> ORIGINAL_RECIPIENT
          and (ldt = '*' or RECIPIENT_ROLE = upper(ldt))
      and (littype = '*' or (ITEM_TYPE = littype))
      and (lstatus is null or lstatus = '*' or (STATUS = lstatus))
      and (lsubject = '*' or (SUBJECT like '%'||upper(lsubject)||'%'))
      and ((BEGIN_DATE is null
              and Worklist.lbeg_sent = '*' and Worklist.lend_sent = '*')
            or
           BEGIN_DATE between
       decode(Worklist.lbeg_sent, '*', BEGIN_DATE, to_date(Worklist.lbeg_sent))
              and decode(Worklist.lend_sent, '*', BEGIN_DATE,
                         to_date(Worklist.lend_sent)+1-(1/(24*60*60))))
      and ((DUE_DATE is null
              and Worklist.lbeg_due = '*' and Worklist.lend_due = '*')
            or
           DUE_DATE between
       decode(Worklist.lbeg_due, '*', DUE_DATE, to_date(Worklist.lbeg_due))
              and decode(Worklist.lend_due, '*', DUE_DATE,
                         to_date(Worklist.lend_due)+1-(1/(24*60*60))))
      and PRIORITY between p0 and p1
      and (lfromuser = '*' or (NA1.TEXT_VALUE = lfromuser))
    order by decode(upper(lorderkey),
             'MESSAGE_TYPE', MESSAGE_TYPE,
             'SUBJECT', SUBJECT,
             'BEGIN_DATE', to_char(W.BEGIN_DATE, 'J.SSSSS'),
             'DUE_DATE', to_char(W.DUE_DATE, 'J.SSSSS'),
             'END_DATE', to_char(W.END_DATE, 'J.SSSSS'),
             'STATUS', STATUS,
             'FROMUSER', FROM_USER,
             'RPRIORITY', to_char(1000000 - PRIORITY, '00000000'),
             to_char(PRIORITY, '00000000'));

  -- General worklist query cursor
  cursor wl_query_g_cursor (uname varchar2, uos varchar2, uosid number,
                          p0 pls_integer, p1 pls_integer) is
    select /*+ ORDERED INDEX (W.WN,WF_NOTIFICATIONS_N1) USE_NL
      (W.WN W.WIT W.WL) */
       W.NID
      ,W.PRIORITY
      ,W.STATUS
      ,W.LANGUAGE
      ,W.MESSAGE_TYPE MESSAGE_TYPE
      ,W.RECIPIENT_ROLE RECIPIENT_ROLE
      ,W.SUBJECT SUBJECT
      ,to_char(W.BEGIN_DATE) BEGIN_DATE
      ,to_char(W.DUE_DATE) DUE_DATE
      ,to_char(W.END_DATE) END_DATE
      ,W.DISPLAY_STATUS DISPLAY_STATUS
      ,W.FROM_USER FROM_USER
      ,W.TO_USER TO_USER
      ,NA1.TEXT_VALUE
    from WF_WORKLIST_V W, WF_NOTIFICATION_ATTRIBUTES NA1
    where W.NID = NA1.NOTIFICATION_ID (+)
      and NA1.NAME (+) = '#FROM_ROLE'
      and (RECIPIENT_ROLE = uname or
           RECIPIENT_ROLE in
           (select WUR.ROLE_NAME
            from WF_USER_ROLES WUR
            where WUR.USER_ORIG_SYSTEM = uos
            and WUR.USER_ORIG_SYSTEM_ID = uosid
            and WUR.USER_NAME = uname))
      and ITEM_TYPE = decode(Worklist.littype,'*',ITEM_TYPE, Worklist.littype)
      and (lstatus is null or lstatus = '*' or (STATUS = lstatus))
      and (lsubject = '*' or (SUBJECT like '%'||upper(lsubject)||'%'))
      and ((BEGIN_DATE is null
             and Worklist.lbeg_sent = '*' and Worklist.lend_sent = '*')
            or
           BEGIN_DATE between
         decode(Worklist.lbeg_sent, '*', BEGIN_DATE, to_date(Worklist.lbeg_sent))
              and decode(Worklist.lend_sent, '*', BEGIN_DATE,
                         to_date(Worklist.lend_sent)+1-(1/(24*60*60))))
      and ((DUE_DATE is null
               and Worklist.lbeg_due = '*' and Worklist.lend_due = '*')
            or
           DUE_DATE between
         decode(Worklist.lbeg_due, '*', DUE_DATE, to_date(Worklist.lbeg_due))
              and decode(Worklist.lend_due, '*', DUE_DATE,
                         to_date(Worklist.lend_due)+1-(1/(24*60*60))))
      and PRIORITY between p0 and p1
      and (lfromuser = '*' or (NA1.TEXT_VALUE = lfromuser))
    order by decode(upper(lorderkey),
             'MESSAGE_TYPE', MESSAGE_TYPE,
             'SUBJECT', SUBJECT,
             'BEGIN_DATE', to_char(W.BEGIN_DATE, 'J.SSSSS'),
             'DUE_DATE', to_char(W.DUE_DATE, 'J.SSSSS'),
             'END_DATE', to_char(W.END_DATE, 'J.SSSSS'),
             'STATUS', STATUS,
             'FROMUSER', FROM_USER,
             'RPRIORITY', to_char(1000000 - PRIORITY, '00000000'),
             to_char(PRIORITY, '00000000'));

  role_info_tbl wf_directory.wf_local_roles_tbl_type;
begin
  -- Check session and current user
  wfa_sec.GetSession(username);

  -- Get all the username find criteria resolved
  wfa_html.validate_display_name (display_owner, t_owner);
  wfa_html.validate_display_name (display_user, t_user);
  wfa_html.validate_display_name (display_fromuser, t_fromuser);
  wfa_html.validate_display_name (display_delegatedto, t_delegatedto);

  if (resetcookie = 0) then
    -- Look for a cookie with params from last call to Worklist.
    -- If current parameters were passed as null, then use the last settings
    -- from the cookie as defaults.
    begin

      if (fromlogin <> 0 ) then
        -- coming from apps login screen, force an exception
        -- so that cookie value is not being used
        raise invalid_cookie;
      end if;

      -- Retrieve cookie and extract value.
      -- If any possible error detected in the cookie, raise an exception to
      -- ignore the cookie and use the defaults instead.
      cookie := owa_cookie.get('WF_WORKLIST_MODE');

      if (cookie.num_vals <> 1) then
--      should not have any htp before owa_util.http_header_close
        raise bad_cookie;
      end if;

      -- Getting the cookie values
      -- ### I know it is a mess of code, we may think about cleaning this
      -- ### up some days
      --
      c1 := instr(cookie.vals(1), ':');
      c2 := instr(cookie.vals(1), ':', 1, 2);
      c3 := instr(cookie.vals(1), ':', 1, 3);
      c4 := instr(cookie.vals(1), ':', 1, 4);
      c5 := instr(cookie.vals(1), ':', 1, 5);
      c6 := instr(cookie.vals(1), ':', 1, 6);
      c7 := instr(cookie.vals(1), ':', 1, 7);
      c8 := instr(cookie.vals(1), ':', 1, 8);
      c9 := instr(cookie.vals(1), ':', 1, 9);
      c10 := instr(cookie.vals(1), ':', 1, 10);
      c11 := instr(cookie.vals(1), ':', 1, 11);
      c12 := instr(cookie.vals(1), ':', 1, 12);
      c13 := instr(cookie.vals(1), ':', 1, 13);
      c14 := instr(cookie.vals(1), ':', 1, 14);

      if ((c1 = 0) or (c2 = 0) or (c3 = 0) or (c4 = 0) or (c5 = 0) or
          (c6 = 0) or (c7 = 0) or (c8 = 0) or (c9 = 0) or (c10 = 0) or
          (c11= 0) or (c12= 0) or (c13= 0) or (c14= 0)) then
        raise bad_cookie;
      end if;

      --
      -- Unless values are passed as argument, use the cookie values
      --
      -- N.B. beware of the number/pls_integer type that we need conversion
      --
      lorderkey := upper(nvl(orderkey, substr(cookie.vals(1), 1, c1-1)));
      lstatus   := upper(nvl(status, substr(cookie.vals(1), c1+1, c2-c1-1)));
      luser     := nvl(t_user, substr(cookie.vals(1), c2+1, c3-c2-1));
      lowner    := upper(nvl(t_owner,substr(cookie.vals(1), c3+1, c4-c3-1)));
      littype   := nvl(ittype,   substr(cookie.vals(1), c4+1, c5-c4-1));
      lsubject  := nvl(msubject, substr(cookie.vals(1), c5+1, c6-c5-1));
      lbeg_sent := nvl(beg_sent, substr(cookie.vals(1), c6+1, c7-c6-1));
      lend_sent := nvl(end_sent, substr(cookie.vals(1), c7+1, c8-c7-1));
      lbeg_due  := nvl(beg_due,  substr(cookie.vals(1), c8+1, c9-c8-1));
      lend_due  := nvl(end_due,  substr(cookie.vals(1), c9+1, c10-c9-1));
      lpriority := nvl(priority, substr(cookie.vals(1), c10+1, c11-c10-1));
      lnid      := nvl(nid,      to_number(
                                  substr(cookie.vals(1), c11+1, c12-c11-1)));
      ldt       := nvl(t_delegatedto, substr(cookie.vals(1), c12+1, c13-c12-1));
      ldbm      := to_number(substr(cookie.vals(1), c13+1, c14-c13-1));
      lfromuser := upper(nvl(t_fromuser,substr(cookie.vals(1), c14+1)));

      -- Check orderkey and status are valid.
      if (lorderkey not in ('PRIORITY', 'MESSAGE_TYPE', 'FROMUSER', 'TOUSER',
                            'SUBJECT', 'BEGIN_DATE',
                            'DUE_DATE', 'END_DATE', 'STATUS', 'RPRIORITY') or
          nvl(lstatus, '*') not in ('OPEN', 'CLOSED', 'CANCELED', 'ERROR', '*')
         ) then
        raise bad_cookie;
      end if;
    exception
      when others then
        -- Either not set or some error encountered.  Use defaults.
        lorderkey := nvl(orderkey, 'PRIORITY');
        lstatus := nvl(status, 'OPEN');
        luser := nvl(t_user, username);
        lowner := '*';
        littype := '*';
        lsubject := '*';
        lbeg_sent := '*';
        lend_sent := '*';
        lbeg_due := '*';
        lend_due := '*';
        lpriority := '*';
        lnid := nvl(nid, -1);
        ldt  := '*';
        ldbm := 0;
        lfromuser := '*';
    end;
  else
  --
  -- When resetcookie is true, we don't set token values from
  -- the values in the cookie.
  -- For example, coming from "Find" screen, you do want to clear the
  -- value of lowner.
  -- On the other hand, you do want to preserve the value of ldbm when
  -- you sort the list of "delegated by me."
  --
    lorderkey := nvl(orderkey, 'PRIORITY');
    lstatus   := nvl(status,   'OPEN');
    luser     := nvl(t_user, '*');
    ldbm      := delegated_by_me;
    lowner    := upper(nvl(t_owner,'*'));
    littype   := nvl(ittype,   '*');
    lsubject  := nvl(msubject, '*');
    lbeg_sent := nvl(beg_sent, '*');
    lend_sent := nvl(end_sent, '*');
    lbeg_due  := nvl(beg_due,  '*');
    lend_due  := nvl(end_due,  '*');
    lpriority := nvl(priority, '*');
    ldt       := nvl(t_delegatedto, '*');
    lnid      := nvl(nid, -1);
    lfromuser := nvl(t_fromuser, '*');
  end if;

  /*
  ** Take care of the case where the item type has a space in it.
  ** We used a + to represent the space in the list of values since you
  ** can escape it in a poplist and pass it through the post.  Here we'll
  ** switch it back and use it in the queries.
  */
  littype := REPLACE(littype, '+', ' ');

  -- Send parameter values back to cookie.
  owa_util.mime_header('text/html', FALSE);
  owa_cookie.send('WF_WORKLIST_MODE', lorderkey||':'||lstatus||':'||luser
      ||':'||lowner||':'||littype||':'||lsubject||':'||lbeg_sent
      ||':'||lend_sent||':'||lbeg_due||':'||lend_due||':'||lpriority
      ||':'||lnid||':'||ldt||':'||ldbm||':'||lfromuser,
      '', '/');
  owa_util.http_header_close;

  -- set the admin role
  admin_role := wf_core.translate('WF_ADMIN_ROLE');

  -- set the username. This may get overwritten if performing a special query
  username := upper(username);

  -- Check whether current user has WF_ADMIN_ROLE privileges when:
  -- 1. Make a NID query
  -- 2. Specify owner in a query
  -- 3. Specify user other than himself in a query
  if (lnid >= 0 or
      lowner <> '*') then

    if (admin_role <> '*' and
        not Wf_Directory.IsPerformer(username, admin_role)) then
      isadmin := FALSE;
      Wf_Core.Token('UNAME', username);
      Wf_Core.Token('ROLE', admin_role);
      Wf_Core.Raise('WFMON_ADMIN_ROLE');
    else
      isadmin := TRUE;
    end if;

    showothers := 1;

  end if;

  -- case 3
  if (luser <> '*') then
    if (upper(luser) <> upper(username)) then
      if (admin_role <> '*' and
          not Wf_Directory.IsPerformer(username, admin_role)) then
        isadmin := FALSE;
        Wf_Core.Token('UNAME', username);
        Wf_Core.Token('ROLE', admin_role);
        Wf_Core.Raise('WFMON_ADMIN_ROLE');
      end if;

      showothers := 1;
      username := luser;  -- override the username field in this case.
    else
      showothers := 0;  -- no need to show others when username is myself
    end if;

    isadmin  := TRUE;
  end if;

  wf_directory.GetRoleInfo2(username, role_info_tbl);
  realname := role_info_tbl(1).display_name;

  -- In Regular User mode, if "Delegate by me", ldbm, is set, we will
  -- show To field, i.e., lshowto with value T.
  if ((ldbm > 0 and ldt = '*') or showothers = 1 ) then
    lshowto := 'T';
  else
    lshowto := 'F';
  end if;

  -- Set page title
  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_WTITLE') || ' - ' || realname);

  wfa_html.create_help_function('wf/links/not.htm?NOTWORK');

  if (instr(owa_util.get_cgi_env('HTTP_USER_AGENT'), 'MSIE') > 0) then
     htp.p('<META HTTP-EQUIV=expires CONTENT=no-cache>');
  end if;

  htp.headClose;


  if worklist.clearbanner = 'TRUE'  then
     wfa_sec.Header(background_only=>TRUE);
  else
     wfa_sec.Header(FALSE, owa_util.get_owa_service_path ||'wfa_html.Find',
         wf_core.translate('WFA_WTITLE'), TRUE);

  end if;

  -- debug info
  htp.p('<!-- Debug Info -->');
  htp.p('<!-- username: '||username||' -->');
  htp.p('<!-- userenv(''LANG''): '||userenv('LANG')||' -->');

  -- Figure out the boundaries for priority
  if (GetPriorityBounds(lpriority, nf_p0, nf_p1) = FALSE) then
    wf_core.token('PRIORITY', lpriority);
    wf_core.raise('WFNTF_PRIORITY');
  end if;

  outTab.DELETE;

  /* ### comment this out
  -- debug info
  if (isadmin) then
    htp.p('<!-- query using admin privilege -->');
  end if;
  htp.p('<!-- luser: '||luser||'-->');
  htp.p('<!-- username: '||username||'-->');
  htp.p('<!-- lowner: '||lowner||'-->');
  htp.p('<!-- lorderkey: '||lorderkey||'-->');
  htp.p('<!-- ldbm: '||to_char(ldbm)||'-->');
  htp.p('<!-- littype: '||littype||'-->');
  htp.p('<!-- lsubject: '||lsubject||'-->');
  htp.p('<!-- lsent: '||lbeg_sent||' - '||lend_sent||'-->');
  htp.p('<!-- ldue: '||lbeg_due||' - '||lend_due||'-->');
  htp.p('<!-- lpriority: '||lpriority||' '||to_char(nf_p0)||'-'||to_char(nf_p1)||'-->');
  htp.p('<!-- ldt: '||ldt||'-->');
  htp.p('<!-- lnid: '||to_char(lnid)||'-->');
  htp.p('<!-- lstatus: '||lstatus||'-->');
  htp.p('<!-- lfromuser: '||lfromuser||'-->');

  ### comment the above out */

  -- default cursor
  if (lorderkey='PRIORITY' and
      ldbm=0 and lowner='*' and littype='*' and lsubject='*' and
      lbeg_sent='*' and lend_sent='*' and lbeg_due='*' and lend_due='*' and
      lpriority='*' and ldt='*' and lnid=-1 and lstatus='OPEN' and
      lfromuser='*') then

   htp.p('<!-- Debug Info -->');
   htp.p('<!-- wl_def_cursor -->');
    i := 0;

    /* JWSMITH BUG2232218 - Added if condition to check if username=role */
    /* If so, then use wl_role_cursor instead of wl_def_cursor */
    /* DLAM - Now wl_def_cursor should handle this as well
    usercolon := instr(username, ':');
    if (usercolon<>0) then
      for rec in wl_role_cursor(username,
                     role_info_tbl(1).orig_system,
                     role_info_tbl(1).orig_system_id) loop
        i := i+1;
        outTab(i).nid      := rec.nid;
        outTab(i).priority := rec.priority;
        outTab(i).status   := rec.status;
        outTab(i).language := rec.language;
        outTab(i).col01    := rec.message_type;
        outTab(i).col02    := rec.recipient_role;
        outTab(i).col03    := rec.subject;
        outTab(i).col04    := rec.begin_date;
        outTab(i).col05    := rec.due_date;
        outTab(i).col06    := rec.end_date;
        outTab(i).col07    := rec.display_status;
        outTab(i).col08    := rec.from_user;
        outTab(i).col09    := rec.to_user;
      end loop;
    else */
    for rec in wl_def_cursor(username,
                     role_info_tbl(1).orig_system,
                     role_info_tbl(1).orig_system_id) loop
        i := i+1;
        outTab(i).nid      := rec.nid;
        outTab(i).priority := rec.priority;
        outTab(i).status   := rec.status;
        outTab(i).language := rec.language;
        outTab(i).col01    := rec.message_type;
        outTab(i).col02    := rec.recipient_role;
        outTab(i).col03    := rec.subject;
        outTab(i).col04    := rec.begin_date;
        outTab(i).col05    := rec.due_date;
        outTab(i).col06    := rec.end_date;
        outTab(i).col07    := rec.display_status;
        outTab(i).col08    := rec.from_user;
        outTab(i).col09    := rec.to_user;
    end loop;
    -- end if;

  elsif (isadmin and  lnid>0) then
-- ###
   htp.p('<!-- Debug Info -->');
   htp.p('<!-- wl_nid_cursor -->');
    -- there should be one row only for nid query
    i := 1;
    for rec in wl_nid_cursor(lnid) loop
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;

  elsif (lorderkey<>'PRIORITY' and
      ldbm=0 and lowner='*' and littype='*' and lsubject='*' and
      lbeg_sent='*' and lend_sent='*' and lbeg_due='*' and lend_due='*' and
      lpriority='*' and ldt='*' and lnid=-1 and lstatus='OPEN' and
      lfromuser='*') then
-- ###
    htp.p('<!-- Debug Info -->');
    htp.p('<!-- wl_def_s__cursor -->');
    i := 0;
    for rec in wl_def_s_cursor(username,
                   role_info_tbl(1).orig_system,
                   role_info_tbl(1).orig_system_id) loop
      i := i+1;
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;

  -- default cursor
  elsif (lorderkey='PRIORITY' and ldbm=0 and lowner='*' and lsubject='*' and
      ldt='*' and lnid=-1 and lfromuser='*') then

    htp.p('<!-- Debug Info -->');
    htp.p('<!-- wl_query_cursor -->');
    i := 0;
    for rec in wl_query_cursor(username,
                   role_info_tbl(1).orig_system,
                   role_info_tbl(1).orig_system_id,
                   nf_p0, nf_p1) loop
      i := i+1;
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;

  elsif (isadmin) then
    htp.p('<!-- Debug Info -->');
    htp.p('<!-- wl_admin_g_cursor -->');
    i := 0;
    for rec in wl_admin_g_cursor(nf_p0, nf_p1) loop
      i := i+1;
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;

  elsif (ldbm <> 0) then
    htp.p('<!-- Debug Info -->');
    htp.p('<!-- wl_dbm_cursor: -->');
    i := 0;
    for rec in wl_dbm_cursor(nf_p0, nf_p1) loop
      i := i+1;
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;

  else
    htp.p('<!-- Debug Info -->');
    htp.p('<!-- wl_query_g_cursor :'||luser||'/'||username||' -->');
    i := 0;
    for rec in wl_query_g_cursor(username,
                   role_info_tbl(1).orig_system,
                   role_info_tbl(1).orig_system_id,
                   nf_p0, nf_p1) loop
      i := i+1;
      outTab(i).nid      := rec.nid;
      outTab(i).priority := rec.priority;
      outTab(i).status   := rec.status;
      outTab(i).language := rec.language;
      outTab(i).col01    := rec.message_type;
      outTab(i).col02    := rec.recipient_role;
      outTab(i).col03    := rec.subject;
      outTab(i).col04    := rec.begin_date;
      outTab(i).col05    := rec.due_date;
      outTab(i).col06    := rec.end_date;
      outTab(i).col07    := rec.display_status;
      outTab(i).col08    := rec.from_user;
      outTab(i).col09    := rec.to_user;
    end loop;
  end if;

  -- If there are no notifications, display a message and exit

  if (outTab.COUNT = 0) then
    htp.tableopen(calign=>'CENTER', cattributes=>'summary=""');
    htp.tablerowopen;
    if (fromfindscreen = 0) then

       htp.tabledata(cvalue=>wf_core.translate('WFA_NO_NOTIFY') ||
             ' ' || realname || ' ('||username||').',
                     cattributes=>'id="' ||
                       wf_core.translate('WFA_NO_NOTIFY') || '"');

    else

       htp.tabledata(cvalue=>wf_core.translate('WFNTF_NO_MATCH'),
                     cattributes=>'id="' ||
                       wf_core.translate('WFA_NO_MATCH') || '"');

    end if;

    htp.tablerowclose;
    htp.tableclose;
    wfa_sec.Footer;
    htp.htmlClose;
    return;
  end if;

  -- Form begins
  htp.p('<FORM NAME="WFA_WORKLIST" ACTION="wfa_html.SubmitSelectedResponse" TARGET="_top" METHOD="POST">');

  -- Hide the fields for which option you selected. Reassign vs Close
  htp.formHidden(cname=>'close', cvalue=>'');

  -- Hide the fields for which option you selected. Reassign vs Close
  htp.formHidden(cname=>'forward', cvalue=>'');

  -- There are some notifications for the user. Construct the page.
  htp.tableOpen('border=1 cellpadding=3 bgcolor=white width=100% summary=""');

  -- Column headers
  htp.tableRowOpen(cattributes=>'bgcolor=#006699');

  htp.tableHeader(cvalue=>'<font color=#FFFFFF>'||
        wf_core.translate('SELECT')||'</font>',
        calign=>'Center',
        cattributes=>'id="' || WF_CORE.Translate('SELECT') || '"');

  htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=PRIORITY&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('PRIORITY')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('PRIORITY') || '"');

  htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=MESSAGE_TYPE&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('TYPE')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('TYPE') || '"');

  htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=FROMUSER&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('FROM')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('FROM') || '"');

  if (lshowto = 'T') then
    htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
        'wfa_html.worklist?orderkey=TOUSER&clearbanner='||clearbanner,
        '<font color=#FFFFFF>'||wf_core.translate('TO')||'</font>',
        null), calign=>'Center',
        cattributes=>'id="' || WF_CORE.Translate('TO') || '"');
  end if;

  htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=SUBJECT&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('SUBJECT')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('SUBJECT') || '"');

  htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=BEGIN_DATE&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('BEGIN_DATE')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('BEGIN_DATE') || '"');

  htp.tableHeader(cvalue=>htf.anchor(
      owa_util.get_owa_service_path||
      'wfa_html.worklist?orderkey=DUE_DATE&clearbanner='||clearbanner,
      '<font color=#FFFFFF>'||wf_core.translate('DUE_DATE')||'</font>',
      null), calign=>'Center',
      cattributes=>'id="' || WF_CORE.Translate('DUE_DATE') || '"');

  -- Add optional end date if querying closed/cancelled/invalid notifications
  if (nvl(lstatus,'x') <> 'OPEN') then

    htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
        'wfa_html.worklist?orderkey=END_DATE&clearbanner='||clearbanner,
        '<font color=#FFFFFF>'||wf_core.translate('END_DATE')||'</font>',
        null), calign=>'Center',
        cattributes=>'id="' || WF_CORE.Translate('END_DATE') || '"');

  end if;

  -- Add optional status if querying all notifications
  if (nvl(lstatus,'x') = '*') then

    htp.tableHeader(cvalue=>htf.anchor(owa_util.get_owa_service_path||
        'wfa_html.worklist?orderkey=STATUS&clearbanner='||clearbanner,
        '<font color=#FFFFFF>'||wf_core.translate('STATUS')||'</font>',
        null), calign=>'Center',
        cattributes=>'id="' || WF_CORE.Translate('STATUS') || '"');

  end if;

  htp.tableRowClose;
  htp.tableRowOpen;
  htp.tableRowClose;

  -- Hidden NIDS Field to handle the case when no notification id is selected
  htp.formHidden('NIDS', -1);

  -- Worklist
  for i in 1..outTab.COUNT loop
    -- Set the variables
    nf_nid      := outTab(i).nid;
    nf_priority := outTab(i).priority;
    nf_status   := outTab(i).status;
    nf_language := outTab(i).language;
    nf_message_type   := outTab(i).col01;
    nf_recipient      := outTab(i).col02;
    nf_subject        := outTab(i).col03;
    nf_begin_date     := outTab(i).col04;
    nf_due_date       := outTab(i).col05;
    nf_end_date       := outTab(i).col06;
    nf_display_status := outTab(i).col07;
    nf_from_user      := outTab(i).col08;
    nf_to_user        := outTab(i).col09;


    -- Check if we need to get denormalized value again
    if (nf_language is null or nf_language <> userenv('LANG')) then
      Wfa_Html_Util.GetDenormalizedValues(nf_nid, userenv('LANG'),
          nf_from_user, nf_to_user, nf_subject);
    end if;

    -- Figure out the priority first
    n_priority := GetPriorityIcon(nf_priority);

    -- Figure out whether response is required
    n_response := null;
    if (nf_status = 'OPEN') then
      open attrs(nf_nid);
      fetch attrs into result;
      if (attrs%found) then
        n_response := wfa_html.image_loc||'reqresp.gif';
      end if;
      close attrs;
    end if;

    -- Displaying a row
    htp.tableRowOpen(null, 'TOP');
      htp.tableData(htf.formCheckbox(cname=>'NIDS', cvalue=>nf_nid,
                    cattributes=>'id="i_nids' || i || '"'), 'center',
        cattributes=>'id="' || WF_CORE.Translate('NOTIFICATION') || '"');
      htp.p('<TD id="' || WF_CORE.Translate('PRIORITY') ||
            '" ALIGN=left>');
        htp.tableOpen('border=0 width="100%" summary=""');
        htp.tableRowOpen(null,'TOP');
        if (n_priority is null) then
          -- ### width below is ignored in html code, takes it out.
          -- ### htp.tableData('&'||'nbsp;', 'left', 'width="50%"');
          htp.tableData('&'||'nbsp;', 'left', cattributes=>'id=""');
        else
          htp.tableData(htf.img(curl=>n_priority, calt=>WFA_HTML.g_priority),
                        'center', cattributes=>'id="' ||
                        WFA_HTML.g_priority || '"');
        end if;
        htp.tableRowClose;
        htp.tableClose;
      htp.p('</TD>');
      htp.tableData(nf_message_type, 'left', cattributes=>'id=""');
      htp.tableData(nvl(nf_from_user, '&nbsp'), 'left', cattributes=>'id=""');
      if (lshowto = 'T') then
        htp.tableData(nf_to_user, 'left', cattributes=>'id=""');
      end if;

    -- If response is required, append response required icon to subject
      if (n_response is null) then
        htp.tableData(
          cvalue=>'<LABEL FOR="i_nids' || i || '">' ||
                  htf.anchor(curl=>Wfa_Sec.DetailURL(nf_nid),
                             cattributes=>'target="_top" id=""',
                             ctext=> nf_subject)  || '</LABEL>',
          calign=>'left');
      else
        htp.tableData(
          cvalue=>'<LABEL FOR="i_nids' || i || '">' ||
                  htf.anchor(curl=>Wfa_Sec.DetailURL(nf_nid),
                             cattributes=>'target="_top" id=""',
                             ctext=> nf_subject) ||'</LABEL>' ||
                '&'||'nbsp;'||htf.img(curl=>n_response,
                      calt=>WF_CORE.Translate('WFSRV_RECIPIENT_MUST_RESPOND')),
                      calign=>'left');
      end if;
      htp.tableData(cvalue=>nf_begin_date, calign=>'left',
          cnowrap=>1, cattributes=>'id=""');
      htp.tableData(cvalue=>nvl(nf_due_date, '<BR>'),
          calign=>'left', cnowrap=>1, cattributes=>'id=""');

     -- Add optional end date if querying closed/cancelled/invalid notifications
     if (nvl(lstatus,'x') <> 'OPEN') then

        htp.tableData(cvalue=>nvl(nf_end_date, '<BR>'),
            calign=>'left', cnowrap=>1, cattributes=>'id=""');

     end if;

     -- Add optional status if querying all notifications
     if (nvl(lstatus,'x') = '*') then

        htp.tableData(nf_display_status, 'left', cattributes=>'id=""');

     end if;

    htp.tableRowClose;

  end loop;

  htp.tableClose;

  htp.formHidden('showto', lshowto);
  htp.formClose;


  htp.tableopen (calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;

  -- Close button
  htp.p('<TD id="' || WF_CORE.Translate('CLOSE') || '">');

  wfa_html.create_reg_button ('javascript:document.WFA_WORKLIST.close.value='||
      ''''||'CLOSE'||''''||
      ';document.WFA_WORKLIST.forward.value='||
      ''''||''''||
      ';document.WFA_WORKLIST.submit()',
      wf_core.translate ('CLOSE_MSG'),
      wfa_html.image_loc,
      '',
      wf_core.translate ('CLOSE'));

  htp.p('</TD>');

  -- Reassign Button
  htp.p('<TD id="' || WF_CORE.Translate('ASSIGN') || '">');

  wfa_html.create_reg_button ('javascript:document.WFA_WORKLIST.forward.value='||
      ''''||'FORWARD'||''''||
      ';document.WFA_WORKLIST.close.value='||
      ''''||''''||
      ';document.WFA_WORKLIST.submit()',
      wf_core.translate ('ASSIGN_MSG'),
      wfa_html.image_loc,
      '',
      wf_core.translate ('ASSIGN'));

  htp.p('</TD>');

  htp.tableRowClose;
  htp.tableClose;
  htp.centerClose;

  wfa_sec.Footer;
  htp.htmlClose;
exception
  when others then
    rollback;
    if (attrs%isopen) then
      close attrs;
    end if;
    wf_core.context('Wfa_Html','WorkList', orderkey, status, user);
    wfa_html.Error;
end Worklist;

--
-- Authenticate (PRIVATE)
--   Verify user is allowed access to this notification
-- IN
--   nid - notification id
--   nkey - notification access key (if disconnected)
-- RETURNS
--   Current user name
--
function Authenticate(
  nid in number,
  nkey in varchar2)
return varchar2
is
  usercolon pls_integer;
  rolecolon pls_integer;
  origcolon pls_integer;
  username varchar2(320);
  recipient varchar2(320);
  orig_recipient varchar2(320);
  dummy pls_integer;
  admin_role varchar2(320);
  slash pls_integer;
  wfsession varchar2(240);

  uos   varchar2(320);
  uosid number;
  ros   varchar2(320);
  rosid number;
  oos   varchar2(320);
  oosid number;
begin
  if (nkey is null) then
    -- No nkey passed, means must be connected.  Get current user.
    Wfa_Sec.GetSession(username);

    -- Get recipient and original recipient of this notification
    begin
      select RECIPIENT_ROLE, ORIGINAL_RECIPIENT
      into recipient, orig_recipient
      from WF_NOTIFICATIONS WN
      where WN.NOTIFICATION_ID = nid;
    exception
      when no_data_found then
        Wf_Core.Token('NID', nid);
        Wf_Core.Raise('WFNTF_NID');
    end;

    -- Verify this notification was sent to this user
    -- Note that username could be the in the recipient role
    -- or in the original recipient role.
    begin
      usercolon := instr(username, ':');
      rolecolon := instr(recipient, ':');
      origcolon := instr(orig_recipient, ':');

      if (usercolon = 0) then
        -- very costly sql statement, return the first row we find.
        select ORIG_SYSTEM, ORIG_SYSTEM_ID
          into uos, uosid
          from WF_USERS
         where NAME = username
           and ORIG_SYSTEM not in ('HZ_PARTY','CUST_CONT')
           and rownum < 2;
      else
         uos   := substr(username, 1, usercolon-1);
         uosid := to_number(substr(username, usercolon+1));
      end if;

      if (rolecolon = 0) then
        -- when recipient = username, user is participate in the role of
        -- the same name, they will have the same orig system and orig
        -- system id.
        if (recipient = username) then
          ros   := uos;
          rosid := uosid;
        else
          Wf_Directory.GetRoleOrigSysInfo(recipient,ros,rosid);
        end if;
      else
        ros   := substr(recipient, 1, rolecolon-1);
        rosid := to_number(substr(recipient, rolecolon+1));
      end if;

      if (origcolon = 0) then
        -- similarly, don't bother to requery the orig_system and
        -- orig_system_id if original recipient matches recipient or username.
        if (orig_recipient = recipient) then
          oos   := ros;
          oosid := rosid;
        elsif (orig_recipient = username) then
          oos   := uos;
          oosid := uosid;
        else
          Wf_Directory.GetRoleOrigSysInfo(orig_recipient,oos,oosid);
        end if;
      else
        oos   := substr(orig_recipient, 1, origcolon-1);
        oosid := to_number(substr(orig_recipient, origcolon+1));
      end if;

      -- rewritten the sql from an or join to union all.
      -- reduced the query time from >25 sec to <0.5 sec.
      select 1
        into dummy
        from sys.dual
       where exists (
         select null
           from WF_USER_ROLES
          where USER_ORIG_SYSTEM = uos
            and USER_ORIG_SYSTEM_ID = uosid
            and USER_NAME = username
            and ROLE_ORIG_SYSTEM = ros
            and ROLE_ORIG_SYSTEM_ID = rosid
            and ROLE_NAME = recipient
        union all
         select null
           from WF_USER_ROLES
          where USER_ORIG_SYSTEM = uos
            and USER_ORIG_SYSTEM_ID = uosid
            and USER_NAME = username
            and ROLE_ORIG_SYSTEM = oos
            and ROLE_ORIG_SYSTEM_ID = oosid
            and ROLE_NAME = orig_recipient
        );

    exception
      when no_data_found then
        -- Check if current user has WF_ADMIN_ROLE privileges.
        -- If so, allow access anyway.
        admin_role := wf_core.translate('WF_ADMIN_ROLE');
        if (admin_role <> '*' and
            not Wf_Directory.IsPerformer(username, admin_role)) then
          Wf_Core.Token('USER', username);
          Wf_Core.Token('NID', to_char(nid));
          Wf_Core.Raise('WFNTF_ACCESS_USER');
        end if;
    end;
  else
    -- Nkey passed, means this must be disconnected (mailed html).
    -- Check the passed access key against the notification key.

    -- Construct wfsession-style access key as <nid>/<accesskey>.
    -- First strip <nid> from nkey if present (only for backward
    -- compatibility, current version only passes <accesskey>),
    -- then construct full key with current nid.
    -- Note: Key is reconstructed here instead of passing full
    -- <nid>/<accesskey> directly to check that the key being passed
    -- is really for this notification.
    slash := instr(nkey, '/');
    if (slash <> 0) then
      wfsession := to_char(nid)||'/'||substr(nkey, slash+1);
    else
      wfsession := to_char(nid)||'/'||nkey;
    end if;

    username := Wf_Notification.AccessCheck(wfsession);
    if (username is null) then
      wf_core.raise('WFNTF_ACCESS_KEY');
    end if;
  end if;

  return(username);

exception
  when others then
    wf_core.context('Wfa_Html', 'Authenticate', to_char(nid), nkey);
    raise;
end Authenticate;

--
-- DetailFrame
--   generate Detail notification screen
-- IN
--   nid - notification id
--   nkey - notification access key (for mailed html only)
--   agent - web agent (OBSOLETE - for back compatibility only)
--   showforms - show form attributes
--
procedure DetailFrame(
  nid in varchar2,
  nkey in varchar2,
  agent in varchar2,
  showforms in varchar2)
as
  slash     pls_integer;
  col       pls_integer;
  first_doc boolean := TRUE;
  wfsession varchar2(240);
  link_name varchar2(240);
  username varchar2(320);
  disprole varchar2(320);
  titlerole varchar2(320);
  s0       varchar2(2000);
  link_text varchar2(2000);
  comment_title varchar2(2000);
  l_document_attributes   fnd_document_management.fnd_document_attributes;
  l_status  boolean := FALSE;
  cnt       pls_integer := 0;
  end_of_text  boolean :=FALSE;
  msgbody   varchar2(32000);
  pseudo_login boolean := FALSE;
  sess_username varchar2(320);
  l_subject     varchar2(2000);
  l_forms_port  varchar2(120);

  -- Select notification info
  cursor notcurs is
    select WN.STATUS,
           WN.RECIPIENT_ROLE,
           WN.ORIGINAL_RECIPIENT,
           WN.PRIORITY,
           WN.BEGIN_DATE,
           WN.DUE_DATE,
           WN.END_DATE,
           WIT.DISPLAY_NAME message_type,
           WL.MEANING disp_status,
           WN.USER_COMMENT,
           WN.FROM_USER,
           WN.TO_USER,
           WN.SUBJECT,
           WN.LANGUAGE
    from WF_NOTIFICATIONS WN, WF_ITEM_TYPES_VL WIT, WF_LOOKUPS WL
    where WN.NOTIFICATION_ID = to_number(nid)
    and WN.MESSAGE_TYPE = WIT.NAME
    and WL.LOOKUP_TYPE = 'WF_NOTIFICATION_STATUS'
    and WN.STATUS = WL.LOOKUP_CODE;

  notrec notcurs%rowtype;


  -- Select attr values, formatting numbers and dates as requested.
  -- The order-by is to handle cases where one attr name is a substring
  -- of another.
  cursor notification_attrs_cursor(nid number) is
    select WNA.NAME, WMA.TYPE, WMA.FORMAT, WMA.DISPLAY_NAME,
           WNA.TEXT_VALUE
    from WF_NOTIFICATION_ATTRIBUTES WNA, WF_NOTIFICATIONS WN,
         WF_MESSAGE_ATTRIBUTES_VL WMA
    where WNA.NOTIFICATION_ID = nid
    and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
    and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
    and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
    and WMA.NAME = WNA.NAME
    and WMA.TYPE IN ('DOCUMENT', 'URL')
    and WMA.ATTACH = 'Y'
    and WNA.TEXT_VALUE IS NOT NULL
    and WMA.SUBTYPE = 'SEND'
    order by length(WNA.NAME) desc;

  -- similar to the above except FORMS do not set ATTACH to Y
  cursor ntf_forms_attrs_cursor(nid number) is
    select WNA.NAME, WMA.TYPE, WMA.FORMAT, WMA.DISPLAY_NAME,
           WNA.TEXT_VALUE
    from WF_NOTIFICATION_ATTRIBUTES WNA, WF_NOTIFICATIONS WN,
         WF_MESSAGE_ATTRIBUTES_VL WMA
    where WNA.NOTIFICATION_ID = nid
    and WN.NOTIFICATION_ID = WNA.NOTIFICATION_ID
    and WN.MESSAGE_TYPE = WMA.MESSAGE_TYPE
    and WN.MESSAGE_NAME = WMA.MESSAGE_NAME
    and WMA.NAME = WNA.NAME
    and WMA.TYPE = 'FORM'
    and WNA.TEXT_VALUE IS NOT NULL
    and WMA.SUBTYPE = 'SEND'
    order by length(WNA.NAME) desc;
begin

  -- Authenticate user
  username := Wfa_Html.Authenticate(to_number(nid), nkey);

  if (nkey is not null) then
    -- Set a cookie for future IC access.

    -- Construct wfsession-style access key as <nid>/<accesskey>.
    -- First strip <nid> from nkey if present (only for backward
    -- compatibility, current version only passes <accesskey>),
    -- then construct full key with current nid.
    -- Note: Key is reconstructed here instead of passing full
    -- <nid>/<accesskey> directly to check that the key being passed
    -- is really for this notification.
    slash := instr(nkey, '/');
    if (slash <> 0) then
      wfsession := nid||'/'||substr(nkey, slash+1);
    else
      wfsession := nid||'/'||nkey;
    end if;

    /*
    ** Create the ICX psuedo session so ICX does not recreate the psuedo
    ** session.
    ** But first check to see if there is a current session
    */
    begin
      wfa_sec.validate_only := TRUE;
      wfa_sec.GetSession(sess_username);
      if (sess_username <> 'ANONYMOUS' and sess_username <> '-1'
          and sess_username is not null) then
        -- there is a valid session already, just use it
        username := sess_username;
      else
        -- username -1 meant user had logged out.  Do this to reset the page.
        if (sess_username = '-1') then
          owa_util.showpage;
        end if;

        -- create a pseudo session for user
        owa_util.mime_header('text/html', FALSE);
        owa_cookie.send('WF_SESSION', wfsession, '', '/');
        wfa_sec.PseudoSession(FALSE, username);
        owa_util.http_header_close;
      end if;
    exception
      when OTHERS then
        -- this is the first attempt to see a detached notfication
        wf_core.clear;
        owa_util.mime_header('text/html', FALSE);
        owa_cookie.send('WF_SESSION', wfsession, '', '/');
        wfa_sec.PseudoSession(FALSE, username);
        owa_util.http_header_close;
    end;
    wfa_sec.validate_only := FALSE;

    pseudo_login := TRUE;
  end if;

  -- Get notification info
  open notcurs;
  fetch notcurs into notrec;
  if (notcurs%notfound) then
    close notcurs;
    wf_core.token('NID', nid);
    wf_core.raise('WFNTF_NID');
  end if;
  close notcurs;

  if (notrec.language = userenv('LANG')) then
    disprole := notrec.to_user;
    l_subject := notrec.subject;
  else
    Wf_Directory.GetRoleInfo(notrec.recipient_role, disprole, s0, s0, s0, s0);
    l_subject := Wf_Notification.GetSubject(to_number(nid));
  end if;
  titlerole := disprole;

  --
  -- Header and Page Title
  --
  htp.htmlOpen;
  htp.headOpen;

  fnd_document_management.get_open_dm_display_window;

  if (notrec.status = 'OPEN') then
    htp.title(wf_core.translate('WFA_DTITLE')||' '||titlerole);
  else
    htp.title(wf_core.translate('WFA_CDTITLE')||' '||titlerole);
  end if;
  wfa_html.create_help_function('wf/links/det.htm?DETNOT');

  -- Make sure the resulting link puts on the top window.
  htp.p('<BASE TARGET="_top">');
  htp.headClose;
  htp.p('<!-- debug info -->');
  htp.p('<!--  username='||username||' -->');
  htp.p('<!--  userenv(LANGUAGE)='||userenv('LANGUAGE')||' -->');
  htp.p('<!--  nid="'||nid||'" -->');
  htp.p('<!--  nkey="'||nkey||'" -->');
  htp.p('<!--  previous session user="'||sess_username||'" -->');

  if (nkey is null) then
    wfa_sec.Header(FALSE, owa_util.get_owa_service_path ||'wfa_html.Find',
           wf_core.translate('WFA_DTITLE_TBAR'), FALSE, pseudo_login);
  else
    -- disabled Find for detached notification
    wfa_sec.Header(FALSE, null,
           wf_core.translate('WFA_DTITLE_TBAR'), FALSE, pseudo_login);
  end if;

  htp.tableOpen(cattributes=>'WIDTH=100% summary=""', calign=>'CENTER');

  --
  -- LINE 0: from user  if it is not null
  --
  if (notrec.from_user is not null) then
    htp.tableRowOpen(cvalign=>'Baseline');
    htp.tableData(cvalue=>wf_core.translate('FROM'),
                  calign=>'right', cattributes=>'id=""');
    htp.tableHeader(cvalue=>notrec.from_user,
                    cnowrap=>1,
                    calign=>'left', cattributes=>'BGCOLOR=WHITE WIDTH="*" id=""');
    htp.tableRowClose;
  end if;

  --
  -- LINE 1: (begin_date -> end_date)
  --
  htp.tableRowOpen(cvalign=>'Baseline');

  -- Always print Sent To and begin_date
  htp.tableData(cvalue=>wf_core.translate('TO'),
                calign=>'right', cattributes=>'id=""');
  htp.tableHeader(cvalue=>disprole,
                  cnowrap=>1,
                  calign=>'left', cattributes=>'BGCOLOR=WHITE WIDTH="*" id=""');
  htp.tableData(cvalue=>wf_core.translate('BEGIN_DATE'),
                calign=>'right', cattributes=>'id=""');
  htp.tableHeader(cvalue=>to_char(notrec.begin_date)||
                          to_char(notrec.begin_date, ' HH24:MI:SS'),
                  cnowrap=>1,
                  calign=>'left', cattributes=>'BGCOLOR=WHITE WIDTH="25%" id=""');
  -- keep track of columns in first row of table
  col := 4;

  -- Due: <due_date>
  --   Do not print Due Date if it is null
  if (to_char(notrec.due_date) is not null) then
    htp.tableData(cvalue=>wf_core.translate('DUE_DATE'),
                  calign=>'right', cattributes=>'id=""');
    htp.tableHeader(cvalue=>to_char(notrec.due_date)||
                            to_char(notrec.due_date, ' HH24:MI:SS'),
                    cnowrap=>1,
                    calign=>'left', cattributes=>'BGCOLOR=WHITE WIDTH="25%" id=""');
    col := col+2;
  end if;

  -- Closed: <end_date> (only if not open)
  if (notrec.status <> 'OPEN') then
    if (notrec.status = 'CANCELED') then
      htp.tableData(cvalue=>wf_core.translate('CANCELED'),
                    calign=>'right', cattributes=>'id=""');
    else
      htp.tableData(cvalue=>wf_core.translate('END_DATE'),
                    calign=>'right', cattributes=>'id=""');
    end if;
    htp.tableHeader(cvalue=>to_char(notrec.end_date)||
                            to_char(notrec.end_date, ' HH24:MI:SS'),
                    cnowrap=>1,
                    calign=>'left', cattributes=>'BGCOLOR=WHITE WIDTH="25%" id=""');
    col := col+2;
  end if;
  htp.tableRowClose;


  --
  -- Subject: <subject>
  --
  htp.tableRowOpen(cvalign=>'Baseline');
  htp.tableData(cvalue=>wf_core.translate('SUBJECT'),
                calign=>'right', cattributes=>'id=""');

  --make colspan 1 less than col because 1 col is taken up by "subject"
  htp.tableHeader(cvalue=>l_subject,
                  calign=>'left',
                  ccolspan=>col-1,
                  cattributes=>'BGCOLOR=WHITE id=""');
  htp.tableRowClose;
  htp.tableClose;

  --
  -- COMMENTS
  --
  if (notrec.user_comment is not null) then
    htp.p(wf_core.translate('COMMENTS')||':');
    htp.tableOpen(cattributes=>'WIDTH=100% BGCOLOR=WHITE summary=""');
    htp.tableRowOpen;
    htp.p('<TD ALIGN="left" id="' || WF_CORE.Translate('COMMENTS') ||
          '">');
    htp.bold(replace(notrec.user_comment, wf_core.newline,
                     htf.br||wf_core.newline));
    htp.p('</TD>');
    htp.tableRowClose;
    htp.tableClose;
  end if;

  --
  -- BODY
  --
  htp.hr;
  htp.tableOpen(cattributes=>'WIDTH=100% BGCOLOR=WHITE summary=""');
  htp.tableRowOpen;

  end_of_text:=FALSE;
  -- print message body. This may be in sections.
  htp.p('<TD  ALIGN="left" id="">');
  while not (end_of_text) loop
       wf_notification.getfullbody(to_number(nid),msgbody,end_of_text,
                                 wf_notification.doc_html);
       htp.prn(msgbody);
  end loop;
  htp.p('</TD>');

  htp.tableRowClose;
  htp.tableClose;

  htp.br;

  for not_attr_row in notification_attrs_cursor(nid) loop

     if (first_doc = TRUE) then

        htp.hr;
        htp.br;
        htp.tableopen(cattributes=>'BORDER=0 cellpadding=0 cellspacing=0 summary=""');
        htp.tablerowopen;
        first_doc := FALSE;

     end if;

     if (not_attr_row.type = 'DOCUMENT') then

        if (UPPER(SUBSTR(not_attr_row.text_value, 1, 2)) = 'DM') then

           /*
           ** Get the HTML text for displaying the document
           */
           fnd_document_management.get_launch_document_url (
              username,
              not_attr_row.text_value,
              FALSE,
              link_text);

           link_text :=  '<A HREF="'||link_text||
                 '" TARGET="'||not_attr_row.format||'">'||
                 '<IMG SRC="'||wfa_html.image_loc||'afdsktop.gif" alt="' ||
                 WF_CORE.Translate('WFITD_ATTR_TYPE_DOCUMENT') || '" BORDER=no></A>';

        elsif (UPPER(SUBSTR(not_attr_row.text_value, 1, 5)) = 'PLSQL') then
   
            if (nkey is null) then
              link_text := '<A HREF="'||
                 wfa_html.base_url||'/wfa_html.show_plsql_doc'||
                 '?nid='||nid||'&aname='||not_attr_row.name||
                 '" TARGET="'||not_attr_row.format||'">'||
                 '<IMG SRC="'||wfa_html.image_loc||'afdsktop.gif" alt="' ||
                 WF_CORE.Translate('WFITD_ATTR_TYPE_DOCUMENT') || '" BORDER=no></A>';
            else
              link_text := '<A HREF="'||
                 wfa_html.base_url||'/wfa_html.show_plsql_doc'||
                 '?nid='||nid||'&aname='||not_attr_row.name||'&nkey='||nkey||
                 '" TARGET="'||not_attr_row.format||'">'||
                 '<IMG SRC="'||wfa_html.image_loc||'afdsktop.gif" alt="' ||
                 WF_CORE.Translate('WFITD_ATTR_TYPE_DOCUMENT') || '" BORDER=no></A>';
            end if;

        end if;

     elsif (not_attr_row.type = 'URL') then

         link_text := wf_notification.geturltext(not_attr_row.text_value, nid);
--### debug
         htp.p('<!-- debug info -->');
         htp.p('<!-- geturltext link_text: '||link_text||' -->');

         link_text := wf_notification.SetFrameworkAgent(link_text);
         htp.p('<!-- setFrameworkAgent link_text: '||link_text||' -->');

         link_text := '<A HREF="'||link_text||
                 '" TARGET="'||not_attr_row.format||'">'||
                 '<IMG SRC="'||wfa_html.image_loc||'afdsktop.gif" alt="' ||
                 WF_CORE.Translate('WFITD_ATTR_TYPE_DOCUMENT') || '" BORDER=no></A>';

     end if;

     htp.tabledata(cvalue=>link_text, calign=>'CENTER', cattributes=>'id=""');

     htp.tabledata(cvalue=>'&nbsp;&nbsp;&nbsp;', calign=>'CENTER', cattributes=>'id=""');

  end loop;

  if (showforms is not null) then
    for not_attr_row in ntf_forms_attrs_cursor(nid) loop
       if (first_doc = TRUE) then

          htp.hr;
          htp.br;
          htp.tableopen(cattributes=>'BORDER=0 cellpadding=0 cellspacing=0 summary=""');
          htp.tablerowopen;
          first_doc := FALSE;

       end if;

       --Check the SOCKET_LISTENER_PORT profile option.
       l_forms_port := 
              Wfa_Sec.Get_Profile_Value('SOCKET_LISTENER_PORT',username);

       htp.p('<TD ALIGN="CENTER" id="">');
         Wf_Forms.Applet(
           fname=>Wf_Notification.GetShortText(not_attr_row.text_value, nid),
           status=>l_status,
           dispname=>not_attr_row.display_name,
           port=>nvl(l_forms_port, '0'));
       htp.p('</TD>');
       htp.tabledata(cvalue=>'&nbsp;&nbsp;&nbsp;', calign=>'CENTER', cattributes=>'id=""');
       if (not l_status) then
         cnt := cnt + 1;
       end if;
    end loop;
  end if;


  -- If you found a row then close the table row you opened and open a new
  -- one for the document title
  if (first_doc = FALSE) then

     htp.tableRowClose;
     htp.tablerowopen;

  end if;

  for not_attr_row in notification_attrs_cursor(nid) loop

     if (not_attr_row.type = 'DOCUMENT') then

        if (UPPER(SUBSTR(not_attr_row.text_value, 1, 2)) = 'DM') then

           /*
           ** Get the HTML text for displaying the document
           */
           fnd_document_management.get_launch_document_url (
              username,
              not_attr_row.text_value,
              FALSE,
              link_text);

           link_text :=  '<A HREF="'||link_text||
                 '" TARGET="'||not_attr_row.format||'">'||
                 not_attr_row.display_name||
                 '</A>';


        elsif (UPPER(SUBSTR(not_attr_row.text_value, 1, 5)) = 'PLSQL') then

            if (nkey is null) then
              link_text := '<A HREF="'||
                 wfa_html.base_url||'/wfa_html.show_plsql_doc'||
                 '?nid='||nid||'&aname='||not_attr_row.name||
                 '" TARGET="'||not_attr_row.format||'">'||
                 not_attr_row.display_name||'</A>';
            else
              link_text := '<A HREF="'||
                 wfa_html.base_url||'/wfa_html.show_plsql_doc'||
                 '?nid='||nid||'&aname='||not_attr_row.name||'&nkey='||nkey||
                 '" TARGET="'||not_attr_row.format||'">'||
                 not_attr_row.display_name||'</A>';
            end if;
        end if;

     elsif (not_attr_row.type = 'URL') then

         link_text := wf_notification.geturltext(not_attr_row.text_value, nid);
         link_text := wf_notification.SetFrameworkAgent(link_text);

         link_text := '<A HREF="'||link_text||
                 '" TARGET="'||not_attr_row.format||'">'||
                 not_attr_row.display_name||'</A>';


     end if;

     htp.tabledata(cvalue=>link_text, calign=>'CENTER', cattributes=>'id=""');

     htp.tabledata(cvalue=>'&nbsp;&nbsp;&nbsp;', calign=>'CENTER', cattributes=>'id=""');

  end loop;

  if (showforms is not null) then
    for not_attr_row in ntf_forms_attrs_cursor(nid) loop
       htp.p('<TD ALIGN="CENTER" id="">');
         htp.p(not_attr_row.display_name);
       htp.p('</TD>');
       htp.tabledata(cvalue=>'&nbsp;&nbsp;&nbsp;', calign=>'CENTER',
                     cattributes=>'id=""');
    end loop;
  end if;

  -- If you found a row then close the table row you opened and open a new
  -- one for the document title
  if (first_doc = FALSE) then
     htp.tableRowClose;
     htp.tableClose;
  end if;

  --
  -- Print warning message
  --
  if (cnt > 0) then
    htp.p('<P>'||wf_core.translate('WF_EXECUTE_FORM_FAILED'));
    htp.br;
  end if;

  --
  -- Page footer
  --
  Wfa_Sec.Footer;
  htp.htmlClose;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'DetailFrame', nid, nkey);
    wfa_html.Error;
end DetailFrame;

--
-- ResponseFrame
--   generate response frame contents
-- IN
--   nid - notification id
--   nkey - notification access key (for mailed html only)
--   agent - web agent (OBSOLETE - for back compatibility only)
--   showforms - show form attributes
--
procedure ResponseFrame(
  nid in varchar2,
  nkey in varchar2,
  agent in varchar2,
  showforms in varchar2)
as
  username varchar2(320);
  recipient varchar2(320);
  realname varchar2(360);
  status   varchar2(8);
  s0       varchar2(2000);
--  url_str  varchar2(240);
  l_status boolean := FALSE;
  cnt      pls_integer := 0;
  pseudo_login boolean := FALSE;
  l_forms_port  varchar2(120);

  cursor attrs(resultflag in varchar2, typeflag in varchar2) is
    select MA.NAME,
           MA.DISPLAY_NAME,
           MA.DESCRIPTION,
           -- remove quotes for onmouse over java func
           replace(MA.DESCRIPTION,'''') description2,
           NA.TEXT_VALUE,
           NA.NUMBER_VALUE,
           NA.DATE_VALUE,
           MA.TYPE,
           MA.FORMAT
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES_VL MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = to_number(ResponseFrame.nid)
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND'
    and MA.TYPE <> 'FORM'
    and ((resultflag = 'RESULT' and MA.NAME = 'RESULT') or
         (resultflag <> 'RESULT' and MA.NAME <> 'RESULT'))
    and MA.TYPE = decode(typeflag, '', MA.TYPE, typeflag)
    order by MA.SEQUENCE;

  cursor forms_attrs is
    select MA.NAME,
           MA.DISPLAY_NAME,
           MA.DESCRIPTION,
           -- remove quotes for onmouse over java func
           replace(MA.DESCRIPTION,'''') description2,
           NA.TEXT_VALUE
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES_VL MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = to_number(ResponseFrame.nid)
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND'
    and MA.TYPE = 'FORM'
    order by MA.SEQUENCE;

  result attrs%rowtype;

  dvalue varchar2(2000);
  respcnt pls_integer;
  urlcount pls_integer;
  urlstring varchar2(4000);
  result_count pls_integer;
  resp_lbl varchar2(80);

  colon pls_integer;

  dmstype varchar2(30) := '';
  document varchar2(32000) := '';

  hide_button varchar2(1);
  sess_username varchar2(320);

begin
  -- Authenticate user
  username := Wfa_Html.Authenticate(to_number(nid), nkey);
  Wf_Notification.GetInfo(to_number(nid), recipient, s0, s0, s0, s0, status);
  Wf_Directory.GetRoleInfo(recipient, realname, s0, s0, s0, s0);

  -- if nkey is not null, it is from email, and we need to create a pseudo
  -- session for it.
  if (nkey is not null) then
    begin
      wfa_sec.validate_only := TRUE;
      wfa_sec.GetSession(sess_username);
      if (sess_username <> 'ANONYMOUS' and sess_username <> '-1'
          and sess_username is not null) then
        -- there is a valid session already, just use it
        username := sess_username;
      else
        -- username -1 meant user had logged out.  Do this to reset the page.
        if (sess_username = '-1') then
          owa_util.showpage;
        end if;

        -- create a pseudo session for user
        owa_util.mime_header('text/html', FALSE);
        wfa_sec.PseudoSession(FALSE, username);
      end if;
    exception
      when OTHERS then
        -- this is the first attempt to see a detached notfication
        wf_core.clear;
        owa_util.mime_header('text/html', FALSE);
        wfa_sec.PseudoSession(FALSE, username);
    end;
    wfa_sec.validate_only := FALSE;
  end if;

  wfa_html_util.GetUrlCount(to_number(nid),urlcount,urlstring);

  -- If there is just one url then replace the response frame with the url
  if (urlcount = 1) then
--    GoToUrl(wf_notification.GetURLText(urlstring, nid),'_self');
    owa_util.redirect_url(wf_notification.GetURLText(urlstring, nid));
    return;
  end if;

  -- bug 2167012 JWSMITH moved header_close to after owa_util.redirect 
  owa_util.http_header_close;
  --
  -- Header and Page Title
  --
  htp.htmlOpen;
  htp.headOpen;
  if (status = 'OPEN') then
    htp.title(wf_core.translate('WFA_DTITLE')||' '||realname);
  else
    htp.title(wf_core.translate('WFA_CDTITLE')||' '||realname);
  end if;

  -- Add the java script to the header to open the dm window for
  -- any DM function that is executed.
  fnd_document_management.get_open_dm_attach_window;
  fnd_document_management.get_open_dm_display_window;


  htp.headClose;

  htp.p('<!-- debug info -->');
  htp.p('<!--  username='||username||' -->');
  htp.p('<!--  userenv(LANGUAGE)='||userenv('LANGUAGE')||' -->');
  htp.p('<!--  nid="'||nid||'" -->');
  htp.p('<!--  nkey="'||nkey||'" -->');
  htp.p('<!--  previous session user="'||sess_username||'" -->');

  --
  -- Response body content
  --
  wfa_sec.header(background_only=>TRUE);

  -- Add the Return to Worklist link before other attributes.
  -- We shows it regardless if we have open response or not.
  -- Fix bug #785206. We don't show the WorkList link if is coming from
  -- email attachment
  if (nkey is null) then
    htp.center(htf.anchor(
            curl => owa_util.get_owa_service_path||'wfa_html.WorkList',
            ctext => wf_core.translate('WFA_WORKLIST_RETURN'),
            cattributes=>'TARGET="_top"'));
  else
    pseudo_login := TRUE;
  end if;

  --
  -- Handle Response Forms Attributes
  -- Note that similar to URL, it is mutally exclusive to other attributes
  --
  -- Do not allow any response if notification is not opened
  --
  if (status = 'OPEN') then
    if (showforms is not null) then
      htp.tableOpen(cattributes=>'summary=""');
      respcnt := 0;
      for rec in forms_attrs loop
        htp.tableRowOpen;
        htp.p('<TD ALIGN="RIGHT" ROWSPAN=2 id="">');
        if (rec.description is not null) then
          htp.p(rec.description);
        else
          htp.br;
        end if;
        htp.p('</TD>');

       --Check the SOCKET_LISTENER_PORT profile option.
       l_forms_port := 
              Wfa_Sec.Get_Profile_Value('SOCKET_LISTENER_PORT',username);

        htp.p('<TD ALIGN="CENTER" id="">');
          Wf_Forms.Applet(fname=>Wf_Notification.GetShortText(rec.text_value,
                            to_number(ResponseFrame.nid)),
                          status=>l_status,
                          port=>nvl(l_forms_port, '0'));
        htp.p('</TD>');
        htp.tableRowClose;

        htp.tableRowOpen;
        htp.tableData(rec.display_name, 'CENTER', cattributes=>'id=""');
        htp.tableRowClose;

        if (not l_status) then
          cnt := cnt + 1;
        end if;

        respcnt := respcnt + 1;
      end loop;
      htp.tableClose;

      --
      -- Print warning message
      --
      if (cnt > 0) then
        htp.p('<P>'||wf_core.translate('WF_EXECUTE_FORM_FAILED'));
        htp.br;
      end if;

      if (respcnt >= 1) then
        Wfa_Sec.Footer;
        htp.htmlClose;
        return;
      end if;
    end if;
  end if;

  --
  -- Check for response URLs.  If more than one is found, display a list of
  -- URL links instead of the standard response frame.  If only one is found
  -- then the main response frame function will be replaced in the detail
  -- procedure
  --
  if (urlcount > 1) then

    htp.tableOpen(cattributes=>'summary=""');
    for rec in attrs('NORESULT', 'URL') loop

       htp.tableRowOpen;
       wfa_html_util.GetUrl(nid, rec.description, rec.text_value);
       htp.tableRowClose;

    end loop;

    htp.tableClose;
    Wfa_Sec.Footer;
    htp.htmlClose;

    return;

  end if;

  if (status = 'OPEN') then

    htp.p('<FORM NAME="WFNOTRESP" ACTION="'||
       owa_util.get_owa_service_path||
       'wfa_html.SubmitResponse" METHOD="POST" ONSUBMIT="return false">');

    htp.formHidden('nkey', nkey);
    htp.formHidden('forward', null);

    -- Add dummy fields to start both array-type input fields.
    -- These dummy values are needed so that the array parameters to
    -- the submit procedure will not be null even if there are no real
    -- response fields.  This would cause a pl/sql error, because array
    -- parameters can't be defaulted.
    htp.formHidden('h_fnames', 'Dummy_Name');
    htp.formHidden('h_fvalues', 'Dummy_Value');
    htp.formHidden('h_fdocnames', 'Dummy_Value');
  else
    -- Add submitted title if ntf not open
    if (status = 'CANCELED') then
      htp.center(htf.bold(wf_core.translate('WFA_NOTIF_CANCELED')));
    else
      if (pseudo_login) then
        htp.center(htf.bold(wf_core.translate('WFA_RESPONSE_COMPLETE')));
      else
        htp.center(htf.bold(wf_core.translate('WFA_SUBMIT_RESPONSE')));
      end if;
    end if;
  end if;

  --
  -- Non-RESULT Response attribute fields
  -- Add a field for every non-result response attribute
  --
  htp.tableOpen(cattributes=>'summary=""');

  respcnt := 0;
  for rec in attrs('NORESULT', '') loop

    htp.tableRowOpen;

    -- Draw prompt with anchor for info
    htp.tableData(
        cvalue=>htf.anchor(
                    curl=>owa_util.get_owa_service_path||
                          'wfa_html.AttributeInfo?nid='||nid||
                          '&'||'name='||rec.name,
                    ctext=>rec.display_name,
                    cattributes=>'OnMouseOver="window.status='''||wfa_html.replace_onMouseOver_quotes(rec.description2)||'''; return true"'),
        calign=>'right',
        cattributes=>'id=""');

    dvalue := wfa_html_util.GetDisplayValue(rec.type, rec.format, rec.text_value,
                 rec.number_value, rec.date_value);
    if (status <> 'OPEN') then

      if (rec.type = 'DOCUMENT' and dvalue is not null) then

         -- Parse doc mgmt system type from dvalue
         colon := instr(dvalue, ':');
         if ((colon <> 0) and (colon < 30)) then
            dmstype := upper(substr(dvalue, 1, colon-1));
         end if;

         if (dmstype = 'DM') then

            /*
            ** Get the HTML text for displaying the document
            */
            fnd_document_management.get_launch_document_url (
               username,
               dvalue,
               FALSE,
               document);

            document := '<A HREF="'||document||
                 '" TARGET="FNDDMwindow">'||rec.display_name||
                 '</A>';

             -- If ntf not open print displayed value as boilerplate
             -- instead of fields.
             htp.tableData(cvalue=>document,
                       cattributes=>'BGCOLOR=WHITE id=""');

         elsif (dmstype = 'PLSQL') then

             -- If ntf not open print displayed value as boilerplate
             -- instead of fields.
             htp.tableData(cvalue=>dvalue,
                       cattributes=>'BGCOLOR=WHITE id=""');

         end if;

      else

         -- If ntf not open print displayed value as boilerplate
         -- instead of fields.
         htp.tableData(cvalue=>dvalue,
                       cattributes=>'BGCOLOR=WHITE id=""');

      end if;

    else

      respcnt := respcnt + 1;
      if (rec.type = 'LOOKUP') then
        wfa_html_util.GetLookup(rec.name, rec.text_value, rec.format, FALSE);
      else
        if (nkey is null) then
          wfa_html_util.GetField(rec.name,rec.type,rec.format,dvalue,respcnt);
        else
          wfa_html_util.GetField(rec.name,rec.type,rec.format,dvalue,respcnt,
             to_number(nid), nkey);
        end if;
      end if;

    end if;

    htp.tableRowClose;

  end loop;


  --
  -- RESULT attribute
  -- Add result attribute to bottom of page
  --
  open attrs('RESULT', '');
  fetch attrs into result;
  if (attrs%notfound) then
    -- No result
    if (status = 'OPEN') then
      if (respcnt > 0) then
        -- Non-result responses exist.
        -- Add a 'Submit' button to submit the form.
        htp.tableRowOpen;
        htp.p('<TD id="">');
        wfa_html.create_reg_button ('javascript:document.WFNOTRESP.submit()',
                                    wf_core.translate ('SUBMIT'),
                                    wfa_html.image_loc,
                                    null,
                                    wf_core.translate ('SUBMIT'));

        htp.p('</TD>');

      else

        -- No responses at all.
        -- Add a message to that effect.
        htp.tableRowOpen;
        htp.tableData(wf_core.translate('WFA_NO_RESPONSE'), cattributes=>'id=""');
        htp.tableRowClose;

        -- Followed by a 'Close' button
        htp.tableRowOpen;
        htp.p('<TD id="">');
        htp.tableopen(cattributes=>'summary=""');
        htp.tablerowopen;
        htp.p('<TD ALIGN=LEFT id="">');
        wfa_html.create_reg_button ('javascript:document.WFNOTRESP.submit()',
                                    wf_core.translate ('CLOSE'),
                                    wfa_html.image_loc,
                                    null,
                                    wf_core.translate ('CLOSE'));

        htp.p('</TD>');

      end if;
    end if;
  else
    -- Result found
    -- Draw prompt with anchor for info
    htp.tableRowOpen;
    htp.tableData(
        cvalue=>htf.anchor(
                    curl=>owa_util.get_owa_service_path||
                          'wfa_html.AttributeInfo?nid='||nid||
                          '&'||'name=RESULT',
                    ctext=>result.display_name,
                    cattributes=>'OnMouseOver="window.status='''||wfa_html.replace_onMouseOver_quotes(result.description2)||'''; return true"'),
        calign=>'right',
        cattributes=>'id=""');

    if (status = 'OPEN') then
      -- Draw response buttons
      htp.p('<TD id="">');
      htp.tableopen(cattributes=>'cellspacing=0 summary=""');
      htp.tablerowopen;
      respcnt := respcnt + 1;
      wfa_html_util.GetButtons(result.text_value, result.format, respcnt);

    else
      -- Not open.  Throw the result into boilerplate.
      htp.tableData(cvalue=>wfa_html_util.GetDisplayValue(result.type, result.format,
                                    result.text_value, result.number_value,
                                    result.date_value),
                      cattributes=>'BGCOLOR=WHITE id=""');
    end if;
  end if;
  close attrs;

  -- Add forward button if still open
  if (status = 'OPEN') then
    -- Hide the Reassign button if a hidden attribute #HIDE_REASSIGN
    -- is set to Y.
    -- Exception handling is needed in case this attribute is not set.
    hide_button := 'N';
    begin
      hide_button := Wf_Notification.GetAttrText(nid, '#HIDE_REASSIGN');
    exception
      when OTHERS then
        -- Do not want anything on the error stack
        Wf_Core.Clear;
    end;
    if (hide_button <> 'Y') then
      htp.p('<TD id="">');
      wfa_html.create_reg_button ('javascript:document.WFNOTRESP.forward.value=1;
                                  document.WFNOTRESP.submit()',
                                  wf_core.translate ('ASSIGN'),
                                  wfa_html.image_loc,
                                  null,
                                  wf_core.translate ('ASSIGN'));

       htp.p('</TD>');
    end if;
  end if;

  htp.p('</TD>');
  htp.tablerowclose;
  htp.tableclose;

  htp.tableRowClose;
  htp.tableClose;

  -- Create hidden fields
  -- NOTE: Do NOT create any more fields for h_names or h_values here.  The
  -- submit buttons created above must be the last values for these fields
  -- to work around an MSIE bug that always sends the submit button last.
  if (status = 'OPEN') then
    htp.formHidden('h_fdocnames', null);
    htp.formHidden('h_counter', to_char(respcnt+1), null);
    htp.formHidden('h_nid', nid);
    htp.formClose;
  end if;

  -- Page footer
  Wfa_Sec.Footer;
  htp.htmlClose;

exception
  when others then
    if (attrs%isopen) then
      close attrs;  -- Close cursor just in case
    end if;
    rollback;
    wf_core.context('Wfa_Html', 'ResponseFrame', nid, nkey);
    wfa_html.Error;
end ResponseFrame;

--
-- ForwardFrame
--   generate forward frame contents
-- IN
--   nid - notification id
--   nkey - notification access key (for mailed html only)
--
procedure ForwardFrame(
  nid in varchar2,
  nkey in varchar2)
as
  username varchar2(320);
  recipient varchar2(320);
  realname varchar2(360);
  status   varchar2(8);
  s0       varchar2(2000);
  lang_codeset varchar2(50); -- Language Codeset from environment
                             -- (e.g. WE8ISO8859P1)
  l_message     varchar2(240)   := wfa_html.replace_onMouseOver_quotes(wf_core.translate ('WFPREF_LOV'));

  l_url         varchar2(1000);
  l_media       varchar2(240) := wfa_html.image_loc;
  l_icon        varchar2(30) := 'FNDILOV.gif';

begin
  -- Authenticate user
  username := Wfa_Html.Authenticate(to_number(nid), nkey);
  Wf_Notification.GetInfo(to_number(nid), recipient, s0, s0, s0, s0, status);
  Wf_Directory.GetRoleInfo(recipient, realname, s0, s0, s0, s0);

  -- Get language codeset
  lang_codeset := substr(userenv('LANGUAGE'),instr(userenv('LANGUAGE'),'.')+1,
                         length(userenv('LANGUAGE')));

  -- Header and Page Title
  htp.htmlOpen;
  htp.headOpen;
  if (status = 'OPEN') then
    htp.title(wf_core.translate('WFA_DTITLE')||' '||realname);
  else
    htp.title(wf_core.translate('WFA_CDTITLE')||' '||realname);
  end if;

  fnd_document_management.get_open_dm_display_window;

--1578431: Moved the form submission into a javascript function to perform
--         field validation.

  htp.p('<SCRIPT LANGUAGE="JavaScript">' || wf_core.newline ||
        '<!-- hide the script''s contents from feeble browsers');

  htp.p(wf_core.newline || 'function SubmitForward() {' || wf_core.newline );
  htp.p('var lcomment = document.WF_HTML.comments.value;' || wf_core.newline );
  htp.p(wf_core.newline || 'if (lcomment.length > 240) {' || wf_core.newline ||
        'alert( " ' || WF_CORE.Translate( 'WFA_MAX_COMMENTS' ) || ' "); }' ); 
  htp.p('else { document.WF_HTML.submit(); }' || wf_core.newline || 
        '}' || wf_core.newline);
  htp.p('<!-- done hiding from old browsers --></SCRIPT>' || wf_core.newline);

  htp.p('<NOSCRIPT>');
  htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
  htp.p('</NOSCRIPT>');

  htp.headClose;

  -- Body contents
  wfa_sec.header(background_only=>TRUE);

  -- Open form and add hidden fields
  htp.formOpen(curl=>owa_util.get_owa_service_path||'wfa_html.SubmitForward',
               cmethod=>'Post', cattributes=>'NAME="WF_HTML"');
  htp.formHidden('nkey', nkey);
  htp.formHidden('h_nid', nid);

  -- Forwardee field
  htp.tableOpen(calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_assignto">' ||
                        wf_core.translate('WFA_ASSIGNTO') ||
                        '</LABEL>',
                calign=>'right', cattributes=>'id=""');

  htp.formHidden('forwardee', null);

  -- add LOV here: Note:bottom is name of frame.
  -- Note: The REPLACE function replaces all the space characters with
  -- the proper escape sequence.
  l_url := 'javascript:fnd_open_dm_display_window('||''''||
            REPLACE('wf_lov.display_lov?p_lov_name='||'owner'||
            '&p_display_name='||'WFA_FIND_USER'||
            '&p_validation_callback=wfa_html.wf_user_val'||
            '&p_dest_hidden_field=top.opener.parent.bottom.document.WF_HTML.forwardee.value'||
            '&p_current_value=top.opener.parent.bottom.document.WF_HTML.display_forwardee.value'||
            '&p_display_key='||'Y'||
            '&p_dest_display_field=top.opener.parent.bottom.document.WF_HTML.display_forwardee.value',
              ' ', '%20')||''''||',500,500)';

  -- print everything together so ther is no gap.
  htp.tabledata(htf.formText(cname=>'display_forwardee', csize=>30, 
                             cmaxlength=>240, cattributes=>'id="i_assignto"')||
               '<A href='||l_url||'>'||
               '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>', cattributes=>'id=""');

  htp.tableRowClose;

  -- Delegate/Transfer field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL>' || htf.formRadio(cname=>'fmode',
                                                   cvalue=>'DELEGATE',
                                                   cchecked=>1) ||
                wf_core.translate('WFA_REASSIGN_DELEGATE') || '</LABEL>',
                calign=>'left', ccolspan=>2, cattributes=>'id=""');
  htp.tableRowClose;
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL>' || htf.formRadio(cname=>'fmode',
                                                   cvalue=>'TRANSFER') ||
                        wf_core.translate('WFA_REASSIGN_TRANSFER') || 
                        '</LABEL>',
                    calign=>'left', ccolspan=>2, cattributes=>'id=""');
  htp.tableRowClose;


  -- Always treat it as Delegate for now
  -- htp.formHidden('fmode','DELEGATE');

  -- Comments field
  htp.tableRowOpen;
  htp.tableData(cvalue=>'<LABEL FOR="i_comments">' || 
                        wf_core.translate('COMMENTS') ||
                        '</LABEL>',
                calign=>'right', cattributes=>'id=""');
  htp.tableData(cvalue=>htf.formTextarea2(cname=>'comments', nrows=>2,
                                         ncolumns=>65, cwrap=>'SOFT', 
                                         cattributes=>'id="i_comments"'),
                calign=>'left', cattributes=>'id=""');
  htp.tableRowClose;
  htp.formClose;
  htp.tableclose;

  -- Add submit button
  htp.tableopen(calign=>'CENTER', cattributes=>'summary=""');
  htp.tableRowOpen;

  htp.p('<TD id="">');

--1578431: Changed button to call SubmitForward() javascript function.
  wfa_html.create_reg_button ('javascript:SubmitForward()',
                              wf_core.translate ('WFMON_OK'),
                              wfa_html.image_loc,
                              'FNDJLFOK.gif',
                              wf_core.translate ('WFMON_OK'));

  htp.p('</TD>');

  htp.p('<TD id="">');

  wfa_html.create_reg_button ('Wfa_Html.ResponseFrame?nid='||nid||
                              '&nkey='||nkey,
                              wf_core.translate ('CANCEL'),
                              wfa_html.image_loc,
                              'FNDJLFCN.gif',
                              wf_core.translate ('CANCEL'));

  htp.p('</TD>');

  htp.tableRowClose;
  htp.tableClose;

  wfa_sec.Footer;
  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'ForwardFrame', nid, nkey);
    wfa_html.Error;
end ForwardFrame;

--
-- AttributeInfo
--   Generate page with details about a response attribute
-- IN
--   nid - notification id
--   name - attribute name
--
procedure AttributeInfo(
  nid in varchar2,
  name in varchar2)
is
  dispname varchar2(80);
  description varchar2(240);
  attrtype varchar2(8);
  format varchar2(240);
  dlookup varchar2(80);
begin
  -- Note:  No user authentication is done here to save time, since
  -- there is nothing secret about attribute descriptions.

  -- Get attribute info
  begin
    select MA.DISPLAY_NAME,
           MA.DESCRIPTION,
           MA.TYPE,
           MA.FORMAT
    into dispname, description, attrtype, format
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES_VL MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = to_number(AttributeInfo.nid)
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.NAME = AttributeInfo.name;
  exception
    when no_data_found then
      wf_core.token('NID', nid);
      wf_core.token('ATTRIBUTE', name);
      wf_core.raise('WFNTF_ATTR');
  end;

  -- Header and Page Title
  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_ATTRINFO')||': '||dispname);
  htp.headClose;

  -- Body contents
  wfa_sec.header(background_only=>TRUE);
  -- Title
  htp.center(htf.bold(wf_core.translate('WFA_ATTRINFO')||' '||dispname));
  htp.tableOpen(cattributes=>'summary=""');

  -- Description
  htp.tableRowOpen;
  htp.tableData(cvalue=>wf_core.translate('DESCRIPTION'), calign=>'right', cattributes=>'id=""');
  htp.tableData(cvalue=>htf.bold(description), calign=>'left',
                cattributes=>'bgcolor=white ehaders=""');
  htp.tableRowClose;

  -- Type
  htp.tableRowOpen;
  htp.tableData(cvalue=>wf_core.translate('TYPE'), calign=>'right', cattributes=>'id=""');
  htp.tableData(cvalue=>htf.bold(wfa_html_util.GetLookupMeaning('WFSTD_ATTRTYPE',
                                                  attrtype)),
                calign=>'left',
                cattributes=>'bgcolor=white id=""');
  htp.tableRowClose;

  -- Format
  htp.tableRowOpen;
  if (attrtype = 'VARCHAR2') then
    htp.tableData(cvalue=>wf_core.translate('MAXLENGTH'), calign=>'right');
    htp.tableData(cvalue=>htf.bold(nvl(format, '2000')), calign=>'left',
                  cattributes=>'bgcolor=white');
  elsif (attrtype = 'LOOKUP') then
    htp.tableData(cvalue=>wf_core.translate('LOOKUP'), calign=>'right', cattributes=>'id=""');

    -- Get displayed name of lookup
    begin
      select WLT.DISPLAY_NAME
      into dlookup
      from WF_LOOKUP_TYPES WLT
      where WLT.LOOKUP_TYPE = AttributeInfo.format;
    exception
      when no_data_found then
        dlookup := format;
    end;
    htp.tableData(cvalue=>htf.bold(dlookup), calign=>'left',
                  cattributes=>'bgcolor=white id=""');

  elsif format is not null then
    -- All others just print format only if it exists
    -- printing "default" is confusing UI.
    htp.tableData(cvalue=>wf_core.translate('FORMAT'), calign=>'right', cattributes=>'id=""');
    htp.tableData(cvalue=>htf.bold(nvl(format, '&'||'lt;'||
                          wf_core.translate('DEFAULT')||'&'||'gt;')),
                  calign=>'left',
                  cattributes=>'bgcolor=white id=""');
  end if;
  htp.tableRowClose;

  htp.tableClose;
  wfa_sec.Footer;
  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'AttributeInfo', nid, name);
    wfa_html.Error;
end AttributeInfo;

--
-- RespFrameSize (RPIVATE)
--   Calculate size of response frame using heuristic
-- IN
--   nid - notification id
-- RETURNS
--   Size of response frame in pixels
--
function RespFrameSize(
  nid in number)
return number
is
  respcnt       pls_integer;
  longcnt       pls_integer;
  urlcnt        pls_integer;
  respsize      pls_integer;

begin
  -- Approximate size of response frame using heuristic:
  -- The rule of thumb being :
  -- 1. Each non-result response counts as 40 pixels
  --    + url and multiline fields count twice
  --    + 1 for result button line
  -- 2. Frame must be in range 100 - 250 pixels
  -- 3. If there is a url respond attributet then go for the max size

  -- Count of multiline response fields
  select count(1)
  into urlcnt
  from WF_MESSAGE_ATTRIBUTES MA,
       WF_NOTIFICATIONS N
  where N.NOTIFICATION_ID = nid
  and MA.MESSAGE_NAME = N.MESSAGE_NAME
  and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
  and MA.SUBTYPE = 'RESPOND'
  and MA.TYPE = 'URL';

  if (urlcnt = 1) then
    respsize := 250;
  else

    -- Count of all response fields
    select count(1)
    into respcnt
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = nid
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND'
    and MA.TYPE <> 'FORM'
    and MA.NAME <> 'RESULT';

    -- Count of multiline response fields
    select count(1)
    into longcnt
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = nid
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND'
    and MA.TYPE = 'VARCHAR2'
    and decode(MA.TYPE, 'VARCHAR2', nvl(to_number(MA.FORMAT), 2000), 0) > 80;


    respsize := (respcnt + longcnt + 1) * 40;
    if (respsize < 100) then
      respsize := 100;
    elsif (respsize > 250) then
      respsize := 250;
    end if;
  end if;

  return(respsize);

exception
  when others then
    wf_core.context('Wfa_Html', 'RespFrameSize', to_char(nid));
    raise;
end RespFrameSize;

--
-- Detail (PROCEDURE)
--   generate detail screen
-- IN
--   nid - notification id
-- NOTE
--   Detail is overloaded.
--   This version is used by the Web notifications page.
--
procedure Detail(
  nid in varchar2)
is
  recipient     varchar2(320);
  realname      varchar2(360);
  s0            varchar2(2000);
  status        varchar2(8);
  respsize      pls_integer;
  username      varchar2(320);
  url_str       varchar2(4000);
  showforms     varchar2(1);
begin

  -- Get status
  Wf_Notification.GetInfo(to_number(nid), recipient, s0, s0, s0, s0, status);
  username := Wfa_Html.Authenticate(to_number(nid), null);
  Wf_Directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  htp.htmlOpen;
  htp.headOpen;
  if (status = 'OPEN') then
    htp.title(wf_core.translate('WFA_DTITLE') || ' ' || realname);
  else
    htp.title(wf_core.translate('WFA_CDTITLE') || ' ' || realname);
  end if;

  wfa_html.create_help_function('wf/links/det.htm?DETNOT');

  -- Add the java script to the header to open the dm window for
  -- any DM function that is executed.
  fnd_document_management.get_open_dm_display_window;

  htp.headClose;

  -- Calculate size of response frame
  respsize := RespFrameSize(to_number(nid));

  -- Open frameset, and set focus to response window.
  -- NOTE: MSIE does not support focus method.
  if (instr(owa_util.get_cgi_env('HTTP_USER_AGENT'), 'MSIE') <> 0) then
    htp.p('<FRAMESET ROWS="*,'||to_char(respsize)||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          owa_util.get_owa_service_path ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">');
  else
    htp.p('<FRAMESET ROWS="*,'||to_char(respsize)||
          '" onLoad="self.bottom.focus()" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          owa_util.get_owa_service_path ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">');
  end if;

  -- Descide to show Forms or not
  if (Wf_Core.translate('WF_INSTALL') = 'EMBEDDED') then
    showforms := 'T';
  else
    showforms := '';
  end if;

  if (showforms is not null) then
    htp.p('<FRAME NAME="top" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
        'src="'||owa_util.get_owa_service_path||
              'wfa_html.DetailFrame?nid='||nid||'&'||'showforms=T'||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          owa_util.get_owa_service_path ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">');
  else
    htp.p('<FRAME NAME="top" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
        'src="'||owa_util.get_owa_service_path||
              'wfa_html.DetailFrame?nid='||nid||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          owa_util.get_owa_service_path ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">');
  end if;

  url_str := owa_util.get_owa_service_path||
            'wfa_html.ResponseFrame?nid='||nid;

  if (showforms is not null) then
    url_str := url_str||'&'||'showforms=T';
  end if;

  -- Note frame name BOTTOM is hardcoded into wfa_html.detail
  htp.p('<FRAME NAME="bottom" MARGINHEIGHT=3 MARGINWIDTH=10 ' ||
        'src="'||url_str||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          owa_util.get_owa_service_path ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">');

  htp.p('</FRAMESET>');
  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html','Detail', nid);
    wfa_html.Error;
end Detail;

--
-- Detail (FUNCTION)
--   return standalone detail screen text
-- IN
--   nid - notification id
--   nkey - notification key
--   agent - web agent URL root
-- NOTE
--   Detail is overloaded.
--   This produces the version used by the mailer.
function Detail(
    nid   in number,
    nkey  in varchar2,
    agent in varchar2)
return varchar2
as
  username  varchar2(320);
  status    varchar2(8);
  realname  varchar2(360);
  s0        varchar2(240);
  result    varchar2(32000);
  respsize  pls_integer;
  key       varchar2(255);
  n_sig_policy varchar2(100);
begin

  Wf_Mail.GetSignaturePolicy(nid, n_sig_policy);

  if (wf_mail.send_accesskey and n_sig_policy not in ('PSIG_ONLY')) then
     key := nkey;

  -- Authenticate the user has access
  username := Wfa_Html.Authenticate(nid, nkey);

  -- Get notification recipient and status
  Wf_Notification.GetInfo(nid, username, s0, s0, s0, s0, status);
  Wf_Directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  -- Set title
  result := htf.htmlOpen ||g_newLine;
  result := result || htf.headOpen||g_newLine;
  if (status = 'OPEN') then
    result := result ||
        htf.title(wf_core.translate('WFA_DTITLE')||' '||realname)||
                  g_newLine;
  else
    result := result ||
        htf.title(wf_core.translate('WFA_CDTITLE')||' '||realname)||
                  g_newLine;
  end if;

--tr: dont execute the help function
--it calls htp procs which causes session to hang
--  wfa_html.create_help_function('wf/links/det.htm?DETNOT');

  result := result || htf.headClose||g_newLine;

  -- Calculate size of response frame
  respsize := RespFrameSize(nid);

  -- Open frameset.
  -- NOTE: Do NOT set the focus here, because it is not supported on
  -- all platforms, and it is unknown at this point what browser will
  -- be used to display the html returned to the mailer.
  result := result||'<FRAMESET ROWS="*,'||to_char(respsize)||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          agent ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||
            g_newLine;
  result := result ||
      '<FRAME NAME="top" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
      'src="'||agent||'/wfa_html.DetailFrame?nid='||to_char(nid)||
      '&'||'nkey='||key||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          agent ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||g_newLine;
  result := result ||
    '<FRAME NAME="bottom" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
    'src="'||agent||'/wfa_html.ResponseFrame?nid='||to_char(nid)||
    '&'||'nkey='||key||'" TITLE="' ||
          WF_CORE.Translate('WFA_DTITLE_TBAR') || '" LONGDESC="' ||
          agent ||
         'wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR">'||g_newLine;
  result := result || '</FRAMESET>'||g_newLine;
  result := result || htf.htmlClose;

  else
  -- Send_accesskey is set to N so we will generate a DirectLogin call.
  -- We do not need to authenticate the user, since the user will have
  -- to authenticate to view the notification.  After authentication,
  -- DirectLogin will redirect to the Detail (Web-interface) procedure so
  -- we will then confirm that the user logged in can also view the
  -- notification.
  key := NULL;

  result := htf.htmlOpen ||g_newLine;
  result := result || htf.headOpen||g_newLine;
  result := result ||
        htf.title(wf_core.translate('WFA_LOGIN_REQUEST'))||
                  g_newLine;
  result := result || htf.headClose||g_newLine;

  result := result||'<FRAMESET ROWS="100%, *">'||g_newLine;
            
  result := result ||
    '<FRAME NAME="DirectLogin" MARGINHEIGHT=10 MARGINWIDTH=10 NORESIZE' ||
    ' src="'||agent || '/' || wfa_sec.DirectLogin(nid) || '">'||g_newLine;
  result := result || '</FRAMESET>'||g_newLine;
  result := result || htf.htmlClose;
end if;

  return(result);
exception
  when others then
    wf_core.context('Wfa_Html', 'Detail', to_char(nid), nkey, agent);
    raise;
end Detail;

--
-- Detail2 (FUNCTION)
--   return standalone detail screen text
-- IN
--   nid - notification id
--   nkey - notification key
--   agent - web agent URL root
-- NOTE
--   Detail is overloaded.
--   This produces the version used by the mailer.
function Detail2(
    nid   in number,
    nkey  in varchar2,
    agent in varchar2)
return varchar2
as
  username  varchar2(320);
  status    varchar2(8);
  realname  varchar2(360);
  s0        varchar2(240);
  result    varchar2(32000);
  n_sig_policy varchar2(100);
  url       varchar2(4000);
  l_function_id number;
  params varchar2(240);
  validateAccess varchar2(1);

begin

  -- Authenticate the user has access
  username := Wfa_Html.Authenticate(nid, nkey);

  -- Get notification recipient and status
  Wf_Notification.GetInfo(nid, username, s0, s0, s0, s0, status);
  Wf_Directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  -- Set title
  result := htf.htmlOpen ||g_newLine;
  result := result || htf.headOpen||g_newLine;
  if (status = 'OPEN') then
    result := result ||
        htf.title(wf_core.translate('WFA_DTITLE')||' '||realname)||
                  g_newLine;
  else
    result := result ||
        htf.title(wf_core.translate('WFA_CDTITLE')||' '||realname)||
                  g_newLine;
  end if;

  result := result || htf.headClose||g_newLine;

  -- Open frameset.
  -- NOTE: Do NOT set the focus here, because it is not supported on
  -- all platforms, and it is unknown at this point what browser will
  -- be used to display the html returned to the mailer.
  if g_wfInstall='EMBEDDED' then
    result := result||'<FRAMESET ROWS="*,0" TITLE="' ||
            WF_CORE.Translate('WFA_DTITLE_TBAR')||'" '|| 
            -- 3428652 Removing reference to MOD PL/SQL
            -- 'LONGDESC="' ||rtrim(agent,'/')||
            -- '/wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR"'||
            '>'||g_newLine;

    url := wf_mail.Get_Ntf_Function_URL(nid => nid, n_key => nkey,
                                        n_sig_policy => n_sig_policy);
    result := result ||
        '<FRAME NAME="top" MARGINHEIGHT=10 MARGINWIDTH=10 ' ||
        'src="'||url||'" TITLE="' ||
            WF_CORE.Translate('WFA_DTITLE_TBAR') || '" '||
            -- 3428652 Removing reference to MOD PL/SQL
            -- 'LONGDESC="' ||rtrim(agent,'/')||
            -- '/wfa_html.LongDesc?p_token=WFA_DTITLE_TBAR"'||
            '>'||g_newLine;
    result := result || '</FRAMESET>'||g_newLine;
    result := result || htf.htmlClose;
  else
    -- While the call is within standalone, continue to 
    ---operate as before.
    result := wfa_html.detail(nid, nkey, agent);
  end if;

  return(result);
exception
  when others then
    wf_core.context('Wfa_Html', 'Detail', to_char(nid), nkey, agent);
    raise;
end Detail2;


-- DetailLink
--   display standalone detail screen text
-- IN
--   nid - notification id
--   nkey - notification key
--   agent - web agent URL root
-- NOTE
--   Detaillink called function Detail above.
--   This produces the version used by the mailer.
procedure DetailLink(
    nid   in number,
    nkey  in varchar2,
    agent in varchar2)
is
  m_html varchar2(32000);
begin
  m_html := Wfa_Html.Detail2(nid, nkey, agent);
  htp.p(m_html);

exception
  when others then
    wf_core.context('Wfa_Html', 'DetailLink', to_char(nid), nkey, agent);
    raise;
end DetailLink;


-- SubmitForward
--   Submit notification forward
-- IN
--   h_nid - notification id
--   forwardee - new recipient field
--   display_forwardee - display name for the new recipient
--   comments - forwarding comments field
--   fmode - reassign mode can be:
--           transfer - transferring responsibility
--           delegate - delegate responsibility
--   submit - submit forward button
--   cancel - cancel forward button
--   nkey - access key for mailed html
procedure SubmitForward(
  h_nid               in varchar2,
  forwardee           in varchar2,
  display_forwardee   in varchar2,
  comments            in varchar2,
  fmode               in varchar2,
  submit              in varchar2,
  cancel              in varchar2,
  nkey                in varchar2)
is
  nid        pls_integer;
  username   varchar2(320);
  l_forwardee  varchar2(320);
  pseudo_login boolean := FALSE;
begin
  -- If CANCEL button, swap frame to ResponseFrame and exit.
  if (cancel is not null) then
    Wfa_Html.ResponseFrame(h_nid, nkey);
    return;
  end if;

  if (nkey is not null) then
    pseudo_login := TRUE;
  end if;

  -- Fully resolve forwardee name
  l_forwardee := forwardee;
  wfa_html.validate_display_name (display_forwardee, l_forwardee);

  -- REASSIGN button.
  -- Authenticate user
  nid := to_number(h_nid);
  username := Wfa_Html.Authenticate(nid, nkey);

  -- Make sure the comments field is <= 240.
  if ( lengthb(comments) > 240 ) then
    WF_CORE.Raise('WFA_MAX_COMMENTS');
  end if;

  -- Submit the forward
  if (fmode = 'DELEGATE') then
    if (comments is not null) then
-- ### implement this in next release
--    wf_notification.Forward(nid, upper(l_forwardee), comments, username);
      wf_notification.Forward(nid, upper(l_forwardee), comments);
    else
-- ### implement this in next release
--    wf_notification.Forward(nid, upper(l_forwardee), '', username);
      wf_notification.Forward(nid, upper(l_forwardee));
    end if;
  elsif (fmode = 'TRANSFER') then
    if (comments is not null) then
-- ### implement this in next release
--    wf_notification.Transfer(nid,upper(l_forwardee), comments, username);
      wf_notification.Transfer(nid,upper(l_forwardee), comments);
    else
-- ### implement this in next release
--    wf_notification.Transfer(nid,upper(l_forwardee), '', username);
      wf_notification.Transfer(nid,upper(l_forwardee));
    end if;
  end if;

  if (pseudo_login) then
    htp.htmlOpen;
    htp.headOpen;

    htp.center(htf.bold(WF_CORE.Translate('WFA_ASSIGNED') || ': ' ||
               WF_DIRECTORY.GetRoleDisplayName(upper(l_forwardee)) || '.'));

    htp.headClose;
    htp.htmlClose;

  else
    -- Putting WorkList in the browser window
    Wfa_Html.GotoURL('Wfa_Html.WorkList', '_top');
  end if;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html','SubmitForward', h_nid, nkey, forwardee,
        comments);
    wfa_html.Error;
end SubmitForward;

-- SubmitResponse
--   Submit notification response
-- IN
--   h_nid - notification id
--   h_fnames - array of field names
--   h_fvalues - array of field values
--   h_fdocnames - array of documentnames - a throwaway value from form
--   h_counter - number of fields passed in fnames and fvalues
--   submit - submit response button
--   forward - forward button
--   nkey - access key for mailed html
procedure SubmitResponse(
  h_nid        in varchar2,
  h_fnames     in Name_Array,
  h_fvalues    in Value_Array,
  h_fdocnames  in Value_Array,
  h_counter    in varchar2,
  submit       in varchar2,
  forward      in varchar2,
  nkey         in varchar2)
as
  nid        pls_integer;
  username   varchar2(320);
  x          pls_integer;
  pseudo_login boolean := FALSE;
begin
  -- If FORWARD button, swap frame to ForwardFrame and exit.
  if (forward is not null) then
    Wfa_Html.ForwardFrame(h_nid, nkey);
    return;
  end if;

  if (nkey is not null) then
     pseudo_login := TRUE;
  end if;

  -- One of RESPOND buttons pushed - submit response.
  -- Authenticate user
  nid := to_number(h_nid);
  username := Wfa_Html.Authenticate(nid, nkey);

  -- Set attributes in the reponse array.
  -- Start at 2 to step over the Dummy_Name/Dummy_Value pair added at
  -- the start of the array.
  for x in 2 .. to_number(h_counter) loop
    wfa_html_util.SetAttribute(nid, h_fnames(x), h_fvalues(x), h_fdocnames(x));
  end loop;

  -- Submit response
  --   If there is a problem, go back to the ResponseFrame
  --   otherwise, go back to the worklist
  begin
    -- Do not need to preserve context
    wf_engine.preserved_context := FALSE;
    wf_notification.Respond(nid, null, username);

  exception
    when others then
      -- ### We do not want this now.  Since there is real error message
      -- ### we want users to see, we raise an exception instead.
      -- Reload response window to reflect changes
      -- Wfa_Html.ResponseFrame(h_nid, nkey);

      -- When an exception ocurr, raise it and show the error stack.
      raise;
  end;

  if (pseudo_login) then
    Wfa_Html.ResponseFrame(h_nid, nkey);

  else
    -- Putting WorkList in the browser window
    Wfa_Html.GotoURL('Wfa_Html.WorkList', '_top');
  end if;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html','SubmitResponse',
                    h_nid, nkey, submit, forward);
    wfa_html.Error;
end SubmitResponse;

-- GotoURL
--   GotoURL let you open an url in a specify place.  This is very useful
--   when you need to go from a child frame to the full browser window,
--   for instnace.
--   So far, this is the only way to break away from a child frame.
-- IN
--   url - Fully qualified universal resouce location
--   location - Where you want to open it.  Samples of values are
--              _blank  - unnamed window
--              _self   - the current frame
--              _parent - the parent frame of the current one
--              _top    - the full Web browser window
--              "myWin" - name of the new window
--
procedure GotoURL(
  url in varchar2,
  location in varchar2,
  attributes in varchar2
)
is
begin
  htp.htmlOpen;
  htp.headOpen;
      htp.p('<SCRIPT LANGUAGE="JavaScript"> <!-- hide the script''s contents from feeble browsers');

      htp.p(
         'function wf_open_url(url,location,attributes)
          {
             window.open(url,location,attributes);
          }
          function wf_open_url(url,location)
          {
             window.open(url,location);
          }'
      );

      htp.p('<!-- done hiding from old browsers --> </SCRIPT>');

      htp.p('<NOSCRIPT>');
      htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
      htp.p('</NOSCRIPT>');

  htp.headClose;

  if (attributes is null) then
    htp.p ('<BODY ONLOAD="wf_open_url('''||url||''', '''||location||''')">');
  else
    htp.p ('<BODY ONLOAD="wf_open_url('''||url||''', '''||location||''', '''
                                ||attributes||''')">');
  end if;
  htp.bodyClose;
  htp.htmlClose;
end;

-- SubmitSelectedResponse
--   Submit selected notification response
-- IN
--   nids - notification ids
--   close - submit response button
--   forward - forward button
--   showto - display the TO column
--   nkey - access key for mailed html
procedure SubmitSelectedResponse(
  nids         in Name_Array,
  close        in varchar2,
  forward      in varchar2,
  showto       in varchar2,
  nkey         in varchar2)
as
  username varchar2(320);    -- Username to query
  n_priority varchar2(80);  -- priority icon
  n_response varchar2(80);  -- required response icon
  l_message     varchar2(240)   := wf_core.translate ('WFPREF_LOV');

  lang_codeset varchar2(50); -- Language Codeset from environment
                             -- (e.g. WE8ISO8859P1)

  nid        pls_integer;
  x          pls_integer;

  l_url         varchar2(1000);
  l_media       varchar2(240) := wfa_html.image_loc;
  l_icon        varchar2(30) := 'FNDILOV.gif';

  cursor s_cursor(mnid in number) is
    select NID,
           PRIORITY,
           LANGUAGE,
           MESSAGE_TYPE,
           RECIPIENT_ROLE,
           SUBJECT,
           BEGIN_DATE,
           DUE_DATE,
           END_DATE,
           DISPLAY_STATUS,
           STATUS,
           FROM_USER,
           TO_USER
    from WF_WORKLIST_V
    where NID = mnid;


  cursor attrs(mnid in number) is
    select MA.NAME
    from WF_NOTIFICATION_ATTRIBUTES NA,
         WF_MESSAGE_ATTRIBUTES_VL MA,
         WF_NOTIFICATIONS N
    where N.NOTIFICATION_ID = mnid
    and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
    and MA.MESSAGE_NAME = N.MESSAGE_NAME
    and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
    and MA.NAME = NA.NAME
    and MA.SUBTYPE = 'RESPOND'
    and MA.TYPE <> 'FORM'
    and MA.NAME = 'RESULT';

  notrec s_cursor%rowtype;
  result attrs%rowtype;
begin
  -- If no nid was passed in, it failed before reaching to this
  -- procedure.

  -- There is always a dummy nid passed in.  We will handle it here.
  -- Make sure subsequent index start at 2 not 1.
  if (to_number(nids.count) = 1) then
    wf_core.raise('WFNTF_NO_SELECT');
  end if;

  -- Get language codeset
  lang_codeset := substr(userenv('LANGUAGE'),instr(userenv('LANGUAGE'),'.')+1,
                         length(userenv('LANGUAGE')));

  if (forward is not null) then
    -- Delegating ...
    -- Submit Everything to the form that get forwardee and comment

    htp.htmlOpen;
      htp.headOpen;
      htp.title(wf_core.translate('WFA_FORWARDTITLE'));

      wfa_html.create_help_function('wf/links/fwd.htm?FWD_WEB');

      fnd_document_management.get_open_dm_display_window;

      htp.headClose;
      wfa_sec.Header(FALSE, owa_util.get_owa_service_path ||'wfa_html.Find',
          wf_core.translate('WFA_FORWARDTITLE'), TRUE);

      htp.formOpen(curl=>owa_util.get_owa_service_path||'wfa_html.ForwardNids',
                   cmethod=>'POST', cattributes=>'TARGET="_top" NAME="WF_HTML"');

      -- Dummy Hidden H_NIDS Field to handle situation when nothing is selected
      htp.formHidden('H_NIDS', -1);

      -- Forwardee field
      htp.tableOpen (calign=>'CENTER', cattributes=>'summary=""');
      htp.tableRowOpen;
      htp.tableData(cvalue=>'<LABEL FOR="i_assignto">' ||
                            wf_core.translate('WFA_ASSIGNTO') ||
                            '</LABEL>',
                    calign=>'right', cattributes=>'id=""');

  htp.formHidden('forwardee', null);

  -- add LOV here: Note:bottom is name of frame.
  -- Note: The REPLACE function replaces all the space characters with
  -- the proper escape sequence.
  l_url := 'javascript:fnd_open_dm_display_window('||''''||
            REPLACE('wf_lov.display_lov?p_lov_name='||'owner'||
            '&p_display_name='||'WFA_FIND_USER'||
            '&p_validation_callback=wfa_html.wf_user_val'||
            '&p_dest_hidden_field=top.opener.parent.document.WF_HTML.forwardee.value'||
            '&p_current_value=top.opener.parent.document.WF_HTML.display_forwardee.value'||
            '&p_display_key='||'Y'||
            '&p_dest_display_field=top.opener.parent.document.WF_HTML.display_forwardee.value',
              ' ', '%20')||''''||',500,500)';

  -- print everything together so ther is no gap.
  htp.tabledata(htf.formText(cname=>'display_forwardee', csize=>30, 
                             cmaxlength=>360,
                             cattributes=>'id="i_assignto"')||
               '<A href='||l_url||'>'||
               '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>', cattributes=>'id=""');

      htp.tableRowClose;

      -- Delegate/Transfer field
      htp.tableRowOpen;
      htp.tableData(cvalue=>'<LABEL>' || htf.formRadio(cname=>'fmode',
                                                       cvalue=>'DELEGATE',
                                                       cchecked=>1) || 
                           wf_core.translate('WFA_GROUP_REASSIGN_DELEGATE') ||
                           '</LABEL>',
                    calign=>'left', ccolspan=>2, cattributes=>'id=""');
      htp.tableRowClose;
      htp.tableRowOpen;
      htp.tableData(cvalue=>'<LABEL>' || htf.formRadio(cname=>'fmode',
                                                       cvalue=>'TRANSFER') || 
                           wf_core.translate('WFA_GROUP_REASSIGN_TRANSFER') || 
                           '</LABEL>',
                    calign=>'left', ccolspan=>2, cattributes=>'id=""');
      htp.tableRowClose;

      -- Always treat it as Delegate for now
      -- htp.formHidden('fmode', 'DELEGATE');

      -- Comments field
      htp.tableRowOpen;
      htp.tableData(cvalue=>'<LABEL FOR="i_comments">' || 
                            wf_core.translate('COMMENTS') ||
                            '</LABEL>',
                    calign=>'right', cattributes=>'id=""');
      htp.tableData(cvalue=>htf.formTextarea2(cname=>'comments', nrows=>2,
                                             ncolumns=>65, cwrap=>'SOFT'),
                    calign=>'left', cattributes=>'id="i_comments"');
      htp.tableRowClose;
      htp.tableClose;

      -- Submit and cancel buttons
      htp.tableopen(calign=>'CENTER', cattributes=>'summary=""');
      htp.tableRowOpen;

      htp.p('<TD id="">');

      wfa_html.create_reg_button ('javascript:document.WF_HTML.submit()',
                                  wf_core.translate ('WFMON_OK'),
                                  wfa_html.image_loc,
                                  'FNDJLFOK.gif',
                                  wf_core.translate ('WFMON_OK'));

      htp.p('</TD>');

      htp.p('<TD id="">');

      wfa_html.create_reg_button ('javascript:window.history.back()',
                                  wf_core.translate ('CANCEL'),
                                  wfa_html.image_loc,
                                  'FNDJLFCN.gif',
                                  wf_core.translate ('CANCEL'));

      htp.p('</TD>');

      htp.tableRowClose;
      htp.tableClose;

      htp.br;

      -- There are some notifications for the user. Construct the page.
      htp.tableOpen('border=1 cellpadding=3 bgcolor=white width=100% summary=""');

      -- Column headers
      htp.tableRowOpen(cattributes=>'bgcolor=#006699');

      htp.tableHeader(cvalue=>'<LABEL FOR="i_select"><font color=#FFFFFF>'||
                      wf_core.translate('SELECT')||'</font></LABEL>',
                      calign=>'Center',
                      cattributes=>'id="' ||
                                   WF_CORE.Translate('SELECT') || '"');

      htp.tableHeader(cvalue=>'<font color=#FFFFFF>'||
                      wf_core.translate('PRIORITY')||'</font>',
                      calign=>'Center',
                      cattributes=>'id="' ||
                                   WF_CORE.Translate('PRIORITY') || '"');

      htp.tableHeader('<font color=#FFFFFF>'||wf_core.translate('TYPE')||
          '</font>', 'Center', cattributes=>'id="' ||
                                            WF_CORE.Translate('TYPE') || '"');

      htp.tableHeader('<font color=#FFFFFF>'||wf_core.translate('FROM')||
          '</font>', 'Center', cattributes=>'id="' ||
                                            WF_CORE.Translate('FROM') || '"');

      if (showto = 'T') then
        htp.tableHeader('<font color=#FFFFFF>'||wf_core.translate('TO')||
          '</font>', 'Center', cattributes=>'id="' ||
                                            WF_CORE.Translate('TO') || '"');
      end if;

      htp.tableHeader('<font color=#FFFFFF>'||wf_core.translate('SUBJECT')
          ||'</font>', 'Center', cattributes=>'id="' ||
                                              WF_CORE.Translate('SUBJECT') ||
                                              '"');

      htp.tableHeader('<font color=#FFFFFF>'||
                      wf_core.translate('BEGIN_DATE')||'</font>', 'Center',
                      cattributes=>'id="' || WF_CORE.Translate('BEGIN_DATE') ||
                      '"');

      htp.tableHeader('<font color=#FFFFFF>'||
          wf_core.translate('DUE_DATE')||'</font>', 'Center',
          cattributes=>'id="' || WF_CORE.Translate('DUE_DATE') || '"');

      htp.tableRowClose;

      -- Print summary
      for x in 2 .. to_number(nids.count) loop
        open s_cursor(nids(x));
        fetch s_cursor into notrec;
        if (s_cursor%notfound) then
          Wf_Core.Token('NID', nids(x));
          Wf_Core.Raise('WFNTF_NID');
          exit;
        end if;
        close s_cursor;

        -- Figure out the priority first
        n_priority := GetPriorityIcon(notrec.priority);

        -- Figure out whether response is required
        n_response := null;
        if (notrec.status = 'OPEN') then
          open attrs(notrec.nid);
          fetch attrs into result;
          if (attrs%found) then
            n_response := wfa_html.image_loc||'reqresp.gif';
          end if;
          close attrs;
        end if;

        -- Displaying a row
        htp.tableRowOpen(null, 'TOP');
          -- We can check nids in this way because nids will be in the same
          -- order of the query.
          --
          htp.tableData(htf.formCheckbox(cname=>'H_NIDS', cvalue=>notrec.nid,
                                         cchecked=>1, 
                                         cattributes=>'id="i_select"'), 
                        'center', cattributes=>'headers="' ||
                                               WF_CORE.Translate('SELECT') ||
                                               '"');

          htp.p('<TD ALIGN=left id="">');
            htp.tableOpen('border=0 width="100%" summary=""');
            htp.tableRowOpen(null,'TOP');
            if (n_priority is null) then
              -- ### width below is ignored in html code, took it out.
              -- htp.tableData('&'||'nbsp;', 'left', 'width="50%"');
              htp.tableData('&'||'nbsp;', 'left', 
                            cattributes=>'headers="' || 
                                         WF_CORE.Translate('PRIORITY') || '"');
            else
              htp.tableData(htf.img(curl=>n_priority, 
                                    calt=>WFA_HTML.g_priority),
                            'center', 
                            cattributes=>'headers="' ||
                                         WF_CORE.Translate('PRIORITY') || '"');
            end if;
            htp.tableRowClose;
            htp.tableClose;
          htp.p('</TD>');
          htp.tableData(notrec.message_type, 'left', 
                        cattributes=>'headers="' || 
                                     WF_CORE.Translate('TYPE') || '"');
          htp.tableData(nvl(notrec.from_user, '&nbsp'), 'left', 
                        cattributes=>'headers="' || 
                                     WF_CORE.Translate('FROM') || '"');
          if (showto = 'T') then
            htp.tableData(notrec.to_user, 'left', 
                          cattributes=>'id="' ||
                                       WF_CORE.Translate('TO') || '"');
          end if;
          -- If response is required, append response required icon to subject
          if (n_response is null) then
               htp.tableData(notrec.subject, calign=>'left', 
                             cattributes=>'headers="' ||
                                          WF_CORE.Translate('SUBJECT') || '"');
          else
               htp.tableData(
                      cvalue=>notrec.subject||'&'||
                              'nbsp;'||htf.img(curl=>n_response,
                      calt=>WF_CORE.Translate('WFSRV_RECIPIENT_MUST_RESPOND')),
                      calign=>'left', 
                      cattributes=>'headers="' || 
                      WF_CORE.Translate('SUBJECT') || '"');
          end if;

          htp.tableData(cvalue=>to_char(notrec.begin_date ), calign=>'left',
              cnowrap=>1, cattributes=>'headers="' ||
                                       WF_CORE.Translate('BEGIN_DATE') || '"');
          htp.tableData(cvalue=>nvl(to_char(notrec.due_date), '<BR>'),
                        calign=>'left', 
                        cnowrap=>1, 
                        cattributes=>'headers="' ||
                                     WF_CORE.Translate('DUE_DATE') || '"');
        htp.tableRowClose;

      end loop;

      htp.tableClose;

      htp.formHidden('nkey',nkey);
      htp.formClose;
    htp.htmlClose;

    goto worklist;
  end if;


  -- For each nid, do the appropriate operation
  for x in 2..nids.count loop
    nid := to_number(nids(x));
    -- Authenticate user
    username := Wfa_Html.Authenticate(nid, nkey);

    if (close is not null) then
      -- Closing and other activities ...
      begin
        wf_notification.Close(nid,username);
      exception
        when others then
          raise;
      end;
    end if;
  end loop;
  -- Go back to WorkList Screen
  -- ### Using GotoURL here will be a bit costly, but has a nice side effect
  -- ### that the "Location" indicated in the browser will match that of
  -- ### what you see.
  -- ### Wfa_html.GotoURL('Wfa_Html.WorkList');
  Wfa_html.WorkList;

  --
  -- Go back to the previous function that will go back to WorkList screen
  --
<<worklist>>
  return;
exception
  when others then
    rollback;
    if (s_cursor%isopen) then
      close s_cursor;
    end if;
    if (attrs%isopen) then
      close attrs;
    end if;
    wf_core.context('Wfa_Html','SubmitSelectedResponse', user);
    wfa_html.Error;
end SubmitSelectedResponse;


-- ForwardNids
--   Forward for each notification ids
--   Forward can be Delegating or Transferring
--   Delegating is for notification only.
--   Transferring is reassign the whole responsibility to other
-- IN
--   h_nids -    hidden notification ids
--   forwardee - forwardee role specified
--   comments -  comments included
--   fmode -     reassign mode can be:
--               transfer -  transferring responsibility
--               delegate -  delegate responsibility
--   cancel -    cancel button
procedure ForwardNids(
  h_nids               in Name_Array,
  forwardee            in varchar2,
  display_forwardee    in varchar2,
  comments             in varchar2,
  fmode                in varchar2,
  submit               in varchar2,
  cancel               in varchar2,
  nkey                 in varchar2)
as
  username   varchar2(320);
  x          pls_integer;
  nid        pls_integer;
  l_forwardee varchar2(320);

begin
  -- There is always a dummy nid passed in.  We will handle it here.
  -- Make sure subsequent index start at 2 not 1.
  if (to_number(h_nids.count) = 1) then
    wf_core.raise('WFNTF_NO_SELECT');
  end if;

  -- Fully resolve forwardee name
  l_forwardee := forwardee;
  wfa_html.validate_display_name (display_forwardee, l_forwardee);

  -- Otherwise, for each notification, delegate or transfer
  for x in 2..h_nids.count loop
    -- Authenticate user
    nid := to_number(h_nids(x));
    username := Wfa_Html.Authenticate(nid, nkey);

    -- Delegating to forwardee with comments
    if (fmode = 'DELEGATE') then
      if (comments is not null) then
-- ### implement this in next release
--      Wf_Notification.Forward(nid, upper(l_forwardee), comments, username);
        Wf_Notification.Forward(nid, upper(l_forwardee), comments);
      else
-- ### implement this in next release
--      Wf_Notification.Forward(nid, upper(l_forwardee), '', username);
        Wf_Notification.Forward(nid, upper(l_forwardee));
      end if;
    elsif (fmode = 'TRANSFER') then
      -- Transferring to fowardee with comments

      if (comments is not null) then
-- ### implement this in next release
--      Wf_Notification.Transfer(nid, upper(l_forwardee), comments, username);
        Wf_Notification.Transfer(nid, upper(l_forwardee), comments);
      else
-- ### implement this in next release
--      Wf_Notification.Transfer(nid, upper(l_forwardee), '', username);
        Wf_Notification.Transfer(nid, upper(l_forwardee));
      end if;
    end if;
  end loop;

  -- Back to the worklist
  <<worklist>>
  Wfa_Html.WorkList;
  return;
  exception
    when others then
      rollback;
      wfa_html.Error;
      return;
end ForwardNids;

/*===========================================================================
  PROCEDURE NAME:       create_help_function

  DESCRIPTION:
                        Create the java script function to support the Help
                        Icon from the header

   Note:  The help file parameter must include the subdirectory under
          /OA_DOC/lang/ and the actual file name which will either be
          wf or wfnew.
      ie  p_help_file = 'wf/notif16.htm'
          p_help_file = 'wfnew/wfnew48.htm'
============================================================================*/
procedure create_help_function (

 p_help_file IN VARCHAR2

) IS

install_type VARCHAR2(80);
l_help_target VARCHAR2(240) := NULL;
l_lang       VARCHAR2(2000);
help_prefix  VARCHAR2(2000);

BEGIN

  BEGIN

  /*
  ** Get the language environment variable
  ** for this user.
  */
  SELECT USERENV('LANG')
  INTO l_lang
  FROM DUAL;

  EXCEPTION
  WHEN OTHERS THEN
     l_lang := 'US';
  END;

  /*
  ** Check the installation type.  If it is workflow standalone
  ** then use the file prefix method of getting to the help
  ** content.  Otherwise use the fnd function method to get and
  ** display the help content.
  */
  install_type := wf_core.translate('WF_INSTALL');

  if (install_type = 'STANDALONE') THEN

     help_prefix := '/OA_DOC/';

     htp.p('<!-- Copyright ' || '&' || '#169; 1997 Oracle Corporation, All rights reserved. -->');
     htp.p('<SCRIPT LANGUAGE="JavaScript">
     <!-- hide the script''s contents from feeble browsers');

     htp.p('function help_window(){
        help_win = window.open('||''''||help_prefix||
                'US/' || p_help_file ||''''||
            ', "help_win","resizable=yes,scrollbars=yes,toolbar=yes,width=600,height=500");
        help_win = window.open('||''''||help_prefix||
               'US/' || p_help_file ||''''||
            ', "help_win","resizable=yes,scrollbars=yes,toolbar=yes,width=600,height=500")
}
');

     htp.p('<!-- done hiding from old browsers --></SCRIPT>');

     htp.p('<NOSCRIPT>');
     htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
     htp.p('</NOSCRIPT>');

  else

     /*
     ** If you're going against apps then strip out everything
     ** except the target name
     */
     IF (INSTR(p_help_file, '?') > 0) THEN

         l_help_target := substrb(p_help_file, INSTR(p_help_file, '?') + 1);

     ELSE

         l_help_target := p_help_file;

     END IF;

     wfa_sec.create_help_syntax (l_help_target, l_lang);

  end if;

exception
  when others then
    Wf_Core.Context('wfa_html', 'create_help_function',
       p_help_file);
    wfa_html.Error;

END create_help_function;

/*===========================================================================
  FUNCTION NAME:        conv_special_url_chars

  DESCRIPTION:
                        Convert all of the ASCII special characters that are
                        disallowed as a part of a URL.  The encoding requires
                        that we convert the special characters to HEX for
                        any characters in a URL string that is built
                        manually outside a form get/post.
                        This API now also converts multibyte characters
                        into their HEX equivalent.

============================================================================*/
FUNCTION conv_special_url_chars (p_url_token IN VARCHAR2) RETURN VARCHAR2
IS
 c_unreserved constant varchar2(72) :=
   '-_.!*''()~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
 c_reserved    constant varchar2(72) := '%">^{}<[]`|/#?&=$:;+';
 l_tmp         varchar2(32767) := '';
 l_onechar     varchar2(4);
 l_byte_len    integer;
 i             integer;
 l_str         varchar2(48);

BEGIN
 if p_url_token is NULL then
    return NULL;
 end if;
 for i in 1 .. length(p_url_token) loop
   l_onechar := substr(p_url_token,i,1);
   --Extracting out each character to be replaced.
   if instr(c_unreserved, l_onechar) > 0 then
     --Check if  it is part of the ASCII unreserved
     --excluded from encoding just append to the URL
     --string
     l_tmp := l_tmp || l_onechar;

   elsif l_onechar = ' ' then
     --Space encoded as '%20'
     l_tmp := l_tmp || '%20';

   elsif instr(c_reserved,l_onechar) >0 then
     --If it is any of the reserved characters in ascii
     --replace with equivalent HEX
     l_onechar := REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(
                  REPLACE(l_onechar,
                  '%','%25'),
                  ' ','%20'),
                  '"','%22'),
                  '>','%3E'),
                  '^','%5E'),
                  '{','%7B'),
                  '}','%7D'),
                  '<','%3C'),
                  '[','%5B'),
                  ']','%5D'),
                  '`','%60'),
                  '|','%7C'),
                  '/','%2F'),
                  '#','%23'),
                  '?','%3F'),
                  '&','%26'),
                  '=','%3D'),
                  '$','%24'),
                  ':','%3A'),
                  ';','%3B'),
                  '+','%2B'),
                  '''','%27');
     l_tmp := l_tmp || l_onechar;
   else
     --For multibyte
     -- 1. Obtain length for each character
     -- 2. ascii(l_char)decimal representation in the database
     --    character set
     -- 3. Change it to the format model :
     --    to_char(ascii(l_onechar),'FM0X')
     -- 4. Add to the already encoded string.
     --    characters
     l_byte_len := lengthb(l_onechar);
     if l_byte_len = 1 then
       l_tmp := l_tmp || '%' ||
        substr(to_char(ascii(l_onechar),'FM0X'),1,2);
     elsif l_byte_len = 2 then
       l_str := to_char(ascii(l_onechar),'FM0XXX');
       l_tmp := l_tmp
            || '%' || substr(l_str,1,2)
            || '%' || substr(l_str,3,2);
     elsif l_byte_len = 3 then
       l_str := to_char(ascii(l_onechar),'FM0XXXXX');
       l_tmp := l_tmp
                || '%' || substr(l_str,1,2)
                || '%' || substr(l_str,3,2)
                || '%' || substr(l_str,5,2);
     elsif l_byte_len = 4 then
       l_str := to_char(ascii(l_onechar),'FM0XXXXXXX');
       l_tmp := l_tmp
                || '%' || substr(l_str,1,2)
                || '%' || substr(l_str,3,2)
                || '%' || substr(l_str,5,2)
                || '%' || substr(l_str,7,2);
     else            -- maximum precision
       wf_core.raise('WFENG_PRECESSION_EXCEED');
     end if;
   end if;
 end loop;
 return l_tmp;
exception
  when others then
    Wf_Core.Context('wfa_html', 'conv_special_url_chars',
       p_url_token);
    wfa_html.Error;
END conv_special_url_chars;


--
-- User_LOV
--   Create the data for the User List of Values
--   NOTE: This is not used by APPS.  Otherwise, we will have performance
--         problem with this query against wf_roles.
--
procedure User_LOV (p_titles_only     IN VARCHAR2,
                    p_find_criteria IN VARCHAR2)

IS

l_username      VARCHAR2(320);
l_display_name  VARCHAR2(360); -- enlarged from 80 to match db definition
l_name          VARCHAR2(320); -- enlarged from 30 to match db definition
l_row_count NUMBER := 0;

CURSOR c_user_lov (c_find_criteria IN VARCHAR2) IS
SELECT
 name,
 display_name
FROM   wf_roles
WHERE  upper(name) like upper(c_find_criteria)
  AND  upper(name) not like '~WF_ADHOC-%'
  AND  status <> 'INACTIVE'
ORDER  BY name;

BEGIN

   -- Authenticate user
   wfa_sec.GetSession(l_username);

   IF (p_titles_only = 'N') THEN

      SELECT COUNT(*)
      INTO   l_row_count
      FROM   wf_roles
      WHERE  upper(name) like upper(p_find_criteria)||'%'
        AND  upper(name) not like '~WF_ADHOC-%'
        AND  status <> 'INACTIVE';

   END IF;

   htp.p(wf_core.translate('WFA_FIND_USER'));
   htp.p('2');
   htp.p(TO_CHAR(l_row_count));
   htp.p(wf_core.translate('NAME'));
   htp.p('40');
   htp.p(wf_core.translate('DISPLAY_NAME'));
   htp.p('60');

   IF (p_titles_only = 'N') THEN

      OPEN c_user_lov (p_find_criteria||'%');

      /*
      ** Loop through all the language rows for the given find_criteria
      ** and write them out to the web page
      */
      LOOP

         FETCH c_user_lov INTO
             l_name, l_display_name;

         EXIT WHEN c_user_lov%NOTFOUND;

         htp.p (l_name);
         htp.p (l_display_name);

      END LOOP;

   END IF;

exception
  when others then
    rollback;
    if (c_user_lov%isopen) then
      close c_user_lov;
    end if;
    wf_core.context('Wfa_Html', 'user_lov',p_titles_only, p_find_criteria);
    wfa_html.Error;
end User_Lov;

procedure logout is
        username varchar2(320);
begin
        wfa_sec.GetSession(username);
        owa_util.mime_header('text/html', FALSE);
        owa_cookie.send('WDB_GATEWAY_LOGOUT','YES', '', '/');
        owa_util.http_header_close;
        htp.htmlOpen;
        htp.headOpen;
        htp.title(wf_core.translate('WFA_HOMETITLE'));
        wfa_html.create_help_function('wf/links/web.htm?WEBHOME');
        htp.headClose;

        -- Page header
        wfa_sec.Header(FALSE, '', wf_core.translate('WF_WORKFLOW_TITLE')||
                        ' - '|| wf_core.translate('WF_VERSION'), FALSE);

        htp.center(wf_core.translate('LOGOUT_MESSAGE')
         ||' '||htf.anchor(curl=>wfa_html.base_url||'/wfa_html.home',
                          ctext=>wf_core.translate('CLICK_HOME')));

        wfa_sec.Footer;
        htp.htmlClose;
exception
  when others then
    wf_core.context('Wfa_Html','logout');
    wfa_html.Error;
end logout;


procedure Home(message in varchar2)
is
  username   varchar2(320);   -- Username to query
  realname   varchar2(360);   -- Display name of username
  admin_role varchar2(320);   -- Role for admin mode
  admin_mode varchar2(1);        -- Does user have admin privledges
  s0         varchar2(2000);

begin

  BEGIN
    -- Check session and current user
    wfa_sec.GetSession(username);
    username := upper(username);

    -- Validate the user
    if (username is null) then
        -- No username entered
        wfa_html.Login('WFA_ENTER_ID');
        return;
    end if;

  EXCEPTION
     WHEN NO_DATA_FOUND THEN
        -- No username entered
        wfa_html.Login('WFA_ENTER_ID');
        return;
     WHEN OTHERS THEN
        raise;
  END;

  wf_directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  admin_mode := 'N';
  admin_role := wf_core.translate('WF_ADMIN_ROLE');
  if (admin_role = '*' or
      Wf_Directory.IsPerformer(username, admin_role)) then
      admin_mode := 'Y';
  end if;

  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_HOMETITLE')||' - '||realname);
  htp.headClose;

  wfa_html.homemenu;

  htp.htmlClose;
exception
  when others then
    rollback;
    wf_core.context('Wfa_Html','home');
    wfa_html.Error;
end home;


procedure Header
is

  username varchar2(320);   -- Username to query

begin
  -- Check session and current user
  wfa_sec.GetSession(username);

  -- Set page title
  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_HOMETITLE'));
  wfa_html.create_help_function('wf/links/web.htm?WEBHOME');
  htp.headClose;
  -- Page header
  wfa_sec.Header(FALSE, '', wf_core.translate('WF_WORKFLOW_TITLE')||
                 ' - '|| wf_core.translate('WF_VERSION'), TRUE);
  wfa_sec.Footer;
  htp.htmlClose;
end;


procedure home_float
is
  username   varchar2(320);   -- Username to query
  realname   varchar2(360);   -- Display name of username
  admin_role varchar2(320);   -- Role for admin mode
  admin_mode varchar2(1);        -- Does user have admin privledges
  s0         varchar2(2000);
  close_anchor varchar2(40);
begin
  -- Check session and current user
  wfa_sec.GetSession(username);
  username := upper(username);
  wf_directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  admin_mode := 'N';
  admin_role := wf_core.translate('WF_ADMIN_ROLE');
  if (admin_role = '*' or
      Wf_Directory.IsPerformer(username, admin_role)) then
      admin_mode := 'Y';
  end if;

  -- Set page title
  htp.htmlOpen;

  htp.headOpen;

  htp.p('<SCRIPT LANGUAGE="Javascript1.2">');
  htp.p('function launch_nav()
         { window.name="bigwin";
          newwind=window.open("'||owa_util.get_owa_service_path||'wfa_html.homemenu?message=&origin=FLOATING","newWindow","status=yes,toolbar=no,resizable=no,scrollbars=yes,width=200,height=250")
          }');
  htp.p('</SCRIPT>');

  htp.p('<NOSCRIPT>');
  htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
  htp.p('</NOSCRIPT>');


  htp.headClose;
  htp.p('<BODY>');


  htp.p('<SCRIPT LANGUAGE="Javascript1.2">');
  htp.p('launch_nav();');
  htp.p('</SCRIPT>');

  htp.p('<NOSCRIPT>');
  htp.p(WF_CORE.Translate('WFA_NOSCRIPT'));
  htp.p('</NOSCRIPT>');

  wfa_sec.Footer;
  htp.htmlClose;

  if (admin_mode = 'Y') then
     wfa_html.WorkList(user=>username,resetcookie=>1);
  else
     wfa_html.WorkList(resetcookie=>1);
  end if;


end home_float;

-- Homemenu
-- Prints the menu for the home page.
-- May also be called direct to print a regular page.

procedure Homemenu(message in varchar2,
               origin  in varchar2)
is
  username   varchar2(320);   -- Username to query
  realname   varchar2(360);   -- Display name of username
  admin_role varchar2(320);   -- Role for admin mode
  admin_mode varchar2(1);        -- Does user have admin privledges
  s0         varchar2(2000);
  anchor_tag varchar2(60);

  wrklstbuf  varchar2(2000); -- buffer to store worklist string
begin

  -- Check session and current user
  wfa_sec.GetSession(username);
  username := upper(username);
  wf_directory.GetRoleInfo(username, realname, s0, s0, s0, s0);

  admin_mode := 'N';
  admin_role := wf_core.translate('WF_ADMIN_ROLE');
  if (admin_role = '*' or
      Wf_Directory.IsPerformer(username, admin_role)) then
      admin_mode := 'Y';
  end if;

  -- Set page title
  htp.htmlOpen;
  htp.headOpen;
  htp.title(wf_core.translate('WFA_HOMETITLE'));
  wfa_html.create_help_function('wf/links/web.htm?WEBHOME');

  htp.headClose;

  if origin = 'FLOATING' then
     anchor_tag := '<A TARGET="bigwin" HREF=';
     wfa_sec.Header(background_only=>TRUE);
  elsif origin = 'FRAME' then
     anchor_tag := '<A TARGET="_top" HREF=';
     wfa_sec.Header(background_only=>TRUE);
  else
     anchor_tag := '<A HREF=';
     wfa_sec.Header(background_only=>FALSE);
  end if;



  if origin = 'NORMAL'  then

     /* ### Do not display version
     -- Version
     htp.p('Oracle Workflow ' || wf_core.translate('WF_VERSION') || '<BR>');

     -- User, Admin Mode
     htp.p(realname || ' (' || username || ')');
     admin_role := wf_core.translate('WF_ADMIN_ROLE');
     if (admin_mode = 'Y') then
         htp.p(' - ' || wf_core.translate('WF_ADMIN'));
     end if;
     htp.p('<BR>');
     */

     -- Additional Message
     if (message is not null) then
         htp.p('<BR>');
         htp.p(message);
     end if;
  end if;

  if origin = 'FRAME' then
     htp.fontOpen(cface=>'ARIAL,HELVETICA',csize=>'-1');
  end if;

  if origin = 'NORMAL' then
     wrklstbuf := ' ('|| to_char(wf_notification.WorkCount(username)) ||
                  ' ' || wf_core.translate('OPEN_NOTIFICATIONS') || ')';
     htp.tableopen(calign=>'LEFT', cattributes=>'WIDTH=80% summary=""');
  else
     -- dont print the "n open notifications" message next to Worklist
     -- because worklist will be displayed.
     wrklstbuf := '';
     htp.tableopen(cattributes=>'summary=""');
  end if;

  if (admin_mode = 'Y') then

     -- WorkList     Event
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('OPEN_NOTIFICATIONS')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wfa_html.WorkList?user='||username||'&'||'resetcookie=1>'||
             wf_core.translate('WFA_WTITLE') || '</A>' ||
             wrklstbuf, cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_LIST_EVENTS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.listevents?resetcookie=T>' ||
             wf_core.translate('WFE_LIST_EVENTS_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Find Notification     Find Event
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFA_FINDTITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path || 'wfa_html.Find>' ||
             wf_core.translate('WFA_FINDTITLE') || '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_FIND_EVENT_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.findevent>' ||
             wf_core.translate('WFE_FIND_EVENT_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Find Route            Systems
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFRTG_LIST_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path || 'wf_route.Find>' ||
             wf_core.translate('WFRTG_FIND_TITLE') || '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_LIST_SYSTEMS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.listsystems?resetcookie=T>' ||
             wf_core.translate('WFE_LIST_SYSTEMS_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Find Process (Monitor)      Find system
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFMON_FINDTITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_monitor.Find_Instance>' ||
             wf_core.translate('WFMON_FINDTITLE') || '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_FIND_SYSTEM_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.findsystem>' ||
             wf_core.translate('WFE_FIND_SYSTEM_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- User Preference            Agents
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFPREF_EDIT_PREFS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_pref.edit>' ||
             wf_core.translate('WFPREF_EDIT_PREFS_TITLE') || '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_LIST_AGENTS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.listagents?resetcookie=T>' ||
             wf_core.translate('WFE_LIST_AGENTS_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Global Perference          Find Agent
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFPREF_EDIT_DEF_PREFS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_pref.edit?edit_defaults=Y>' ||
             wf_core.translate('WFPREF_EDIT_DEF_PREFS_TITLE') || '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_FIND_AGENT_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.findagent>' ||
             wf_core.translate('WFE_FIND_AGENT_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Document Nodes            Subscriptions
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFDM_EDIT_NODE_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'fnd_document_management.dm_nodes_display>' ||
             wf_core.translate('WFDM_EDIT_NODE_TITLE')|| '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_LIST_SUBSC_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.listsubscriptions?resetcookie=T>' ||
             wf_core.translate('WFE_LIST_SUBSC_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Item Type Definition       Find Subscriptions
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFITD_ITEM_TYPE_DEFINITION')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_item_definition.find_item_type>' ||
             wf_core.translate('WFITD_ITEM_TYPE_DEFINITION')|| '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_FIND_SUBSC_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.findsubscription>' ||
             wf_core.translate('WFE_FIND_SUBSC_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Launch Process              Raise Business Event
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFINIT_ITEM_TYPE_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_initiate.itemtype>' ||
             wf_core.translate('WFINIT_ITEM_TYPE_TITLE')|| '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||
        'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_RAISE_EVENT_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.entereventdetails?p_event_name=%>' ||
             wf_core.translate('WFE_RAISE_EVENT_TITLE')|| '</A>', cattributes=>'id=""');

     -- bug 3855093 - Check setup menu not required
     -- htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
     --        wf_core.translate('WFE_CHECK_ALL_TITLE')||'">'||
     --        anchor_tag||owa_util.get_owa_service_path ||
     --        'wf_setup.check_all>' ||
     --        wf_core.translate('WFE_CHECK_ALL_TITLE')|| '</A>', cattributes=>'id=""');

     htp.tablerowclose;

     -- Demo                         System Signup
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WF_DEMO_MENU')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_demo.home>' ||
             wf_core.translate('WF_DEMO_MENU')|| '</A>', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||
        'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_SYSTEM_SIGNUP_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.entereventdetails?p_event_name=oracle.apps.wf.event.system.signup>' ||
             wf_core.translate('WFE_SYSTEM_SIGNUP_TITLE')|| '</A>', cattributes=>'id=""');

     -- bug 3855093 - Check setup removed. Moved Raise Business Event one cell above
     -- htp.tabledata('<img src="'||wfa_html.image_loc||
     --   'FNDWATHS.gif" height=18 width=18 alt="'||
     --        wf_core.translate('WFE_RAISE_EVENT_TITLE')||'">'||
     --        anchor_tag||owa_util.get_owa_service_path ||
     --        'wf_event_html.entereventdetails?p_event_name=%>' ||
     --        wf_core.translate('WFE_RAISE_EVENT_TITLE')|| '</A>', cattributes=>'id=""');

     htp.tablerowclose;

     -- Get System Identifier
     htp.tablerowopen;

     htp.tabledata('', cattributes=>'id=""');

     htp.tabledata('<img src="'||wfa_html.image_loc||
        'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFE_SYSTEM_IDENTIFIER_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_event_html.getsystemidentifier>' ||
             wf_core.translate('WFE_SYSTEM_IDENTIFIER_TITLE')|| '</A>', cattributes=>'id=""');

     -- bug 3855093 - Check setup removed. Moved System Signup one cell above
     -- htp.tabledata('<img src="'||wfa_html.image_loc||
     --   'FNDWATHS.gif" height=18 width=18 alt="'||
     --        wf_core.translate('WFE_SYSTEM_SIGNUP_TITLE')||'">'||
     --        anchor_tag||owa_util.get_owa_service_path ||
     --        'wf_event_html.entereventdetails?p_event_name=oracle.apps.wf.event.system.signup>' ||
     --        wf_core.translate('WFE_SYSTEM_SIGNUP_TITLE')|| '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Get System Identifier (moved above)
     -- htp.tablerowopen;

     -- htp.tabledata('', cattributes=>'id=""');

     -- bug 3855093 - Check setup removed. Moved System Identifier one cell above
     -- htp.tabledata('<img src="'||wfa_html.image_loc||
     --   'FNDWATHS.gif" height=18 width=18 alt="'||
     --        wf_core.translate('WFE_SYSTEM_IDENTIFIER_TITLE')||'">'||
     --        anchor_tag||owa_util.get_owa_service_path ||
     --        'wf_event_html.getsystemidentifier>' ||
     --        wf_core.translate('WFE_SYSTEM_IDENTIFIER_TITLE')|| '</A>', cattributes=>'id=""');

     -- htp.tablerowclose;

     -- Standard Event Queues (Deprecated)
     -- htp.tablerowopen;

     -- htp.tabledata('', cattributes=>'id=""');

     -- bug 3855093 - Event Queue Summary removed
     -- htp.tabledata('<img src="'||wfa_html.image_loc||
     --   'FNDWATHS.gif" height=18 width=18 alt="'||
     --        wf_core.translate('WFE_EVENT_QUEUE_SUMMARY_TITLE')||'">'||
     --        anchor_tag||owa_util.get_owa_service_path ||
     --        'wf_event_html.eventqueuedisplay>' ||
     --        wf_core.translate('WFE_EVENT_QUEUE_SUMMARY_TITLE')|| '</A>', cattributes=>'id=""'); 
     -- htp.tablerowclose;


  else
     -- Worklist
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('OPEN_NOTIFICATIONS')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wfa_html.WorkList?resetcookie=1>'||
             wf_core.translate('WFA_WTITLE') || '</A>' ||
             wrklstbuf, cattributes=>'id=""');
     htp.tablerowclose;

     -- Find Notification
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFA_FINDTITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path || 'wfa_html.Find>' ||
             wf_core.translate('WFA_FINDTITLE') || '</A>', cattributes=>'id=""');

     htp.tablerowclose;

     -- List Route
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
              wf_core.translate('WFRTG_LIST_TITLE')||'">'||
              anchor_tag||owa_util.get_owa_service_path || 'wf_route.List>' ||
              wf_core.translate('WFRTG_LIST_TITLE') || '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Find Process (Monitor)
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFMON_FINDTITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_monitor.Find_Instance>' ||
             wf_core.translate('WFMON_FINDTITLE') || '</A>', cattributes=>'id=""');
     htp.tablerowclose;

     -- Personal Preference
     htp.tablerowopen;
     htp.tabledata('<img src="'||wfa_html.image_loc||'FNDWATHS.gif" height=18 width=18 alt="'||
             wf_core.translate('WFPREF_EDIT_PREFS_TITLE')||'">'||
             anchor_tag||owa_util.get_owa_service_path ||
             'wf_pref.edit>' ||
             wf_core.translate('WFPREF_EDIT_PREFS_TITLE') || '</A>', cattributes=>'id=""');
     htp.tablerowclose;

  end if;

  htp.tableclose;

  wfa_sec.Footer;
  htp.htmlClose;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'Homemenu');
    wfa_html.Error;
end Homemenu;

procedure create_reg_button (
when_pressed_url  IN VARCHAR2,
onmouseover       IN VARCHAR2,
icon_top          IN VARCHAR2,
icon_name         IN VARCHAR2,
show_text         IN VARCHAR2)
IS

onmouseover_text varchar2(240) := null;

BEGIN

   htp.p('<TABLE border=0 cellpadding=0 cellspacing=0 align=left summary="">');

   htp.p('<TR><TD height=22 rowspan=3 id="">');

   htp.p('<A href="'||when_pressed_url||'" alt="">');

   htp.p('<IMG src="/OA_MEDIA/FNDJLFRL.gif" alt="" height=22 width=15 border=0></A></TD>');

   htp.p('<TD height=1 bgcolor=#FFFFFF id=""><IMG src="/OA_MEDIA/FNDINVDT.gif" alt="" height=1 width=1></TD>');

   htp.p('<TD height=22 rowspan=3 id="">');

   htp.p('<A href="'||when_pressed_url||'" alt="">');

   htp.p('<IMG src="/OA_MEDIA/FNDJLFRR.gif" alt="" height=22 width=15 border=0></A></TD></TR>');

   htp.p('<TR>');
   htp.p('<TD height=20 align=center valign=center bgcolor=#cccccc nowrap id="">');

   htp.p('<A href="'||when_pressed_url||'" style="text-decoration:none"'||
          ' alt="'||wfa_html.replace_onMouseOver_quotes(onmouseover)||'">');

   htp.p('<FONT size=2 face="Arial,Helvetica,Geneva"  color=000000>'||show_text||'</FONT></A></TD></TR>');

   htp.p('<TR><TD height=1 bgcolor=000000 id=""><IMG src="/OA_MEDIA/FNDINVDT.gif" alt="" width=1 height=1></TD></TR>');

   htp.p('</TABLE>');

exception
  when others then
    rollback;
    wf_core.context('Wfa_html', 'create_reg_button',when_pressed_url,onmouseover,
                    icon_top,icon_name,show_text);
    wfa_html.Error;

end create_reg_button;

-- show_plsql_doc
--   Show the content of a plsql document in a browser window
--   Called from the related documents function

procedure show_plsql_doc (
  nid in number,
  aname in varchar2,
  nkey in varchar2)
is

username varchar2(320);

clob_loc   clob;
blob_loc   blob;
clob_id    number;
clob_chunk number := 0;
doctext    varchar2(32000);
end_of_text boolean :=FALSE;
attr_name varchar2(30);

slash           pls_integer;
wfsession       varchar2(240);

doctype varchar2(1000);
lobsize number;
amount number;

l_enpos    pls_integer;
l_copos    pls_integer;
l_encoding varchar2(100);

begin

  -- Check current user has admin authority
  if (nkey is null) then
    wfa_sec.GetSession(username);
  else
    -- copy this from wfa_html.authenticate
    slash := instr(nkey, '/');
    if (slash <> 0) then
      wfsession := to_char(nid)||'/'||substr(nkey, slash+1);
    else
      wfsession := to_char(nid)||'/'||nkey;
    end if;

    username := Wf_Notification.AccessCheck(wfsession);
    if (username is null) then
      wf_core.raise('WFNTF_ACCESS_KEY');
    end if;
  end if;
  username := upper(username);

  -- note that GetAttrDoc will not translate for PLSQLCLOB
  doctext := wf_notification.getattrdoc(nid, aname,wf_notification.doc_html);

  -- if the attribute wasn't translated then try to translate for plsqlclobs.
  if doctext = '&'||aname then
     dbms_lob.createTemporary(clob_loc, false, dbms_lob.call);
     Wf_Notification.GetAttrCLOB(nid, aname, wf_notification.doc_html,
                                 clob_loc, doctype, attr_name);
                                 
    -- We have the document. Now determine the output method.
    -- HTML documents can be output as they are.
    -- Binary documents can only be downloaded
    if doctype in (wf_notification.doc_text, wf_notification.doc_html) then
       -- HTML or text document.
       htp.htmlOpen;
       htp.headOpen;
       htp.p('<BASE TARGET="_top">');
       htp.title(wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'));
       wfa_html.create_help_function('wfnew/wfnew52.htm#nrr');
       htp.headClose;
       wfa_sec.Header(FALSE, '',wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'), 
                      TRUE);
       htp.br;
    
       lobsize := dbms_lob.getlength(clob_loc);
       amount := 32000;
       wf_notification.clob_chunk := 0;
       while not (end_of_text) loop
          wf_notification.readattrclob(nid, aname, doctext, end_of_text);
          htp.prn(doctext);
       end loop;
       wfa_sec.Footer;
       htp.htmlClose;
    elsif attr_name is not null then
       -- BINARY Document
       l_enpos := instr(upper(doctype), 'ENCODING=', 1);
       if (l_enpos > 0) then
          l_enpos := l_enpos + length('ENCODING=');
          l_copos := instr(doctype, ';', l_enpos);
          if (l_copos > 0) then
             l_encoding := substr(doctype, l_enpos, (l_copos-l_enpos));
          else
             l_encoding := substr(doctype, l_enpos);
          end if;
          -- Decode base64 encoded content
          if (upper(trim(l_encoding)) = 'BASE64') then
             dbms_lob.createTemporary(blob_loc, FALSE, dbms_lob.call);

             wf_mail_util.decodeBLOB(clob_loc, blob_loc);
             owa_util.mime_header(doctype, FALSE);
             htp.p( 'Content-length: ' || dbms_lob.getlength(blob_loc));
             owa_util.http_header_close;

             wpg_docload.download_file(blob_loc);
             dbms_lob.freeTemporary(blob_loc);
          end if;
       else
          -- This provides limited binary document support.
          -- It assumes that the document in stored as raw in varchar.
          owa_util.mime_header(doctype, TRUE);
          lobsize := dbms_lob.getlength(clob_loc);
          amount := 32000;
          wf_notification.clob_chunk := 0;
          while not (end_of_text) loop
             wf_notification.readattrclob(nid, aname, doctext, end_of_text);
             htp.p(doctext);
          end loop;
       end if;
    else
       -- attr_name is null try for a PLSQLBLOB document
       dbms_lob.createTemporary(blob_loc, false, dbms_lob.call);
       Wf_Notification.GetAttrBLOB(nid, aname, wf_notification.doc_html,
                                   blob_loc, doctype, attr_name);
       
       owa_util.mime_header(doctype, FALSE);
       htp.p( 'Content-length: ' || dbms_lob.getlength(blob_loc));
       owa_util.http_header_close;

       wpg_docload.download_file(blob_loc);
       dbms_lob.freeTemporary(blob_loc);
    end if;
   
  else
     -- Set page title
     htp.htmlOpen;
     htp.headOpen;
     htp.title(wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'));
     wfa_html.create_help_function('wfnew/wfnew52.htm#nrr');
     htp.headClose;
     wfa_sec.Header(FALSE, '',wf_core.translate('WFITD_ATTR_TYPE_DOCUMENT'), 
                    TRUE);
     htp.br;
               
     htp.p (doctext);

     wfa_sec.Footer;
     htp.htmlClose;
  end if;

exception
  when others then
    wf_core.context('Wfa_Html','show_plsql_doc',nid, aname);
    wfa_html.Error;
end show_plsql_doc;

-- base_url
-- Get the base url for the current browser where you have launched the
-- login for Workflow
function base_url  (get_from_resources BOOLEAN)
return varchar2 IS

l_base_url   VARCHAR2(2000) := NULL;

BEGIN

    BEGIN

    IF (get_from_resources = FALSE) THEN

       -- Need to strip off trailing / to match wf_web_agent format
       l_base_url  := SUBSTR(RTRIM(owa_util.get_owa_service_path), 1,
                          LENGTH(RTRIM(owa_util.get_owa_service_path)) - 1);

    ELSE

       l_base_url := wf_core.translate ('WF_WEB_AGENT');

    END IF;

    EXCEPTION
    WHEN OTHERS THEN

       l_base_url := wf_core.translate ('WF_WEB_AGENT');

    END;

    return (l_base_url);

exception
  when others then
    wf_core.context('Wfa_Html','base_url');
    wfa_html.Error;
end base_url;

--
-- wf_user_val
--   Create the lov content for our user lov.  This function
--   is called by the generic lov function
-- IN
-- RETURNS
--
procedure  wf_user_val (
p_mode           in varchar2,
p_lov_name       in varchar2,
p_start_row      in number,
p_max_rows       in number,
p_hidden_value   in out nocopy varchar2,
p_display_value  in out nocopy varchar2,
p_result         out nocopy number)


IS

CURSOR c_user_lov (c_find_criteria IN VARCHAR2) IS
SELECT
 name,
 display_name
FROM   wf_roles
where  status <> 'INACTIVE'
and   (UPPER(display_name) LIKE UPPER(c_find_criteria)||'%'
and    (display_name  LIKE LOWER(SUBSTR(c_find_criteria, 1, 2))||'%'
 or     display_name  LIKE LOWER(SUBSTR(c_find_criteria, 1, 1))||
                        UPPER(SUBSTR(c_find_criteria, 2, 1))||'%'
 or    display_name   LIKE INITCAP(SUBSTR(c_find_criteria, 1, 2))||'%'
 or    display_name   LIKE UPPER(SUBSTR(c_find_criteria, 1, 2))||'%'))
or
(orig_system not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
                     'HZ_GROUP','CUST_CONT')
and UPPER(name) LIKE UPPER(c_find_criteria)||'%'
and    (name  LIKE LOWER(SUBSTR(c_find_criteria, 1, 2))||'%'
 or     name  LIKE LOWER(SUBSTR(c_find_criteria, 1, 1))||
                        UPPER(SUBSTR(c_find_criteria, 2, 1))||'%'
 or    name   LIKE INITCAP(SUBSTR(c_find_criteria, 1, 2))||'%'
 or    name   LIKE UPPER(SUBSTR(c_find_criteria, 1, 2))||'%'))
and   status <> 'INACTIVE'
order by display_name;

-- Added additional where condition "status <> 'INACTIVE' so only ACTIVE 
-- roles display 

-- CURSOR c_user_display_value (c_name IN VARCHAR2) IS
-- select name, display_name
-- from   wf_roles
-- where  name = c_name;

ii           NUMBER := 0;
nn           NUMBER := 0;
l_total_rows NUMBER := 0;
l_id         NUMBER;
l_name       VARCHAR2 (320);  -- enlarged from 30 to match db definition
l_display_name VARCHAR2 (360); -- enlarged from 80 to match db definition 
l_result     NUMBER := 1;  -- This is the return value for each mode

colon        NUMBER;

role_info_tbl wf_directory.wf_local_roles_tbl_type;

BEGIN

if (p_mode = 'LOV') then

   /*
   ** Need to get a count on the number of rows that will meet the
   ** criteria before actually executing the fetch to show the user
   ** how many matches are available.
   */
   select count(*)
   into   l_total_rows
   FROM   wf_roles
   where  status <> 'INACTIVE'
   and   (UPPER(display_name) LIKE UPPER(p_display_value)||'%'
   and    (display_name  LIKE LOWER(SUBSTR(p_display_value, 1, 2))||'%'
   or     display_name  LIKE LOWER(SUBSTR(p_display_value, 1, 1))||
                        UPPER(SUBSTR(p_display_value, 2, 1))||'%'
   or    display_name   LIKE INITCAP(SUBSTR(p_display_value, 1, 2))||'%'
   or    display_name   LIKE UPPER(SUBSTR(p_display_value, 1, 2))||'%'))
     or
      (orig_system not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
                           'HZ_GROUP','CUST_CONT')
       and UPPER(name) LIKE UPPER(p_display_value)||'%'
       and    (name  LIKE LOWER(SUBSTR(p_display_value, 1, 2))||'%'
       or     name  LIKE LOWER(SUBSTR(p_display_value, 1, 1))||
                            UPPER(SUBSTR(p_display_value, 2, 1))||'%'
       or    name   LIKE INITCAP(SUBSTR(p_display_value, 1, 2))||'%'
       or    name   LIKE UPPER(SUBSTR(p_display_value, 1, 2))||'%'))
       and status <> 'INACTIVE';

   wf_lov.g_define_rec.total_rows := l_total_rows;

   wf_lov.g_define_rec.add_attr1_title := wf_core.translate ('WFITD_INTERNAL_NAME');

   open c_user_lov (p_display_value);

   LOOP

     FETCH c_user_lov INTO l_name, l_display_name;

     EXIT WHEN c_user_lov%NOTFOUND OR nn >= p_max_rows;

     ii := ii + 1;

     IF (ii >= p_start_row) THEN

        nn := nn + 1;

        wf_lov.g_value_tbl(nn).hidden_key      := l_name;
        wf_lov.g_value_tbl(nn).display_value   := l_display_name;
        wf_lov.g_value_tbl(nn).add_attr1_value := l_name;

     END IF;

   END LOOP;

   l_result := 1;

elsif (p_mode = 'GET_DISPLAY_VAL') THEN

   Wf_Directory.GetRoleInfo2(p_hidden_value,role_info_tbl);
   l_name         := role_info_tbl(1).name;
   l_display_name := role_info_tbl(1).display_name;
   p_display_value:= l_name;

   l_result := 1;

elsif (p_mode = 'VALIDATE') THEN

   /*
   ** If mode = VALIDATE then see how many rows match the criteria
   ** If its 0 then thats not good.  Raise an error and tell them to use LOV
   ** If its 1 then thats great.
   ** If its more than 1 then check to see if they used the LOV to select
   ** the value
   */
   open c_user_lov (p_display_value);

   LOOP

     FETCH c_user_lov INTO l_name, l_display_name;

     EXIT WHEN c_user_lov%NOTFOUND OR ii = 2;

     ii := ii + 1;

     p_hidden_value := l_name;

   END LOOP;

   /*
   ** If ii=0 then no rows were found and you have an error in the value
   **     entered so present a no rows found and use the lov icon to select
   **     value
   ** If ii=1 then one row is found then you've got the right value
   ** If ii=2 then more than one row was found so check to see if the display
   ** value taht was selected is not unique in the LOV (Person Name) and
   ** that the LOV was used so the Hidden value has been set to a unique
   ** value.  If it comes up with more than 1 in this case then present
   ** the please use lov icon to select value.
   */
   if (ii = 2) then

     -- copy logic from wf_directory.getroleinfo2
     colon := instr(p_display_value,':');
     if (colon = 0) then
       select count(*)
         into ii
         from WF_ROLES
        where NAME = p_display_value
          and ORIG_SYSTEM not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
                                  'HZ_GROUP','CUST_CONT');
     else
       select count(*)
         into ii
         from WF_ROLES
        where NAME = p_display_value
          and ORIG_SYSTEM    = substr(p_display_value, 1, colon-1)
          and ORIG_SYSTEM_ID = substr(p_display_value, colon+1);
     end if;

   END IF;

   l_result := ii;

end if;

p_result := l_result;

exception
  when others then
    rollback;
    wf_core.context('Wfa_Html', 'wf_user_val');
    raise;
end wf_user_val;


function replace_onMouseOver_quotes(p_string in varchar2) return varchar2 is

temp_string varchar2(2000);
c_browser varchar2(400) := owa_util.get_cgi_env('HTTP_USER_AGENT');

begin

-- replace single quotes
temp_string := replace(p_string,'''','\''');

-- replace double quotes
if (instr(c_browser, 'MSIE') <> 0) then
    temp_string := replace(temp_string,'"','\''');
else
    temp_string := replace(temp_string,'"','`&quot;');
end if;

-- check for double escapes
temp_string := replace(temp_string,'\\','\');

return temp_string;

end replace_onMouseOver_quotes;

procedure validate_display_name (
p_display_name in varchar2,
p_user_name    in out nocopy varchar2) IS

l_colon         NUMBER := 0;
l_names_count   NUMBER := 0;
l_name          VARCHAR2(320);
l_upper_name    VARCHAR2(360);
l_orig_system_id NUMBER;
l_get_role      BOOLEAN := TRUE;

role_info_tbl wf_directory.wf_local_roles_tbl_type;

BEGIN

   /*
   ** Make sure to blank out the internal name if the user originally
   ** used the LOV to select the name and then blanked out the display
   ** name then make sure here to blank out the insternal name and return
   */
   if (p_display_name is null) then

      p_user_name := NULL;
      return;

   end if;
   
   /*
   ** Bug# 2236250 validating the display name to contain a valid number
   ** after the colon to be used as a internal name for the role
   */ 
   l_colon := instr(p_display_name, ':');
   if (l_colon > 0) then
      begin
         l_orig_system_id := to_number(substr(p_display_name, l_colon+1));
      exception
         when invalid_number then
             l_get_role := FALSE;
         when others then
             raise;
      end;
      l_colon := 0;
   end if;

   /*
   ** First look first for internal name to see if you find a match.  If
   ** there are duplicate internal names that match the criteria then
   ** there is a problem with directory services but what can you do.  Go
   ** ahead and pick the first name so you return something
   **
   ** Bug# 2236250 calling Wf_Directory.GetRoleInfo2 only if the value
   ** after ':' is numeric.
   */
   if (l_get_role) then
      l_upper_name := upper(p_display_name);
      Wf_Directory.GetRoleInfo2(l_upper_name,role_info_tbl);
      l_name := role_info_tbl(1).name;
   end if;

   /*
   ** If you found a match on internal name then set the p_user_name
   ** accordingly.
   */
   if (l_name IS NOT NULL) then

      p_user_name := l_name;

   /*
   ** If there was no match on internal name then check for a display
   ** name
   */
   else

      /*
      ** Check out how many names match the display name
      */
      select count(1)
      into   l_names_count
      from   wf_roles
      where  display_name = p_display_name;

      /*
      ** If there are no matches for the display name then raise an error
      */
      if (l_names_count = 0) then

         -- Not displayed or internal role name, error
         wf_core.token('ROLE', p_display_name);
         wf_core.raise('WFNTF_ROLE');

      /*
      ** If there is just one match then get the internal name
      ** and assign it.
      */
      elsif (l_names_count = 1) then

         select name
         into   l_name
         from   wf_roles
         where  display_name = p_display_name;

         p_user_name  := l_name;

      /*
      ** If there is more than one match then see if the user
      ** used the lov to select the name in which case the combination
      ** of the display name and the user name should be unique
      */
      else

        -- copy logic from wf_directory.getroleinfo2
        l_colon := instr(p_user_name,':');
 
        if (l_colon = 0) then
          select count(1)
            into l_names_count
            from WF_ROLES
           where NAME = p_user_name
             and ORIG_SYSTEM not in ('HZ_PARTY','POS','ENG_LIST','AMV_CHN',
                                     'HZ_GROUP','CUST_CONT')
             and DISPLAY_NAME = p_display_name;
        else
        /*
        ** Bug# 2236250 validate if the value after ':' is number
        ** before using it in the query 
        */
          begin
             l_orig_system_id := to_number(substr(p_user_name, l_colon+1));
          exception
             when invalid_number then
                wf_core.raise('WFNTF_ORIGSYSTEMID');
             when others then
                raise;
          end;
          select count(1)
            into l_names_count
            from WF_ROLES
           where NAME = p_user_name
             and ORIG_SYSTEM    = substr(p_user_name, 1, l_colon-1)
             and ORIG_SYSTEM_ID = l_orig_system_id
             and DISPLAY_NAME = p_display_name;
        end if;

        if (l_names_count <> 1) then
          wf_core.token('ROLE', p_display_name);
          wf_core.raise('WFNTF_UNIQUE_ROLE');
        end if;

      end if;

   end if;

exception
  when others then
    wf_core.context('Wfa_Html', 'validate_display_name', p_display_name,
      p_user_name);
    raise;
end validate_display_name;

-- LongDesc
--  Displays an html page with the token message.  This is called from
--  frames for the LONGDESC attribute.
procedure LongDesc (p_token       in varchar2)
as
BEGIN
    htp.htmlOpen;
    htp.headOpen;
    htp.title(wf_core.translate('LONG_DESC'));
    htp.headClose;

      begin
        wfa_sec.Header(background_only=>TRUE);
      exception
        when others then
          htp.bodyOpen;
      end;

    htp.p(WF_CORE.Translate(UPPER(p_token)));

    wfa_sec.Footer;
    htp.htmlClose;

END LongDesc;

end WFA_HTML;
/
commit;


create or replace package body WFA_HTML_UTIL as
/* $Header: wfhtmb.pls 26.64 2005/03/11 06:18:55 anachatt ship $ */


--
-- Package Globals
--
result_button_threshold pls_integer := 3;  -- Max number of submit buttons

--
-- GetUrl (PRIVATE)
--   Produce URL link in response portion
-- IN
--   nid -
--   description - instructions
--   value - url string not token substituted
procedure GetUrl(
    nid          in number,
    description  in varchar2,
    value        in varchar2)
as
urlstring varchar2(1950);
begin
  -- Ignore if no URL provided
  if (value is null) then
    return;
  end if;

 htp.tableRowOpen;

  -- Include description if needed.
  -- NOTE: Description are printed here instead of in the prompt link
  -- as for other fields, because the prompt is already used for the
  -- URL itself.
  if (description is not null) then
    htp.tableData(description, 'right', cattributes=>'id=""');
  else
    htp.tableData(htf.br, cattributes=>'id=""');
  end if;

  -- Print URL
  urlstring:=wf_notification.GetURLText(value, nid);
  htp.p('<td id=""> <a href="'||urlstring||'">'||urlstring||'</a></td>');

  htp.tableRowClose;

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetUrl', value, description, to_char(nid));
    raise;
end GetUrl;

--
-- GetField (PRIVATE)
--   Produce a varchar2/number/date response field
-- IN
--   name - field name
--   type - field type (VARCHAR2, NUMBER, DATE)
--   format - format mask
--   dvalue - default value
--   index - the attribute element number in the attribute list
--
procedure GetField(
  name         in varchar2,
  type        in varchar2,
  format       in varchar2,
  dvalue       in varchar2,
  index_num    in number,
  nid          in number,
  nkey         in varchar2)
is
  len             pls_integer;
  l_url           varchar2(1000);
  l_media         varchar2(240) := wfa_html.image_loc;
  l_icon          varchar2(30) := 'FNDILOV.gif';
  l_username      varchar2(320);   -- Username to query
  l_document_name         Varchar2(240) := NULL;
  l_callback_URL  varchar2(4000);
  l_attach_URL    varchar2(4000);
  l_document_attributes   fnd_document_management.fnd_document_attributes;
  l_message               varchar2(400) := NULL;

  slash           pls_integer;
  wfsession       varchar2(240);

begin
  -- Figure field len
  if (type = 'VARCHAR2') then
    len := nvl(to_number(format), 2000);
  else
    len := 62;
  end if;

  -- Draw field
  htp.formHidden('h_fnames', name||'#'||type||'#'||format);

  /* Need to create a hidden document name field if this is not a document
  ** resond attrubute, otherwise the index will reference index elements
  ** that don't exist because the element lists are out of sync
  */
  if (type NOT IN  ('DOCUMENT' , 'ROLE')) THEN
     htp.formHidden('h_fdocnames', '');
  end if;

  if (len <= 80) then

    /*
    ** If this is a document field then hide the actual h_fvalue field
    ** Since this will store the document info that gets passed to the
    ** document attribute.  You then need to create a name field so the
    ** user can see what they've selected.
    */

    if (type = 'DOCUMENT') THEN

       htp.formhidden ('h_fvalues', dvalue);

       -- Set the destination field name for the document id
       fnd_document_management.set_document_id_html (
             'bottom',
             'WFNOTRESP',
             'h_fvalues['||index_num||']',
             'h_fdocnames['||index_num||']',
             l_callback_url);

       -- Check session and current user
       if (nkey is null) then
         wfa_sec.GetSession(l_username);
       else
         -- copy this from wfa_html.authenticate
         slash := instr(nkey, '/');
         if (slash <> 0) then
           wfsession := to_char(nid)||'/'||substr(nkey, slash+1);
         else
           wfsession := to_char(nid)||'/'||nkey;
         end if;

         l_username := Wf_Notification.AccessCheck(wfsession);
         if (l_username is null) then
           wf_core.raise('WFNTF_ACCESS_KEY');
         end if;

       end if;
       l_username := upper(l_username);

       fnd_document_management.get_launch_attach_url (
             l_username,
             l_callback_url,
             TRUE,
             l_attach_url);

       /*
       ** If the default value is a dm document then go get the
       ** title from the DM system and place it in the field.  If
       ** its a plsql doc then just put the default value in the field
       */
       IF (SUBSTR(dvalue, 1, 3) = 'DM:') THEN

          /*
          ** get the document name
          */
          fnd_document_management.get_document_attributes(l_username,
             dvalue,
             l_document_attributes);


          l_document_name := l_document_attributes.document_name;

       ELSE

          l_document_name := dvalue;

       END IF;

       -- document field
       htp.tableData(
           cvalue=>htf.formText(cname=>'h_fdocnames', csize=>len-30,
                                cmaxlength=>len, cvalue=>l_document_name)||
                                '&nbsp&nbsp&nbsp'||
                                l_attach_URL,
                                calign=>'Left', cattributes=>'id=""');

    else
       -- single line field
       -- htp.tableData(
       --    cvalue=>htf.formText(cname=>'h_fvalues', csize=>len,
       --                         cmaxlength=>len, cvalue=>dvalue),
       --    calign=>'Left');
       htp.p('<TD ALIGN="LEFT" id="">');

       if (type <> 'ROLE') then
           htp.formText(cname=>'h_fvalues', csize=>len,
                    cmaxlength=>len, cvalue=>dvalue);
       else

         l_message := wf_core.translate ('WFPREF_LOV');

         htp.formhidden ('h_fvalues', dvalue);

         -- add LOV here: Note:bottom is name of frame.
         -- Note: The REPLACE function replaces all the space characters with
         -- the proper escape sequence.
         l_url := 'javascript:fnd_open_dm_display_window('||''''||
                  REPLACE('wf_lov.display_lov?p_lov_name='||'owner'||
                  '&p_display_name='||'WFA_FIND_USER'||
                  '&p_validation_callback=wfa_html.wf_user_val'||
                  '&p_dest_hidden_field=top.opener.parent.bottom.document.WFNOTRESP.h_fvalues['||to_char(index_num)||'].value'||
                  '&p_current_value=top.opener.parent.bottom.document.WFNOTRESP.h_fdocnames['||to_char(index_num)||'].value'||
                  '&p_display_key='||'Y'||
                  '&p_dest_display_field=top.opener.parent.bottom.document.WFNOTRESP.h_fdocnames['||to_char(index_num)||'].value',
                     ' ', '%20')||''''||',500,500)';

         -- print everything together so ther is no gap.
         htp.p(htf.formText(cname=>'h_fdocnames', csize=>len, cmaxlength=>240,
                    cvalue=>dvalue)||
                    '<A href='||l_url||'>'||
                    '<IMG src="'||l_media||l_icon||'" border=0 alt="'||
                    l_message||'" onmouseover="window.status='||''''||
                    l_message||''''||';return true"></A>');
       end if;
       htp.p('</TD>');

    end if;

  else
    -- multi line field
    htp.tableData(
        cvalue=>htf.formTextareaOpen2(
                    cname=>'h_fvalues',
                    nrows=>2,
                    ncolumns=>65,
                    cwrap=>'SOFT',
                    cattributes=>'maxlength='||to_char(len))||
                dvalue||
                htf.formTextareaClose,
        calign=>'Left', cattributes=>'id=""');
  end if;
exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetField', name, type, format, dvalue);
    raise;
end GetField;

--
-- GetLookup (PRIVATE)
--   Produce a lookup response field
-- IN
--   name - field name
--   value - default value (lookup code)
--   format - lookup type
--   submit - flag include a submit button for result field
--
procedure GetLookup(
  name in varchar2,
  value in varchar2,
  format in varchar2,
  submit in boolean)
as
  cursor lookup_codes(p_lookup_type varchar2) is
    select MEANING, LOOKUP_CODE
    from   WF_LOOKUPS
    where  LOOKUP_TYPE = p_lookup_type
    order by MEANING;

  template varchar2(4000);

begin
  -- Create hidden field and select list
  template := htf.formHidden('h_fnames', name||'#LOOKUP#'||format)||
              wf_core.newline||
              htf.formSelectOpen('h_fvalues');


  -- Add all lookups to select list
  for i in lookup_codes(format) loop
    if (i.lookup_code = value) then
      template := template||wf_core.newline||
            htf.formSelectOption(i.meaning, 'SELECTED','VALUE="'||i.lookup_code||'"');
    else
      template := template||wf_core.newline||
            htf.formSelectOption(i.meaning,null,'VALUE="'||i.lookup_code||'"');
    end if;
  end loop;
  template := template||wf_core.newline||htf.formSelectClose;

  if (not submit) then
    -- Draw a normal field
    htp.tableData(template, 'left', cattributes=>'id=""');
    htp.formHidden('h_fdocnames', '');

  else
    -- Draw a submit-style field for the result.
    -- Leave TableData open so reassign button can be added to same cell.

    htp.p('<TD ALIGN=left id="">'||wf_core.newline||template||'</TD>');

    htp.p('<TD id="">');
    wfa_html.create_reg_button ('javascript:document.WFNOTRESP.submit()',
                                wf_core.translate ('SUBMIT'),
                                wfa_html.image_loc,
                                null,
                                wf_core.translate ('SUBMIT'));

     htp.p('</TD>');


  end if;

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetLookup', name, value, format);
    raise;
end GetLookup;

--
-- GetButtons (PRIVATE)
--   Produce a response field as submit buttons
-- IN
--   value - default value
--   format - lookup type
--
procedure GetButtons(
  value   in varchar2,
  format  in varchar2,
  otherattr in number)
as
  respcnt pls_integer;
  indexer     number := otherattr;

  cursor lookup_codes(p_lookup_type varchar2) is
    select MEANING, LOOKUP_CODE
    from   WF_LOOKUPS
    where  LOOKUP_TYPE = p_lookup_type
    order by MEANING;
begin
  -- Check number of response values.
  begin
    select count(1)
    into respcnt
    from WF_LOOKUPS
    where LOOKUP_TYPE = format;
  exception
    when no_data_found then
      return;
  end;

  if (respcnt > wfa_html_util.result_button_threshold) then
    -- If number of responses over threshold use a select list instead.
    wfa_html_util.GetLookup('RESULT', value, format, TRUE);
  else
    -- Use buttons.

    -- Add a hidden field for the result field name
    htp.formHidden('h_fnames', 'RESULT#LOOKUP#'||format);
    htp.formHidden('h_fvalues', null);

    -- Add a button for every lookup
    for i in lookup_codes(format) loop
      htp.p('<TD id="">');
      wfa_html.create_reg_button ('javascript:document.WFNOTRESP.h_fvalues['||
                                  TO_CHAR(indexer)||'].value='||
                                  ''''||i.lookup_code||''''||';document.WFNOTRESP.submit()',
                                  i.meaning,
                                  wfa_html.image_loc,
                                  null,
                                  i.meaning);
      htp.p('</TD>');

      /*htp.formSubmit('h_fvalues', i.meaning, 'NOBORDER');*/
    end loop;

  end if;

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetButtons', value, format);
    raise;
end GetButtons;

--
-- SetAttribute (PRIVATE)
--   Set response attributes when processing a response.
-- IN
--   nid - notification id
--   attr_name_type - attribute name#type#format
--   attr_value - attribute value
--
procedure SetAttribute(
  nid            in number,
  attr_name_type in varchar2,
  attr_value     in varchar2,
  doc_name       in varchar2)
as
  first     pls_integer;
  second    pls_integer;
  attr_type varchar2(8);
  attr_name varchar2(30);
  attr_fmt  varchar2(240);
  lovcode   varchar2(30);
  l_attr_value varchar2(30);

begin
  -- Parse out name#type#format
  first  := instr(attr_name_type, '#', 1);
  second := instr(attr_name_type, '#', 1, 2);
  attr_name := substr(attr_name_type, 1, first-1);
  attr_type := substr(attr_name_type, first+1, second-first-1);
  attr_fmt  := substr(attr_name_type, second+1,
                      length(attr_name_type)-second);

  if (attr_type = 'DATE') then
    if (attr_fmt is not null) then
      wf_notification.SetAttrDate(nid, attr_name,
                                  to_date(attr_value, attr_fmt));
    else
      wf_notification.SetAttrDate(nid, attr_name,
                                  to_date(attr_value));
    end if;
  elsif (attr_type = 'NUMBER') then
    if (attr_fmt is not null) then
      wf_notification.SetAttrNumber(nid, attr_name,
                                    to_number(attr_value, attr_fmt));
    else
      wf_notification.SetAttrNumber(nid, attr_name,
                                    to_number(attr_value));
    end if;
  elsif (attr_type = 'ROLE') then

    /*
    ** If this is a role then try to get the unique role name for the
    ** user that was selected.  Since this could be a display name
    ** or an internal name, make sure to get the unique internal name
    */
    l_attr_value := attr_value;

    wfa_html.validate_display_name (doc_name, l_attr_value);

    --
    -- Set the role to upper
    --
    wf_notification.SetAttrText(nid, attr_name, l_attr_value);

  elsif (attr_type = 'DOCUMENT') then
     -- if PLSQL then use the display value into which the user typed
     if upper(substr(doc_name,1, 5)) = 'PLSQL' then

      wf_notification.SetAttrText(nid, attr_name, doc_name);
     -- use the hidden field populated by doc lov
     else

      wf_notification.SetAttrText(nid, attr_name, attr_value);

     end if;

  else
    -- VARCHAR2 or LOOKUP or misc value
    wf_notification.SetAttrText(nid, attr_name, attr_value);
  end if;

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'SetAttribute',
                    to_char(nid), attr_name_type, attr_value);
    raise;
end SetAttribute;

--
-- GetLookupMeaning (PRIVATE)
--   Retrieve displayed value of lookup
-- IN
--   ltype - lookup type
--   lcode - lookup code
-- RETURNS
--   Displayed meaning of lookup code
--
function GetLookupMeaning(
  ltype in varchar2,
  lcode in varchar2)
return varchar2
is
  meaning varchar2(80);
begin
  select WL.MEANING
  into meaning
  from WF_LOOKUPS WL
  where WL.LOOKUP_TYPE = GetLookupMeaning.ltype
  and WL.LOOKUP_CODE = GetLookupMeaning.lcode;

  return(meaning);
exception
  when no_data_found then
    return(lcode);
  when others then
    wf_core.context('Wfa_Html_Util', 'GetLookupMeaning', ltype, lcode);
    raise;
end GetLookupMeaning;

--
-- GetUrlCount (PRIVATE)
-- IN
--   nid - notification id
-- OUT
--   urlcnt  - number of urls as reponse attributes
--   urlstrg - one of the urls if it exist
--             this is generally discarded unless there is only one
procedure GetUrlCount(
  nid in number,
  urlcnt out nocopy number,
  urlstrg out nocopy varchar2)
is
  buf pls_integer;
begin
  select count(1),max(NA.TEXT_VALUE)
  into   urlcnt, urlstrg
  from WF_NOTIFICATION_ATTRIBUTES NA,
       WF_MESSAGE_ATTRIBUTES MA,
       WF_NOTIFICATIONS N
  where N.NOTIFICATION_ID = nid
  and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
  and MA.MESSAGE_NAME = N.MESSAGE_NAME
  and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
  and MA.NAME = NA.NAME
  and MA.SUBTYPE = 'RESPOND'
  and MA.TYPE = 'URL';

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetUrlCount', to_char(nid));
    raise;
end GetUrlCount;

--
-- GetResponseUrl (PRIVATE)
--   Return single response url.
--   NOTE: this assumes there is exactly one response url attribute.
-- IN
--   nid - notification id
-- RETURNS
--   Response url
--
function GetResponseUrl(
  nid in number)
return varchar2
is
  buf varchar2(4000);
begin
  select text_value
  into buf
  from WF_NOTIFICATION_ATTRIBUTES NA,
       WF_MESSAGE_ATTRIBUTES_VL MA,
       WF_NOTIFICATIONS N
  where N.NOTIFICATION_ID = nid
  and NA.NOTIFICATION_ID = N.NOTIFICATION_ID
  and MA.MESSAGE_NAME = N.MESSAGE_NAME
  and MA.MESSAGE_TYPE = N.MESSAGE_TYPE
  and MA.NAME = NA.NAME
  and MA.SUBTYPE = 'RESPOND'
  and MA.TYPE = 'URL'
  and ROWNUM = 1;

  return(buf);

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetResponseUrl', to_char(nid));
    raise;
end GetResponseUrl;

--
-- GetDisplayValue (PRIVATE)
--   Get displayed value of a response field
-- IN
--   type - field type (VARCHAR2, NUMBER, DATE, LOOKUP, URL)
--   format - field format (depends on type)
--   tvalue - text value
--   nvalue - number value
--   dvalue - date value
-- RETURNS
--   Displayed value
--
function GetDisplayValue(
  type in varchar2,
  format in varchar2,
  tvalue in varchar2,
  nvalue in number,
  dvalue in date)
return varchar2
is
  s0 varchar2(2000);
  value varchar2(4000);
begin
  if (type = 'VARCHAR2') then
    value := tvalue;
  elsif (type = 'NUMBER') then
    if (format is null) then
      value := to_char(nvalue);
    else
      value := to_char(nvalue, format);
    end if;
  elsif (type = 'DATE') then
    if (format is null) then
      value := to_char(dvalue);
    else
      value := to_char(dvalue, format);
    end if;
  elsif (type = 'LOOKUP') then
    value := wfa_html_util.GetLookupMeaning(format, tvalue);
  elsif (type = 'URL') then
    value := tvalue;
  elsif (type = 'ROLE') then
    wf_directory.GetRoleInfo(tvalue, value, s0, s0, s0, s0);
  else
    -- Default to return text value unchanged
    value := tvalue;
  end if;

  return(value);

exception
  when others then
    wf_core.context('Wfa_Html_Util', 'GetDisplayWindow', type, format,
                    tvalue, to_char(nvalue), to_char(dvalue));
    raise;
end GetDisplayValue;

--
-- GetDenormalizedValues
--   Populate WF_NOTIFICATIONS with the needed values with supplied langcode.
--   Then returns those values via the out variables.
-- IN:
--   nid - notification id
--   langcode - language code
-- OUT:
--   from_user - display name of from role
--   to_user - display name of recipient_role
--   subject - subject of the notification
--
procedure GetDenormalizedValues(nid       in  number,
                                langcode  in  varchar2,
                                from_user out nocopy varchar2,
                                to_user   out nocopy varchar2,
                                subject   out nocopy varchar2)
is
begin
  Wf_Notification.Denormalize_Notification(nid=>nid,langcode=>langcode);

  begin
    select FROM_USER, TO_USER, SUBJECT
      into from_user, to_user, subject
      from WF_NOTIFICATIONS
     where NOTIFICATION_ID = nid;
  exception
    when OTHERS then
      from_user := null;
      to_user   := null;
      subject   := null;
  end;

exception
  when OTHERS then
    wf_core.context('Wfa_Html_Util', 'GetDenormalizedValues',
                    to_char(nid), langcode);
    raise;
end GetDenormalizedValues;

end WFA_HTML_UTIL;
/
commit;
exit;