/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public License
 * Version 1.0 (the "NPL"); you may not use this file except in
 * compliance with the NPL.  You may obtain a copy of the NPL at
 * http://www.mozilla.org/NPL/
 *
 * Software distributed under the NPL is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
 * for the specific language governing rights and limitations under the
 * NPL.
 *
 * The Initial Developer of this code under the NPL is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
 * Reserved.
 */

#include "stdafx.h"

#include "prefapi.h"

#include "netsdoc.h"
#include "template.h"
#ifdef MOZ_LDAP
#include "dirprefs.h"
#endif
#ifdef MOZ_MAIL_NEWS
#include "compfrm.h"
#endif
#ifdef EDITOR
//#include "edview.h"
#endif

#ifdef NSPR20
#include "private/prpriv.h"
#endif

// This is the NSPR priority of the main GUI thread (ie. mozilla)

#ifndef NSPR20
#ifdef XP_WIN32
#define MOZILLA_THREAD_PRIORITY 15
#else
#define MOZILLA_THREAD_PRIORITY 2
#endif
#else
#ifdef XP_WIN32
#define MOZILLA_THREAD_PRIORITY PR_PRIORITY_NORMAL
#else
#define MOZILLA_THREAD_PRIORITY PR_PRIORITY_LOW
#endif
#endif

#if defined(JAVA) || defined(MOCHA)

#ifndef XP_PC
#define XP_PC
#endif
#ifdef XP_WIN32
#ifndef HW_THREADS
#define HW_THREADS
#endif
#else
#ifndef SW_THREADS
#define SW_THREADS
#endif
#endif

#ifndef X386
#define X386
#endif

#include "nspr.h"
#include "java.h"
#endif /* JAVA || MOCHA */

#if defined(XP_PC) && !defined(_WIN32)
#ifdef JAVA
extern "C" PR_PUBLIC_API(void) SuspendAllJavaThreads(void);
#endif
#endif

// Shared event queue used to pass messages between the java threads and
// the main navigator thread...
extern "C" {
PREventQueue *mozilla_event_queue;
PRThread     *mozilla_thread;
};


//
// Call layout with the red green and blue values of the current COLORREF
//
MODULE_PRIVATE void
wfe_SetLayoutColor(int type, COLORREF color)
{

	uint8 red   = GetRValue(color);
	uint8 green	= GetGValue(color);
	uint8 blue  = GetBValue(color);

	LO_SetDefaultColor(type, red, green, blue);

}

void OpenDraftExit (URL_Struct *url_struct, int/*status*/,MWContext *pContext)
{
	XP_ASSERT (url_struct && pContext);

	if (!url_struct) return;

	NET_FreeURLStruct ( url_struct );
}

#ifdef MOZ_LDAP
// This function handles callbacks for all of the *bad* things which we
// are caching in netscape.h...In general, we should try to move these but
// the mnprefs.cpp & mnwizard.cpp are such a mess that I am punting for now
int PR_CALLBACK
DirServerListChanged(const char *pref, void *data)
{
	CString msg = "abook.nab";

	DIR_GetServerPreferences(&theApp.m_directories, msg);
	return TRUE;
}
#endif // MOZ_LDAP

// This function handles callbacks for all of the *bad* things which we
// are caching in netscape.h...In general, we should try to move these but
// the mnprefs.cpp & mnwizard.cpp are such a mess that I am punting for now
int PR_CALLBACK
WinFEPrefChangedFunc(const char *pref, void *data)
{
        if (!strcmpi(pref,"browser.startup.homepage")) {
		LPSTR	lpszHomePage = NULL;

                PREF_CopyCharPref("browser.startup.homepage", &lpszHomePage);
		theApp.m_pHomePage = lpszHomePage;
		if (lpszHomePage)
			XP_FREE(lpszHomePage);

        } else if (!strcmpi(pref,"browser.cache.directory")) {
		LPSTR	lpszCacheDir;

                PREF_CopyCharPref("browser.cache.directory",&lpszCacheDir);
		theApp.m_pCacheDir = lpszCacheDir;
		if (lpszCacheDir)
			XP_FREE(lpszCacheDir);
        } else if (!strcmpi(pref,"browser.bookmark_location")) {
		LPSTR	lpszPref;

                PREF_CopyCharPref("browser.bookmark_location",&lpszPref);
		theApp.m_pBookmarkFile = lpszPref;
		if (lpszPref)
			XP_FREE(lpszPref);
		}
		else if (!strcmpi(pref,"mime.types.all_defined")) { //Begin CRN_MIME
			fe_UpdateMControlMimeTypes();				
		}//End CRN_MIME

	return PREF_NOERROR;
};

