// winapp.h

#if !defined(WINAPP_H)

/* WINAPP:
An object of this class is defined once for every application. It contains the
items passed to WinMain, as well as access functions for returning them. The
constructor initializes them.
*/

class WinApp    // Windows application class
    {
        static HANDLE hInstance;
        static HANDLE hPrevInstance;
        static LPSTR lpszCmdLine;
        static int nCmdShow;
    public:
        WinApp(HANDLE hinst, HANDLE hpinst, LPSTR cmdline, int cmdshow)
            {
            hInstance = hinst;
            hPrevInstance = hpinst;
            lpszCmdLine = cmdline;
            nCmdShow = cmdshow;
            }
        static HANDLE GetInstance(void) { return hInstance; }
        static HANDLE GetPrevInstance(void) { return hPrevInstance; }
        static LPSTR GetCmdLine(void) { return lpszCmdLine; }
        static int GetCmdShow(void) { return nCmdShow; }
        static int MessageLoop(void);    // default message loop processing
   };


/* WINCLASS
*/
const NOSTYLE = 0;
const NOEXTRABYTES = 0;

class WinClass : WNDCLASS
    {
        BOOL    class_registered;
    public:
        WinClass(void)
            {
            style = NOSTYLE;
            lpfnWndProc = DefWindowProc;
            cbClsExtra = NOEXTRABYTES;
            cbWndExtra = NOEXTRABYTES;
            hInstance = NULL;
            hIcon = LoadIcon(NULL, IDI_APPLICATION);
            hCursor = LoadCursor(NULL, IDC_ARROW);
            hbrBackground = GetStockObject(WHITE_BRUSH);
            lpszMenuName = NULL;
            lpszClassName = NULL;
            class_registered = FALSE;
            }
            // since 'this' is derived from WNDCLASS, it's passed as one
        void Register(void)
            {
            RegisterClass(this);
            class_registered = TRUE;
            }
        BOOL Registered(void)   { return class_registered; }
        friend class Window;    // allow Window to modify members
    };

/* WINHANDLE
An object of this class is created with every instance of Window (below). It
contains data that controls Window creation handling, as well as the window
handle.
 */

class WinHandle
    {
        HWND hWnd;
        LPSTR classname;
        LPSTR windowname;
        DWORD winstyle;
        int upper_left_x;
        int upper_left_y;
        int winwidth;
        int winheight;
        HWND winParent;
        HMENU menu;
        HANDLE hInstance;
        LPSTR lpParam;
    public:
        WinHandle(void)
            {
            hWnd = NULL;
            classname = (LPSTR)"WinApp";
            windowname = (LPSTR)"WinApp:Window";
            winstyle = 0;
            upper_left_x = upper_left_y = winwidth = winheight = 0;
            winParent = NULL;
            menu = NULL;
            hInstance = 0;
            lpParam = NULL;
            }

        HWND GetHandle(void) { return hWnd; }
        HWND Create(void)
            {
            if(hWnd)    // if window's already created, return TRUE
                return TRUE;

            hWnd = CreateWindow(classname,windowname,winstyle,upper_left_x,
                upper_left_y,winwidth,winheight,winParent,menu,hInstance,
                lpParam);

            return (hWnd ? TRUE : FALSE);
            }

        friend class Window;    // allow Window to modify members
    };


