///////////////////
// GDI interface //
///////////////////

#ifndef __PTC_IGDI_H
#define __PTC_IGDI_H

#include "idummy.h"
#include "isoft.h"
#include "surface.h"
#include "thread.h"
#include "keyboard.h"

#ifdef __VFW__
#include "vfw.h"
#endif








#ifdef __GDI__

class IGDI : public ISoftware
{
    public:

        // setup
        IGDI(WINDOW window=NULL);
        virtual ~IGDI();

        // interface information
        virtual Interface::INFO GetInfo();
        virtual int GetModeList(List<MODE> &modelist);

        // display mode routines
        virtual int SetMode(MODE const &info);
        virtual int SetMode(int x,int y,int id,int output,int frequency,int layout);
        virtual int SetMode(int x,int y,FORMAT const &format,int output,int frequency,int layout);
        virtual MODE GetMode();

        // palette routines
        virtual int SetPalette(Palette &palette);
        virtual int GetPalette(Palette &palette);
        
        // hardware functions
        virtual int WaitForRetrace();
        
        // primary surface operations
        virtual int SetPrimary(Surface &surface);
        virtual Surface* GetPrimary();
        virtual int SetOrigin(int x,int y);
        virtual int GetOrigin(int &x,int &y);

        // video memory management
        virtual int GetTotalVideoMemory();
        virtual int GetFreeVideoMemory();
        virtual int CompactVideoMemory();

        // console routines
        virtual int getch();
        virtual int kbhit();

        // window routines
        virtual int SetTitle(char title[]);
        virtual int GetTitle(char title[]);

        // native access
        virtual int NativeType();
        virtual void* GetNative();

        // data access
        virtual void GetName(char name[]) const;
        virtual int GetXResolution() const;
        virtual int GetYResolution() const;
        virtual int GetBitsPerPixel() const;
        virtual int GetBytesPerPixel() const;
        virtual int GetOutput() const;
        virtual int GetFrequency() const;
        virtual int GetLayout() const;
        virtual FORMAT GetFormat() const;
        virtual WINDOW GetWindow() const;

        // object state
        virtual int ok() const;

    protected:
        
        // surface update
        virtual int Update(Surface &src,void *extra);
        virtual int Update(Surface &src,RECTANGLE const &rect,void *extra);
        virtual int Update(Surface &src,RECTANGLE const &src_rect,RECTANGLE const &dest_rect,void *extra);

        // internal software surface
        class SURFACE : public Interface::SURFACE
        {
            public:
            
                // setup
                SURFACE();
                ~SURFACE();

                // initialize
                int Init(int &width,int &height,FORMAT &format,int &type,int &orientation,int &advance,int &layout);

                // surface interface
                virtual void* Lock(int wait);
                virtual void Unlock();
                virtual int LockCount();
                virtual int NativeType();
                virtual void* GetNative();

                // status
                virtual int ok();

                // data
                void *Buffer;                   // memory buffer
                HBITMAP Bitmap;                 // bitmap handle
                BITMAPINFO *BitmapInfo;         // bitmap information
                int LockOffset;                 // lock offset
                int Count;                      // lock count
        };

        // internal surface management
        virtual Interface::SURFACE* RequestSurface(int &width,int &height,FORMAT &format,int &type,int &orientation,int &advance,int &layout);

        // object attach and detach
        virtual int Detach(Surface *surface);

    private:

        // window thread parm struct
        struct WINDOWTHREADINFO
        {
            IGDI *i;
            char *title;
            int width;
            int height;
            int output;
            int frequency;
            HANDLE event;
        };

        // display management
        int InitDisplay(int x,int y,int output,int frequency,int layout);
        void CloseDisplay();
        int UpdateDisplay(Surface &src,RECTANGLE const &src_rect,RECTANGLE const &dest_rect);

        // window management
        int RegisterWindowClasses();
        int InitWindow(int width,int height,int output,int frequency,char *title=NULL);
        int ResizeWindow(int width,int height,char *title);
        void CloseWindow();
        void AdjustWindowSize(int &width,int &height);
        static void WindowThreadFunction(WINDOWTHREADINFO *info);
        static LRESULT CALLBACK WndProcCommon(IGDI *i,HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
        static LRESULT CALLBACK WndProcWindowed(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);
        static LRESULT CALLBACK WndProcFullscreen(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam);

        // secondary management
        int InitSecondary();
        void CloseSecondary();

        // palette management
        int InitPalette();
        void ClosePalette();

        // internal gdi routines
        int SetDisplayMode(int x,int y,int frequency);
        int SetDisplayMode(DEVMODE devmode);
        void RestoreDisplayMode();
        MODE GetDisplayMode();
        DEVMODE GetDisplayDeviceMode();
        int GetDisplayFrequency();
        FORMAT GetDisplayFormat();
        FORMAT GetDeviceFormat(HDC dc);

        // interface lookup
        int RegisterWindow(HWND window);
        int UnregisterWindow(HWND window);
        static IGDI* LookupInterface(HWND window);

        // local critical section management
        void InitLocalCriticalSections();
        void CloseLocalCriticalSections();

        // static criticial section manangement
        void InitStaticCriticalSection();
        void CloseStaticCriticalSection();

        // modelist
        void AddMode(MODE const &mode);

        // internals
        uint XResolution;                   // x resolution of display
        uint YResolution;                   // y resolution of display
        FORMAT Format;                      // pixel format of display
        int Output;                         // output mode
        int Frequency;                      // output frequency
        Surface *Secondary;                 // secondary surface
        Palette InternalPalette;            // internal palette object
        LOGPALETTE *LogicalPalette;         // logical palette
        HPALETTE PaletteHandle;             // palette handle
        List<MODE> ModeList;                // list of display modes
        DEVMODE OriginalDeviceMode;         // original device mode
        DEVMODE FullscreenDeviceMode;       // fullscreen device mode

        // window internals
        HWND Window;                        // output window handle
        HDC WindowDC;                       // output window device context
        int Managed;                        // managed window (0=false, 1=true)
        Keyboard WindowKeyboard;            // window keyboard buffer
        HANDLE WindowKeyboardEvent;         // window signal event
        Thread *WindowThread;               // window thread

        // local critical sections
        CRITICAL_SECTION InputCriticalSection;
        CRITICAL_SECTION UpdateCriticalSection;
        CRITICAL_SECTION WindowCriticalSection;         
        CRITICAL_SECTION PaletteCriticalSection;         

        // recent surface
        Surface *Recent;                    // most recently updated surface
        RECTANGLE RecentSourceRect;         // recent update source rectangle
        RECTANGLE RecentDestinationRect;    // recent update destination rectangle
        
        // video for windows
        #ifdef __VFW__
        VFW *VideoForWindows;
        #endif

        // status
        int Status;                         // status variable (1=OK, 0=INVALID)

        // static interface lookup list
        struct LOOKUP
        {
            HWND window;
            IGDI *i;
        };
        static List<LOOKUP> InterfaceLookupList;

        // static critical section data
        static CRITICAL_SECTION StaticCriticalSection;
        static int StaticCriticalSectionReferenceCount;
};

#else

class IGDI : public IDummy
{
    public:

        // dummy object
        IGDI(WINDOW window=NULL) { if (window); };
};

#endif








#endif