#ifdef XP_WIN16
/////////////////////////////////////////////////////////////////////////////
// 16-bit RTL helper functions
//
// These functions are used by NSPR to access RTL functions that are
// not available from 16-bit DLLs...  They provide the necessary
// "mov DS, SS" entry prolog to fix "DS == SS" which is assumed
// by the MS RTL...
//
#ifdef DEBUG
extern "C" int _heapchk();
extern "C" {
	extern unsigned long hcCount;
	extern unsigned long hcMallocCount;
	extern unsigned long hcFreeCount;
	extern unsigned long hcLimit;
}

static void chk()
{
	static unsigned long checkCount;

	if (_heapchk() != _HEAPOK)
		__asm { int 3 }
	hcCount += 1;
	if (hcCount >= hcLimit)
		__asm { int 3 }
}

extern "C" static void aFchkstk(void)
{
}

#endif

#if defined(XP_WIN16)
//  Only used when debug build on win16.
BOOL PR_CALLBACK DefaultBlockingHook(void) {
     MSG msg;
    BOOL ret = FALSE;

    /*
     * Only dispatch messages if the current thread is mozilla...
     */
    if (mozilla_thread == PR_CurrentThread()) {
	/* get the next message if any */
	ret = (BOOL)PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);
	/* if we got one, process it */
	if (ret) {
	    ret = theApp.NSPumpMessage();
	}
    }
     /* TRUE if we got a message */
     return ret;
}
#endif

#ifdef MOZ_USE_MS_MALLOC
/*--------------------------------------------------------------------------*/
/* 32-bit aligned memory management routines				    */
/*--------------------------------------------------------------------------*/
/*									    */
/* The strategy for aligning memory to 32-bit boundaries is to allocate an  */
/* extra 32-bits for each allocation - A 16-bit header and a 16-bit padding */
/*									    */
/* If the memory returned from	_fmalloc() is not 32-bit aligned, then the  */
/* pointer is adjusted forward by 2 bytes to correctly align the memory.    */
/* The resulting 2-byte header is initialized to PR_NON_ALIGNED_HEADER.     */
/* There is also an "extra" 2 byte padding at the end of the block which    */
/* are unused.								    */
/*									    */
/* If the memory returned from _fmalloc() is already 32-aligned, then the   */
/* pointer is adjusted forward by 4 bytes to maintain alignment.  The first */
/* 2 bytes are filled with a pad value in DEBUG mode and the next 2 bytes   */
/* are initialized to PR_ALIGNED_HEADER 				    */
/*									    */
/*--------------------------------------------------------------------------*/

#define PR_HEADER_SIZE		4
#define PR_ALIGNED_PAD		0xDEAD
#define PR_ALIGNED_HEADER	0xAD04
#define PR_NONALIGNED_HEADER	0xAD02

#define PR_IS_ALIGNED(p)	( !(OFFSETOF(p) & 0x03) )
#define PR_GET_HEADER_WORD(p)	( *((WORD*)(((char *)(p))-2)) )
#define PR_GET_HEADER_PAD(p)	( *((WORD*)(((char *)(p))-4)) )
#define PR_GET_ROOT(p)		( (void *)(((unsigned long)(p)) - (unsigned long)(PR_GET_HEADER_WORD(p) & 0x000F)) )

