/*
* Copyright (c) 2000 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include "nw_wml_core.h"
#include "wml_url_utils.h"
#include "wml_task.h"
#include "nw_wml1x_wml1xformliaisoni.h" 
#include "nw_wml1x_wml1xcontenthandler.h"
#include "nw_adt_resizablevector.h"
#include "NW_Text_Abstract.h"
#include "nw_hed_documentroot.h"
#include "wml_elm_attr.h"
#include "BrsrStatusCodes.h"
#include "wml_ops.h"

/* ------------------------------------------------------------------------- *
   private types
 * ------------------------------------------------------------------------- */

typedef enum {
  NW_Wml1x_FormControlType_None,
  NW_Wml1x_FormControlType_InputPassword, /* <input type=password> */
  NW_Wml1x_FormControlType_InputText,     /* <input type=text> */
  NW_Wml1x_FormControlType_Option         /* <option> */
} NW_Wml1x_FormControlType_t;


/* ------------------------------------------------------------------------- *
   private methods
 * ------------------------------------------------------------------------- */

static
NW_Wml1x_FormControlType_t
NW_Wml1x_FormLiaison_GetControlType(NW_Wml1x_FormLiaison_t  *thisObj,
                                    void                    *elemId);

static
NW_Wml1x_FormControlType_t
NW_Wml1x_FormLiaison_GetInputType(NW_Wml1x_FormLiaison_t  *thisObj,
                                  void                    *elemId);


static NW_Ucs2* FormatGetMask(const NW_Ucs2 *format);

/*****************************************************************

  Name:         NW_Wml1x_FormLiaison_GetControlType()

  Description:

  Parameters:

  Algorithm:

  Return Value:

*****************************************************************/
static
NW_Wml1x_FormControlType_t
NW_Wml1x_FormLiaison_GetControlType(NW_Wml1x_FormLiaison_t  *thisObj,
                                    void                    *elemId)
{
  NW_Wml1x_FormControlType_t  type = NW_Wml1x_FormControlType_None;
  NW_Wml_ElType_e             elType = UNKNOWN_ELEMENT;
  NW_Wml_Element_t            *el;
  NW_Uint16                   elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  (void) NW_Wml_GetElementType(&(thisObj->contentHandler->wmlInterpreter),
															 elementIdAsUint16,
															 &elType,
															 &el);

  switch (elType) {
  case INPUT_ELEMENT:
    type = NW_Wml1x_FormLiaison_GetInputType(thisObj, elemId);
    break;
  case OPTION_ELEMENT:
    type = NW_Wml1x_FormControlType_Option;
    break;
  default:
    type = NW_Wml1x_FormControlType_None;
    break;
  }

  return type;
}

/*****************************************************************

  Name:         NW_Wml1x_FormLiaison_GetInputType()

  Description:

  Parameters:

  Algorithm:

  Return Value:

*****************************************************************/
static
NW_Wml1x_FormControlType_t
NW_Wml1x_FormLiaison_GetInputType(NW_Wml1x_FormLiaison_t  *thisObj,
                                  void                    *elemId)
{
  /* default to <input type=text> */
  NW_Wml1x_FormControlType_t  type = NW_Wml1x_FormControlType_InputText;
  NW_Ucs2                     *retString = NULL;

  static const NW_Ucs2 passwordTag[] = {'p','a','s','s','w','o','r','d'};
  NW_Uint16                   elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  (void) NW_Wml_GetAttribute (&(thisObj->contentHandler->wmlInterpreter),
		                          elementIdAsUint16,
															TYPE_ATTR,
															&retString);

  if (retString != NULL)
  {
    if (NW_Mem_memcmp(retString,
                     passwordTag,
                     sizeof(passwordTag)) == 0)
    {
      type = NW_Wml1x_FormControlType_InputPassword;
    }

    NW_Mem_Free(retString);
  }

  return type;
}



