/*
* Copyright (c) 1999 - 2001 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: 
*
*/


/*
    $Workfile: wml_history.c $

    Purpose:

        Class: WmlBrowser

        Maintain browser's history state logic
*/

#include "wml_history.h"

#include "nwx_string.h"
#include "nwx_http_header.h"
#include "nw_evlog_api.h"
#include "nw_wae.h"
#include "nwx_ctx.h"
#include "nw_hed_documentroot.h"
#include "BrsrStatusCodes.h"
#include "MemoryManager.h"


/*------------------------------------------------------------------------
 * StringCopy -- makes a copy of src string, puts its address in *dest,
 * and returns true iff the copy was successful (failure means we ran
 * out of memory).  If src is NULL, the 'copy' just consists of a copy
 * of the NULL pointer, and is considered successful.
 -----------------------------------------------------------------------*/
static NW_Bool StringCopy(NW_Ucs2 **dest, NW_Ucs2 *src)
{
  if (src) {
    *dest = NW_Str_Newcpy(src);
    if (*dest != NULL) {
      return NW_TRUE;
    } else {
      return NW_FALSE;
    }
  } else {
    *dest = NULL;
    return NW_TRUE;
  }
}

/* Create a new history entry object */
static NW_Wml_History_t *Wml_HistoryNewEntry(NW_Ucs2 *req_url)
{
  NW_Wml_History_t *entry;

  /* Note: NULL args are acceptable */
  entry = (NW_Wml_History_t*) NW_Mem_Malloc(sizeof(NW_Wml_History_t));
  if (entry != NULL) {
    if (StringCopy(&(entry->req_url), req_url) == NW_TRUE) {
       return entry;
    } else {
      NW_Str_Delete(entry->req_url);
      entry->req_url = NULL;
    }
    NW_Mem_Free(entry);
  }

  return NULL;
}

/* Creates a copy of a Wml History entry using information from HED history.
   Returns a pointer to the new entry or NULL when failed.*/
static NW_Wml_History_t *HEDtoWmlHistoryEntry(NW_HED_HistoryEntry_t *entry)
{
  NW_Ucs2          *reqUrl;
  NW_Wml_History_t *dest;

  reqUrl = (NW_Ucs2 *)NW_HED_UrlRequest_GetRawUrl(entry->urlRequest);
  dest = Wml_HistoryNewEntry(reqUrl);
  return (dest);
}

/* Delete a history entry object */
void NW_Wml_HistoryDeleteEntry(NW_Wml_History_t *entry)
{
  if (entry != NULL) {
    NW_Str_Delete(entry->req_url);
    entry->req_url = NULL;
    NW_Mem_Free(entry);
  }
  return;
}


/*-------------------------------------------------------------------------
 * NW_Wml_HistoryInit -- initialize the history stack
 ------------------------------------------------------------------------*/
void NW_Wml_HistoryInit(NW_Wml_t *wml)
{
  NW_ASSERT(wml != NULL);

  wml->history_resp_url = NULL;
  return;
}


/*--------------------------------------------------------------------------
 * NW_Wml_HistoryClear -- clear all history entries, but preserve the
 *                        current entry
 -------------------------------------------------------------------------*/

void NW_Wml_HistoryClear(NW_Wml_t *wml)
{
  NW_HED_DocumentRoot_t *dr;
  NW_HED_HistoryStack_t *history;
  NW_HED_HistoryEntry_t *entry;

  NW_ASSERT(wml != NULL);

  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);

  history = NW_HED_DocumentRoot_GetHistoryStack (dr);
  if (history == NULL) {
    return;
  }
  /* remove the current entry from the history */
  entry = NW_HED_HistoryStack_RemoveEntry (history, NW_HED_HistoryStack_Direction_Current); 
  if (entry == NULL) {
    return;
  }

  /* delete all of the remaining entries */
  NW_HED_HistoryStack_DeleteAll (history);

  /* add the current entry back */
  NW_HED_HistoryStack_PushEntry (history, entry);
}


/*---------------------------------------------------------------------------
 * NW_Wml_HistoryForIntradeckLoad
 *
 * Crates a new entry in the global history to reflect intradeck load
 * -------------------------------------------------------------------------*/