//
// This macro verifies that a memory block is 32-bit aligned and contains
// the proper header values...
//
#ifdef DEBUG
#define PR_VALIDATE_BLOCK(p)	ASSERT( PR_IS_ALIGNED(p) );					 \
				if (p) {							 \
				    if (PR_GET_HEADER_WORD(p) == PR_ALIGNED_HEADER) {		 \
					ASSERT( PR_GET_HEADER_PAD(p) == PR_ALIGNED_PAD );	 \
				    } else {							 \
					ASSERT( PR_GET_HEADER_WORD(p) == PR_NONALIGNED_HEADER ); \
				    }								 \
				}
#else
#define PR_VALIDATE_BLOCK(p)
#endif

void * malloc(size_t size) {
    char *p;
    /* allocate a 16-bit aligned block of memory */
    p = (char *)_fmalloc(size + PR_HEADER_SIZE);

    /* Memory is already 32-bit aligned */
    if ( PR_IS_ALIGNED(p) ) {
#ifdef DEBUG
	*((WORD *)p) = PR_ALIGNED_PAD;
#endif
	p  = ((char *)p) + 2;
	*((WORD *)p) = PR_ALIGNED_HEADER;

    }
    /* Align memory to 32-bit boundary */
    else {
	*((WORD *)p) = PR_NONALIGNED_HEADER;
    }
    p  = ((char *)p) + 2;

    PR_VALIDATE_BLOCK(p);
    return (void *)p;

}

void free(void *p) {
    void *h;

    if (p) {
	PR_VALIDATE_BLOCK(p);

	h = PR_GET_ROOT(p);
	ASSERT( (OFFSETOF(p) - OFFSETOF(h)) <= PR_HEADER_SIZE );
    } else {
	h = NULL;
    }
    _ffree(h);
}

void * realloc(void *p, size_t size) {
    size_t old_size;
    void *new_block;
    void *h;

    if (p) {
	PR_VALIDATE_BLOCK(p);

	h	 = PR_GET_ROOT(p);
	old_size = _fmsize(h) - (PR_GET_HEADER_WORD(p) == PR_ALIGNED_HEADER ? 4 : 2);
	ASSERT( (OFFSETOF(p) - OFFSETOF(h)) <= PR_HEADER_SIZE );
    } else {
	h	 = NULL;
	old_size = 0;
    }


    /* allocate a 32-bit aligned block of memory */
    new_block = malloc(size);

    if (p && new_block) {
	/* copy the original data into the new block of memory */
	memcpy(new_block, p, (old_size < size ? old_size : size));
	/* free the old block of memory */
	_ffree(h);
    }

    p = new_block;

    PR_VALIDATE_BLOCK(p);
    return p;
}

void * calloc(size_t size, size_t number) {
    void *p;
    long bytes;

    bytes = (long)size * (long)number;
    ASSERT(bytes < 0xFFF0L);

    /* allocate a 32-bit aligned block of memory */
    p = malloc((size_t)bytes);

    if (p) {
	memset(p, 0x00, (size_t)bytes);
    }
    PR_VALIDATE_BLOCK(p);
    return p;
}
#endif
/*--------------------------------------------------------------------------*/


void * PR_CALLBACK __ns_malloc(size_t size) {
    return malloc(size);
}

void PR_CALLBACK __ns_free(void *p) {
    free(p);
}

void* PR_CALLBACK __ns_realloc(void *p, size_t size) {
    return realloc(p, size);
}

void* PR_CALLBACK __ns_calloc(size_t size, size_t number) {
    return calloc(size, number);
}

int PR_CALLBACK __ns_gethostname(char * name, int namelen) {
    return gethostname(name, namelen);
}

struct hostent * PR_CALLBACK __ns_gethostbyname(const char * name) {
    return gethostbyname(name);
}

struct hostent * PR_CALLBACK __ns_gethostbyaddr(const char * addr, int len, int type) {
    return gethostbyaddr(addr, len, type);
}