/* ------------------------------------------------------------------------- *
   class definition
 * ------------------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
const
NW_Wml1x_FormLiaison_Class_t NW_Wml1x_FormLiaison_Class = {
  { /* NW_Object_Core          */
    /* super                   */ &NW_FBox_FormLiaison_Class,
    /* queryInterface          */ _NW_Object_Base_QueryInterface
  },
  { /* NW_Object_Base          */
    /* interfaceList           */ NULL
  },
  { /* NW_Object_Dynamic       */
    /* instanceSize            */ sizeof (NW_Wml1x_FormLiaison_t),
    /* construct               */ _NW_Wml1x_FormLiaison_Construct,
    /* destruct                */ _NW_Wml1x_FormLiaison_Destruct
  },
  { /* NW_FBox_FormLiaison     */
    /* getWBXMLVersion         */ _NW_Wml1x_FormLiaison_GetWBXMLVersion,
    /* addControl              */ NULL,
    /* setInitialStringValue   */ _NW_Wml1x_FormLiaison_SetInitialStringValue,
    /* setStringValue          */ _NW_Wml1x_FormLiaison_SetStringValue,
    /* validateStringValue     */ _NW_Wml1x_FormLiaison_ValidateStringValue,
    /* getStringValue          */ _NW_Wml1x_FormLiaison_GetStringValue,
    /* getStringName           */ _NW_Wml1x_FormLiaison_GetStringName,
    /* getStringTitle          */ _NW_Wml1x_FormLiaison_GetStringTitle,
    /* setBoolValue            */ _NW_Wml1x_FormLiaison_SetBoolValue,
    /* resetRadioValue         */ NULL,
    /* toggleBoolValue         */ _NW_Wml1x_FormLiaison_ToggleBoolValue,
    /* getBoolValue            */ _NW_Wml1x_FormLiaison_GetBoolValue,
    /* reset                   */ NULL,
    /* submit                  */ NULL,
    /* focus                   */ NULL,
    /* isOptionMultiple        */ NULL,
    /* isOptionSelected        */ NULL,
    /* optionHasOnPick         */ _NW_Wml1x_FormLiaison_OptionHasOnPick,
    /* isLocalNavOnPick        */ _NW_Wml1x_FormLiaison_IsLocalNavOnPick,
    /* getInitialValue         */ NULL,
    /* getDocRoot              */ _NW_Wml1x_FormLiaison_GetDocRoot,
    /* delegateEcmaEvent       */ _NW_Wml1x_FormLiaison_DelegateEcmaEvent,
   },
  { /* NW_Wml1x_FormLiaison    */
    /* unused                  */ NW_Object_Unused
  }
};

/* ------------------------------------------------------------------------- *
   virtual methods
 * ------------------------------------------------------------------------- */

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_Construct()

  Description:

  Parameters:

  Algorithm:

  Return Value: KBrsrSuccess
                or, return value from superclass constructor

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_Construct (NW_Object_Dynamic_t  *dynamicObject,
                                 va_list              *argp)
{
  NW_Wml1x_FormLiaison_t  *thisObj;

  /* parameter assertions */
  NW_ASSERT (dynamicObject != NULL);
  NW_ASSERT (NW_Object_IsInstanceOf (dynamicObject,
                                     &NW_Wml1x_FormLiaison_Class));
  NW_ASSERT (argp != NULL);

  /* for convenience */
  thisObj = NW_Wml1x_FormLiaisonOf (dynamicObject);

  /* initialize our member variables */
  thisObj->contentHandler = va_arg (*argp, NW_Wml1x_ContentHandler_t*);

  /* successful completion */
  return KBrsrSuccess;
}

/* ------------------------------------------------------------------------- */
void
_NW_Wml1x_FormLiaison_Destruct(NW_Object_Dynamic_t* dynamicObject)
{
  NW_Wml1x_FormLiaison_t  *thisObj;

  /* for convenience */
  thisObj = NW_Wml1x_FormLiaisonOf (dynamicObject);

  NW_Object_Delete (thisObj->lastStringValue);
}

/* ------------------------------------------------------------------------- *
   final methods
 * ------------------------------------------------------------------------- */

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_GetWBXMLVersion()

  Description:  The WBXML version of the WML document is retrieved and translated
                to an enum as defined by TWapDocType in "rb_tempest\fbox\include\
                CoreWrapper.h"

  Parameters:   aWapDocType is an "out" parameter, representative of spec level of
                conformance with WAPFORUM WML the gateway encoder used to
                encode the content from the origin server.

  Algorithm:    Using NW_FBox_FormLiaison_t, look up the version field
                maintained under tinyparser/domtree/doc/version.

  Return Value: KBrsrSuccess, if pointers valid and a value exists
                otherwise, return KBrsrFailure

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetWBXMLVersion(NW_FBox_FormLiaison_t*  thisObj,
                                      NW_Uint32*               wmlVersion)
{
  NW_Wml1x_FormLiaison_t  *formLiaison;
  TBrowserStatusCode             status = KBrsrSuccess;

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  if (formLiaison == NULL)
  {
    status = KBrsrFailure;
  }
  else
  {
    status = NW_Wml_GetPublicId(&(formLiaison->contentHandler->wmlInterpreter),
                                wmlVersion );
  }
  return status;
}
/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_SetInitialStringValue()

  Description:  Sets the initial value for the input form control from the content.
                Currently, not used in WML, so this is just a stub.

  Return Value: KBrsrSuccess 

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_SetInitialStringValue(NW_FBox_FormLiaison_t  *thisObj,
                                            void                   *elemId,
																						NW_Text_Length_t			 maxChars)
{
  NW_REQUIRED_PARAM( thisObj );
  NW_REQUIRED_PARAM( elemId );
  NW_REQUIRED_PARAM( maxChars );

  return KBrsrSuccess;
}

