//
// Copyright 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();
}
