//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
//
// This file implements a class which keeps the state information of the plugin
//
// The child window created by Netscape Navigator for the plug-in is sub-classed here
//
// This particular example handles left and right mouse clicks, paint messages, and has a
// set of Avi specific calls.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.

#ifndef __PLGWND_H__
#include "plgwnd.h"
#endif

#include "resource.h"

extern HINSTANCE g_hDllInstance;

// used to register this object instance in the window property
LPSTR CPluginWindow::_ThisLookUp = "this ptr";


//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// PluginWndProc
//
//	static member function of CPluginWindow
//	this is the window proc used to subclass the plugin window the 
//	navigator created and passed in NPP_SetWindow (npshell.c)
//
LRESULT CALLBACK
CPluginWindow::PluginWndProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM lParam)
{
	// pull out the instance object receiving the message
	CPluginWindow* pluginObj = (CPluginWindow*)GetProp(hWnd, CPluginWindow::_ThisLookUp);

	// message switch
	switch (Msg) {
		
		case WM_LBUTTONDOWN: 
		{
			POINT p;
			p.x = LOWORD(lParam);
			p.y = HIWORD(lParam);
			pluginObj->OnLButtonDown(WParam, &p);
		break;
		}
		
		case WM_RBUTTONDOWN:
		{
			POINT p;
			p.x = LOWORD(lParam);
			p.y = HIWORD(lParam);
			pluginObj->OnRButtonDown(WParam, &p);
		break;
		}
		
		case WM_PAINT:
		{
			PAINTSTRUCT  PaintStruct;
			::BeginPaint(hWnd, &PaintStruct);
			pluginObj->OnPaint();
			::EndPaint(hWnd, &PaintStruct);
		break;
		}
		
		case WM_PALETTECHANGED:
			pluginObj->OnPaletteChanged((HWND)WParam);
		break;

		//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
		// the following two messages are used from the CAvi class
		// 
		// MM_MCINOTIFY informs about a stop event
		case MM_MCINOTIFY:
			pluginObj->GetAviStream().OnStop();
		break;
		
		// WM_TIMER is used to update the position status
		case WM_TIMER:
			pluginObj->GetAviStream().OnPositionChange();
		break;
		//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.

		// menu handling
		// pass to CPluginWindow instance? (too much work...)
		//
		// WARNING
		// those ids are also used from the native functions (avijava.cpp)
		// when the flag isAsync is setted to TRUE (see avijava.cpp and AviPlayer.java)
		case WM_COMMAND:
			if (!HIWORD(WParam)) {
				switch LOWORD(WParam) {
					case ID_VIDEO_PLAY:
						//pluginObj->GetAviStream().Play();
						pluginObj->OnLButtonDown(0, 0);
					return 0;
					case ID_VIDEO_STOP:
						pluginObj->GetAviStream().Stop();
					return 0;
					case ID_VIDEO_REWIND:
						pluginObj->GetAviStream().Rewind();
					return 0;
					case ID_VIDEO_FORWARD:
						pluginObj->GetAviStream().Forward();
					return 0;
					case ID_VIDEO_FRAME_BACK:
						pluginObj->GetAviStream().FrameBack();
					return 0;
					case ID_VIDEO_FRAME_FORWARD:
						pluginObj->GetAviStream().FrameForward();
					return 0;
					// this is hidden to the menu but it's used from 
					// the java class in asynchronous mode (see AviPlayer.java
					// and avijava.cpp)
					case ID_VIDEO_SEEK:
						pluginObj->GetAviStream().Seek(lParam);
					return 0;
				}
			}
		default:
		return CallWindowProc(pluginObj->GetWndProc(), hWnd, Msg, WParam, lParam);
	};
	return 0;
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// CPluginWindow constructor and destructor
//
CPluginWindow::CPluginWindow(BOOL bAutoStart, BOOL bLoop, uint16 mode, NPP instance)
{
	// initialized in SetWindow
	_hPluginWnd = 0;
	_pfnDefault = 0;

	_mode = mode;
	// make an avi object
	// passing the NPP instance down is necessary becouse of the
	// java callback in CAvi (see CAvi::OnStop() and CAvi::OnPositionChange()
	_pAvi = new CAvi(bAutoStart, bLoop, instance);
}

CPluginWindow::~CPluginWindow()
{
	// delete the avi object
	delete _pAvi;
	// restore the old window proc and delete the property
	if (_pfnDefault) {
		::SetWindowLong(_hPluginWnd, GWL_WNDPROC, (LONG)_pfnDefault);
		::RemoveProp(_hPluginWnd, CPluginWindow::_ThisLookUp);
	}
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// SetWindow
//
//	store the window handle and subclass the window proc
//	Associate "this" with the window handle so we can redirect window 
//	messages to the proper instance
//
void		
CPluginWindow::SetWindow(HWND hWnd)
{
	_hPluginWnd = hWnd;
	// subclass
	_pfnDefault = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)CPluginWindow::PluginWndProc);
	// register "this" with the window structure
    ::SetProp(hWnd, CPluginWindow::_ThisLookUp, (HANDLE)this);
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// Print 
//
void		
CPluginWindow::Print(NPPrint* printInfo) const
{
	if (printInfo->mode == NP_FULL) {
        //
        // *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;
        
        printInfo->print.fullPrint.pluginPrinted = FALSE; // Do the default
        
	}
    else {   // If not fullscreen, we must be embedded
        //
        // *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;

        HPEN hPen, hPenOld;
#ifdef WIN32
        /* Initialize the pen's "brush" */
        LOGBRUSH lb;
        lb.lbStyle = BS_SOLID;
        lb.lbColor = RGB(128, 128, 128);
        lb.lbHatch = 0;

        hPen = ::ExtCreatePen(PS_COSMETIC | PS_SOLID, 1, &lb, 0, NULL);
#else
        COLORREF cref = RGB(128, 128, 128);
        hPen = ::CreatePen(PS_SOLID, 32, cref);
#endif
        HDC hDC = (HDC)(DWORD)platformPrint;
        hPenOld = (HPEN)::SelectObject(hDC, hPen);

        BOOL result = ::Rectangle(hDC,
                                (int)(printWindow->x),
                                (int)(printWindow->y),
                                (int)(printWindow->x + printWindow->width),
                                (int)(printWindow->y + printWindow->height));
        ::SelectObject(hDC, hPenOld);
        ::DeleteObject(hPen);
	}

}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// OnLButtonDown
//
//	reverse the avi state to stop or play
//
void 
CPluginWindow::OnLButtonDown(UINT uFlags, LPPOINT pPoint) 
{
    if (_pAvi->isPlaying()) {
		// if plying, stop
        _pAvi->Stop();
    } 
	else {
		// if stopped, play
        DWORD dwPos, dwLen;
        dwPos = _pAvi->GetPosition();
        dwLen = _pAvi->GetLength();

        if (dwPos >= dwLen)
            _pAvi->Rewind();
        _pAvi->Play();
    }
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// OnRButtonDown
//
//	bring up a menu with avi commands
//
void 
CPluginWindow::OnRButtonDown(UINT uFlags, LPPOINT pPoint) 
{
    UINT uState;
    char szMenuString[128];
    
    //  Create the popup.
    HMENU hPopup = ::CreatePopupMenu();
    if(hPopup == 0)  {
        return;
    }

    if(_pAvi->isPlaying()) 
		uState = MF_GRAYED;
    else 
		uState = MF_ENABLED;

    ::LoadString(g_hDllInstance, MENU_PLAY, szMenuString, 128);
    ::AppendMenu(hPopup, uState, ID_VIDEO_PLAY, szMenuString); //"Play...");   
    ::LoadString(g_hDllInstance, MENU_PAUSE, szMenuString, 128);
    ::AppendMenu(hPopup, !uState, ID_VIDEO_STOP, szMenuString); //"Pause...");

    //  Separator
    ::AppendMenu(hPopup, MF_SEPARATOR, 0, 0);

    uState = MF_ENABLED;    
    ::LoadString(g_hDllInstance, MENU_REWIND, szMenuString, 128);
    ::AppendMenu(hPopup, uState, ID_VIDEO_REWIND, szMenuString); //"Rewind (Start of movie)...");
    ::LoadString(g_hDllInstance, MENU_FORWARD, szMenuString, 128);
    ::AppendMenu(hPopup, uState, ID_VIDEO_FORWARD, szMenuString); //"Forward (End of movie)...");

	//  Separator
    ::AppendMenu(hPopup, MF_SEPARATOR, 0, 0);
    
    ::LoadString(g_hDllInstance, MENU_FRAME_BACK, szMenuString, 128);
    ::AppendMenu(hPopup, uState, ID_VIDEO_FRAME_BACK, szMenuString); //"Frame Back...");
    ::LoadString(g_hDllInstance, MENU_FRAME_FORWARD, szMenuString, 128);
    ::AppendMenu(hPopup, uState, ID_VIDEO_FRAME_FORWARD, szMenuString); //"Frame Forward...");

    ::ClientToScreen(_hPluginWnd, pPoint);
    ::TrackPopupMenu(hPopup, 
						TPM_LEFTALIGN | TPM_RIGHTBUTTON, 
						pPoint->x, 
						pPoint->y, 
						0, 
						_hPluginWnd, 
						NULL);
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// OnPaint
//
//	run update on the avi.
//	A HDC should be passed here (?!)
//
void 
CPluginWindow::OnPaint() 
{
	_pAvi->Update();
}

//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
////\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//.
// OnPaletteChanged
//
//	why do palettes exist?
//
void 
CPluginWindow::OnPaletteChanged(HWND hFocusWnd) 
{
    //  Don't do this if we caused it to happen.
    if(hFocusWnd != _hPluginWnd)   {
		_pAvi->Realize();
    }
}