//*****************************************************************
//
//  Name:         _NW_Wml1x_FormLiaison_SetStringValue()
//
//  Description:
//
//  Parameters:   elemId is the actual element Id, not a pointer to anything
//                  so some fancy casting is necessary to avoid confusing the compiler
//                value is a pointer to a text object which we are responsible 
//                  for deleting when we're done with it.
//
//  Algorithm:    Using the elemId, look up the name of the variable to be set.
//                Convert the passed-in value to a Ucs2 string.
//                If NW_Evt_HandleInputEvent() allows the value,
//                  use NW_Wml_SetVar() to save the value on the variable.
//                Else 
//                  notify the user
//
//  Return Value: KBrsrFailure if elemId not an Input element;
//                otherwise, return value from
//
//*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_SetStringValue(NW_FBox_FormLiaison_t  *thisObj,
                                    void                    *elemId,
                                    NW_Text_t               *value)
  {
  TBrowserStatusCode      status = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Ucs2                 *varName = NULL;
  NW_Ucs2                 *varValue = NULL;
  NW_Bool                 freeValue;
  NW_Uint16               elementIdAsUint16;
  NW_Wml_ElType_e         elType = UNKNOWN_ELEMENT;
  NW_Wml_Element_t        *el;
  NW_Bool                 validateOk;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  // NOTE: this assumes (void*) is 32 bits 

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);

  switch (NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId))
       {
       // Password input boxes ignore format attribute, so no longer need to validate input box value
       // against format.  Simply use and save whatever user has entered.
       case NW_Wml1x_FormControlType_InputPassword:  
       varValue = 
           (NW_Ucs2*) NW_Text_GetUCS2Buffer (value,
                                         NW_Text_Flags_NullTerminated | NW_Text_Flags_Aligned,
                                         NULL,
                                         &freeValue);
 
       // lookup name 
       status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
                                        elementIdAsUint16,
                                        NAME_ATTR,
                                        &varName);
       if (status == KBrsrSuccess)
           {
           // password content no longer must match a format, that is to say, formats are now
           // ignored for password fields, so simply set the variable in the formLiaison.
           status = NW_Wml_SetVar (&(formLiaison->contentHandler->wmlInterpreter),
                                    varName,
                                    varValue);
           }
       // free the name string 
       NW_Str_Delete(varName);

       if (freeValue) 
           {
           NW_Str_Delete(varValue);
           }
       break;

       case NW_Wml1x_FormControlType_InputText:    
       varValue = 
          (NW_Ucs2*) NW_Text_GetUCS2Buffer (value,
                                        NW_Text_Flags_NullTerminated | NW_Text_Flags_Aligned,
                                        NULL,
                                        &freeValue);

       // perform WML processing on new varValue
       status = NW_Wml_GetElementType(&(formLiaison->contentHandler->wmlInterpreter),
                                        elementIdAsUint16,
                                        &elType,
                                        &el);

       if (status == KBrsrSuccess)
           {
           // lookup name 
           status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
                                        elementIdAsUint16,
                                        NAME_ATTR,
                                        &varName);

       // setting NW_FALSE for the update variable and sending the address of a 
       // boolean to receive the results of the validate operation, allows us to
       // non-destructively find out if the input matches the input mask (if any)
       //
       status = NW_Wml_HandleInputEvent(&(formLiaison->contentHandler->wmlInterpreter),
                                       el,
                                       varValue,
                                       NW_FALSE,
                                       &validateOk);
       if (validateOk)
           {
           status = NW_Wml_SetVar (&(formLiaison->contentHandler->wmlInterpreter),
                                       varName,
                                       varValue);
           }
       else
           {
           status = KBrsrWmlbrowserInputNonconformingToMask;
           }

       // free the name string
       NW_Str_Delete(varName); 
       }

       if (freeValue) 
           {
           NW_Str_Delete(varValue);
           }
       break;

       default:
       //
       // cannot set value; the input element is not text type
       //
       status = KBrsrFailure;
       break;
       }

  NW_Object_Delete(value);
  return status;
  }