/* WINDOW

Every window is derived from this abstract class.

Every class derived from this one must have a WinClass object (or a pointer
to one created by a derived class) and pass it back to Window.

And each must supply its own WndProc for the class.
*/
class Window
    {
        WinHandle WHdl;
        int     current_display;
        int     previously_visible;
        void    Show(void)
            { previously_visible = ShowWindow(GetHandle(),current_display); }
    protected:
        WinClass *MyWc;
        WinApp *MyApp;

    public:
        Window(WinApp *app, WinClass *wc)
            {
            MyApp = app;
            MyWc = wc;
            DefaultDisplay();
            previously_visible = FALSE;
            };

            // displays window and creates if not already created
        BOOL Display(void)
            {
            Register();

            if(!Create())
                return FALSE;

            Show();

            Update();

            return TRUE;
            }

        BOOL Display(int display_style)
            {
            current_display = display_style;
            return Display();
            }
            // should call SetClassInstance and SetClassName if not called
        void Register(void)
            {
            if(!MyWc->Registered())         // if class not registered
                {
                SetClassWinXbytes(sizeof(Window *));
                SetClassInstance();         // insert instance handle
                if(!GetClassName())         // if class name not set
                    SetClassName("WinApp");
                MyWc->Register();           // register the class
                }
            }

        BOOL Create(void)
            {
            Register();
            WHdl.hInstance = MyApp->GetInstance();
            WHdl.classname = MyWc->lpszClassName;
            WHdl.lpParam = (LPSTR)this;
            return WHdl.Create();
            }

        HWND GetHandle(void) { return WHdl.hWnd; }

        void Hide(void)  // hides the window
            { Display(SW_HIDE); }
        void Minimize(void)  // minimizes the window
            { Display(SW_MINIMIZE); }
        void Maximize(void)  // maximizes the window
            { Display(SW_SHOWMAXIMIZED); }
        void Normalize(void) // displays window in original size and position
            { Display(SW_SHOWNORMAL); }
        void DefaultDisplay(void)
            { current_display = MyApp->GetCmdShow(); }

        void Paint(void)     // paints window
            {
            PAINTSTRUCT ps;
            RECT    rect;

            BeginPaint(GetHandle(), &ps);
            EndPaint(GetHandle(), &ps);
            }

        void Update(void)   // updates window
            { UpdateWindow(GetHandle()); }

             // vocab of functions for modifying the registration info
        void SetClassInstance(void)
            { MyWc->hInstance = MyApp->GetInstance(); }
        void SetClassName(LPSTR classname)
            { MyWc->lpszClassName = classname; }
        void SetClassStyle(unsigned newstyle)    { MyWc->style = newstyle;  }
        void AddClassStyle(unsigned addstyle)    { MyWc->style |= addstyle; }
        void SetClassWinProc(long (FAR PASCAL *lpfnWndProc)(HWND, unsigned,
            WORD, LONG))
            { MyWc->lpfnWndProc = lpfnWndProc; }
        void SetClassWinXbytes(int xtrabytes)
            { MyWc->cbWndExtra = xtrabytes; }
        void SetClassIcon(LPSTR iconname)
            {
            if(MyWc->hInstance)
                MyWc->hIcon = LoadIcon(MyWc->hInstance,iconname);
            }

        LPSTR GetClassName(void)    { return MyWc->lpszClassName; }

        // vocab of functions for modifying the create info
        void SetWinName(LPSTR winname)  { WHdl.windowname = winname; }
        void SetWinStyle(DWORD dword)    { WHdl.winstyle = dword; }
        void AddWinStyle(DWORD dword)    { WHdl.winstyle |= dword;  }
        void SetWinX(int x)              { WHdl.upper_left_x = x; }
        void SetWinY(int y)              { WHdl.upper_left_y = y; }
        void SetWinWidth(int width)      { WHdl.winwidth = width; }
        void SetWinHeight(int height)    { WHdl.winheight = height; }
        void SetWinInstance(HANDLE hinst){ WHdl.hInstance = hinst; }
    };


inline void *GetPointer(HWND hWnd)
    {
#if defined(__SMALL__) || defined(__MEDIUM__)
    return (void *)GetWindowWord(hWnd,0);
#elif defined(__LARGE__) || defined(__COMPACT__)
    return (void *)GetWindowLong(hWnd,0);
#else
    #error Must use Small, Medium, Large or Compact models!
#endif
    }

inline void SetPointer(HWND hWnd, void *ptr)
    {
#if defined(__SMALL__) || defined(__MEDIUM__)
    SetWindowWord(hWnd,0,(WORD)ptr);
#elif defined(__LARGE__) || defined(__COMPACT__)
    SetWindowLong(hWnd,0,(LONG)ptr);
#else
    #error Must use Small, Medium, Large or Compact models!
#endif
    }


#define WINAPP_H
#endif