char* PR_CALLBACK __ns_getenv(const char *varname)
{
    return getenv(varname);
}

int PR_CALLBACK __ns_putenv(const char *varname)
{
    return putenv(varname);
}

int PR_CALLBACK __ns_auxOutput(const char *string)
{
#ifdef DEBUG
    ::OutputDebugString(string);
#endif
    return 0;
}

void PR_CALLBACK __ns_exit(int exitCode)
{
    ASSERT(0);
    exit(exitCode);
}

size_t PR_CALLBACK __ns_strftime(char *s, size_t len, const char *fmt, const struct tm *p)
{
    return strftime(s, len, fmt, p);
}


u_long	PR_CALLBACK __ns_ntohl(u_long netlong)
{
    return ntohl(netlong);
}

u_short PR_CALLBACK __ns_ntohs(u_short netshort)
{
    return ntohs(netshort);
}

int PR_CALLBACK __ns_closesocket(SOCKET s)
{
    return closesocket(s);
}

int PR_CALLBACK __ns_setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen)
{
    return setsockopt(s, level, optname, optval, optlen);
}

SOCKET	PR_CALLBACK __ns_socket(int af, int type, int protocol)
{
    return socket(af, type, protocol);
}

int PR_CALLBACK __ns_getsockname(SOCKET s, struct sockaddr FAR *name, int FAR * namelen)
{
    return getsockname(s, name, namelen);
}

u_long	PR_CALLBACK __ns_htonl(u_long hostlong)
{
    return htonl(hostlong);
}

u_short PR_CALLBACK __ns_htons(u_short hostshort)
{
    return htons(hostshort);
}

unsigned long PR_CALLBACK __ns_inet_addr(const char FAR * cp)
{
    return inet_addr(cp);
}

int PR_CALLBACK __ns_WSAGetLastError(void)
{
    return WSAGetLastError();
}

int PR_CALLBACK __ns_connect(SOCKET s, const struct sockaddr FAR *name, int namelen)
{
    return connect(s, name, namelen);
}

int PR_CALLBACK __ns_recv(SOCKET s, char FAR * buf, int len, int flags)
{
    return recv(s, buf, len, flags);
}

int PR_CALLBACK __ns_ioctlsocket(SOCKET s, long cmd, u_long FAR *argp)
{
    return ioctlsocket(s, cmd, argp);
}

int PR_CALLBACK __ns_recvfrom(SOCKET s, char FAR * buf, int len, int flags, struct sockaddr FAR *from, int FAR * fromlen)
{
    return recvfrom(s, buf, len, flags, from, fromlen);
}

int PR_CALLBACK __ns_send(SOCKET s, const char FAR * buf, int len, int flags)
{
    return send(s, buf, len, flags);
}

int PR_CALLBACK __ns_sendto(SOCKET s, const char FAR * buf, int len, int flags, const struct sockaddr FAR *to, int tolen)
{
    return sendto(s, buf, len, flags, to, tolen);
}

SOCKET PR_CALLBACK __ns_accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)
{
    return accept(s, addr, addrlen);
}

int PR_CALLBACK __ns_listen(SOCKET s, int backlog)
{
    return listen(s, backlog);
}

int PR_CALLBACK __ns_bind(SOCKET s, const struct sockaddr FAR *addr, int namelen)
{
    return bind(s, addr, namelen);
}

int PR_CALLBACK __ns_select(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout)
{
    return select(nfds, readfds, writefds, exceptfds, timeout);
}

int PR_CALLBACK __ns_getsockopt(SOCKET s, int level, int optname, char FAR * optval, int FAR *optlen)
{
    return getsockopt(s, level, optname, optval, optlen);
}

struct protoent * PR_CALLBACK __ns_getprotobyname(const char FAR * name)
{
    return getprotobyname(name);
}

int PR_CALLBACK __ns_WSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
                                    long lEvent)
{
    return WSAAsyncSelect(s, hWnd, wMsg, lEvent);
}


