//
// Copyright (c) 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "SampleApplication.h"

#include <algorithm>
#include <cmath>
#include <vector>

#include "util/Matrix.h"
#include "util/random_utils.h"
#include "util/shader_utils.h"

using namespace angle;

class MultiWindowSample : public SampleApplication
{
  public:
    MultiWindowSample(int argc, char **argv)
        : SampleApplication("MultiWindow", argc, argv, 2, 0, 256, 256)
    {}

    bool initialize() override
    {
        constexpr char kVS[] = R"(attribute vec4 vPosition;
void main()
{
    gl_Position = vPosition;
})";

        constexpr char kFS[] = R"(precision mediump float;
void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
})";

        mProgram = CompileProgram(kVS, kFS);
        if (!mProgram)
        {
            return false;
        }

        // Set an initial rotation
        mRotation = 45.0f;

        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

        window rootWindow;
        rootWindow.osWindow = getWindow();
        rootWindow.surface  = getSurface();
        mWindows.push_back(rootWindow);

        const size_t numWindows = 5;
        for (size_t i = 1; i < numWindows; i++)
        {
            window window;

            window.osWindow = OSWindow::New();
            if (!window.osWindow->initialize("MultiWindow", 256, 256))
            {
                return false;
            }

            window.surface = eglCreateWindowSurface(getDisplay(), getConfig(),
                                                    window.osWindow->getNativeWindow(), nullptr);
            if (window.surface == EGL_NO_SURFACE)
            {
                return false;
            }

            window.osWindow->setVisible(true);

            mWindows.push_back(window);
        }

        int baseX = rootWindow.osWindow->getX();
        int baseY = rootWindow.osWindow->getY();
        for (auto &window : mWindows)
        {
            int x      = baseX + mRNG.randomIntBetween(0, 512);
            int y      = baseY + mRNG.randomIntBetween(0, 512);
            int width  = mRNG.randomIntBetween(128, 512);
            int height = mRNG.randomIntBetween(128, 512);
            window.osWindow->setPosition(x, y);
            window.osWindow->resize(width, height);
        }

        return true;
    }

    void destroy() override { glDeleteProgram(mProgram); }

    void step(float dt, double totalTime) override
    {
        mRotation = fmod(mRotation + (dt * 40.0f), 360.0f);

        for (auto &window : mWindows)
        {
            window.osWindow->messageLoop();
        }
    }

    void draw() override
    {
        OSWindow *rootWindow = mWindows[0].osWindow;
        int left             = rootWindow->getX();
        int right            = rootWindow->getX() + rootWindow->getWidth();
        int top              = rootWindow->getY();
        int bottom           = rootWindow->getY() + rootWindow->getHeight();

        for (auto &windowRecord : mWindows)
        {
            OSWindow *window = windowRecord.osWindow;
            left             = std::min(left, window->getX());
            right            = std::max(right, window->getX() + window->getWidth());
            top              = std::min(top, window->getY());
            bottom           = std::max(bottom, window->getY() + window->getHeight());
        }

        float midX = (left + right) * 0.5f;
        float midY = (top + bottom) * 0.5f;

        Matrix4 modelMatrix = Matrix4::translate(Vector3(midX, midY, 0.0f)) *
                              Matrix4::rotate(mRotation, Vector3(0.0f, 0.0f, 1.0f)) *
                              Matrix4::translate(Vector3(-midX, -midY, 0.0f));
        Matrix4 viewMatrix = Matrix4::identity();

        for (auto &windowRecord : mWindows)
        {
            OSWindow *window   = windowRecord.osWindow;
            EGLSurface surface = windowRecord.surface;

            eglMakeCurrent(getDisplay(), surface, surface, getContext());

            Matrix4 orthoMatrix =
                Matrix4::ortho(static_cast<float>(window->getX()),
                               static_cast<float>(window->getX() + window->getWidth()),
                               static_cast<float>(window->getY() + window->getHeight()),
                               static_cast<float>(window->getY()), 0.0f, 1.0f);
            Matrix4 mvpMatrix = orthoMatrix * viewMatrix * modelMatrix;

            Vector3 vertices[] = {
                Matrix4::transform(mvpMatrix, Vector4(midX, static_cast<float>(top), 0.0f, 1.0f)),
                Matrix4::transform(mvpMatrix, Vector4(static_cast<float>(left),
                                                      static_cast<float>(bottom), 0.0f, 1.0f)),
                Matrix4::transform(mvpMatrix, Vector4(static_cast<float>(right),
                                                      static_cast<float>(bottom), 0.0f, 1.0f)),
            };

            // Set the viewport
            glViewport(0, 0, window->getWidth(), window->getHeight());

            // Clear the color buffer
            glClear(GL_COLOR_BUFFER_BIT);

            // Use the program object
            glUseProgram(mProgram);

            // Load the vertex data
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices[0].data());
            glEnableVertexAttribArray(0);

            glDrawArrays(GL_TRIANGLES, 0, 3);

            eglSwapBuffers(getDisplay(), surface);
        }
    }

    // Override swap to do nothing as we already swapped the root
    // window in draw() and swapping another time would invalidate
    // the content of the default framebuffer.
    void swap() override {}

  private:
    // Handle to a program object
    GLuint mProgram;

    // Current rotation
    float mRotation;

    // Window and surface data
    struct window
    {
        OSWindow *osWindow;
        EGLSurface surface;
    };
    std::vector<window> mWindows;

    RNG mRNG;
};

int main(int argc, char **argv)
{
    MultiWindowSample app(argc, argv);
    return app.run();
}