TBrowserStatusCode NW_Wml_HistoryPushIntraDeckLoad(NW_Wml_t *wml,
                                            NW_Ucs2  *reqUrl, 
                                            NW_Ucs2  *respUrl)
{
  NW_HED_DocumentRoot_t *dr;
  NW_HED_ContentHandler_t *thisObj;
  NW_HED_HistoryEntry_t *newEntry = NULL;
  NW_Text_UCS2_t        requestUrl;
  NW_Text_UCS2_t        responseUrl;
  TBrowserStatusCode           status = KBrsrOutOfMemory;

  NW_ASSERT(wml != NULL);
  NW_ASSERT(reqUrl != NULL);
  NW_ASSERT(respUrl != NULL);

  /* get the document-root and content-handler */
  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);
  NW_THROWIF_NULL (dr);
  NW_THROWIF_NULL (thisObj = NW_HED_ContentHandlerOf (wml->browser_app));

  /* wrap the urls as NW_Text_t */
  NW_THROWIF_ERROR (status = NW_Text_UCS2_Initialize (&requestUrl, reqUrl, NW_Str_Strlen (reqUrl), 0));
  NW_THROWIF_ERROR (status = NW_Text_UCS2_Initialize (&responseUrl, respUrl, NW_Str_Strlen (respUrl), 0));

  /* create the new entry */
  NW_THROWIF_NULL (newEntry = NW_HED_ContentHandler_CreateIntraDocumentHistoryEntry (thisObj, 
      &requestUrl, &responseUrl));

  /* push the new entry on the history stack */
  NW_THROWIF_ERROR (status = NW_HED_HistoryStack_PushEntry (dr->historyStack, newEntry));

  /* update the content handler to point to the associated history entry */
  NW_THROWIF_ERROR (status = NW_HED_ContentHandler_SetAssociatedHistoryEntry (thisObj, newEntry));

  return KBrsrSuccess; 

NW_CATCH_ERROR
  
  NW_Object_Delete (newEntry);
  return status;
}


/*-------------------------------------------------------------------------- 
 * NW_Wml_HistoryToPrev
 *  RETURN: KBrsrSuccess
 *          KBrsrFailure
 *          KBrsrOutOfMemory
 * Returns the current history entry in NW_Wml_History_t structure (when wmlEntry!=0). 
 * Return (1)value KBrsrSuccess indicates a successful move to the previous 
 * entry in the HED history and (2)wmlEntry when requested. 
 * KBrsrFailure indicates an absence of the previous entry.
 * KBrsrOutOfMemory is returned when not enough memory to create wmlEntry
 *
 * Note -- the 'wmlEntry' argument may be NULL, indicating that the caller 
 * only wants to move to the previous entry.
 *------------------------------------------------------------------------*/
TBrowserStatusCode NW_Wml_HistoryToPrev(NW_Wml_t *wml, NW_Wml_History_t **wmlEntry) 
{
  NW_HED_DocumentRoot_t *dr;
  TBrowserStatusCode           nwStatus = KBrsrSuccess;

  NW_ASSERT(wml != NULL);

  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);

  if (wmlEntry)
  {
    NW_HED_HistoryEntry_t *HEDhistEntry;
    HEDhistEntry = NW_HED_HistoryStack_GetEntry (dr->historyStack,
                             NW_HED_HistoryStack_Direction_Current);
    NW_ASSERT(HEDhistEntry);

    *wmlEntry = HEDtoWmlHistoryEntry(HEDhistEntry);
    if (*wmlEntry == NULL) {
      nwStatus = KBrsrOutOfMemory;
    }
  }

  if (nwStatus == KBrsrSuccess) {
    nwStatus = NW_HED_HistoryStack_SetCurrent(dr->historyStack,
                           NW_HED_HistoryStack_Direction_Previous);
  }
  return nwStatus; 
}


/*---------------------------------------------------------------------
 * sets the history_resp_url member of NW_Wml_t.  This is separate from
 * SetLastLoad, because at the time SetLastLoad is called, we don't
 * know what the response url will be (could be redirected).
 */
TBrowserStatusCode NW_Wml_HistorySetResponseUrl(NW_Wml_t* wml, NW_Ucs2 *resp_url)
{
  NW_ASSERT(wml != NULL);
  NW_ASSERT(resp_url != NULL);

  NW_Str_Delete(wml->history_resp_url);
  wml->history_resp_url = NW_Str_Newcpy(resp_url);

  if (wml->history_resp_url == NULL) {
    return KBrsrOutOfMemory;
  } else {
    return KBrsrSuccess;
  }
}

/*----------------------------------------------------------------------
 * Gets the 'req_url member of top-of-stack, and makes a new copy of it
 * in the mem_scope given.  The address is return in *ret_string; if the req_url
 * was null, *ret_string is also null.
 ---------------------------------------------------------------------*/