/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_ValidateStringValue()

  Description:

  Parameters:   elemId is the actual element Id, not a pointer to anything
                  so some fancy casting is necessary to avoid confusing the compiler
                value is a pointer to a text object which we are responsible 
                  for deleting when we're done with it.

  Algorithm:    Using the elemId, look up the name of the variable to be set.
                If NW_WmlInput_ValidateValue() disallows the value,
                  notify the user

  Return Value: KBrsrFailure if elemId not an Input element;
                otherwise, return value from NW_WmlInput_ValidateValue()

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_ValidateStringValue (NW_FBox_FormLiaison_t* thisObj,
                                           void* elemId,
                                           const NW_Text_t* value)
{
  TBrowserStatusCode             status        = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Uint32               publicId;
  NW_Ucs2                 *strValue     = NULL;
  NW_Ucs2                 *format       = NULL;
  NW_Ucs2                 *emptyok_str  = NULL;
  NW_Ucs2                 *maxLengthStr = NULL;
  NW_WmlInput_EmptyOk_t   emptyok       = NW_WmlInput_EmptyOk_None;
  NW_Bool                 freeValue     = NW_FALSE;
  NW_Uint16               elementIdAsUint16;
  NW_Bool                 validateOk    = NW_FALSE;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);

  switch (NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId))
  {
   case NW_Wml1x_FormControlType_InputPassword: /* FALL THROUGH */
   case NW_Wml1x_FormControlType_InputText:     /* FALL THROUGH */

    /* get string from NW_Text_UCS2 object */
    strValue = (NW_Ucs2*) NW_Text_GetUCS2Buffer (value,
                                    NW_Text_Flags_NullTerminated | NW_Text_Flags_Aligned,
                                    NULL,
                                    &freeValue);

    /* get FORMAT attr value */
    status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                elementIdAsUint16,
                                FORMAT_ATTR,
                                &format);
    if (status != KBrsrSuccess) {
      goto cleanup;
    }

    /* get EMPTYOK attr value */
    status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                elementIdAsUint16,
                                EMPTYOK_ATTR,
                                &emptyok_str);
    if (status != KBrsrSuccess) {
      goto cleanup;
    }

    status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                elementIdAsUint16,
                                MAXLENGTH_ATTR,
                                &maxLengthStr);
    if (status != KBrsrSuccess) {
      goto cleanup;
    }

    /* maxLengthStr set to NULL if attr not found */
    if (maxLengthStr != NULL) {
			NW_Int32 maxLength = -1; /* Initialize to invalid length */
			if(NW_Str_StrIsValidLength(maxLengthStr))
			{
				maxLength = NW_Str_Atoi(maxLengthStr);
			}
			if(maxLength < 0)
			{
				break;
			}
      else if (NW_Str_Strlen(strValue) > ((NW_Uint32)maxLength))
			{
        validateOk = NW_FALSE;
        break;
      }
    }

    emptyok = NW_WmlInput_EmptyOk_None;
    /* if no format is specified, default for format is *M and emptyok=true.  (WML-191, section 11.6.3 - emptyok) */
    if (emptyok_str == NULL && (format == NULL || *format == NULL)) 
    {
      emptyok = NW_WmlInput_EmptyOk_True;
    }
    else
    {
      if ( emptyok_str != NULL) {  
        if (NW_Str_StrcmpConst(emptyok_str, WAE_ASC_TRUE_STR) == 0) {
          emptyok = NW_WmlInput_EmptyOk_True;
        } else if (NW_Str_StrcmpConst(emptyok_str, WAE_ASC_FALSE_STR) == 0) {
          emptyok = NW_WmlInput_EmptyOk_False;
        } 
      }
    }
    

    /* get Document Public Id value */
    status = NW_Wml_GetPublicId(&(formLiaison->contentHandler->wmlInterpreter),
                                &publicId);
    if (status != KBrsrSuccess) {
      goto cleanup;
    }

    /* Do a full string validatation because this should be called after
       input dialog is closed.  jwild 26-Jan-2002. */
    validateOk = NW_WmlInput_ValidateValue(strValue,
                                           format,
                                           emptyok,
                                           NW_FALSE, /* Full string validation */
                                           publicId);

    break;

   default:
    /*
     * cannot set value; the input element is not text type.  No need to
     * warn user about invalid input.
     */
    validateOk = NW_TRUE;
    status = KBrsrFailure;
    break;
  }

  if (validateOk)
  {
    status = KBrsrSuccess;
  }
  else
  {
    status = KBrsrWmlbrowserInputNonconformingToMask;
  }


cleanup:
  if (freeValue) {
    NW_Str_Delete(strValue);
  }

  NW_Str_Delete(format);
  NW_Str_Delete(emptyok_str);
  NW_Str_Delete(maxLengthStr);

  return status;

}


