/* -*- Mode: C; tab-width: 4; -*- */
/******************************************************************************
 * Copyright (c) 1996 Netscape Communications. All rights reserved.
 ******************************************************************************/
/*
 * UnixShell.c
 *
 * Netscape Client Plugin API
 * - Function that need to be implemented by plugin developers
 *
 * This file defines a "Template" plugin that plugin developers can use
 * as the basis for a real plugin.  This shell just provides empty
 * implementations of all functions that the plugin can implement
 * that will be called by Netscape (the NPP_xxx methods defined in 
 * npapi.h). 
 *
 * dp Suresh <dp@netscape.com>
 *
 */

#include <stdio.h>
extern "C" {
#include "npapi.h"
};

//#define WS_DEBUG

#ifdef _WINDOWS
#ifndef WS_DEBUG
#include <win/WSDwinAppDev.h>
#endif
#include <windows.h>
extern LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM uParam,LPARAM lParam);
#endif /* _WINDOWS */

#ifdef XP_UNIX
#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#endif /* XP_UNIX */
#include <WSCdevice.h>

/***********************************************************************
 * Instance state information about the plugin.
 *
 * PLUGIN DEVELOPERS:
 *	Use this struct to hold per-instance information that you'll
 *	need in the various functions in this file.
 ***********************************************************************/

#ifndef WS_DEBUG
#include <WScom.h>
#include <WSCbase.h>
#include <WSDappDev.h>
#endif

