/* **********************************************************************************************************************
   Included Header Files
   **********************************************************************************************************************/

#include "VDMapEditor.h"



/* **********************************************************************************************************************
   Constructor
   **********************************************************************************************************************/

VDMapEditor::VDMapEditor() {
    window = NULL;
    transparencyColor = NULL;
    loadSpriteButton = NULL;
    tileSheet = NULL;
    (void) strcpy_s(tileSheetImageLocation, "");
    (void) SecureZeroMemory(&tileSheetDimensions, sizeof(tileSheetDimensions));
    selectedTile = NULL;
    (void) strcpy_s(selectedTileImageLocation, "");
    (void) SecureZeroMemory(&tileSheetSourceRectangle, sizeof(tileSheetSourceRectangle));
    shiftTileSpriteUp = NULL;
    shiftTileSpriteDown = NULL;
    shiftTileSpriteLeft = NULL;
    shiftTileSpriteRight = NULL;
    tileSpawnsListBox = NULL;
    creaturesListBox = NULL;
    removeSpawnButton = NULL;
    addSpawnButton = NULL;
    nullTileOption = NULL;
    openTileOption = NULL;
    impassableTileOption = NULL;
    newAreaTileOption = NULL;
    loadNewAreaButton = NULL;
    newAreaStatic = NULL;
    (void) strcpy_s(newAreaFileLocation, "");
    newAreaStartingPointX = NULL;
    newAreaStartingPointY = NULL;
    npcsListBox = NULL;
    npcSprite = NULL;
    (void) strcpy_s(selectedNPCImageLocation, "");
    (void) strcpy_s(previousNPCSelection, "");
    (void) SecureZeroMemory(&npcSpriteDimensions, sizeof(npcSpriteDimensions));
    previousAnimationButton = NULL;
    nextAnimationButton = NULL;
    nullNPCOption = NULL;
    normalNPCOption = NULL;
    staticNPCOption = NULL;
    tileSelected = FALSE;
};



/* **********************************************************************************************************************
   Destructor
   **********************************************************************************************************************/

VDMapEditor::~VDMapEditor() {
    FreeMemory();
};



// TODO - fill Free Memory on all errors
void VDMapEditor::FreeMemory() {
    if (npcSprite != NULL) {
        npcSprite->FreeTexture();
        delete npcSprite;
        npcSprite = NULL;
    };
    if (selectedTile != NULL) {
        selectedTile->FreeTexture();
        delete selectedTile;
        selectedTile = NULL;
    };
    if (tileSheet != NULL) {
        tileSheet->FreeTexture();
        delete tileSheet;
        tileSheet = NULL;
    };
};



/* **********************************************************************************************************************
   CreateMapEditor
   ---------------
   Creates a new Map Editor window.
   #param  instance      The instance of the application.
   #param  parentWindow  Handle to the main window (to use for the starting x, y position)
   #param  className     The name of the window class.
   #return  Handle to the window.
   **********************************************************************************************************************/