//*****************************************************************
//
//  Name:         _NW_Wml1x_FormLiaison_GetStringValue()
//
//  Description:
//
//  Parameters:   out parameters: valueOut = initial value | format
//                                initialValueUsed = "value" attribute present
//
//  Algorithm:    Using the elemId, look up the name of the variable to get.
//                Use NW_Wml_GetVar() to retrieve the value of the variable.
//                Convert the value to a NW_Text_t object and set valueOut
//                to point to that object.
//
//  Return Value: KBrsrFailure if elemId not an Input element;
//                otherwise, return value from
//
//*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetStringValue (NW_FBox_FormLiaison_t  *thisObj,
                                      void                   *elemId,
                                      NW_Text_t             **valueOut,
                                      NW_Bool                *initialValueUsed)
  {
  TBrowserStatusCode             status = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Ucs2                 *varName = NULL;
  NW_Ucs2                 *retString = NULL;
  NW_Uint32               publicId = 0;
  NW_Ucs2                 *emptyok_str  = NULL;
  NW_Ucs2                 *maxLengthStr = NULL;
  NW_WmlInput_EmptyOk_t   emptyok       = NW_WmlInput_EmptyOk_None;
  NW_Ucs2                 *format = NULL;
  NW_Ucs2                 *formatMask = NULL;
  NW_Uint16               elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  // NOTE: this assumes (void*) is 32 bits 

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  
  NW_Object_Delete (formLiaison->lastStringValue);
  formLiaison->lastStringValue = NULL;

  switch (NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId))
  {
  case NW_Wml1x_FormControlType_InputPassword:
    // Password input boxes ignore format attribute, so there is no validation
    // to perform.
    // lookup name
    status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
                                 elementIdAsUint16,
                                 NAME_ATTR,
                                 &varName);
    if (status == KBrsrOutOfMemory)
       {
       return status;   
       }
    
    if (varName != NULL)
       {
       // get value 
       status = NW_Wml_GetVar (&(formLiaison->contentHandler->wmlInterpreter),
                               varName,
                               &retString);

       // deal with the failure code returned by GetVar() when the variable is empty 
       if (status == KBrsrFailure)
           {
           status = KBrsrSuccess;
           }

       NW_Mem_Free (varName);
       varName = NULL;
       }

    
    if (retString != NULL)
       {   
       // get maxLengthStr value 
       status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                 elementIdAsUint16,
                                 MAXLENGTH_ATTR,
                                 &maxLengthStr);
       if (status == KBrsrOutOfMemory)
           {
           return status;    
           }
      
       // maxLengthStr set to NULL if attr not found 
       if (maxLengthStr != NULL)
           {
           NW_Int32 maxLength = -1; // Initialize to invalid length
           if(NW_Str_StrIsValidLength(maxLengthStr))
               {
               maxLength = NW_Str_Atoi(maxLengthStr);
               }
           if (maxLength < 0)
               {
               NW_Mem_Free(maxLengthStr);
               break;
               }
           }    
       emptyok = NW_WmlInput_EmptyOk_True;
       }
       *initialValueUsed = (NW_Bool) ( (retString) ? NW_TRUE : NW_FALSE );
       // if value is not available, create an empty string value 
       if (retString == NULL) 
           {
           retString = NW_Str_NewcpyConst( "" );
           }
       if (retString != NULL)
           {
           // convert to text object 
           formLiaison->lastStringValue = (NW_Text_t*)
                NW_Text_UCS2_New (retString, NW_Str_Strlen(retString), NW_Text_Flags_TakeOwnership);
           if (formLiaison->lastStringValue == NULL)
               {
               NW_Mem_Free(retString);
               status = KBrsrOutOfMemory;
               }
           retString = NULL;
           }
       else
           {
           status = KBrsrOutOfMemory;
           }
       break;


  case NW_Wml1x_FormControlType_InputText:    
    // Retrieve var name, var value and format used and validate value against format.
    // lookup name 
    status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
                                 elementIdAsUint16,
                                 NAME_ATTR,
                                 &varName);
    if (status == KBrsrOutOfMemory)
        {
        return status; 
        }
     
    // get FORMAT attr value 
    status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                elementIdAsUint16,
                                FORMAT_ATTR,
                                &format);
    if (status == KBrsrOutOfMemory)
        {
        return status;     
        }
    
    if (varName != NULL)
        {
        // get value 
        status = NW_Wml_GetVar (&(formLiaison->contentHandler->wmlInterpreter),
                                varName,
                                &retString);

        // deal with the failure code returned by GetVar() when the variable is empty 
        if (status == KBrsrFailure)
            {
            status = KBrsrSuccess;
            }

        NW_Mem_Free (varName);
        varName = NULL;
        }

    
    if (retString != NULL)
       {
       // get EMPTYOK attr value 
       status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                  elementIdAsUint16,
                                  EMPTYOK_ATTR,
                                  &emptyok_str);
       if (status == KBrsrOutOfMemory)
            {
            return status;    
            }
       // get Document Public Id value 
       status = NW_Wml_GetPublicId(&(formLiaison->contentHandler->wmlInterpreter),
                                  &publicId);    
       // get maxLengthStr value 
       status = NW_Wml_GetAttribute(&(formLiaison->contentHandler->wmlInterpreter),
                                  elementIdAsUint16,
                                  MAXLENGTH_ATTR,
                                  &maxLengthStr);
       if (status == KBrsrOutOfMemory)
           {
           return status;    
           }      
       // maxLengthStr set to NULL if attr not found 
       if (maxLengthStr != NULL) 
           {
				   NW_Int32 maxLength = -1; // Initialize to invalid length
				   if(NW_Str_StrIsValidLength(maxLengthStr))
				       {
					     maxLength = NW_Str_Atoi(maxLengthStr);
				       }
           if (maxLength < 0)
				       {
               break;
               }
           // to make WML and XHTML behaviour consistent, if the defined maxlength is less than the length
           //  of the value string do not display any initial string.  See the Series 60 XHTML UI SPEC,
           //  section 9.6.4 for additional information regarding the "value" and "maxlen" attribute.
           if (maxLength > NULL && maxLength < (NW_Int32)NW_Str_Strlen( retString ))
               {
               NW_Str_Delete(retString);
               retString = NULL;
               }
           }
    
       emptyok = NW_WmlInput_EmptyOk_None;
       // if no format is specified, default for format is *M and emptyok=true.  (WML-191, section 11.6.3 - emptyok) 
       if (emptyok_str == NULL && (format == NULL || *format == NULL)) 
           {
           emptyok = NW_WmlInput_EmptyOk_True;
           }
       else
           {
           if ( emptyok_str != NULL) 
               {  
               if (NW_Str_StrcmpConst(emptyok_str, WAE_ASC_TRUE_STR) == 0) 
                   {
                   emptyok = NW_WmlInput_EmptyOk_True;
                   }
               else if (NW_Str_StrcmpConst(emptyok_str, WAE_ASC_FALSE_STR) == 0) 
                   {
                   emptyok = NW_WmlInput_EmptyOk_False;
                   } 
               }
           }

       }

       *initialValueUsed = (NW_Bool) ( (retString) ? NW_TRUE : NW_FALSE );

       if ((format !=NULL) && (retString == NULL))
           {
           if ((formatMask = FormatGetMask(format)) != NULL) 
               {
               retString = formatMask;
               }
           }
       else
           {
           if ( NW_WmlInput_ValidateValue(retString, format, emptyok, NW_FALSE, publicId) == NW_FALSE) 
               {
               if (format && (formatMask = FormatGetMask(format)) != NULL) 
                   {
                   NW_Str_Delete(retString);
                   retString = formatMask;
                   }
               else
                   {
                   NW_Str_Delete(retString);
                   retString = NULL;
                   }
               }
           }
   
       // if value is not available, create an empty string value 
       if (retString == NULL) 
           {
           retString = NW_Str_NewcpyConst( "" );
           }
       if (retString != NULL)
           {
           // convert to text object 
           formLiaison->lastStringValue = (NW_Text_t*)
                NW_Text_UCS2_New (retString, NW_Str_Strlen(retString), NW_Text_Flags_TakeOwnership);
           retString = NULL;
           }
       else
           {
           status = KBrsrOutOfMemory;
           }
    break;

    default:
        //
        // cannot get value; the input element is not text type
        //
        status = KBrsrFailure;
        break;
  }

  if (valueOut != NULL)
      {
      *valueOut = formLiaison->lastStringValue;
      }

  NW_Str_Delete(retString);
  NW_Str_Delete(format);
  NW_Str_Delete(emptyok_str);
  NW_Str_Delete(maxLengthStr);

  return status;
  }

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_GetStringName()

  Description:

  Parameters:

  Algorithm:    Using the elemId, look up the name of the variable.
                Convert the name to a NW_Text_t object and set nameOut
                to point to that object.

  Return Value: KBrsrFailure if elemId not an Input element;
                otherwise, return value from

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetStringName(NW_FBox_FormLiaison_t  *thisObj,
                                    void                   *elemId,
                                    NW_Ucs2             **nameOut)
{
  TBrowserStatusCode             status = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Ucs2                 *varName = NULL;
  NW_Uint16               elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  
  /* lookup name */
  status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
    elementIdAsUint16,
    NAME_ATTR,
    &varName);
  
  if (varName == NULL)
  {
    status = KBrsrFailure;
  }
  *nameOut = varName;

  return status;
}

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_GetStringTitle()

  Description:

  Parameters:

  Algorithm:    Using the elemId, look up the name of the variable.
                Convert the name to a NW_Text_t object and set nameOut
                to point to that object.

  Return Value: KBrsrFailure if elemId not an Input element;
                otherwise, return value from

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetStringTitle(NW_FBox_FormLiaison_t  *thisObj,
                                    void                    *elemId,
                                    NW_Ucs2                **titleOut)
{
  TBrowserStatusCode             status = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Ucs2                 *varTitle = NULL;
  NW_Uint16               elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  
  /* lookup name */
  status = NW_Wml_GetAttribute (&(formLiaison->contentHandler->wmlInterpreter),
    elementIdAsUint16,
    TITLE_ATTR,
    &varTitle);
  
  if (varTitle == NULL)
  {
    status = KBrsrFailure;
  }
  *titleOut = varTitle;

  return status;
}

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_SetBoolValue()

  Description:

  Parameters:

  Algorithm:

  Return Value: KBrsrFailure if elemId not an option element;
                otherwise, return value from NW_UI_SetOptState()

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_SetBoolValue (NW_FBox_FormLiaison_t  *thisObj,
                                    void                   *elemId,
                                    NW_Bool                *value)
{
  TBrowserStatusCode             status;
  NW_Wml1x_FormLiaison_t         *formLiaison;
  NW_Uint16                      elementIdAsUint16;
  NW_Wml_ElType_e                elType = UNKNOWN_ELEMENT;
  NW_Wml_Element_t               *el;
  NW_HED_DocumentRoot_t          *docRoot; 

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);

  switch (NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId))
  {
  case NW_Wml1x_FormControlType_Option:
    /* TODO:  is there a better way to access the setOptState() api function? */
    status = (formLiaison->contentHandler->wmlInterpreter.wml_api->display->setOptState)
                  ((formLiaison->contentHandler),
                    elementIdAsUint16,
                    *value);

    /* perform WML processing on new option value */
    status = NW_Wml_GetElementType(&(formLiaison->contentHandler->wmlInterpreter),
                                   elementIdAsUint16,
                                   &elType,
                                   &el);
    if (status == KBrsrSuccess)
    {
      status = NW_Wml_HandleOptionEvent(&(formLiaison->contentHandler->wmlInterpreter), el);
      if (status == KBrsrWmlbrowserOnPickEx)
      {
        /* an onpick event was associated with the option whose state was
        ** just changed so send a message to close the dialog where the
        ** option was changed, since its context may be no longer valid
        */
        docRoot = (NW_HED_DocumentRoot_t*)
          NW_HED_DocumentNode_GetRootNode (formLiaison->contentHandler);

        /* for ISA, does a CallClass((objref) &SelectList, PM_SELECTLIST_CLEANUP, 0, 0, 0); */
        if (docRoot->appServices->selectListApi.cleanup != NULL)
        {
          (docRoot->appServices->selectListApi.cleanup)();
        }
      }
    }

    break;

  default:
    /*
     * cannot set value; the element is not option type,
     */
    status = KBrsrFailure;
    break;
  }

  return status;
}

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_ToggleBoolValue()

  Description:

  Parameters:

  Algorithm:

  Return Value: KBrsrFailure if elemId not an option element;
                KBrsrSuccess otherwise

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_ToggleBoolValue(NW_FBox_FormLiaison_t *thisObj,
                                     void                   *elemId)
{
  NW_Bool value;
  TBrowserStatusCode status = KBrsrSuccess;

  if ((status = NW_FBox_FormLiaison_GetBoolValue(thisObj, elemId, &value)) !=
      KBrsrSuccess)
  {
    return status;
  }

  value = (NW_Bool) !value;
  status = NW_FBox_FormLiaison_SetBoolValue(thisObj,
                                            elemId,
                                            &value);

  return status;
}