void PR_CALLBACK __ns_WSASetLastError(int iError)
{
    WSASetLastError(iError);
}

int PR_CALLBACK MozillaNonblockingNetTicklerCallback(void)
{
//	We need to tickle the network and the UI if we
//	are stuck in java networking code.

    MSG msg;

    if (PR_CurrentThread() == mozilla_thread) {
        /* get the next message if any */
	if (PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)) {
	    (void) theApp.NSPumpMessage();
            return FALSE;
	}
    }
    return TRUE;
}

#endif /* XP_WIN16 */

void fe_InitJava()
{
}

void fe_InitNSPR(void* stackBase)
{
#ifdef XP_WIN16
#if !defined(NSPR20)
//
// The 16-bit MS RTL prohibits 16-bit DLLs from calling some RTL functions.
//   ie.
//	 malloc/free
//	 strftime
//	 sscanf
//	 etc...
// To fix this limitation, function pointers are passed to NSPR which
// route the RTL functions "into the EXE" where the actual RTL function
// is available.  (Oh what a tangled web we weave :-( )
//
static struct PRMethodCallbackStr DLLCallbacks = {
    __ns_malloc,
    __ns_realloc,
    __ns_calloc,
    __ns_free,
    __ns_gethostname,
    __ns_gethostbyname,
    __ns_gethostbyaddr,
    __ns_getenv,
    __ns_putenv,
    __ns_auxOutput,
    __ns_exit,
    __ns_strftime,

    __ns_ntohl,
    __ns_ntohs,
    __ns_closesocket,
    __ns_setsockopt,
    __ns_socket,
    __ns_getsockname,
    __ns_htonl,
    __ns_htons,
    __ns_inet_addr,
    __ns_WSAGetLastError,
    __ns_connect,
    __ns_recv,
    __ns_ioctlsocket,
    __ns_recvfrom,
    __ns_send,
    __ns_sendto,
    __ns_accept,
    __ns_listen,
    __ns_bind,
    __ns_select,
    __ns_getsockopt,
    __ns_getprotobyname,
    __ns_WSAAsyncSelect,
    __ns_WSASetLastError
    };

    // Perform the 16-bit ONLY callback initialization...
    PR_MDInit(&DLLCallbacks);
#endif	/* NSPR20 */
#endif /* XP_WIN16 */

#if defined(JAVA) || defined(MOCHA)
#ifndef NSPR20
    // Initialize the NSPR library
    PR_Init( "mozilla", MOZILLA_THREAD_PRIORITY, 1, stackBase);

    mozilla_thread = PR_CurrentThread();
#else
	PR_STDIO_INIT()
    mozilla_thread = PR_CurrentThread();
    PR_SetThreadGCAble();
    PR_SetThreadPriority(mozilla_thread, MOZILLA_THREAD_PRIORITY);
    PL_InitializeEventsLib("mozilla");
#endif
#endif /* JAVA || MOCHA */
}

BOOL fe_ShutdownJava()
{
	BOOL bRetval = TRUE;

#ifdef JAVA
    bRetval = (LJ_ShutdownJava() == LJJavaStatus_Enabled);
#if defined(XP_PC) && !defined(_WIN32)
    SuspendAllJavaThreads();
#endif
#endif

	return(bRetval);
}

//
// Register our document icons
//
static const CString strMARKUP_KEY = "NetscapeMarkup";