HWND VDMapEditor::CreateMapEditor(HINSTANCE instance, HWND parentWindow, LPCSTR className) {
    // create the menu resource
    HMENU menu = LoadMenu(instance, MAKEINTRESOURCE(VD_MENU));
    if (menu == NULL) {
        VDError("Failed to create the menu resource.", __FILE__, __LINE__);
    };

    // create the window
    RECT windowDimensions;
    (void) GetWindowRect(parentWindow, &windowDimensions);
    window = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,      // extended window styles
                            className,                             // class name
                            "Map Editor",                          // window name
                            WS_CAPTION | WS_VISIBLE,               // window styles
                            windowDimensions.left + 100,           // x coordinate (0 = left)
                            windowDimensions.top + 100,            // y coordinate (0 = top)
                            277,                                   // width
                            700,                                   // height
                            NULL,                                  // parent/owner window
                            menu,                                  // menu
                            instance,                              // instance
                            NULL);                                 // used for CREATESTRUCT structure
    if (window == NULL) {
        VDError("Failed to create the map editor window.", __FILE__, __LINE__);
    };

    HWND transparentColorStatic = CreateWindow("Static", "Transparency Color:", WS_CHILD | WS_VISIBLE, 10, 10, 135, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_TRANSPARENCY, instance, NULL);
    transparencyColor = CreateWindow("Edit", "0xFF000000", WS_CHILD | WS_VISIBLE | WS_BORDER, 150, 10, 95, 18, window, (HMENU) VD_MAP_EDITOR_TRANSPARENCY, instance, NULL);
    loadSpriteButton = CreateWindow("Button", "Load Sprite Sheet", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 35, 125, 20, window, (HMENU) VD_MAP_EDITOR_LOAD_SPRITE, instance, NULL);
    if (loadSpriteButton == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    if (tileSheet != NULL) {
        tileSheet->FreeTexture();
        delete tileSheet;
        tileSheet = NULL;
    };
    (void) strcpy_s(tileSheetImageLocation, "");
    (void) SetRect(&tileSheetDimensions, 10, 65, 170, 225);
    if (selectedTile != NULL) {
        selectedTile->FreeTexture();
        delete selectedTile;
        selectedTile = NULL;
    };
    (void) strcpy_s(selectedTileImageLocation, "");
    (void) SetRect(&tileSheetSourceRectangle, 0, 0, 32, 32);
    shiftTileSpriteUp = CreateWindow("Button", "/\\", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 170, 65, 20, 20, window, (HMENU) VD_MAP_EDITOR_UP, instance, NULL);
    shiftTileSpriteDown = CreateWindow("Button", "\\/", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 170, 205, 20, 20, window, (HMENU) VD_MAP_EDITOR_DOWN, instance, NULL);
    shiftTileSpriteLeft = CreateWindow("Button", "<", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 225, 20, 20, window, (HMENU) VD_MAP_EDITOR_LEFT, instance, NULL);
    shiftTileSpriteRight = CreateWindow("Button", ">", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 150, 225, 20, 20, window, (HMENU) VD_MAP_EDITOR_RIGHT, instance, NULL);
    HWND tileSpawnsStatic = CreateWindow("Static", "Tile Spawns:", WS_CHILD | WS_VISIBLE, 10, 250, 100, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_TILE_SPAWNS, instance, NULL);
    if (tileSpawnsStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    tileSpawnsListBox = CreateWindow("ListBox", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 10, 270, 120, 100, window, (HMENU) VD_MAP_EDITOR_TILE_SPAWNS, instance, NULL);
    if (tileSpawnsListBox == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    HWND creaturesStatic = CreateWindow("Static", "Creature:", WS_CHILD | WS_VISIBLE, 140, 250, 80, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_CREATURES, instance, NULL);
    if (creaturesStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    creaturesListBox = CreateWindow("ListBox", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 140, 270, 120, 100, window, (HMENU) VD_MAP_EDITOR_CREATURES, instance, NULL);
    if (creaturesListBox == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    removeSpawnButton = CreateWindow("Button", "Remove Spawn", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 10, 375, 110, 20, window, (HMENU) VD_MAP_EDITOR_REMOVE_SPAWN, instance, NULL);
    if (removeSpawnButton == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    addSpawnButton = CreateWindow("Button", "Add Spawn", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 140, 375, 80, 20, window, (HMENU) VD_MAP_EDITOR_ADD_SPAWN, instance, NULL);
    if (addSpawnButton == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    HWND tileTypesStatic = CreateWindow("Static", "Tile Types:", WS_CHILD | WS_VISIBLE, 10, 400, 80, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_TILE_TYPES, instance, NULL);
    if (tileTypesStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    nullTileOption = CreateWindow("Button", "Null", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP, 10, 420, 50, 18, window, (HMENU) VD_MAP_EDITOR_TILE_OPTION_NULL, instance, NULL);
    if (nullTileOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    (void) SendMessage(nullTileOption, BM_SETCHECK, BST_CHECKED, 0);
    openTileOption = CreateWindow("Button", "Open", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 10, 440, 60, 18, window, (HMENU) VD_MAP_EDITOR_TILE_OPTION_OPEN, instance, NULL);
    if (openTileOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    impassableTileOption = CreateWindow("Button", "Impassable", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 10, 460, 100, 18, window, (HMENU) VD_MAP_EDITOR_TILE_OPTION_IMPASSABLE, instance, NULL);
    if (impassableTileOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    newAreaTileOption = CreateWindow("Button", "New Area", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 10, 480, 80, 18, window, (HMENU) VD_MAP_EDITOR_TILE_OPTION_NEW_AREA, instance, NULL);
    if (newAreaTileOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    loadNewAreaButton = CreateWindow("Button", "Load New Area", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 140, 400, 110, 20, window, (HMENU) VD_MAP_EDITOR_LOAD_NEW_AREA, instance, NULL);
    if (loadNewAreaButton == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    newAreaStatic = CreateWindow("Static", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 140, 425, 120, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_NEW_AREA, instance, NULL);
    if (newAreaStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    (void) strcpy_s(newAreaFileLocation, "");
    HWND newAreaStartingPointStatic = CreateWindow("Static", "New Area\nStarting Point:", WS_CHILD | WS_VISIBLE, 140, 445, 120, 35, window, (HMENU) VD_MAP_EDITOR_STATIC_STARTING_POINT, instance, NULL);
    if (newAreaStartingPointStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    newAreaStartingPointX = CreateWindow("Edit", "0", WS_CHILD | WS_VISIBLE | WS_BORDER, 140, 480, 30, 18, window, (HMENU) VD_MAP_EDITOR_STARTING_POINT_X, instance, NULL);
    if (newAreaStartingPointX == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    newAreaStartingPointY = CreateWindow("Edit", "0", WS_CHILD | WS_VISIBLE | WS_BORDER, 180, 480, 30, 18, window, (HMENU) VD_MAP_EDITOR_STARTING_POINT_Y, instance, NULL);
    if (newAreaStartingPointY == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    HWND divider2 = CreateWindow("Static", "----------------------------------------------------------------------", WS_CHILD | WS_VISIBLE, 10, 500, 250, 10, window, (HMENU) VD_MAP_EDITOR_DIVIDER2, instance, NULL);
    if (divider2 == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };

    // add npc
    HWND addNPCStatic = CreateWindow("Static", "[Add NPC's]", WS_CHILD | WS_VISIBLE, 10, 515, 80, 18, window, (HMENU) VD_MAP_EDITOR_STATIC_ADD_NPC, instance, NULL);
    if (addNPCStatic == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    npcsListBox = CreateWindow("ListBox", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 10, 540, 120, 100, window, (HMENU) VD_MAP_EDITOR_NPCS, instance, NULL);
    if (npcsListBox == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    HWND spriteBorderStatic = CreateWindow("Static", "", WS_CHILD | WS_VISIBLE | WS_BORDER, 140, 515, 48, 48, window, (HMENU) VD_MAP_EDITOR_STATIC_SPRITE_BORDER, instance, NULL);
    if (spriteBorderStatic == NULL) {
        FreeMemory();
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    if (npcSprite != NULL) {
        npcSprite->FreeTexture();
        delete npcSprite;
        npcSprite = NULL;
    };
    (void) strcpy_s(selectedNPCImageLocation, "");
    (void) strcpy_s(previousNPCSelection, "");
    (void) SetRect(&npcSpriteDimensions, 148, 523, 180, 555);
    previousAnimationButton = CreateWindow("Button", "<", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 140, 563, 20, 20, window, (HMENU) VD_MAP_EDITOR_PREVIOUS_ANIMATION, instance, NULL); 
    nextAnimationButton = CreateWindow("Button", ">", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 168, 563, 20, 20, window, (HMENU) VD_MAP_EDITOR_PREVIOUS_ANIMATION, instance, NULL); 
    nullNPCOption = CreateWindow("Button", "Null NPC", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 140, 580, 110, 18, window, (HMENU) VD_MAP_EDITOR_NPC_OPTION_NULL, instance, NULL);
    if (nullNPCOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    normalNPCOption = CreateWindow("Button", "Normal NPC", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 140, 600, 110, 18, window, (HMENU) VD_MAP_EDITOR_NPC_OPTION_NORMAL, instance, NULL);
    if (normalNPCOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };
    staticNPCOption = CreateWindow("Button", "Static NPC", WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON, 140, 620, 100, 18, window, (HMENU) VD_MAP_EDITOR_NPC_OPTION_STATIC, instance, NULL);
    if (staticNPCOption == NULL) {
        VDError("Failed to create an interface resource.", __FILE__, __LINE__);
    };

    tileSelected = FALSE;

    return window;
};



/* **********************************************************************************************************************
   ProcessMapEditor
   ----------------
   Processes messages sent and received by and from the Map Editor.
   **********************************************************************************************************************/

void VDMapEditor::ProcessMapEditor(LPDIRECT3DDEVICE9 direct3DDevice, VDInput *input, vector<VDNPC>* npcs) {
    // Load Sprite Sheet button
    ///////////////////////////

    if (SendMessage(loadSpriteButton, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        char text[FILE_NAME_MAX_SIZE];

        // open a sprite image
        VDOpenFile(window, "Sprites (*.png,*.bmp)\0*.png;*.bmp\0All Files\0*.*\0", text);

        // make sure the user selected a file
        if (strcmp(text, "") != 0) {
            // set the sprite file location
            (void) strcpy_s(tileSheetImageLocation, text);

            // clear the selected sprite stuff
            if (selectedTile != NULL) {
                delete selectedTile;
                selectedTile = NULL;
            };
            tileSelected = FALSE;

            // add the sprite to the editor so it may be drawn
            RECT drawingArea;
            (void) SetRect(&drawingArea, 0, 0, 160, 160);
            if (tileSheet != NULL) {
                tileSheet->FreeTexture();
                delete tileSheet;
                tileSheet = NULL;
            };
            tileSheet = new VDSprite(direct3DDevice, text, drawingArea, D3DXVECTOR3((float) tileSheetDimensions.left, (float) tileSheetDimensions.top, 0.0f), 0xFF000000, FALSE, FALSE);
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // user selects a tile
    //////////////////////

    if (tileSheet != NULL) {
        // get the current cursor position
        POINT mousePosition;
        GetCursorPos(&mousePosition);

        // take a look at the Map Editor window location
        RECT windowDimensions;
        (void) GetWindowRect(window, &windowDimensions);

        // acquire the real mouse position
        POINT mapEditorMousePosition;
        mapEditorMousePosition.x = mousePosition.x - GetSystemMetrics(SM_CXFIXEDFRAME) - windowDimensions.left;
        mapEditorMousePosition.y = mousePosition.y - (GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CYMENU)) - windowDimensions.top;

        // see if cursor is in the sprite area
        if (mapEditorMousePosition.x >= tileSheetDimensions.left && mapEditorMousePosition.x < tileSheetDimensions.right && mapEditorMousePosition.y >= tileSheetDimensions.top && mapEditorMousePosition.y < tileSheetDimensions.bottom) {
            // set the mouse input to the Map Editor
            if (input->GetCurrentWindow() != window) {
                input->ChangeMouseWindow(window);
            };

            // user clicks on the sprite sheet
            if (input->GetMouseInput().rgbButtons[0] & 0x80) {
                // let the map editor know we selected a tile
                tileSelected = TRUE;

                // set up the tile source rectangle
                mapEditorMousePosition.x -= tileSheetDimensions.left;
                mapEditorMousePosition.y -= tileSheetDimensions.top;
                LONG tileSelectedX = mapEditorMousePosition.x - (mapEditorMousePosition.x % 32);
                LONG tileSelectedY = mapEditorMousePosition.y - (mapEditorMousePosition.y % 32);

                // get the current source rectangle selection
                RECT currentSelection;
                tileSheet->GetSourceRectangle(&currentSelection);
                currentSelection.left += tileSelectedX;
                currentSelection.top += tileSelectedY;
                currentSelection.right = currentSelection.left + 32;
                currentSelection.bottom = currentSelection.top + 32;

                // make sure we selected a different tile
                if (tileSheetSourceRectangle.left != currentSelection.left || tileSheetSourceRectangle.top != currentSelection.top || tileSheetSourceRectangle.right != currentSelection.right || tileSheetSourceRectangle.bottom != currentSelection.bottom) {
                    // set the new 32x32 source rectangle
                    tileSheetSourceRectangle.left = currentSelection.left;
                    tileSheetSourceRectangle.top = currentSelection.top;
                    tileSheetSourceRectangle.right = currentSelection.right;
                    tileSheetSourceRectangle.bottom = currentSelection.bottom; 

                    if (selectedTile != NULL) {
                        selectedTile->FreeTexture();
                        delete selectedTile;
                        selectedTile = NULL;
                    };
                    selectedTile = NULL;
                };
            };
        };
    };

    // Up button
    ////////////

    if (SendMessage(shiftTileSpriteUp, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        if (tileSheet != NULL) {
            // get the sprite's source rectangle
            RECT drawingArea;
            (void) tileSheet->GetSourceRectangle(&drawingArea);

            // see if we're wrapping around
            if (drawingArea.top == 0) {
                LONG bottom = tileSheet->GetSpriteHeight();
                tileSheet->SetSourceRectangle(drawingArea.left, bottom - 160, drawingArea.right, bottom);
            } else {
                tileSheet->SetSourceRectangle(drawingArea.left, drawingArea.top - 32, drawingArea.right, drawingArea.bottom - 32);
            };

            // let the map editor know we need to reselect
            if (selectedTile != NULL) {
                selectedTile->FreeTexture();
                delete selectedTile;
                selectedTile = NULL;
            };
            selectedTile = NULL;
            tileSelected = FALSE;
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // Down button
    //////////////

    if (SendMessage(shiftTileSpriteDown, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        if (tileSheet != NULL) {
            // get the sprite's source rectangle
            RECT drawingArea;
            (void) tileSheet->GetSourceRectangle(&drawingArea);

            // see if we're wrapping around
            LONG bottom = tileSheet->GetSpriteHeight();
            if (drawingArea.bottom == bottom) {
                tileSheet->SetSourceRectangle(drawingArea.left, 0, drawingArea.right, 160);
            } else {
                tileSheet->SetSourceRectangle(drawingArea.left, drawingArea.top + 32, drawingArea.right, drawingArea.bottom + 32);
            };

            // let the map editor know we need to reselect
            tileSelected = FALSE;
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // Left button
    //////////////

    if (SendMessage(shiftTileSpriteLeft, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        if (tileSheet != NULL) {
            // get the sprite's source rectangle
            RECT drawingArea;
            (void) tileSheet->GetSourceRectangle(&drawingArea);

            // see if we're wrapping around
            if (drawingArea.left == 0) {
                LONG right = tileSheet->GetSpriteWidth();
                tileSheet->SetSourceRectangle(right - 160, drawingArea.top, right, drawingArea.bottom);
            } else {
                tileSheet->SetSourceRectangle(drawingArea.left - 32, drawingArea.top, drawingArea.right - 32, drawingArea.bottom);
            };

            // let the map editor know we need to reselect
            tileSelected = FALSE;
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // Right button
    ///////////////

    if (SendMessage(shiftTileSpriteRight, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        if (tileSheet != NULL) {
            // get the sprite's source rectangle
            RECT drawingArea;
            (void) tileSheet->GetSourceRectangle(&drawingArea);

            // see if we're wrapping around
            LONG right = tileSheet->GetSpriteWidth();
            if (drawingArea.right == right) {
                tileSheet->SetSourceRectangle(0, drawingArea.top, 160, drawingArea.bottom);
            } else {
                tileSheet->SetSourceRectangle(drawingArea.left + 32, drawingArea.top, drawingArea.right + 32, drawingArea.bottom);
            };

            // let the map editor know we need to reselect
            tileSelected = FALSE;
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // Load New Area button
    ///////////////////////

    if (SendMessage(loadNewAreaButton, BM_GETSTATE, 0, 0) == BST_FOCUS) {
        char text[FILE_NAME_MAX_SIZE];

        // open the new world file
        VDOpenFile(window, "VDEngine Maps\0*.vdm\0", text);

        // make sure the user selected a file
        if (strcmp(text, "") != 0) {
            // set the new area location
            (void) strcpy_s(newAreaFileLocation, text);

            // remove the path name
            char actualName[FILE_NAME_MAX_SIZE];
            int n = 0, m = 0, p = 0, numSlashes = 0;
            while (text[n] != '\0') {
                if (text[n] == '\\') {
                    numSlashes++;
                };
                n++;
            };
            n = 0;
            while (text[n] != '\0') {
                if (text[n] == '\\') {
                    m++;
                };
                n++;
                if (text[n] != '\0' && m == numSlashes) {
                    actualName[p] = text[n];
                    p++;
                };
            };
            actualName[p] = '\0';

            // display the new world file
            SetWindowText(newAreaStatic, actualName);
        };

        // make sure we're not still focused on the button
        (void) SetFocus(window);
    };

    // user has an NPC selected
    ///////////////////////////

    int currentNPCIndex = (int) SendMessage(npcsListBox, LB_GETCURSEL, 0, 0);
    if (currentNPCIndex != LB_ERR) {
        // get the name of the current selected NPC
        char currentNPCSelection[FILE_NAME_MAX_SIZE];
        (void) strcpy_s(currentNPCSelection, "");
        (void) SendMessage(npcsListBox, LB_GETTEXT, (WPARAM) currentNPCIndex, (LPARAM) &currentNPCSelection);

        // < button
        ///////////

        if (SendMessage(previousAnimationButton, BM_GETSTATE, 0, 0) == BST_FOCUS) {
            if (npcSprite != NULL) {
                // get the sprite's source rectangle
                RECT drawingArea;
                (void) npcSprite->GetSourceRectangle(&drawingArea);

                // see if we're wrapping around
                if (drawingArea.left == 0) {
                    LONG right = npcSprite->GetSpriteWidth();
                    npcSprite->SetSourceRectangle(right - 32, drawingArea.top, right, drawingArea.bottom);
                } else {
                    npcSprite->SetSourceRectangle(drawingArea.left - 32, drawingArea.top, drawingArea.right - 32, drawingArea.bottom);
                };
            };

            // make sure we're not still focused on the button
            (void) SetFocus(window);
        };

        // > button
        ///////////

        if (SendMessage(nextAnimationButton, BM_GETSTATE, 0, 0) == BST_FOCUS) {
            if (npcSprite != NULL) {
                // get the sprite's source rectangle
                RECT drawingArea;
                (void) npcSprite->GetSourceRectangle(&drawingArea);

                // see if we're wrapping around
                LONG right = npcSprite->GetSpriteWidth();
                if (drawingArea.right == right) {
                    npcSprite->SetSourceRectangle(0, drawingArea.top, 32, drawingArea.bottom);
                } else {
                    npcSprite->SetSourceRectangle(drawingArea.left + 32, drawingArea.top, drawingArea.right + 32, drawingArea.bottom);
                };
            };

            // make sure we're not still focused on the button
            (void) SetFocus(window);
        };

        // user selects a different NPC
        ///////////////////////////////

        if (strcmp(previousNPCSelection, currentNPCSelection) != 0) {
            // copy the current selection to previous
            (void) strcpy_s(previousNPCSelection, currentNPCSelection);

            // make sure the editor knows the file location
            for (unsigned int n = 0; n < npcs->size(); n++) {
                if (strcmp(currentNPCSelection, npcs->at(n).GetName()) == 0) {
                    (void) strcpy_s(selectedNPCImageLocation, npcs->at(n).GetImageFileLocation());
                };
            };

            // update the window
            RECT drawingArea;
            (void) SetRect(&drawingArea, 0, 0, 32, 32);
            if (npcSprite != NULL) {
                npcSprite->FreeTexture();
                delete npcSprite;
                npcSprite = NULL;
            };
            npcSprite = new VDSprite(direct3DDevice, selectedNPCImageLocation, drawingArea, D3DXVECTOR3((float) npcSpriteDimensions.left, (float) npcSpriteDimensions.top, 0.0f), 0xFF000000, FALSE, FALSE);
        };
    };
};
// TODO: If the NPC Editor added new NPC's, this thing needs to know


/* **********************************************************************************************************************
   VDOpenFile
   ----------
   Creates an open file box and sets the file name parameter to the chosen file.
   #param  window    Handle to the window opening the box.
   #param  filter    The type of filter to distinguish which types of files to open.
   #param  fileName  (out) The chosen file location.
   **********************************************************************************************************************/

void VDMapEditor::VDOpenFile(HWND window, LPSTR filter, LPSTR fileName) {
    char file[FILE_NAME_MAX_SIZE];
    OPENFILENAME openFileBox;

    // zero out the open file box just to be on the safe side
    SecureZeroMemory(&openFileBox, sizeof(OPENFILENAME));

    // set up the open file structure
                openFileBox.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR;
            openFileBox.hwndOwner = window;
            openFileBox.lpstrFile = file;
         openFileBox.lpstrFile[0] = '\0';
       openFileBox.lpstrFileTitle = NULL;
          openFileBox.lpstrFilter = filter;
      openFileBox.lpstrInitialDir = NULL;
          openFileBox.lStructSize = sizeof(OPENFILENAME);
         openFileBox.nFilterIndex = 1;
             openFileBox.nMaxFile = sizeof(file);
        openFileBox.nMaxFileTitle = NULL;

    // open a file
    BOOL returnValue = GetOpenFileName(&openFileBox);
    if (returnValue != 0) {
        (void) strcpy_s(fileName, sizeof(file), file);
    } else {
        (void) strcpy_s(fileName, sizeof(file), "");
    };
};



/* **********************************************************************************************************************
   Accessors and Modifiers
   **********************************************************************************************************************/

HWND VDMapEditor::GetWindow() {
    return window;
};

HWND VDMapEditor::GetTransparencyColor() {
    return transparencyColor;
};

HWND VDMapEditor::GetLoadSpriteButton() {
    return loadSpriteButton;
};

VDSprite* VDMapEditor::GetTileSheet() {
    return tileSheet;
};

void VDMapEditor::SetTileSheet(VDSprite *newSprite) {
    if (tileSheet != NULL) {
        tileSheet->FreeTexture();
        delete tileSheet;
        tileSheet = NULL;
    };
    tileSheet = newSprite;
};

LPCSTR VDMapEditor::GetTileSheetImageLocation() {
    return tileSheetImageLocation;
};

void VDMapEditor::SetTileSheetImageLocation(LPCSTR imageLocation) {
    (void) strcpy_s(tileSheetImageLocation, imageLocation);
};

LPRECT VDMapEditor::GetTileSheetDimensions(LPRECT outRect) {
    outRect->left = tileSheetDimensions.left;
    outRect->top = tileSheetDimensions.top;
    outRect->right = tileSheetDimensions.right;
    outRect->bottom = tileSheetDimensions.bottom;

    return &tileSheetDimensions;
};

VDSprite* VDMapEditor::GetSelectedTile() {
    return selectedTile;
};

void VDMapEditor::SetSelectedTile(VDSprite *newSprite) {
    if (selectedTile != NULL) {
        selectedTile->FreeTexture();
        delete selectedTile;
        selectedTile = NULL;
    };
    selectedTile = newSprite;
};

LPCSTR VDMapEditor::GetSelectedTileImageLocation() {
    return selectedTileImageLocation;
};

void VDMapEditor::SetSelectedTileImageLocation(LPCSTR imageLocation) {
    (void) strcpy_s(selectedTileImageLocation, imageLocation);
};

LPRECT VDMapEditor::GetTileSheetSourceRectangle(LPRECT outRect) {
    outRect->left = tileSheetSourceRectangle.left;
    outRect->top = tileSheetSourceRectangle.top;
    outRect->right = tileSheetSourceRectangle.right;
    outRect->bottom = tileSheetSourceRectangle.bottom;

    return &tileSheetSourceRectangle;
};

void VDMapEditor::SetTileSheetSourceRectangle(LONG left, LONG top, LONG right, LONG bottom) {
    tileSheetSourceRectangle.left = left;
    tileSheetSourceRectangle.top = top;
    tileSheetSourceRectangle.right = right;
    tileSheetSourceRectangle.bottom = bottom;
};

HWND VDMapEditor::GetShiftTileSpriteUp() {
    return shiftTileSpriteUp;
};

HWND VDMapEditor::GetShiftTileSpriteDown() {
    return shiftTileSpriteDown;
};

HWND VDMapEditor::GetShiftTileSpriteLeft() {
    return shiftTileSpriteLeft;
};

HWND VDMapEditor::GetShiftTileSpriteRight() {
    return shiftTileSpriteRight;
};

HWND VDMapEditor::GetTileSpawnsListBox() {
    return tileSpawnsListBox;
};

HWND VDMapEditor::GetCreaturesListBox() {
    return creaturesListBox;
};

HWND VDMapEditor::GetRemoveSpawnButton() {
    return removeSpawnButton;
};

HWND VDMapEditor::GetAddSpawnButton() {
    return addSpawnButton;
};

HWND VDMapEditor::GetNullTileOption() {
    return nullTileOption;
};

HWND VDMapEditor::GetOpenTileOption() {
    return openTileOption;
};

HWND VDMapEditor::GetImpassableTileOption() {
    return impassableTileOption;
};

HWND VDMapEditor::GetNewAreaTileOption() {
    return newAreaTileOption;
};

HWND VDMapEditor::GetLoadNewAreaButton() {
    return loadNewAreaButton;
};

HWND VDMapEditor::GetNewAreaStatic() {
    return newAreaStatic;
};

LPCSTR VDMapEditor::GetNewAreaFileLocation() {
    return newAreaFileLocation;
};

void VDMapEditor::SetNewAreaFileLocation(LPCSTR aFileLocation) {
    (void) strcpy_s(newAreaFileLocation, aFileLocation);
};

HWND VDMapEditor::GetNewAreaStartingPointX() {
    return newAreaStartingPointX;
};

HWND VDMapEditor::GetNewAreaStartingPointY() {
    return newAreaStartingPointY;
};

HWND VDMapEditor::GetNPCListBox() {
    return npcsListBox;
};

VDSprite* VDMapEditor::GetNPCSprite() {
    return npcSprite;
};

void VDMapEditor::SetNPCSprite(VDSprite *newSprite) {
    if (npcSprite != NULL) {
        npcSprite->FreeTexture();
        delete npcSprite;
        npcSprite = NULL;
    };
    npcSprite = newSprite;
};

LPCSTR VDMapEditor::GetSelectedNPCImageLocation() {
    return selectedNPCImageLocation;
};

void VDMapEditor::SetSelectedNPCImageLocation(LPCSTR imageLocation) {
    (void) strcpy_s(selectedNPCImageLocation, imageLocation);
};

void VDMapEditor::SetPreviousNPCSelection(LPCSTR npcName) {
    (void) strcpy_s(previousNPCSelection, npcName);
};

LPRECT VDMapEditor::GetNPCSpriteDimensions(LPRECT outRect) {
    outRect->left = npcSpriteDimensions.left;
    outRect->top = npcSpriteDimensions.top;
    outRect->right = npcSpriteDimensions.right;
    outRect->bottom = npcSpriteDimensions.bottom;

    return &npcSpriteDimensions;
};

HWND VDMapEditor::GetPreviousAnimationButton() {
    return previousAnimationButton;
};

HWND VDMapEditor::GetNextAnimationButton() {
    return nextAnimationButton;
};

HWND VDMapEditor::GetNullNPCOption() {
    return nullNPCOption;
};

HWND VDMapEditor::GetNormalNPCOption() {
    return normalNPCOption;
};

HWND VDMapEditor::GetStaticNPCOption() {
    return staticNPCOption;
};

BOOL VDMapEditor::IsTileSelected() {
    return tileSelected;
};

void VDMapEditor::SetTileSelected(BOOL isSelected) {
    tileSelected = isSelected;
};