/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_GetBoolValue()

  Description:

  Parameters:

  Algorithm:

  Return Value: KBrsrFailure if elemId not an option element;
                KBrsrSuccess otherwise

*****************************************************************/
TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetBoolValue(NW_FBox_FormLiaison_t  *thisObj,
                                  void                    *elemId,
                                  NW_Bool                 *valueOut)
{
  TBrowserStatusCode             status = KBrsrSuccess;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Uint16               elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);

  switch (NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId))
  {
  case NW_Wml1x_FormControlType_Option:
    /* TODO:  is there a better way to access the getOptState() api function? */
    status = (formLiaison->contentHandler->wmlInterpreter.wml_api->display->getOptState)
                  ((formLiaison->contentHandler),
                    elementIdAsUint16,
                    valueOut);
    break;

  default:
    status = KBrsrFailure;
    break;
  }

  return status;
}


/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_OptionHasOnPick()

  Description:

  Parameters:

  Algorithm:

  Return Value: NW_TRUE if elemId has OnPick propert;
                NW_FALSE otherwise

*****************************************************************/
NW_Bool
_NW_Wml1x_FormLiaison_OptionHasOnPick(NW_FBox_FormLiaison_t* thisObj,
                                      void* elemId)
{
  TBrowserStatusCode             status;
  NW_Wml1x_FormLiaison_t  *formLiaison;
  NW_Uint16               elementIdAsUint16;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */

  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);

  NW_ASSERT(NW_Wml1x_FormLiaison_GetControlType(formLiaison, elemId) == NW_Wml1x_FormControlType_Option);

  status = NW_Wml_HasOnpick(&(formLiaison->contentHandler->wmlInterpreter), elementIdAsUint16);

  if (status == KBrsrSuccess)
  {
    return NW_TRUE;
  }

  return NW_FALSE;
}