BOOL fe_RegisterOLEIcon ( LPSTR szCLSIDObject,	 // Class ID of the Object
		       LPSTR szObjectName,    // Human Readable Object Name
		       LPSTR szIconPath )     // Path and Index of Icon
{
    HKEY hKey;
    LONG lRes = 0L;

    char lpszCLSID[]       = "CLSID";         // OLE Class ID Section of eg DB
    char lpszDefIcon[]     = "\\DefaultIcon"; // Default Icon Subkey
    char lpBuffer[64];			      // Working buffer

    // Open the reg db for the "CLSID" key, this top-level key
    // is where OLE2 and other OLE aware apps will look for
    // this information.

    lRes = RegOpenKey(HKEY_CLASSES_ROOT, lpszCLSID, &hKey);

    if (ERROR_SUCCESS != lRes)
      {
      TRACE("RegOpenKey failed.\n");
      return FALSE;
      }

    // Register the Object

    // Set the value of the CLSID Entry to the Human Readable
    // name of the Object

    lRes = RegSetValue( hKey,
			szCLSIDObject,
			REG_SZ,
			szObjectName,
			lstrlen(szObjectName)
		      );

    if (ERROR_SUCCESS != lRes)	// bail on failure
      {
      RegCloseKey(hKey);
      return FALSE;
      }

    // Build "defaulticon" subkey string  "{ <class id> }\\DefaultIcon"
    lstrcpy (lpBuffer, szCLSIDObject);
    lstrcat (lpBuffer, lpszDefIcon);

    // Set Object's default icon entry to point to the
    // default icon for the object

    lRes = RegSetValue( hKey,
			lpBuffer,
			REG_SZ,
			szIconPath,
			lstrlen(szIconPath)
		      );

    if (ERROR_SUCCESS != lRes)	// bail on failure
      {
      RegCloseKey(hKey);
      return FALSE;
      }

    // Close the reg db

    RegCloseKey(hKey);


//
//
//

    lRes = RegOpenKey(HKEY_CLASSES_ROOT, (const char*)strMARKUP_KEY, &hKey);

    if (ERROR_SUCCESS != lRes)
      {
      TRACE("RegOpenKey failed.\n");
      return FALSE;
      }

    // Set Object's default icon entry to point to the
    // default icon for the object

    lRes = RegSetValue( hKey,
			lpszCLSID,
			REG_SZ,
			szCLSIDObject,
			lstrlen(szCLSIDObject)
		      );

    if (ERROR_SUCCESS != lRes)	// bail on failure
      {
      RegCloseKey(hKey);
      return FALSE;
      }


    // Set Object's default icon entry to point to the
    // default icon for the object

    lRes = RegSetValue( hKey,
                        "DefaultIcon",
			REG_SZ,
			szIconPath,
			lstrlen(szIconPath)
		      );

    if (ERROR_SUCCESS != lRes)	// bail on failure
      {
      RegCloseKey(hKey);
      return FALSE;
      }

    // Close the reg db

    RegCloseKey(hKey);



    return TRUE;
}

#if defined(XP_WIN16)
/****************************************************************************/
/*									    */
/* BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE!  */
/*									    */
/* The following code is duplicated from ns\modules\applet\src\lj_embed.c   */
/* It is ONLY required for 16-bit until JAVA becomes integrated into the    */
/* build!								    */
/*									    */
/* BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE! BEWARE!  */
/*									    */
/****************************************************************************/
#if defined(MOCHA) && !defined(JAVA)
#include "prevent.h"
#include "prlog.h"

PR_LOG_DEFINE(Event);

/*
 * There is currently a race between which thread destroys synchronous
 *   events.  See bug 32832 for a full description.
 */
void
LJ_ProcessEvent()
{
    PREvent* event;

    for (;;) {
        PR_LOG_BEGIN(Event, debug, ("$$$ getting event\n"));

	event = PR_GetEvent(mozilla_event_queue);
	if (event == NULL) {
	    return;
	}

	if(event->synchronousResult) {
	    PR_HandleEvent(event);
            PR_LOG_END(Event, debug, ("$$$ done with sync event\n"));
	}
	else {
	    PR_HandleEvent(event);
            PR_LOG_END(Event, debug, ("$$$ done with async event\n"));
	    PR_DestroyEvent(event);
	}

    }
}
#endif	// MOCHA && !JAVA
#endif	// XP_WIN16

#ifdef XP_WIN16
#if defined(NSPR20)
#include "private\prpriv.h"
#endif
void fe_yield(void)
{
	PR_Sleep(PR_INTERVAL_NO_WAIT);
}
#endif