extern "C" {
typedef struct _PluginInstance
{
    NPWindow*               fWindow;
    uint16                  fMode;

#ifdef _WINDOWS
        HWND                    fhWnd;
        WNDPROC                 fDefaultWindowProc;
#endif /* _WINDOWS */

#ifdef XP_UNIX
    Window window;
    Display *display;
    uint32 x, y;
    uint32 width, height;
#endif /* XP_UNIX */
} PluginInstance;

/*******************************************************************************
 * Windows-only declarations
 ******************************************************************************/

#ifdef _WINDOWS
//LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
const char* gInstanceLookupString = "instance->pdata";
#endif


/***********************************************************************
 *
 * Empty implementations of plugin API functions
 *
 * PLUGIN DEVELOPERS:
 *	You will need to implement these functions as required by your
 *	plugin.
 *
 ***********************************************************************/

#ifdef XP_UNIX
char*
NPP_GetMIMEDescription(void)
{
static WSCstring ret;
   ret << "application/x-" << WSGIappDev()->getInstanceName()
       << "-plugin:smp:" << WSGIappDev()->getInstanceName();
   return ret;
}

NPError
NPP_GetValue(void *future, NPPVariable variable, void *value)
{
	NPError err = NPERR_NO_ERROR;

	switch (variable) {
		case NPPVpluginNameString:
			*((char **)value) = "Template plugin";
			break;
		case NPPVpluginDescriptionString:
			*((char **)value) =
				"This plugins handles nothing. This is only"
				" a template.";
			break;
		default:
			err = NPERR_GENERIC_ERROR;
	}
	return err;
}
#endif /* XP_UNIX */

NPError
NPP_Initialize(void)
{

    return NPERR_NO_ERROR;
}


jref
NPP_GetJavaClass()
{
    return NULL;
}

void
NPP_Shutdown(void)
{
}
#ifndef WS_DEBUG
static WSClistData _instance_list;
static WSClistData _base_list;
#endif

NPError 
NPP_New(NPMIMEType pluginType,
	NPP instance,
	uint16 mode,
	int16 argc,
	char* argn[],
	char* argv[],
	NPSavedData* saved)
{
        PluginInstance* This;
static long _init = 0;
if (_init == 0){
_init = 1;
_dbprintf_init();
}
	if (instance == NULL)
		return NPERR_INVALID_INSTANCE_ERROR;
		
	instance->pdata = NPN_MemAlloc(sizeof(PluginInstance));
	
	This = (PluginInstance*) instance->pdata;
dbprintf("NPP_New %s:%d start This=0x%x\n",__FILE__,__LINE__,This);

//printf("New This=0x%x\n",This);
#ifdef XP_UNIX
static long initialized = 0;
if (initialized == 0){
  initialized = 1;
  void* _context;
  NPN_GetValue(instance,NPNVxtAppContext,(void*)&_context);
extern void _ws_initialize(void*);
  _ws_initialize(_context);
}
#endif /* XP_UNIX */
#ifndef WS_DEBUG
	if (This != NULL){
          _instance_list.add((void*)This);
          _base_list.add((void*)NULL);
        }
#endif
dbprintf("NPP_New %s:%d done This=0x%x\n",__FILE__,__LINE__,This);
	if (This != NULL)
		return NPERR_NO_ERROR;
	else
		return NPERR_OUT_OF_MEMORY_ERROR;
}


NPError 
NPP_Destroy(NPP instance, NPSavedData** save)
{
	PluginInstance* This;
dbprintf("NPP_Destroy %s:%d start\n",__FILE__,__LINE__);

	if (instance == NULL)
		return NPERR_INVALID_INSTANCE_ERROR;

	This = (PluginInstance*) instance->pdata;
dbprintf("NPP_Destroy %s:%d  This=0x%x\n",__FILE__,__LINE__,This);


#if 1
long inst_num = _instance_list.getNum();
long i;
for(i=0; i<inst_num; i++){
  PluginInstance* item = (PluginInstance*)_instance_list[i];
  WSCbase* inst = (WSCbase*)_base_list[i];
dbprintf("NPP_Destroy %s:%d item=0x%x inst=0x%x\n",__FILE__,__LINE__,item,inst);
  if (item == This){
//printf("NPP_SetWindow.. create base\n");
      _instance_list.delPos(i);
      _base_list.delPos(i);
    if (inst != NULL){
//printf("NPP_SetWindow.. vis=%d\n",inst->getVisible());
dbprintf("NPP_Destroy %s:%d destroy inst=%s\n",__FILE__,__LINE__,inst->getInstanceName());
      delete inst;
    }
  }
}
        WSGIappDevice()->clearDeleteList();
#endif
//printf("NPP_Destroy.. \n");
#ifdef _WINDOWS
        if (WSGIwinAppDev()->getWindowResource()){
          DestroyWindow((HWND)WSGIwinAppDev()->getWindowResource());
        }
#endif


	/* PLUGIN DEVELOPERS:
	 *	If desired, call NP_MemAlloc to create a
	 *	NPSavedDate structure containing any state information
	 *	that you want restored if this plugin instance is later
	 *	recreated.
	 */

	if (This != NULL) {
		NPN_MemFree(instance->pdata);
		instance->pdata = NULL;
	}

dbprintf("NPP_Destroy %s:%d done This=0x%x\n",__FILE__,__LINE__,This);
	return NPERR_NO_ERROR;
}

NPError 
NPP_SetWindow(NPP instance, NPWindow* window)
{
	PluginInstance* This;
dbprintf("NPP_SetWindow %s:%d start\n",__FILE__,__LINE__);
	if (instance == NULL)
		return NPERR_INVALID_INSTANCE_ERROR;

	if (window == NULL)
		return NPERR_NO_ERROR;

	This = (PluginInstance*) instance->pdata;
dbprintf("NPP_SetWindow %s:%d This=0x%x\n",__FILE__,__LINE__,This);

	/*
	 * PLUGIN DEVELOPERS:
	 *	Before setting window to point to the
	 *	new window, you may wish to compare the new window
	 *	info to the previous window (if any) to note window
	 *	size changes, etc.
	 */

#ifdef XP_UNIX
        {
                Widget netscape_widget;

                This->window = (Window) window->window;
                This->x = window->x;
                This->y = window->y;
                This->width = window->width;
                This->height = window->height;
                This->display = ((NPSetWindowCallbackStruct *)window->ws_info)->display;

            netscape_widget = XtWindowToWidget(This->display, This->window);

extern void _ws_set_window(void*);
extern WSCbase* _ws_create_window();

      _ws_set_window((void*)netscape_widget);
//printf("NPP_SetWindow.. widget=0x%x\n",netscape_widget);
long inst_num = _instance_list.getNum();
long i;
for(i=0; i<inst_num; i++){
  PluginInstance* item = (PluginInstance*)_instance_list[i];
  WSCbase* inst = (WSCbase*)_base_list[i];
  if (item == This){
    if (inst == NULL){
//printf("NPP_SetWindow.. create base\n");
      _base_list.setData(i, _ws_create_window());
      break;
    }else{
//printf("NPP_SetWindow.. vis=%d\n",inst->getVisible());
     This->width = window->width;
     This->height = window->height;
      Arg args[2];
      XtSetArg(args[0],XtNwidth, This->width);
      XtSetArg(args[1],XtNheight,This->height);
      XtSetValues(netscape_widget,args,2);
      inst->setVisible(True);
    }
  }
}
        }
#endif /* XP_UNIX */
#ifdef _WINDOWS
#ifndef WS_DEBUG
    {
      if( window != NULL && window->window != NULL ){
        HINSTANCE hInst = (HINSTANCE)GetWindowLong((HWND)window->window,GWL_HINSTANCE);
        if (hInst != NULL){
          WSGIwinAppDev()->setInstanceHandle(hInst);
static long _win_initialized = 0;
dbprintf("NPP_SetWindow %s:%d hInst=0x%x init=%d\n",__FILE__,__LINE__,hInst,_win_initialized);
          if (_win_initialized == 0){
            _win_initialized = 1;
extern void _ws_initialize(void*);
            _ws_initialize(NULL);
          }
        }

      }
dbprintf("NPP_SetWindow %s:%d This->fhWnd=0x%x window->window=0x%x\n",__FILE__,__LINE__,This->fhWnd,window->window);
      if( (window == NULL) || ( window->window == NULL ) ){
        SetWindowLong( This->fhWnd, GWL_WNDPROC,
                       (LONG)This->fDefaultWindowProc);
        This->fDefaultWindowProc = NULL;
        This->fhWnd = NULL;
        return NPERR_NO_ERROR;
      }

      This->fDefaultWindowProc = (WNDPROC)SetWindowLong(
                                           (HWND)window->window,
                                           GWL_WNDPROC,
                                           (LONG)WndProc);
      WSGIwinAppDev()->setWndProc((void*)WndProc);
      This->fhWnd = (HWND) window->window;
      SetProp( This->fhWnd, gInstanceLookupString, (HANDLE)This);

extern void _ws_set_window(void*);
extern WSCbase* _ws_create_window();
//printf("NPP_SetWindow.. window=0x%x\n",This->fhWnd);
long inst_num = _instance_list.getNum();
long i;
for(i=0; i<inst_num; i++){
  PluginInstance* item = (PluginInstance*)_instance_list[i];
  WSCbase* inst = (WSCbase*)_base_list[i];
  if (item == This){
    if (inst == NULL){
//printf("NPP_SetWindow.. create base\n");
dbprintf("NPP_SetWindow %s:%d inst created..\n",__FILE__,__LINE__);
      _ws_set_window((void*)This->fhWnd);
      _base_list.setData(i, _ws_create_window());
      break;
    }else{
//printf("NPP_SetWindow.. vis=%d\n",inst->getVisible());
dbprintf("NPP_SetWindow %s:%d inst=%s vis=%d\n",__FILE__,__LINE__,inst->getInstanceName(),inst->getVisible());
      inst->setVisible(True);
    }
  }
}

      InvalidateRect( This->fhWnd, NULL, TRUE );
      UpdateWindow( This->fhWnd );
    }
#endif
#endif /* _WINDOWS */
dbprintf("NPP_SetWindow %s:%d done This=0x%x\n",__FILE__,__LINE__,This);
    return NPERR_NO_ERROR;
}


NPError 
NPP_NewStream(NPP instance,
			  NPMIMEType type,
			  NPStream *stream, 
			  NPBool seekable,
			  uint16 *stype)
{
	NPByteRange range;
	PluginInstance* This;

	if (instance == NULL)
		return NPERR_INVALID_INSTANCE_ERROR;

	This = (PluginInstance*) instance->pdata;

	return NPERR_NO_ERROR;
}


/* PLUGIN DEVELOPERS:
 *	These next 2 functions are directly relevant in a plug-in which
 *	handles the data in a streaming manner. If you want zero bytes
 *	because no buffer space is YET available, return 0. As long as
 *	the stream has not been written to the plugin, Navigator will
 *	continue trying to send bytes.  If the plugin doesn't want them,
 *	just return some large number from NPP_WriteReady(), and
 *	ignore them in NPP_Write().  For a NP_ASFILE stream, they are
 *	still called but can safely be ignored using this strategy.
 */

int32 STREAMBUFSIZE = 0X0FFFFFFF; /* If we are reading from a file in NPAsFile
				   * mode so we can take any size stream in our
				   * write call (since we ignore it) */

int32 
NPP_WriteReady(NPP instance, NPStream *stream)
{
	PluginInstance* This;
	if (instance != NULL)
		This = (PluginInstance*) instance->pdata;

	return STREAMBUFSIZE;
}


int32 
NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
{
	if (instance != NULL)
	{
		PluginInstance* This = (PluginInstance*) instance->pdata;
	}

	return len;		/* The number of bytes accepted */
}


NPError 
NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
{
	PluginInstance* This;

	if (instance == NULL)
		return NPERR_INVALID_INSTANCE_ERROR;
	This = (PluginInstance*) instance->pdata;
#if 0
long inst_num = _instance_list.getNum();
long i;
for(i=0; i<inst_num; i++){
  PluginInstance* item = (PluginInstance*)_instance_list[i];
  WSCbase* inst = (WSCbase*)_base_list[i];
  if (item == This){
    if (inst != NULL){
      _instance_list.delPos(i);
      _base_list.delPos(i);
      delete inst;
      break;
    }
  }
}
#endif

	return NPERR_NO_ERROR;
}


void 
NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
{
	PluginInstance* This;
	if (instance != NULL)
		This = (PluginInstance*) instance->pdata;
}


void 
NPP_Print(NPP instance, NPPrint* printInfo)
{
	if(printInfo == NULL)
		return;

	if (instance != NULL) {
		PluginInstance* This = (PluginInstance*) instance->pdata;
	
		if (printInfo->mode == NP_FULL) {
		    /*
		     * PLUGIN DEVELOPERS:
		     *	If your plugin would like to take over
		     *	printing completely when it is in full-screen mode,
		     *	set printInfo->pluginPrinted to TRUE and print your
		     *	plugin as you see fit.  If your plugin wants Netscape
		     *	to handle printing in this case, set
		     *	printInfo->pluginPrinted to FALSE (the default) and
		     *	do nothing.  If you do want to handle printing
		     *	yourself, printOne is true if the print button
		     *	(as opposed to the print menu) was clicked.
		     *	On the Macintosh, platformPrint is a THPrint; on
		     *	Windows, platformPrint is a structure
		     *	(defined in npapi.h) containing the printer name, port,
		     *	etc.
		     */

			void* platformPrint =
				printInfo->print.fullPrint.platformPrint;
			NPBool printOne =
				printInfo->print.fullPrint.printOne;
			
			/* Do the default*/
			printInfo->print.fullPrint.pluginPrinted = FALSE;
		}
		else {	/* If not fullscreen, we must be embedded */
		    /*
		     * PLUGIN DEVELOPERS:
		     *	If your plugin is embedded, or is full-screen
		     *	but you returned false in pluginPrinted above, NPP_Print
		     *	will be called with mode == NP_EMBED.  The NPWindow
		     *	in the printInfo gives the location and dimensions of
		     *	the embedded plugin on the printed page.  On the
		     *	Macintosh, platformPrint is the printer port; on
		     *	Windows, platformPrint is the handle to the printing
		     *	device context.
		     */

			NPWindow* printWindow =
				&(printInfo->print.embedPrint.window);
			void* platformPrint =
				printInfo->print.embedPrint.platformPrint;
		}
	}
}
};

void WSGFwsNsPluginInitialize(){
  WSGIappDev()->setMode(WS_MODE_NS_PLUGIN);
}