/*****************************************************************

  Name:         _NW_Wml1x_FormLiaison_IsLocalNavOnPick()

  Description:  Determine if ONPICK attribute points to a "local"
                card within the same deck as the current card.

  Parameters:   NW_FBox_FormLiaison_t* thisObj - used to derive WML context
                void* elemId - id number of OPTION element, needed for GetAttribute
                               subroutine to obtain ONPICK attribute value.

  Algorithm:

  Return Value: NW_TRUE if elemId has OnPick property and nav is considered local;
                NW_FALSE otherwise

*****************************************************************/
NW_Bool
_NW_Wml1x_FormLiaison_IsLocalNavOnPick(NW_FBox_FormLiaison_t* thisObj,
                                      void* elemId)
{
  NW_Uint16                   elementIdAsUint16;
  NW_Ucs2                     *retString = NULL;  // returned URL
  NW_Ucs2                     *target_url = NULL;
  NW_Wml1x_FormLiaison_t      *formLiaison;
  NW_DeckDecoderIter_t        iter;
  NW_Wml_Element_t*           option_el = 0;
  NW_Wml_Element_t            new_el;
  NW_Wml_ElType_e             el_type;
  TBrowserStatusCode          status = NW_FALSE;
  NW_Wml_t*                   wmlObj = NULL;

  elementIdAsUint16 = NW_UINT16_CAST ((NW_Uint32) elemId);  /* NOTE: this assumes (void*) is 32 bits */
  formLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  wmlObj = &(formLiaison->contentHandler->wmlInterpreter);
  (void) NW_Wml_GetAttribute (wmlObj, elementIdAsUint16, ONPICK_ATTR, &retString);

  if (retString)
  {
	status = NW_Wml_GetFullUrl(wmlObj, retString, &target_url);
    NW_Mem_Free(retString);
    if (status != KBrsrSuccess && status != KBrsrFailure)
    {
      /* FAILURE does not imply a fatal error */
      return NW_FALSE;
    }
  }
  else
  {  /* if no "onpick" attr found, try for "onevent" element with "type=onpick" used in the option list */
    if ((status = NW_Wml_GetElementType(wmlObj, elementIdAsUint16, &el_type, &option_el)) != KBrsrSuccess)
	  {
         return NW_FALSE;
	  }

    /* look for a task element */
    if (NW_DeckDecoderIter_InitializeAll_Children(&iter, wmlObj->decoder, option_el) != KBrsrSuccess)
    {
	    return NW_FALSE;
    }

    while ( NW_DeckDecoderIter_GetNextElement(&iter, &new_el) )
    {
	    NW_Wml_ElType_e el_type;

	    NW_DeckDecoder_GetType(wmlObj->decoder, &new_el, &el_type);

   		if (el_type == ONEVENT_ELEMENT)
   		{
   		   if (NW_DeckDecoder_HasAttributeWithValue (wmlObj->decoder, &new_el, TYPE_ATTR,
                    WAE_ASC_ONPICK_STR, wmlObj->var_list))
   		   {
		        while ( NW_DeckDecoderIter_GetNextElement(&iter, &new_el) )
		        {
			         NW_DeckDecoder_GetType(wmlObj->decoder, &new_el, &el_type);

			         if (el_type == GO_ELEMENT)
			         {
			            break;
			         }
		        }

                /* GetHrefAttr & FetchUrl handle 12.5.1.2 */
			    status = NW_Wml_GetHrefAttr(wmlObj, &new_el, &target_url);

    		    if (el_type == GO_ELEMENT)
			      {			     
			         if (status != KBrsrSuccess && status != KBrsrFailure)
			         {
			            /* FAILURE does not imply a fatal error */
			            return NW_FALSE;
			         }
			      }
                else // finished the inner while loop without finding a GO_ELEMENT
                  {
                    if (target_url == NULL)
                    {
                        return NW_TRUE;
                    }
                    else
                    {
                        break;
                    }
                  }
		     } //end if (NW_DeckDecoder......

        }//end if (el_type == ONEVENT_ELEMENT)

    }//end while
    
  } //end else

  if (target_url != NULL)
  {
    status = NW_Wml_IsCardInCurrentDeck(wmlObj, target_url);
    NW_Mem_Free(target_url);
    
    if (status == KBrsrSuccess)
    {
      return NW_TRUE;
    }
  }

  return NW_FALSE;
}