TBrowserStatusCode NW_Wml_HistoryGetRequestUrl(NW_Wml_t *wml,
                                        NW_Ucs2 **req_url) 
{
  NW_Ucs2               *url;
  NW_HED_DocumentRoot_t *dr;
  NW_HED_HistoryEntry_t *currEntry;
  TBrowserStatusCode           nwStatus = KBrsrSuccess;

  NW_ASSERT(wml != NULL);
  NW_ASSERT(req_url != NULL);
  *req_url = NULL;

  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);

  currEntry = NW_HED_HistoryStack_GetEntry (dr->historyStack,
                         NW_HED_HistoryStack_Direction_Current);
  NW_ASSERT(currEntry);

  url = (NW_Ucs2 *)NW_HED_UrlResponse_GetRawUrl(currEntry->urlResponse);
  if (url) {
    *req_url = NW_Str_Newcpy(url);
    if (!*req_url) {
      nwStatus = KBrsrOutOfMemory;
    }
  }
  return nwStatus;
}

/*----------------------------------------------------------------------
 * Gets the history_resp_url member of NW_Wml_t, and makes a new copy of it
 * in the mem_scope given.  The address is return in *resp_url; if the 
 * response_url was null, *resp_url is also null.
 ---------------------------------------------------------------------*/
 
TBrowserStatusCode NW_Wml_HistoryGetResponseUrl(NW_Wml_t *wml,
                                         NW_Ucs2  **resp_url) 
{
  NW_ASSERT(wml != NULL);
  NW_ASSERT(resp_url != NULL);

  if (wml->history_resp_url  != NULL) {
    *resp_url = NW_Str_Newcpy(wml->history_resp_url);
    if (*resp_url == NULL)
      return KBrsrOutOfMemory;
  } else {
    *resp_url = NULL;
  }

  return KBrsrSuccess;
}

/*----------------------------------------------------------------------
 * Gets the responseUrl member of the previous-history-entry, and makes a new copy of it
 * in the mem_scope given.  The address is return in *resp_url; if the 
 * response_url was null, *resp_url is also null.
 ---------------------------------------------------------------------*/
TBrowserStatusCode NW_Wml_HistoryGetPrevResponseUrl(NW_Wml_t *wml,
                                             NW_Ucs2  **resp_url)
{
  NW_Ucs2               *url;
  NW_HED_DocumentRoot_t *dr;
  NW_HED_HistoryEntry_t *currEntry;

  NW_ASSERT(wml != NULL);
  NW_ASSERT(resp_url != NULL);
  *resp_url = NULL;

  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);

  currEntry = NW_HED_HistoryStack_GetEntry (dr->historyStack,
                         NW_HED_HistoryStack_Direction_Previous);
  if (currEntry == NULL) {
    return KBrsrFailure;
  }

  url = (NW_Ucs2 *)NW_HED_UrlResponse_GetRawUrl(currEntry->urlResponse);
  if (url) {
    *resp_url = NW_Str_Newcpy(url);
    if (!*resp_url) {
      return KBrsrOutOfMemory;
    }
  }
  return KBrsrSuccess;
}


/*-------------------------------------------------------------------------------
 * NW_Wml_HistoryPrevCard
 * 
 * RETURN: KBrsrSuccess -- there is a previous card, and you got info about it
 *         KBrsrFailure -- there is no previous card, and you didn't get much
 *         KBrsrOutOfMemory -- you're out of memory
 *
 * Note -- you get a mutated copy of the history-stack entry in NW_Wml_History_t format.
 * Any non-null string pointers are replaced by pointers to brand new copies of the
 * original strings, in the mem_scope of your choice.
 ------------------------------------------------------------------------------*/
TBrowserStatusCode NW_Wml_HistoryPrevCard(NW_Wml_t          *wml, 
                                   NW_Wml_History_t **entry)
{
  NW_HED_DocumentRoot_t *dr;
  NW_HED_HistoryEntry_t *prevEntry;
  TBrowserStatusCode           nwStatus = KBrsrSuccess;

  NW_ASSERT(wml != NULL);
  NW_ASSERT(entry != NULL);

  dr = (NW_HED_DocumentRoot_t*)
    NW_HED_DocumentNode_GetRootNode (wml->browser_app);

  prevEntry = NW_HED_HistoryStack_GetEntry(dr->historyStack,
                                  NW_HED_HistoryStack_Direction_Previous);
  if (prevEntry == NULL) {
    nwStatus = KBrsrFailure;
    *entry = NULL;
  }
  else {
    *entry = HEDtoWmlHistoryEntry(prevEntry);
    if (*entry == NULL) {
      nwStatus = KBrsrOutOfMemory;
    }
  }
  return nwStatus;
}
