/*
	Wheels Of Steel
	Copyright (c) 2006, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef WINDOW_H
#define WINDOW_H

//##############################################################################
// Defines
//##############################################################################

#define WIN32_LEAN_AND_MEAN    // Trim crap from windows

//##############################################################################
// Includes
//##############################################################################

#include <windows.h>
#include <stdlib.h>
#include <time.h>
#include "ProgramError.h"
#include "Bitmap.h"

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   Window
// Purpose:      Win32 windowing and drawing functions in one class.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

class Window
{
 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Public functions and constants
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 public:

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Various enums
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Fill pattern type for solid objects

        enum FillPattern
        {
             FILL_PATTERN_HORIZONTAL       = 0,
             FILL_PATTERN_VERTICAL         = 1,
             FILL_PATTERN_RIGHT_DIAGONAL   = 2,
             FILL_PATTERN_LEFT_DIAGONAL    = 3,
             FILL_PATTERN_CROSSED          = 4,
             FILL_PATTERN_DIAGONAL_CROSSED = 5
        };

        // Fill mode for solid objects

        enum FillMode
        {
             FILL_MODE_FILLED  = 0,
             FILL_MODE_NO_FILL = 1,
             FILL_MODE_PATTERN = 2
        };

        // Line pattern

        enum LinePattern
        {
             LINE_PATTERN_NORMAL = 0,
             LINE_PATTERN_DASHED = 1,
             LINE_PATTERN_DOTTED = 2,
             LINE_PATTERN_NONE   = 5
        };

        // Text alignment mode

        enum TextAlignmentMode
        {
             TEXT_ALIGNMENT_LEFT    = 0,
             TEXT_ALIGNMENT_CENTRE  = 1,
             TEXT_ALIGNMENT_RIGHT   = 2
        };

        // Mouse buttons

        enum MouseButton
        {
             MOUSE_BUTTON_LEFT   = 0x01,
             MOUSE_BUTTON_RIGHT  = 0x02,
             MOUSE_BUTTON_MIDDLE = 0x04
        };

        // Cursor types

        enum CursorType
        {
            CURSOR_NONE ,
            CURSOR_ARROW,
            CURSOR_CROSS
        };

        // Keyboard special key codes: letters are all received as uppercase ascii

        enum KeyboardKey
        {
            KEYBOARD_BACKSPACE       = 0x08,
            KEYBOARD_TAB    	     = 0x09,
            KEYBOARD_RETURN          = 0x0D,
            KEYBOARD_SHIFT	         = 0x10,
            KEYBOARD_CTRL	         = 0x11,
            KEYBOARD_ALT	         = 0x12,
            KEYBOARD_PAUSE	         = 0x13,
            KEYBOARD_CAPSLOCK	     = 0x14,
            KEYBOARD_ESCAPE	         = 0x1B,
            KEYBOARD_SPACE	         = 0x20,
            KEYBOARD_PAGE_UP	     = 0x21,
            KEYBOARD_PAGE_DOWN	     = 0x22,
            KEYBOARD_END	         = 0x23,
            KEYBOARD_HOME	         = 0x24,
            KEYBOARD_LEFT	         = 0x25,
            KEYBOARD_UP	             = 0x26,
            KEYBOARD_RIGHT	         = 0x27,
            KEYBOARD_DOWN	         = 0x28,
            KEYBOARD_INSERT	         = 0x2D,
            KEYBOARD_DELETE	         = 0x2E,
            KEYBOARD_NUMPAD_0	     = 0x60,
            KEYBOARD_NUMPAD_1	     = 0x61,
            KEYBOARD_NUMPAD_2	     = 0x62,
            KEYBOARD_NUMPAD_3	     = 0x63,
            KEYBOARD_NUMPAD_4	     = 0x64,
            KEYBOARD_NUMPAD_5	     = 0x65,
            KEYBOARD_NUMPAD_6	     = 0x66,
            KEYBOARD_NUMPAD_7	     = 0x67,
            KEYBOARD_NUMPAD_8	     = 0x68,
            KEYBOARD_NUMPAD_9	     = 0x69,
            KEYBOARD_MULTIPLY	     = 0x6A,
            KEYBOARD_ADD	         = 0x6B,
            KEYBOARD_SUBTRACT	     = 0x6D,
            KEYBOARD_DECIMAL	     = 0x6E,
            KEYBOARD_DIVIDE	         = 0x6F,
            KEYBOARD_F1	             = 0x70,
            KEYBOARD_F2	             = 0x71,
            KEYBOARD_F3	             = 0x72,
            KEYBOARD_F4	             = 0x73,
            KEYBOARD_F5	             = 0x74,
            KEYBOARD_F6	             = 0x75,
            KEYBOARD_F7	             = 0x76,
            KEYBOARD_F8	             = 0x77,
            KEYBOARD_F9	             = 0x78,
            KEYBOARD_F10	         = 0x79,
            KEYBOARD_F11	         = 0x7A,
            KEYBOARD_F12	         = 0x7B
        };

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Functions
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Do message processing and input etc. for window

        void run() const;

        // Clear the window to the specified clear color

        void clear
        (
            char clearcol_r ,
            char clearcol_g ,
            char clearcol_b

        ) const;

        // Set fullscreen or not

        void setFullscreen
        (
            bool    fullscreen      = true,
            int     resolution_x    = 640 ,
            int     resolution_y    = 480
        );

        //----------------------------------------------------------------------
        // Query window state
        //----------------------------------------------------------------------

        bool exists()           const;  // does the window actually exist ?
        int  getX()             const;  // Window position
        int  getY()             const;  // Window position
        int  getWidth()         const;  // Window size
        int  getHeight()        const;  // Window size
        int  getClientWidth()   const;  // Window size (drawing area)
        int  getClientHeight()  const;  // Window size (drawing area)
        int  getScreenWidth()   const;  // Get the width of the screen
        int  getScreenHeight()  const;  // Get the height of the screen
        bool isFullscreen()     const;  // Is the window in fullscreen mode ?

        //----------------------------------------------------------------------
        // Bitmap loading and creation functions
        //----------------------------------------------------------------------

        class Bitmap * loadBitmap       // Load a bitmap (transparent or non transparent) from a file and return its pointer. Transparent color is the bottom right pixel.
        (
            char * fileName,
            bool transparent
        );

        class Bitmap * loadBitmap       // Create a bitmap from a user defined array of 32-bit pixels in ARGB format. 'A' value is ignored.
        (
            const unsigned int * data,
            int width,
            int height,
            bool transparent
        );

        //----------------------------------------------------------------------
        // Show a question box , message box, and and a non-fatal error warning box
        //----------------------------------------------------------------------

        bool showQuestionBox   ( char * question , char * title );
        void showMessageBox    ( char * message  , char * title );
        void showErrorBox      ( char * message );

        //----------------------------------------------------------------------
        // Text drawing functions
        //----------------------------------------------------------------------

        void drawText           // Draw text (single-line) to the screen
        (
            char *  text,
            int     x,
            int     y
        );

        void drawText           // Draw wrapped (multi-line) text within a specified rectangle and with specified alignment
        (
            char *  text,
            int     x,
            int     y,
            int     rect_width,
            int     rect_height,
            TextAlignmentMode alignment
        );

        void drawTextCentered   // Draw text (single-line) centred horizontally
        (
            char * text ,
            int y
        );

        void drawTextCentered (char * text );   // Draw text (single-line) centred horizontally and vertically

        //----------------------------------------------------------------------
        // Shape drawing functions
        //----------------------------------------------------------------------

        void drawLine          (int x1, int y1 , int x2, int y2)            const;  // Draw a line to the screen
        void drawRectangle     (int x1 ,int y1 , int x2, int y2)            const;  // Draw a rectangle
        void drawEllipse       (int x1 ,int y1 , int x2, int y2)            const;  // Draw an ellipse
        void drawPolygon       (int xyCoords[] , int numPoints )            const;  // Draw a polygon
        void drawPixel         (int x, int y, char r, char g, char b )      const;  // Put a pixel to the screen

        //----------------------------------------------------------------------
        // Bitmap drawing functions
        //----------------------------------------------------------------------

        void drawBitmap                 // Draw a bitmap to the screen
        (
            class Bitmap * bitmap ,
            int x ,
            int y

        ) const;

        void drawBitmap                 // Draw a scaled bitmap to the screen
        (
            class Bitmap * bitmap ,
            int x ,
            int y ,
            int width ,
            int height

        ) const;

        void drawBitmapSection          // Draw an unscaled section of the input bitmap
        (
            class Bitmap * bitmap,
            int destination_x,
            int destination_y,
            int source_x,
            int source_y,
            int source_width,
            int source_height

        ) const;

        void drawBitmapSection          // Draw a scaled section of the input bitmap
        (
            class Bitmap * bitmap,
            int destination_x,
            int destination_y,
            int destination_width,
            int destination_height,
            int source_x,
            int source_y,
            int source_width,
            int source_height

        ) const;

        //----------------------------------------------------------------------
        // Line settings
        //----------------------------------------------------------------------

        void setLineWidth   ( int width												);     // set line thickness
        void setLineColor   ( unsigned char r , unsigned char g , unsigned char b   );     // set line color
        void setLinePattern ( Window::LinePattern pattern							);     // set the line pattern

        //----------------------------------------------------------------------
        // Fill settings
        //----------------------------------------------------------------------

        void setFillColor   ( char r , char g , char b  );          // Fill color
        void setFillMode    ( Window::FillMode     fillMode    );   // Fill mode: no-fill,solid,pattern
        void setFillPattern ( Window::FillPattern  fillPattern );   // Fill pattern type: if pattern used

        //----------------------------------------------------------------------
        // Text settings
        //----------------------------------------------------------------------

        void setFontColor     (char r , char g , char b );    // Set the text color
        void setFontSize      (int width , int height );      // Set the text size
        void setFontWeight    (int weight);                   // Set font thickness (100 to 900)
        void setFontName      (char * fontName);              // Set the text font face
        void setFontItalic    (bool italic);                  // Set if text is italic
        void setFontUnderline (bool underlined);              // Set if text is italic
        void setFontStrikeOut (bool strikeout);               // Set if text is struck out

        //----------------------------------------------------------------------
        // Query text size
        //----------------------------------------------------------------------

        int getTextWidth  ( char * text ) const;    // Return width of a string of text with current font
        int getTextHeight ( char * text ) const;    // Return height of a string of text with current font

        //----------------------------------------------------------------------
        // Window settings
        //----------------------------------------------------------------------

        void setResizeable  ( bool sizeable );                       // set if window is resizeablee
        void setSize        ( int width , int height );              // set window size
        void setClientSize  ( int clientWidth , int clientHeight );  // set window drawing area size (window automatically resizes too)
        void setPosition    ( int x , int y );                       // set window position
        void setTitle       ( char * title  );                       // sets window title
        void setCursor      ( CursorType cursor );                   // sets the window cursor

        //----------------------------------------------------------------------
        // Minimize, maximize, restore, repaint , close , center , and request repaint of the window
        //----------------------------------------------------------------------

        void close();
        void minimize();
        void maximize();
        void restore();
        void center();
        void requestRepaint();

        //----------------------------------------------------------------------
        // Query if mouse and keyboard keys are pressed
        //----------------------------------------------------------------------

        bool keyboardKeyPressed(char key ) const;
        bool keyboardKeyPressed(Window::KeyboardKey key) const;
        bool mouseButtonPressed(Window::MouseButton button) const;

        //----------------------------------------------------------------------
        // Set event handlers for the window
        //----------------------------------------------------------------------

        void setEvent_mouseDown       ( void (*function)(Window & window, int x , int y , Window::MouseButton button ) );
        void setEvent_mouseUp         ( void (*function)(Window & window, int x , int y , Window::MouseButton button ) );
        void setEvent_keyDown         ( void (*function)(Window & window, Window::KeyboardKey key) );
        void setEvent_keyUp           ( void (*function)(Window & window, Window::KeyboardKey key) );
        void setEvent_mouseMove       ( void (*function)(Window & window, int x , int y ) );
        void setEvent_closing         ( void (*function)(Window & window ) );
        void setEvent_closed          ( void (*function)(Window & window ) );
        void setEvent_paint           ( void (*function)(Window & window ) );
        void setEvent_resize          ( void (*function)(Window & window ) );

        //----------------------------------------------------------------------
        // Constructor
        //----------------------------------------------------------------------

        Window::Window(char * title , int width , int height);

        //----------------------------------------------------------------------
        // Destructor
        //----------------------------------------------------------------------

        Window::~Window();

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Inlined functions for faster drawing
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        inline void Window::selectBrush(HBRUSH windowsBrush)
        {
            SelectObject(memoryDeviceContext,windowsBrush);
        }

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Protected functions and data
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 protected:

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Constants
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        static const char * Window::WINDOW_CLASSNAME;
        static const char * Window::WINDOW_DEFAULT_TITLE;

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Variables
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Windows handles:

        HINSTANCE  programHandle;           // Process handle
        HWND       windowHandle;            // Window handle
        HDC        deviceContext;           // Front buffer
        HDC        memoryDeviceContext;     // Back buffer
        HDC        bitmapDeviceContext;     // Device context to select bitmaps into
        HBITMAP    memoryDeviceBitmap;      // Actual back buffer bitmap

        // Window graphics objects and their pointers

        LOGBRUSH    brush;                // Structures to hold info on gdi objects
        LOGPEN      pen;
        LOGFONT     font;

        HBRUSH      brushHandle;          // Handles to actual windows gdi objects
        HPEN        penHandle;
        HFONT       fontHandle;

        // Last time the window was painted (ms)

        unsigned int lastPaintTime;

        // Is app showing a dialog box ? If true skip user defined paint function for first time..
        // If we don't do this dialog box gets lost and is not seen...
        // This allows the dialog box time to create itself presumably..

        bool showingDialogBox;

        // Is window in fullscreen mode?

        bool fullscreenMode;

        // Cursor to use for the window:

        CursorType windowCursor;

        // Function pointers

        void ( * event_keyDown   )( Window & window, Window::KeyboardKey key );
        void ( * event_keyUp     )( Window & window, Window::KeyboardKey key );
        void ( * event_mouseDown )( Window & window, int x , int y , Window::MouseButton button );
        void ( * event_mouseUp   )( Window & window, int x , int y , Window::MouseButton button );
        void ( * event_mouseMove )( Window & window, int x , int y );
        void ( * event_closing   )( Window & window );
        void ( * event_closed    )( Window & window );
        void ( * event_paint     )( Window & window );
        void ( * event_resize    )( Window & window );

        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Functions
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Main window setup code:

        void initWindow();

        // Check for an error with windows and print it out if there is one. also function for clearing errors.

        void checkError(char * msgStart);
        void clearError();

        // Swap the back buffer into the front buffer

        void swapBuffers();

        // Window procedure: not a member function but must be common to all instances

        static LRESULT CALLBACK windowProcedure( HWND , UINT , WPARAM , LPARAM );

}; // end of: class Window{}

#endif // end of: ifndef WINDOW_H