TBrowserStatusCode
_NW_Wml1x_FormLiaison_GetDocRoot(NW_FBox_FormLiaison_t  *thisObj,
                                    NW_HED_DocumentRoot_t **docRoot)
{
  NW_Wml1x_FormLiaison_t  *wml1xFormLiaison ;
  NW_ASSERT (docRoot != NULL);
  wml1xFormLiaison = NW_Wml1x_FormLiaisonOf(thisObj);
  *docRoot =
    (NW_HED_DocumentRoot_t*) NW_HED_DocumentNode_GetRootNode (wml1xFormLiaison->contentHandler);
  return KBrsrSuccess;
}


TBrowserStatusCode
_NW_Wml1x_FormLiaison_DelegateEcmaEvent(NW_FBox_FormLiaison_t *thisObj,
                                        void* eventNode,
                                        NW_ECMA_Evt_Type_t ecmaEvent)

{
  NW_REQUIRED_PARAM( thisObj );
  NW_REQUIRED_PARAM( eventNode );
  NW_REQUIRED_PARAM( ecmaEvent );
  return KBrsrSuccess;
}


/* ------------------------------------------------------------------------- *
   convenience functions
 * ------------------------------------------------------------------------- */

/*****************************************************************

  Name:         NW_Wml1x_FormLiaison_New()

  Description:

  Parameters:

  Algorithm:

  Return Value:

*****************************************************************/
NW_Wml1x_FormLiaison_t*
NW_Wml1x_FormLiaison_New (NW_Wml1x_ContentHandler_t *contentHandler)
{
  return (NW_Wml1x_FormLiaison_t*)
    NW_Object_New (&NW_Wml1x_FormLiaison_Class, contentHandler);
}


static NW_Ucs2* FormatGetMask(const NW_Ucs2 *format) 
{
 
  NW_Ucs2 *format_mask = NULL ;
  NW_Int32 countM=0, countF=0;
  NW_Int32 lastStatic;
  
  format_mask = NW_Str_New(NW_Str_Strlen (format));
  if (format_mask == NULL) {
    return NULL;
  }

  /* find the last static character */
  lastStatic = -1;
  countF = 0;
  while (format && format[countF] ) {
    if (format[countF] == '\\') {
      lastStatic=countF;
    }
    countF++;
  }

  /* if there are static characters - create mask */
  if (lastStatic != -1) {
    countF = 0;
    while (format && format[countF] && countF<=lastStatic) {
    if (format[countF++] == '\\') {
      format_mask[countM++] = format[countF++];
    } 
      else {
        format_mask[countM++] = ' ';
      }
  }

    format_mask[countM] = '\0';
  }
  else {
    NW_Str_Delete(format_mask);
    format_mask = NULL;
  }

  return format_mask;
}



