#include "ofApp.h"
#include "imgui_impl_glfw_gl2.h"
//#include "imgui_impl_glfw_gl3.h"
//#include <stdio.h>
#include <GLFW/glfw3.h>

static void glfw_error_callback(int error, const char* description)
{
    fprintf(stderr, "Error %d: %s\n", error, description);
    //ofLogVerbose() << "Error %d: %s\n", error, description;
}

// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    std::cout << key << std::endl;
    if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

//--------------------------------------------------------------
void ofApp::setup()
{
    ofSetLogLevel(OF_LOG_VERBOSE);

    // Setup window
    glfwSetErrorCallback(glfw_error_callback);
    glfwInit();

    //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#if __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    window = glfwCreateWindow(1280, 720, "ImGui GLFW+OpenGL2 example", NULL, NULL);
    if (!window)
    {
	fprintf(stderr, "Failed to open GLFW window.\n");
	glfwTerminate();
	ofExit();
    }
    glfwMakeContextCurrent(window);
    //glfwSwapInterval(1); // Enable vsync
    //gl3wInit();


    // Setup Dear ImGui binding
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls
    ImGui_ImplGlfwGL2_Init(window, true);
    ////ImGui_ImplGlfwGL3_Init(window, true);

    //required call
    //gui.setup();
     // Setup style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsClassic();

    ImGui::GetIO().MouseDrawCursor = false;
    //backgroundColor is stored as an ImVec4 type but can handle ofColor
    backgroundColor = ofColor(114, 144, 154);
    show_test_window = true;
    show_another_window = false;
    floatValue = 0.0f;
    
    //load your own ofImage
    imageButtonSource.load("of.png");
    //imageButtonID = loadImage(imageButtonSource);
    //imageButtonID.load("of.png");
    
    //or have the loading done for you if you don't need the ofImage reference
    //imageButtonID = gui.loadImage("of.png");
    //imageButtonID.load("of.png");
    
    //can also use ofPixels in same manner
    //ofLoadImage(pixelsButtonSource, "of_upside_down.png");
    ////pixelsButtonID = gui.loadPixels(pixelsButtonSource);
    
    //and alt method
    //pixelsButtonID = gui.loadPixels("of_upside_down.png");
    //pixelsButtonID.load("of_upside_down.png");
    
    //pass in your own texture reference if you want to keep it
    ////textureSourceID = gui.loadTexture(textureSource, "of_upside_down.png");
    
    //or just pass a path
    //textureSourceID = gui.loadTexture("of_upside_down.png");
    //textureSourceID.load("of_upside_down.png");

    ofLogVerbose() << "textureSourceID: " << textureSourceID;

    cout << "Vendor :" << glGetString(GL_VENDOR) << endl;
    cout << "GPU : "<< glGetString(GL_RENDERER) << endl;
    cout << "OpenGL ver. " << glGetString(GL_VERSION) << endl;
    cout << "GLSL ver. " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;

}

//--------------------------------------------------------------
void ofApp::update() {
    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);

    if(glfwWindowShouldClose(window)){
	ofExit();
    }
}

bool doThemeColorsWindow = false;
//--------------------------------------------------------------
void ofApp::draw() {
    
    //backgroundColor is stored as an ImVec4 type but is converted to ofColor automatically
    //ofSetBackgroundColor(backgroundColor);
    
    //required to call this at beginning
    //gui.begin();
    //if (!glfwWindowShouldClose(window)) {
    glfwPollEvents();
    ImGui_ImplGlfwGL2_NewFrame();
    //ImGui_ImplGlfwGL3_NewFrame();

    //In between gui.begin() and gui.end() you can use ImGui as you would anywhere else
    
    // 1. Show a simple window
    {
        ImGui::Text("Hello, world!");
        ImGui::SliderFloat("Float", &floatValue, 0.0f, 1.0f);
        
        //this will change the app background color
        ImGui::ColorEdit3("Background Color", (float*)&backgroundColor);
        if(ImGui::Button("Demo Window"))
        {
            show_test_window = !show_test_window;
        }
        
        if (ImGui::Button("Another Window"))
        {
            //bitwise OR
            show_another_window ^= 1;
            
        }
        ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    }
    // 2. Show another window, this time using an explicit ImGui::Begin and ImGui::End
    if (show_another_window) {
        //note: ofVec2f and ImVec2f are interchangeable
        ImGui::SetNextWindowSize(ofVec2f(200,100), ImGuiCond_FirstUseEver);
        ImGui::Begin("Another Window", &show_another_window);
        ImGui::Text("Hello");
        ImGui::End();
    }
    
    // 3. Show the ImGui test window. Most of the sample code is in ImGui::ShowDemoWindow()
    if (show_test_window) {
        ImGui::SetNextWindowPos(ofVec2f(650, 20), ImGuiCond_FirstUseEver);
        ImGui::ShowDemoWindow(&show_test_window);
    }
    
    ImGui::ShowTabsDemo("Tabs Demo");

    //bool pressed = ImGui::ImageButton((ImTextureID)(uintptr_t)imageButtonID, ImVec2(200, 200));
    //    pressed = ImGui::ImageButton((ImTextureID)(uintptr_t)pixelsButtonID, ImVec2(200, 200));
    //    pressed = ImGui::ImageButton((ImTextureID)(uintptr_t)textureSourceID, ImVec2(200, 200));
    
    if(doThemeColorsWindow) {
        //gui.openThemeColorWindow();
    }
    
    //required to call this at end
    //gui.end();

    // Rendering
    int display_w, display_h;
    glfwGetFramebufferSize(window, &display_w, &display_h);
    glViewport(0, 0, display_w, display_h);
    glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
    glClear(GL_COLOR_BUFFER_BIT);
    //glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context where shaders may be bound, but prefer using the GL3+ code.
    ImGui::Render();
    ImGui_ImplGlfwGL2_RenderDrawData(ImGui::GetDrawData());
    //ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
    glfwSwapBuffers(window);

    if(textureSource.isAllocated()) {
        //textureSource.draw(ofRandom(200), ofRandom(200));
    }
 // }
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key) {

    ofLogVerbose(__FUNCTION__) << key;
    switch (key)
    {
        case 'w': {
            doThemeColorsWindow = !doThemeColorsWindow;
            break;
        }
        case 'e': {
            ImGui::StyleColorsDark();
            break;
        }
        case 'r': {
            ImGui::StyleColorsClassic();
            break;
        }
        case 't': {
            gui.setTheme(new ThemeTest());
            break;
        }
        case 'z': {
            gui.setDefaultTheme();
            break;
        }
    }

}

void ofApp::exit( ofEventArgs & args )
{
    // Cleanup
    ImGui_ImplGlfwGL2_Shutdown();
    //ImGui_ImplGlfwGL3_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);
    glfwTerminate();
}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){
    ofLogVerbose(__FUNCTION__) << key;
    
}

//--------------------------------------------------------------
void ofApp::mouseScrolled(float x, float y) {
    ofLogVerbose(__FUNCTION__) << "x: " << x << " y: " << y;
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y) {
}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button) {
}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {
}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button) {
}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h) {
}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg) {
}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo) {
}