#include "SvgShapeElement.h"

#include "XmlAttribute.h"
#include "StringUtils.h"

#include <sstream>

SvgShapeElement::SvgShapeElement(const std::string& tagName, std::size_t precision)
    : SvgElement(tagName),
        mPrecision(precision)
{

}

Transform SvgShapeElement::getTransform() const
{
    Transform transform;
    const std::string translate_key = "translate";
    const std::string scale_key = "scale";

    if (auto attr = getAttribute("transform"); attr)
    {
        const auto val = attr->getValue();
        std::string working_string;
        bool in_translate = false;
        bool in_scale = false;
        for (auto c : val)
        {
            if (StringUtils::stripSurroundingWhitepsace(working_string) == translate_key)
            {
                in_translate = true;
                working_string.clear();
                continue;
            }
            else if (StringUtils::stripSurroundingWhitepsace(working_string) == scale_key)
            {
                in_scale = true;
                working_string.clear();
                continue;
            }
            else if (c == '(')
            {
                continue;
            }
            else if (c == ')')
            {
                if (in_translate)
                {
                    const auto loc = parsePoint(working_string, 0.0);
                    transform.setLocation(loc);
                    in_translate = false;
                }
                else if (in_scale)
                {
                    const auto loc = parsePoint(working_string, 1.0);
                    Scale scale(loc.getX(), loc.getY(), loc.getZ());
                    transform.setScale(scale);
                    in_scale = false;
                }
                working_string.clear();
            }
            else
            {
                working_string += c;
            }
        }
    }
    return transform;
}

std::string SvgShapeElement::getLabelledContent(const std::string& key, const std::string& content) const
{
    return content.substr(key.size(), content.size() - key.size() - 2);
}

Point SvgShapeElement::parsePoint(const std::string& pointString, double defaultVal) const
{
    double x = defaultVal;
    double y = defaultVal;
    double z = defaultVal;

    const auto split = StringUtils::split(pointString);
    for (std::size_t idx = 0; idx < split.size(); idx++)
    {
        if (idx == 0)
        {
            x = std::stod(split[idx]);
        }
        else if (idx == 1)
        {
            y = std::stod(split[idx]);
        }
        else if (idx == 2)
        {
            z = std::stod(split[idx]);
        }
    }
    return { x, y, z };
}

bool SvgShapeElement::hasTransform() const
{
    return bool(getAttribute("transform"));
}

void SvgShapeElement::setNoFill()
{
    auto attr = std::make_unique<XmlAttribute>("fill");
    attr->setValue("none");
    addAttribute(std::move(attr));
}

void SvgShapeElement::setNoStroke()
{
    auto attr = std::make_unique<XmlAttribute>("stroke");
    attr->setValue("none");
    addAttribute(std::move(attr));
}

void SvgShapeElement::setFill(const Color& fill)
{
    auto attr = std::make_unique<XmlAttribute>("fill");

    std::stringstream sstr;
    sstr << "rgb(" << fill.toString() << ")";
    attr->setValue(sstr.str());

    addAttribute(std::move(attr));
}

void SvgShapeElement::setStrokeWidth(double width)
{
    auto attr = std::make_unique<XmlAttribute>("stroke-width");
    attr->setValue(std::to_string(width));
    addAttribute(std::move(attr));
}

void SvgShapeElement::setFillOpacity(float opacity)
{
    auto attr = std::make_unique<XmlAttribute>("fill-opacity");
    attr->setValue(std::to_string(opacity));
    addAttribute(std::move(attr));
}

void SvgShapeElement::setStrokeColor(const Color& stroke)
{
    auto attr = std::make_unique<XmlAttribute>("stroke");

    std::stringstream sstr;
    sstr << "rgb(" << stroke.toString() << ")";
    attr->setValue(sstr.str());

    addAttribute(std::move(attr));
}
