#include "atlas.h"
#include <GL/glew.h>
#include <tinyxml2.h>
#include <list>
#include <log.h>
#include <cmath>

using namespace tinyxml2;

namespace render{
namespace sprite{
textureAtlas::textureAtlas(const std::string &path, bool smooth)
{
    load(path, smooth);
}

textureAtlas::~textureAtlas()
{
    free();
}

vec4f textureAtlas::getTexCoord(uint32_t c) const
{
    if(c >= elements.size()) {
        return vec4f(0, 0, 1, 1);
    }

    return vec4f(elements[c].pos/_size, elements[c].size/_size);
}

#define CheckAttribute(x, y, z) \
        if(z->QueryAttribute(x, y))\
            Logger::Warning("Can't find attribute %s\n", x);


bool textureAtlas::load(const std::string &path, bool smooth, bool flip)
{
    Logger::Debug("Loading texture atlas : %s\n", path.c_str());
    tinyxml2::XMLDocument document;

    if(document.LoadFile(path.c_str()))
        return 0;
    free();

    tinyxml2::XMLElement *element = document.RootElement();

    if(!texture::load(path.substr(0,path.rfind('/')+1)+element->Attribute("imagePath"), smooth, flip))
        return 0;
    parameteri(GL_TEXTURE_WRAP_S, GL_CLAMP);
    parameteri(GL_TEXTURE_WRAP_T, GL_CLAMP);
    element = element->FirstChildElement("sprite");

    for(int i = 0;element; i++, element = element->NextSiblingElement())
    {
        textureAtlasNode temp;
        temp.angle = 0;
        temp.scale = vec2f(1);

        CheckAttribute("x", &temp.pos.x, element);
        CheckAttribute("y", &temp.pos.y, element);
        CheckAttribute("w", &temp.size.x, element);
        CheckAttribute("h", &temp.size.y, element);
        CheckAttribute("pX", &temp.center.x, element);
        CheckAttribute("pY", &temp.center.y, element);

        const char *name = element->Attribute("n");
        if(name)
            temp.name = name;
        else Logger::Warning("Can't find attribute \"n\"\n");

        temp.size += vec2f(1);

        mathRotate(temp);

        elements.push_back(temp);
    }

    return 1;
}

void textureAtlas::mathRotate(textureAtlasNode &p) noexcept
{
    vec2f offset[6] = {vec2f(0, 1), vec2f(1), vec2f(1, 0),
                       vec2f(1, 0), vec2f(0), vec2f(0, 1)};
    float msin, mcos;
    sincosf(p.angle, &msin, &mcos);

    for(int i = 0; i < 6; i++)
    {
        offset[i] -= p.center;
        offset[i] *= p.size;

        p.rotMatrix[i].x = offset[i].x*mcos-offset[i].y*msin;
        p.rotMatrix[i].y = offset[i].x*msin+offset[i].y*mcos;
    }
}

void textureAtlas::mathRotate(icon &p) const noexcept
{
    vec2f offset[6] = {vec2f(0, 1), vec2f(1), vec2f(1, 0),
                       vec2f(1, 0), vec2f(0), vec2f(0, 1)};
    float msin, mcos;
    sincosf(p.angle, &msin, &mcos);

    for(int i = 0; i < 6; i++)
    {
        offset[i] -= p.center;
        offset[i] *= p.size;

        p._rotMatrix[i].x = offset[i].x*mcos-offset[i].y*msin;
        p._rotMatrix[i].y = offset[i].x*msin+offset[i].y*mcos;
    }

    p._angle  = p.angle;
    p._size   = p.size;
    p._center = p.center;
}

int textureAtlas::getNodeId(const std::string &name) const noexcept
{
    for(uint32_t i = 0; i < elements.size(); i++)
        if(elements[i].name == name)
            return i;
    return -1;
}

uint32_t textureAtlas::getNodesCount() const noexcept
{
    return elements.size();
}

icon textureAtlas::getIcon(uint32_t c) const noexcept
{
    icon temp;
    if(c >= elements.size())
        return temp;

    memcpy(&temp, &elements[c], sizeof(textureAtlasNode));
    temp._parent = this;
    return temp;
}
void textureAtlas::getIcon(const std::string &name, icon &ic) const noexcept
{
    for(auto &i: elements)
        if(i.name == name)
        {
            ic = i;
            ic._parent = this;
            return;
        }
}

icon::icon()
{
    _parent = 0;
    color = color::white;
    scale = vec2f(1);
}

void icon::draw(const vec2f &p) noexcept
{
    if(!_parent)
        return;
    _parent->draw(p, *this);
}

void icon::draw(const vec2f &p) const noexcept
{
    if(!_parent)
        return;
    _parent->draw(p, *this);
}

icon &icon::operator=(const textureAtlasNode &node)
{
    size = _size = _isize = node.size;
    angle = _angle = node.angle;
    center = _center = node.center;
    _pos = node.pos;
    memcpy(_rotMatrix, node.rotMatrix, sizeof(vec2f)*6);
	return *this;
}

const vec2f *icon::getVertices() const noexcept
{
    return _rotMatrix;
}

}}
