/*
 * Copyright 2016 Canonical Ltd.
 *
 * This program 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; version 3.
 *
 * 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/>.
 *
 * Author: Loïc Molinari <loic.molinari@canonical.com>
 */

// FIXME(loicm)
// - Merge that with createshapetextures.
// - Generate a class providing access to all the textures per context.

#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtCore/QtMath>
#include <QtGui/QImage>
#include <QtGui/QPainter>
#include <QtSvg/QSvgRenderer>

const double shapeOffset = 0.0625;
const int widthMipmap = 256;
const int heightMipmap = 256;
const int sizeMipmap = widthMipmap * heightMipmap;
const int mipmapCount = 9;  // Minimum size is 1.
static uint renderBuffer[sizeMipmap];
static uint textureDataMipmap[sizeMipmap];

static void clearRenderBuffer()
{
    memset(renderBuffer, 0, sizeMipmap * sizeof(uint));
}

static void createTexture(QSvgRenderer* svg, QPainter* painter, uint* data, int width, int height)
{
    const int size = width * height;

    clearRenderBuffer();
    painter->resetTransform();
    painter->translate(shapeOffset * width, shapeOffset * height);
    svg->render(painter);
    for (int i = 0; i < size; i++) {
        data[i] = renderBuffer[i] >> 24;
    }
}

static void dump(QTextStream& cppOut, const uint* data, int size)
{
    cppOut.setIntegerBase(16);
    for (int i = 0; i < size; i++) {
        cppOut << ((i % 16 != 0) ? "," : ((i != 0) ? ",\n    " : "    ")) << "0x"
               << qSetFieldWidth(2) << qSetPadChar('0')
               << data[i]
               << qSetFieldWidth(0) << qSetPadChar(' ');
    }
    cppOut.setIntegerBase(10);
}

int main(int argc, char* argv[])
{
    if (argc != 3) {
        qWarning("Usage: createshapetextures input_svg output_cpp");
        return 1;
    }
    const char* svgFilename = argv[1];
    const char* cppFilename = argv[2];

    // Open files.
    QSvgRenderer svg;
    if (!svg.load(QString(svgFilename))) {
        qWarning("Can't open input SVG file \'%s\'", svgFilename);
        return 1;
    }
    QFile cppFile(cppFilename);
    if (!cppFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning("Can't create output C++ file \'%s\'", cppFilename);
        return 1;
    }

    QTextStream cppOut(&cppFile);
    cppOut << "// Copyright 2015 Canonical Ltd.\n"
           << "// Automatically generated by the createshapetextures tool.\n\n";

    // Create the mipmap textures and write them to the C++ file.
    cppOut << "const float shapeOffset = " << shapeOffset << "f;\n"
           << "const int shapeMipmapBaseSize = " << widthMipmap << ";\n"
           << "const int shapeMipmapCount = " << mipmapCount << ";\n"
           << "static const int shapeMipmapOffsets[" << mipmapCount << "] = {\n"
           << "    0";
    int size = 0, i = 0;
    for (int i = 0; i < mipmapCount-1; i++) {
        size += (widthMipmap >> i) * (heightMipmap >> i);
        cppOut << ", " << size;
    }
    size += (widthMipmap >> (mipmapCount-1)) * (heightMipmap >> (mipmapCount-1));
    cppOut << "\n};\n";
    cppOut << "static const unsigned char shapeMipmapData[" << size << "] = {\n";
    QPainter painter;
    for (int i = 0; i < mipmapCount; i++) {
        const int width = widthMipmap >> i;
        const int height = heightMipmap >> i;
        QImage shapeMipmap(reinterpret_cast<uchar*>(renderBuffer), width, height,
                           width * 4, QImage::Format_ARGB32_Premultiplied);
        painter.begin(&shapeMipmap);
        createTexture(&svg, &painter, textureDataMipmap, width, height);
        if (i) {
            cppOut << ",\n";
        }
        cppOut << "    // Mipmap level " << i << ".\n";
        dump(cppOut, textureDataMipmap, width * height);
        painter.end();
    }
    cppOut << "\n};\n";

    return 0;
}
