/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
 * Copyright 2018 Pelican Mapping
 * http://osgearth.org
 *
 * osgEarth is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
#ifndef OSGEARTH_IMGUI_CONTENTBROWSER_GUI
#define OSGEARTH_IMGUI_CONTENTBROWSER_GUI

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgEarth/FileUtils>

namespace osgEarth {
    namespace GUI
    {
        using namespace osgEarth;
        using namespace osgEarth::Util;

        struct ContentBrowserGUI : public BaseGUI
        {
            std::vector< std::string > _drives;
            std::string _selectedFilename;
            osg::ref_ptr< osg::Texture2D > _currentTexture;
            osg::ref_ptr< osg::Node > _currentNode;

            ContentBrowserGUI() :
                BaseGUI("Content Browser")
            {
                _drives = getListOfDrives();
            }

            void load(const Config& conf) override
            {
            }

            void save(Config& conf) override
            {
            }

            std::vector<std::string> getListOfDrives() {
                std::vector<std::string> arrayOfDrives;
#ifdef WIN32
                char* szDrives = new char[MAX_PATH]();
                if (GetLogicalDriveStringsA(MAX_PATH, szDrives))
                {
                    for (int i = 0; i < 100; i += 4)
                        if (szDrives[i] != (char)0)
                            arrayOfDrives.push_back(std::string{ szDrives[i],szDrives[i + 1],szDrives[i + 2] });
                }
                delete[] szDrives;
#else
                arrayOfDrives.push_back("/");
#endif
                return arrayOfDrives;
            }

            void drawDirectoryTree()
            {             
                ImGui::BeginChild("DirectoryTree");
                for (auto& drive : _drives)
                {
                    traverseDir(drive);
                }                
                ImGui::EndChild();
            }



            void traverseDir(const std::string& path)
            {
                std::string shortName = osgDB::getSimpleFileName(path);
                if (shortName.empty())
                {
                    shortName = path;
                }

                if (osgDB::fileType(path) == osgDB::DIRECTORY)
                {
                    if (ImGui::TreeNode(shortName.c_str()))
                    {
                        osgDB::DirectoryContents files = osgDB::getDirectoryContents(path);
                        for (osgDB::DirectoryContents::const_iterator f = files.begin(); f != files.end(); ++f)
                        {
                            if (f->compare(".") == 0 || f->compare("..") == 0)
                                continue;

                            std::string filepath = osgDB::concatPaths(path, *f);
                            traverseDir(filepath);
                        }
                        ImGui::TreePop();
                    }
                }
                else if (osgDB::fileType(path) == osgDB::REGULAR_FILE)
                {
                    ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
                    if (_selectedFilename == path)
                    {
                        node_flags |= ImGuiTreeNodeFlags_Selected;
                    }
                    ImGui::TreeNodeEx(path.c_str(), node_flags, shortName.c_str());
                    if (ImGui::IsItemClicked())
                    {
                        setSelectedFilename(path);
                    }

                    if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
                    {
                        if (_currentNode.valid())
                        {
                            void* ptr = _currentNode.get();
                            ImGui::SetDragDropPayload("NODE", &ptr, sizeof(ptr));
                        }                        
                        else if (_currentTexture.valid())
                        {
                            void* ptr = _currentTexture.get();
                            ImGui::SetDragDropPayload("TEXTURE", &ptr, sizeof(ptr));
                        }
                        ImGui::EndDragDropSource();
                    }
                }
            }

            void setSelectedFilename(const std::string& filename)
            {
                if (_selectedFilename != filename)
                {
                    _selectedFilename = filename;
                    if (_currentTexture)
                    {
                        _currentTexture->releaseGLObjects();
                        _currentTexture = nullptr;
                    }

                    if (_currentNode)
                    {
                        _currentNode->releaseGLObjects();
                        _currentNode = nullptr;
                    }

                    // Try to load the file as an image
                    osg::ref_ptr< osg::Image > image = osgDB::readImageFile(_selectedFilename);
                    if (image)
                    {
                        _currentTexture = new osg::Texture2D(image.get());
                        _currentTexture->setResizeNonPowerOfTwoHint(false);
                    }

                    // Try to load it as a node.
                    if (!image)
                    {
                        _currentNode = osgDB::readNodeFile(_selectedFilename);
                    }
                }
            }

            void drawPreview(osg::RenderInfo& ri)
            {
                ImGui::BeginChild("Preview");
                if (!_selectedFilename.empty() && !_currentTexture.valid() && !_currentNode.valid())
                {
                    ImGui::Text("Couldn't load %s", _selectedFilename.c_str());
                    return;
                }

                if (_currentTexture.valid())
                {
                    ImGuiUtil::Texture(_currentTexture.get(), ri, 250, 0);
                    osg::Image* image = _currentTexture->getImage();
                    ImGui::Text(image->getFileName().c_str());
                    ImGui::Text("Dimensions: %d x %d", image->s(), image->t());
                    ImGui::Text("Compressed: %s", image->isCompressed() ? "Yes" : "No");                    
                    ImGui::Text("Data Type: %s", getGLString(image->getDataType()).c_str());
                    ImGui::Text("Texture Format: %s", getGLString(image->getInternalTextureFormat()).c_str());
                    ImGui::Text("Mipmap Levels: %d", image->getNumMipmapLevels());
                    ImGui::Text("Pixel Format: %s", getGLString(image->getPixelFormat()).c_str());
                }

                if (_currentNode.valid())
                {
                    ImGui::Text("Loaded Node");
                }
                ImGui::EndChild();
            }

            const std::string& getGLString(int value)
            {
                return osgDB::Registry::instance()->getObjectWrapperManager()->getString("GL", value);
            }

            void draw(osg::RenderInfo& ri)
            {
                if (!isVisible())
                    return;

                ImGui::Begin(name(), visible());
                {         
                    ImVec2 window_size = ImGui::GetWindowSize();

                    if (ImGui::BeginTable("Content Browser", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_Borders))
                    {
                        ImGui::TableNextColumn();
                        drawDirectoryTree();

                        ImGui::TableNextColumn();
                        drawPreview(ri);

                        ImGui::EndTable();
                    }
                }
                ImGui::End();
            }
        };
    }
}

#endif // OSGEARTH_IMGUI_CONTENTBROWSER_GUI
