#include "JsonEditor.h"

#include "Font.h"
#include "Globals.h"
#include "Image.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "Regex.h"
#include "TextField.h"

using namespace Framework;
using namespace JSON;

const char* errors[] = {"Unexpected start of object",
    "Unexpected start of array",
    "Unexpected value",
    "Unexpected ','",
    "Unexpected ':'",
    "Unexpected end of object",
    "Unexpected end of array",
    "Unexpected start of string",
    "Invalid json value",
    ""};

class EditableJsonElementReference : public virtual AbstractElement,
                                     public virtual ReferenceCounter,
                                     public virtual AbstractBool,
                                     public virtual AbstractNumber,
                                     public virtual AbstractString,
                                     public virtual AbstractArray,
                                     public virtual AbstractObject
{
private:
    EditableJsonElement* root;
    RCArray<EditableJsonElementReference>* children;

    EditableJsonElementReference(EditableJsonElement* root,
        RCArray<EditableJsonElementReference>* children)
        : root(root),
          children(children)
    {}

public:
    EditableJsonElementReference(EditableJsonElement* root)
        : root(root),
          children(new RCArray<EditableJsonElementReference>())
    {}

    ~EditableJsonElementReference()
    {
        children->release();
    }

    AbstractType getType() const override
    {
        if (root->hasError() || root->getValue().isEqual("null"))
        {
            return AbstractType::NULL_;
        }
        else if (root->getOpeningControllChar() == '{')
        {
            return AbstractType::OBJECT;
        }
        else if (root->getOpeningControllChar() == '[')
        {
            return AbstractType::ARRAY;
        }
        else if (root->getValue().isEqual("true")
                 || root->getValue().isEqual("false"))
        {
            return AbstractType::BOOLEAN;
        }
        else if (root->getValue().hasAt(0, "\""))
        {
            return AbstractType::STRING;
        }
        else
        {
            return AbstractType::NUMBER;
        }
    }

    const AbstractBool* asAbstractBool() const override
    {
        return this;
    }

    const AbstractNumber* asAbstractNumber() const override
    {
        return this;
    }

    const AbstractString* asAbstractString() const override
    {
        return this;
    }

    const AbstractArray* asAbstractArray() const override
    {
        return this;
    }

    const AbstractObject* asAbstractObject() const override
    {
        return this;
    }

    Text toString() const override
    {
        return root->getRecursiveContent();
    }

    bool getBool() const override
    {
        return (bool)root->getValue();
    }

    double getNumber() const override
    {
        return (double)root->getValue();
    }

    Text getString() const override
    {
        Text txt = root->getValue().getText() + 1;
        txt.remove(txt.getLength() - 1, 1);
        return (double)root->getValue();
    }

    AbstractElement* zAbstractValue(int i) const override
    {
        EditableJsonElement* e = root->zFirstChildren();
        while (e && i > 0)
        {
            e = e->zMextSibling();
            i--;
        }
        if (e)
        {
            EditableJsonElementReference* result
                = new EditableJsonElementReference(e, children);
            children->add(result);
            return result;
        }
        return 0;
    }

    int getLength() const override
    {
        EditableJsonElement* e = root->zFirstChildren();
        int i = 0;
        while (e)
        {
            e = e->zMextSibling();
            i++;
        }
        return i;
    }

    AbstractElement* zAbstractValue(Text field) const override
    {
        EditableJsonElement* e = root->zFirstChildren();
        while (e)
        {
            if (e->getKey().isEqual(field))
            {
                EditableJsonElementReference* result
                    = new EditableJsonElementReference(e, children);
                children->add(result);
                return result;
            }
            e = e->zMextSibling();
        }
        return 0;
    }

    int getFieldCount() const override
    {
        return getLength();
    }

    Text getFieldKey(int i) const override
    {
        EditableJsonElement* e = root->zFirstChildren();
        while (e && i > 0)
        {
            e = e->zMextSibling();
            i--;
        }
        if (e)
        {
            return e->getKey();
        }
        return 0;
    }

    bool hasValue(Text field) const override
    {
        EditableJsonElement* e = root->zFirstChildren();
        while (e)
        {
            if (e->getKey().isEqual(field))
            {
                return 1;
            }
            e = e->zMextSibling();
        }
        return 0;
    }
};

SyntaxError::SyntaxError(int start, int end, SyntaxErrorType errorType)
    : start(start),
      end(end),
      errorType(errorType)
{}

SyntaxError::SyntaxError()
    : start(-1),
      end(-1),
      errorType(SyntaxErrorType::OTHER)
{}

int SyntaxError::getStart() const
{
    return start;
}

int SyntaxError::getEnd() const
{
    return end;
}

SyntaxErrorType SyntaxError::getErrorType() const
{
    return errorType;
}

Framework::JSON::ParserState::ParserState(
    JsonStructure parent, bool valueExpected)
    : index(0),
      keyStart(-1),
      keyEnd(0),
      valueStart(-1),
      valueEnd(0),
      errorStart(0),
      parent(parent),
      inString(0),
      escaped(0),
      colon(parent != JsonStructure::OBJECT),
      key(parent != JsonStructure::OBJECT),
      value(0),
      inValue(0),
      valueValidationNeeded(0),
      openingControllChar(0),
      closingControllChar(0),
      valueExpected(valueExpected)
{}

bool Framework::JSON::ParserState::next(
    const char* current, const char* next, SyntaxError& error)
{
    if (current[0] == 0) return next == 0;
    bool stop = 0;
    if (current[0] == '{' && !inString)
    {
        stop = 1;
        if (!colon || value)
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_OBJECT_START;
        }
        value = 1;
        openingControllChar = current[0];
    }
    else if (current[0] == '[' && !inString)
    {
        stop = 1;
        if (!colon || value)
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_ARRAY_START;
        }
        value = 1;
        openingControllChar = current[0];
    }
    else if (current[0] == '}' && !inString)
    {
        stop = current[1] == ']' || current[1] == '}';
        if (!stop)
        {
            const char* n = current + 1;
            while (*n && (*n == ' ' || *n == '\t' || *n == '\r' || *n == '\n'))
            {
                n++;
            }
            stop = *n == ']' || *n == '}';
            if (!stop && next)
            {
                n = next;
                while (
                    *n && (*n == ' ' || *n == '\t' || *n == '\r' || *n == '\n'))
                {
                    n++;
                }
                stop = *n == ']' || *n == '}';
            }
        }
        if (parent != JsonStructure::OBJECT || (!value && valueExpected))
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_END_OF_OBJECT;
        }
        value = 1;
        closingControllChar = current[0];
    }
    else if (current[0] == ']' && !inString)
    {
        stop = current[1] == ']' || current[1] == '}';
        if (!stop)
        {
            const char* n = current + 1;
            while (*n && (*n == ' ' || *n == '\t' || *n == '\r' || *n == '\n'))
            {
                n++;
            }
            stop = *n == ']' || *n == '}';
            if (!stop && next)
            {
                n = next;
                while (
                    *n && (*n == ' ' || *n == '\t' || *n == '\r' || *n == '\n'))
                {
                    n++;
                }
                stop = *n == ']' || *n == '}';
            }
        }
        if (parent != JsonStructure::ARRAY || (!value && valueExpected))
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_END_OF_ARRAY;
        }
        value = 1;
        closingControllChar = current[0];
    }
    else if (current[0] == '"' && !escaped)
    {
        inString = !inString;
        if (inString)
        {
            if (!key)
            {
                keyStart = index + 1;
            }
            else if (colon && !value)
            {
                valueStart = index;
            }
            else
            {
                error.start = index;
                error.end = index + 1;
                error.errorType = SyntaxErrorType::UNEXPECTED_START_OF_STRING;
            }
        }
        else
        {
            if (!key)
            {
                keyEnd = index;
                key = 1;
            }
            else if (colon && !value)
            {
                valueEnd = index + 1;
                value = 1;
            }
        }
    }
    else if (current[0] == '\\' && inString)
    {
        escaped = !escaped;
    }
    else if (current[0] == ':' && !inString)
    {
        if (key && !colon)
        {
            colon = 1;
        }
        else
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_COLON;
        }
    }
    else if (current[0] == ',' && !inString)
    {
        stop = 1;
        if (!value)
        {
            error.start = index;
            error.end = index + 1;
            error.errorType = SyntaxErrorType::UNEXPECTED_COMMA;
        }
    }
    else
    {
        escaped = 0;
        if (!inString && current[0] != ' ' && current[0] != '\t'
            && current[0] != '\n' && current[0] != '\r')
        {
            if (colon && !value)
            {
                if (!inValue)
                {
                    valueStart = index;
                    inValue = 1;
                }
            }
            else
            {
                if (!inValue)
                {
                    errorStart = index;
                    inValue = 1;
                }
            }
            if (inValue
                && (current[1] == ':' || current[1] == '"' || current[1] == '{'
                    || current[1] == '[' || current[1] == ']'
                    || current[1] == '}' || current[1] == ','))
            {
                inValue = 0;
                if (colon && !value)
                {
                    value = 1;
                    valueEnd = index + 1;
                    valueValidationNeeded = 1;
                }
                else
                {
                    error.start = errorStart;
                    error.end = index;
                    error.errorType = SyntaxErrorType::UNEXPECTED_VALUE;
                }
            }
        }
        else if (inValue)
        {
            inValue = 0;
            if (colon && !value)
            {
                valueEnd = index;
                value = 1;
                valueValidationNeeded = 1;
            }
            else
            {
                error.start = errorStart;
                error.end = index;
                error.errorType = SyntaxErrorType::UNEXPECTED_VALUE;
            }
        }
    }
    index++;
    return stop;
}

EditableJsonElement::EditableJsonElement(Regex::Automata<char>* valueValidator)
    : ReferenceCounter(),
      content(),
      valueStart(-1),
      keyStart(-1),
      valueValidator(valueValidator),
      newLineCount(0)
{
    children = 0;
    siblings = 0;
    lastChild = 0;
    parent = 0;
    hidden = false;
    parentStructure = JsonStructure::VALUE;
}

Framework::JSON::EditableJsonElement::EditableJsonElement(
    Regex::Automata<char>* valueValidator, const char* content)
    : EditableJsonElement(valueValidator)
{
    setContent(content);
    valueValidator->release();
}

EditableJsonElement::~EditableJsonElement()
{
    if (children)
    {
        children->release();
    }
    if (siblings)
    {
        siblings->release();
    }
}

void Framework::JSON::EditableJsonElement::setContentOnly(const char** content,
    int& startPos,
    Array<EditableJsonElement*>& afterList,
    Array<EditableJsonElement*>& deleteList)
{
    errors.clear();
    int start = startPos;
    EditableJsonElement* before = zBefore(0, false, 0);
    ParserState p(parentStructure,
        before
            ? before->getContent()[before->getContent().getLength() - 1] == ','
            : 0);
    SyntaxError error;
    key = "";
    value = "";
    this->content = "";
    while (true)
    {
        const char* current = (*content) + startPos++;
        const char* next = 0;
        if (afterList.getEntryCount())
        {
            next = afterList.get(0)->getContent();
        }
        if (p.next(current, next, error))
        {
            break;
        }
        if (error.getErrorType() != SyntaxErrorType::OTHER)
        {
            errors.add(error);
            error = SyntaxError();
        }
        if (!*current)
        {
            startPos--;
        }
        if (!(*content)[startPos])
        {
            if (!afterList.getEntryCount())
            {
                break;
            }
            else
            {
                if (p.keyStart >= 0
                    && (p.keyEnd < p.keyStart || p.keyEnd + start >= 0)
                    && parentStructure == JsonStructure::OBJECT)
                {
                    int s = p.keyStart + start < 0 ? 0 : p.keyStart + start;
                    int e = p.keyEnd < p.keyStart ? p.index : p.keyEnd + start;
                    key += Text(*content, s, e - s);
                }
                if (p.valueStart >= 0
                    && (p.valueEnd < p.valueStart || p.valueEnd + start >= 0)
                    && parentStructure == JsonStructure::OBJECT)
                {
                    int s = p.valueStart + start < 0 ? 0 : p.valueStart + start;
                    int e = p.valueEnd < p.valueStart ? p.index + start
                                                      : p.valueEnd + start;
                    value += Text(*content, s, e - s);
                }
                this->content += Text(*content,
                    start < 0 ? 0 : start,
                    start < 0 ? startPos : startPos - start);
                EditableJsonElement* next = afterList.get(0);
                int i = 0;
                afterList.remove(i);
                if (next->children)
                {
                    afterList.add(next->children, i);
                    i++;
                }
                if (next->siblings)
                {
                    afterList.add(next->siblings, i);
                }
                next->disconnect();
                deleteList.add(next);
                *content = next->getContent();
                startPos = 0;
                start = -p.index;
            }
        }
    }
    if (error.getErrorType() != SyntaxErrorType::OTHER)
    {
        errors.add(error);
        error = SyntaxError();
    }
    if (p.keyStart >= 0 && (p.keyEnd < p.keyStart || p.keyEnd + start >= 0)
        && parentStructure == JsonStructure::OBJECT)
    {
        int s = p.keyStart + start < 0 ? 0 : p.keyStart + start;
        int e = p.keyEnd < p.keyStart ? p.index : p.keyEnd + start;
        key += Text(*content, s, e - s);
    }
    if (p.valueStart >= 0
        && (p.valueEnd < p.valueStart || p.valueEnd + start >= 0))
    {
        int s = p.valueStart + start < 0 ? 0 : p.valueStart + start;
        int e
            = p.valueEnd < p.valueStart ? p.index + start : p.valueEnd + start;
        value += Text(*content, s, e - s);
    }
    if (p.valueValidationNeeded)
    {
        if (!isValueValid(value, 0, value.getLength()))
        {
            errors.add(SyntaxError(
                p.valueStart, p.valueEnd, SyntaxErrorType::INVALID_VALUE));
        }
    }
    this->content += Text(*content,
        start < 0 ? 0 : start,
        start < 0 ? startPos : startPos - start);
    newLineCount = this->content.countOf('\n');
    openingControllChar = p.openingControllChar;
    closingControllChar = p.closingControllChar;
    valueStart = p.valueStart;
    keyStart = p.keyStart;
    if ((*content)[startPos]
        && ((*content)[startPos - 1] == '[' || (*content)[startPos - 1] == '{'))
    {
        EditableJsonElement* next = new EditableJsonElement(valueValidator);
        addChildren(next);
        next->setContentRecursive(content, startPos, afterList, deleteList);
    }
    // TODO: set parent structure of children
    // TODO: update tree
}

void Framework::JSON::EditableJsonElement::setContentRecursive(
    const char** content,
    int& startPos,
    Array<EditableJsonElement*>& afterList,
    Array<EditableJsonElement*>& deleteList)
{
    setContentOnly(content, startPos, afterList, deleteList);
    char lastControl = closingControllChar;
    while ((*content)[startPos]
           && !((lastControl == ']' && parentStructure == JsonStructure::ARRAY)
                || (lastControl == '}'
                    && parentStructure == JsonStructure::OBJECT)))
    {
        if (closingControllChar == ']'
            && parentStructure == JsonStructure::ARRAY)
        {
            break;
        }
        EditableJsonElement* next = new EditableJsonElement(valueValidator);
        addSibling(next);
        next->setContentOnly(content, startPos, afterList, deleteList);
        lastControl = next->getClosingControllChar();
    }
}

void Framework::JSON::EditableJsonElement::format(
    int indent, bool insertNewLine)
{
    Text content = this->content;
    content.removeWhitespaceAfter(0);
    int index = 0;
    if (insertNewLine)
    {
        content.insert(0, "\n");
        for (int i = 0; i < indent; i++)
        {
            content.insert(1, "    ");
        }
        index = indent * 4 + 1;
    }
    bool keyStart = false;
    bool keyEnd = false;
    bool colonFound = false;
    bool valueStart = false;
    bool valueEnd = false;
    bool escaped = false;
    for (int i = index; i < content.getLength(); i++)
    {
        if ((content[i] == '{' || content[i] == '[' || content[i] == ',')
            && !(keyStart && !keyEnd) && !(valueStart && !valueEnd))
        {
            if (content[i] == ',')
            {
                i -= content.removeWhitespaceBefore(i);
            }
            content.removeWhitespaceAfter(i + 1);
        }
        else if ((content[i] == '}' || content[i] == ']')
                 && !(keyStart && !keyEnd) && !(valueStart && !valueEnd))
        {
            content.removeWhitespaceAfter(i + 1);
            if (!parent || parent->children != this)
            {
                i -= content.removeWhitespaceBefore(i);
                content.insert(i, '\n');
                for (int j = 0; j < indent - 1; j++)
                {
                    content.insert(i + 1, "    ");
                }
                i += 1 + (indent > 0 ? (indent - 1) * 4 : 0);
            }
            else
            {
                i -= content.removeWhitespaceBefore(i);
            }
        }
        else if (content[i] == '"' && !escaped)
        { // format whitespaces arround values and keys
            if (!keyStart)
            {
                keyStart = true;
            }
            else
            {
                if (!keyEnd)
                {
                    keyEnd = true;
                    content.removeWhitespaceAfter(i + 1);
                }
                else
                {
                    if (colonFound)
                    {
                        if (!valueStart)
                        {
                            valueStart = true;
                        }
                        else if (!valueEnd)
                        {
                            valueEnd = true;
                            content.removeWhitespaceAfter(i + 1);
                        }
                    }
                }
            }
        }
        else if (content[i] == ':' && !(keyStart && !keyEnd)
                 && !(valueStart && !valueEnd))
        {
            if (!colonFound && keyEnd)
            {
                colonFound = true;
                content.removeWhitespaceAfter(i + 1);
                content.insert(i + 1, " ");
            }
        }
        else if (content[i] == '\t' && !(keyStart && !keyEnd)
                 && !(valueStart && !valueEnd))
        {
            content.remove(i, 1);
            i--;
        }
        else if (content[i] == '\\')
        {
            if ((keyStart && !keyEnd) || (valueStart && !valueEnd))
            {
                escaped = !escaped;
            }
        }
        else
        {
            escaped = false;
        }
    }
    int count = 0;
    Array<EditableJsonElement*> empty;
    const char* tmp = content.getText();
    setContentOnly(&tmp, count, empty, empty);
    if (count < content.getLength())
    {
        throw "Illegal State Exception: tree changed after formatting";
    }
    if (children)
    {
        children->formatRecursive(indent + 1, true);
    }
}

void Framework::JSON::EditableJsonElement::formatRecursive(
    int indent, bool insertNewLine)
{
    format(indent, insertNewLine);
    EditableJsonElement* tmp = siblings;
    while (tmp)
    {
        tmp->format(indent, true);
        tmp = tmp->siblings;
    }
}

bool Framework::JSON::EditableJsonElement::isValueValid(
    const char* content, int start, int end)
{
    Text value(content, start, end - start);
    if (value.isEqual("null") || value.isEqual("true")
        || value.isEqual("false"))
    {
        return true;
    }
    RCArray<Regex::Result>* results
        = valueValidator->match(value, value.getLength());
    bool ok = results->getEntryCount() == 1;
    results->release();
    return ok;
}

void Framework::JSON::EditableJsonElement::setContent(
    const char* content, int& startPos, Array<EditableJsonElement*>& afterList)
{
    if (children)
    {
        afterList.add(children);
    }
    if (siblings)
    {
        afterList.add(siblings);
    }
    EditableJsonElement* p = parent;
    EditableJsonElement* last = this;
    while (p)
    {
        if (p->siblings)
        {
            afterList.add(p->siblings);
            p->siblings = 0;
        }
        p->lastChild = last;
        last = p;
        p = p->parent;
    }
    lastChild = 0;
    children = 0;
    siblings = 0;
    if (parent)
    {
        parent->lastChild = this;
    }
    Array<EditableJsonElement*> deleteList;
    setContentRecursive(&content, startPos, afterList, deleteList);
    if (content[startPos])
    {
        EditableJsonElement* next = new EditableJsonElement(valueValidator);
        if (parent)
        {
            parent->addSibling(next);
        }
        else
        {
            addSibling(next);
        }
        next->setContent(content, startPos, afterList);
    }
    else if (afterList.getEntryCount())
    {
        if (openingControllChar)
        {
            while (afterList.getEntryCount()
                   && (!lastChild
                       || !((openingControllChar == '['
                                && lastChild->closingControllChar == ']')
                            || (openingControllChar == '{'
                                && lastChild->closingControllChar == '}'))))
            {
                EditableJsonElement* next = afterList.get(0);
                afterList.remove(0);
                EditableJsonElement* end = next;
                while (end)
                {
                    if ((end->closingControllChar == ']'
                            && this->openingControllChar == '[')
                        || (end->closingControllChar == '}'
                            && this->openingControllChar == '{'))
                    {
                        if (end->siblings)
                        {
                            afterList.add(end->siblings, 0);
                            end->siblings = 0;
                        }
                        break;
                    }
                    end = end->siblings;
                }
                addChildren(next);
                next->checkSyntax();
                while (next->siblings)
                {
                    next = next->siblings;
                    next->checkSyntax();
                }
            }
        }
        EditableJsonElement* p = parent;
        EditableJsonElement* c = this;
        while (afterList.getEntryCount())
        {
            if (p)
            {
                if (p->siblings)
                {
                    afterList.add(p->siblings);
                    p->siblings = 0;
                    if (p->parent)
                    {
                        p->parent->lastChild = p;
                    }
                }
                while (
                    afterList.getEntryCount()
                    && (!p->lastChild
                        || !((p->openingControllChar == '['
                                 && p->lastChild->closingControllChar == ']')
                             || (p->openingControllChar == '{'
                                 && p->lastChild->closingControllChar == '}'))))
                {
                    EditableJsonElement* next = afterList.get(0);
                    afterList.remove(0);
                    EditableJsonElement* end = next;
                    while (end)
                    {
                        if ((end->closingControllChar == ']'
                                && p->openingControllChar == '[')
                            || (end->closingControllChar == '}'
                                && p->openingControllChar == '{'))
                        {
                            if (end->siblings)
                            {
                                afterList.add(end->siblings, 0);
                                end->siblings = 0;
                            }
                            break;
                        }
                        end = end->siblings;
                    }
                    p->addChildren(next);
                    next->checkSyntax();
                    while (next->siblings)
                    {
                        next = next->siblings;
                        next->checkSyntax();
                    }
                }
                c = p;
                p = p->parent;
            }
            else
            {
                while (afterList.getEntryCount())
                {
                    EditableJsonElement* next = afterList.get(0);
                    afterList.remove(0);
                    c->addSibling(next);
                    next->checkSyntax();
                    while (next->siblings)
                    {
                        next = next->siblings;
                        next->checkSyntax();
                    }
                }
            }
        }
    }
    for (EditableJsonElement* e : deleteList)
    {
        e->release();
    }
}

void Framework::JSON::EditableJsonElement::checkSyntax()
{
    errors.clear();
    EditableJsonElement* before = zBefore(0, false, 0);
    ParserState p(parentStructure,
        before
            ? before->getContent()[before->getContent().getLength() - 1] == ','
            : 0);
    SyntaxError error;
    key = "";
    value = "";
    int pos = 0;
    while (pos < content.getLength())
    {
        const char* current = content.getText() + pos++;
        p.next(current, 0, error);
        if (error.getErrorType() != SyntaxErrorType::OTHER)
        {
            errors.add(error);
            error = SyntaxError();
        }
    }
    if (error.getErrorType() != SyntaxErrorType::OTHER)
    {
        errors.add(error);
        error = SyntaxError();
    }
    if (p.keyStart >= 0 && p.keyEnd >= p.keyStart
        && parentStructure == JsonStructure::OBJECT)
    {
        key += Text(content, p.keyStart, p.keyEnd - p.keyStart);
    }
    if (p.valueStart >= 0 && p.valueEnd >= p.valueStart)
    {
        value += Text(content, p.valueStart, p.valueEnd - p.valueStart);
    }
    if (p.valueValidationNeeded)
    {
        if (!isValueValid(value, 0, value.getLength()))
        {
            errors.add(SyntaxError(
                p.valueStart, p.valueEnd, SyntaxErrorType::INVALID_VALUE));
        }
    }
    openingControllChar = p.openingControllChar;
    closingControllChar = p.closingControllChar;
    valueStart = p.valueStart;
    keyStart = p.keyStart;
}

void EditableJsonElement::setContent(const char* content)
{
    Array<EditableJsonElement*> afterList;
    int p = 0;
    setContent(content, p, afterList);
}

void EditableJsonElement::addChildren(EditableJsonElement* content)
{
    JsonStructure currentStructure
        = openingControllChar == '['
            ? JsonStructure::ARRAY
            : (openingControllChar == '{' ? JsonStructure::OBJECT
                                          : JsonStructure::VALUE);
    if (this->children)
    {
        this->lastChild->siblings = content;
    }
    else
    {
        this->children = content;
        this->lastChild = content;
    }
    if (content->parent != this)
    {
        content->parent = this;
        content->parentStructure = currentStructure;
        for (; lastChild->siblings; lastChild = lastChild->siblings)
        {
            lastChild->siblings->parent = this;
            lastChild->siblings->parentStructure = currentStructure;
        }
    }
    while (lastChild->siblings)
    {
        lastChild = lastChild->siblings;
    }
}

void Framework::JSON::EditableJsonElement::setNextSibling(
    EditableJsonElement* content)
{
    this->siblings = content;
    EditableJsonElement* current = this;
    if (content->parent != parent)
    {
        for (; current->siblings; current = current->siblings)
        {
            current->siblings->parent = parent;
            current->siblings->parentStructure = parentStructure;
        }
    }
    if (parent)
    {
        parent->lastChild = current;
        while (parent->lastChild->siblings)
        {
            parent->lastChild = parent->lastChild->siblings;
        }
    }
}

void EditableJsonElement::addSibling(EditableJsonElement* content)
{
    EditableJsonElement* current = parent ? parent->lastChild : this;
    while (current->siblings)
    {
        current = current->siblings;
    }
    current->siblings = content;
    if (content->parent != parent)
    {
        for (; current->siblings; current = current->siblings)
        {
            current->siblings->parent = parent;
            current->siblings->parentStructure = parentStructure;
        }
    }
    if (parent)
    {
        parent->lastChild = current;
        while (parent->lastChild->siblings)
        {
            parent->lastChild = parent->lastChild->siblings;
        }
    }
}

void Framework::JSON::EditableJsonElement::format()
{
    int indent = getIndent();
    formatRecursive(indent, false);
}

const Text& Framework::JSON::EditableJsonElement::getContent()
{
    return content;
}

Text Framework::JSON::EditableJsonElement::getRecursiveContent()
{
    Text result
        = content + (children ? children->getRecursiveContent() : Text(""));
    EditableJsonElement* s = siblings;
    while (s)
    {
        result += s->content
                + (s->children ? s->children->getRecursiveContent() : Text(""));
        s = s->siblings;
    }
    return result;
}

int Framework::JSON::EditableJsonElement::lineCount()
{
    return newLineCount;
}

bool Framework::JSON::EditableJsonElement::lineCount(bool includeChildren,
    bool includeSiblings,
    EditableJsonElement* stop,
    int& count)
{
    count += newLineCount;
    if (this == stop)
    {
        return false;
    }
    if (includeChildren && children)
    {
        if (!children->lineCount(true, true, stop, count))
        {
            return false;
        }
    }
    if (includeSiblings && siblings)
    {
        return siblings->lineCount(true, true, stop, count);
    };
    return true;
}

bool Framework::JSON::EditableJsonElement::isHidden()
{
    return hidden;
}

void Framework::JSON::EditableJsonElement::setHidden(bool hidden)
{
    this->hidden = hidden;
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zParent()
{
    return parent;
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zMextSibling()
{
    return siblings;
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zFirstChildren()
{
    return children;
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zLastChildren()
{
    return lastChild;
}

char Framework::JSON::EditableJsonElement::getOpeningControllChar()
{
    return openingControllChar;
}

char Framework::JSON::EditableJsonElement::getClosingControllChar()
{
    return closingControllChar;
}

Text& Framework::JSON::EditableJsonElement::getKey()
{
    return key;
}

Text& Framework::JSON::EditableJsonElement::getValue()
{
    return value;
}

void Framework::JSON::EditableJsonElement::disconnect()
{
    children = 0;
    lastChild = 0;
    siblings = 0;
    parent = 0;
}

void Framework::JSON::EditableJsonElement::removeChild(
    EditableJsonElement* zElement)
{
    // TODO: needed?
    if (children == zElement)
    {
        children = 0;
        lastChild = 0;
    }
    else
    {
        EditableJsonElement* current = children;
        while (current)
        {
            if (current->siblings == zElement)
            {
                current->siblings = 0;
                if (current->parent)
                {
                    current->parent->lastChild = current;
                }
                break;
            }
            current = current->siblings;
        }
    }
}

void Framework::JSON::EditableJsonElement::getWordBounds(
    int pos, int* left, int* right)
{
    bool escaped = false;
    int lastStartStr = -1;
    int lastBlank = 0;
    bool found = false;
    int len = content.getLength();
    for (int i = 0; i < len; i++)
    {
        if ((content[i] == ' ' || content[i] == ',' || content[i] == '\n')
            && lastStartStr == -1)
        {
            if (i >= pos)
            {
                if (left)
                {
                    *left = lastBlank;
                }
                if (right)
                {
                    *right = i;
                }
                found = true;
                break;
            }
            lastBlank = i + 1;
        }
        else if (content[i] == '"')
        {
            if (lastStartStr == -1)
            {
                lastStartStr = i + 1;
                if (i >= pos)
                {
                    if (left)
                    {
                        *left = i;
                    }
                    if (right)
                    {
                        *right = i + 1;
                    }
                    found = true;
                    break;
                }
            }
            else if (!escaped)
            {
                if (i >= pos)
                {
                    if (left)
                    {
                        *left = lastStartStr;
                    }
                    if (right)
                    {
                        *right = i;
                    }
                    found = true;
                    break;
                }
                lastStartStr = -1;
            }
        }
        else if (content[i] == '\\' && lastStartStr >= 0)
        {
            escaped = !escaped;
        }
        else
        {
            escaped = false;
        }
    }
    if (!found && lastBlank >= 0)
    {
        if (left)
        {
            *left = lastBlank;
        }
        if (right)
        {
            *right = len;
        }
    }
}

bool Framework::JSON::EditableJsonElement::hasError(int column) const
{
    for (const SyntaxError& error : errors)
    {
        if (error.getStart() <= column && error.getEnd() >= column)
        {
            return true;
        }
    }
    return false;
}

SyntaxError Framework::JSON::EditableJsonElement::getError(int column) const
{
    for (const SyntaxError& error : errors)
    {
        if (error.getStart() <= column && error.getEnd() >= column)
        {
            return error;
        }
    }
    return SyntaxError();
}

bool Framework::JSON::EditableJsonElement::hasError() const
{
    return errors.getEntryCount() > 0;
}

void Framework::JSON::EditableJsonElement::makeVisible()
{
    EditableJsonElement* current = parent;
    while (current)
    {
        current->setHidden(false);
        current = current->zParent();
    }
}

bool Framework::JSON::EditableJsonElement::isVisible() const
{
    EditableJsonElement* current = parent;
    while (current)
    {
        if (current->isHidden())
        {
            return false;
        }
        current = current->zParent();
    }
    return true;
}

int Framework::JSON::EditableJsonElement::getIndent() const
{
    int indent = 0;
    EditableJsonElement* tmp = parent;
    while (tmp)
    {
        indent++;
        tmp = tmp->parent;
    }
    return indent;
}

int Framework::JSON::EditableJsonElement::getColor(int index)
{
    int color = 0xFFA0A0A0;
    if (hasError(index))
    {
        color = 0xFFFF3030;
    }
    else if (keyStart >= 0 && index >= keyStart - 1
             && index < keyStart + key.getLength() + 1)
    {
        color = 0xFF7070C0;
    }
    else if (valueStart >= 0 && index >= valueStart
             && index < valueStart + value.getLength())
    {
        if (value[0] == '"')
        {
            color = 0xFF70C070;
        }
        else if (value.isEqual("null"))
        {
            color = 0xFFC0A070;
        }
        else if (value.isEqual("true") || value.isEqual("false"))
        {
            color = 0xFFC070C0;
        }
        else
        {
            color = 0xFF70C0C0;
        }
    }
    return color;
}

void Framework::JSON::EditableJsonElement::removeUntil(
    int startIndex, EditableJsonElement* end, int endIndex)
{
    Text* result = content.getTeilText(0, startIndex);
    if (end == this)
    {
        Text* tmp = content.getTeilText(endIndex);
        result->append(*tmp);
        tmp->release();
        setContent(*result);
        result->release();
        return;
    }
    else
    {
        Array<EditableJsonElement*> toDelete;
        Stack<EditableJsonElement*> stack;
        if (siblings)
        {
            stack.push(siblings);
        }
        if (children)
        {
            stack.push(children);
        }
        if (!stack.getSize())
        {
            EditableJsonElement* p = parent;
            while (p)
            {
                if (p->siblings)
                {
                    stack.push(p->siblings);
                    break;
                }
                p = p->parent;
            }
        }
        if (stack.getSize())
        {
            EditableJsonElement* next = stack.pop();
            while (true)
            {
                if (next->siblings)
                {
                    stack.push(siblings);
                }
                if (next->children)
                {
                    stack.push(children);
                }
                if (!stack.getSize() && next != end)
                {
                    EditableJsonElement* p = next->parent;
                    while (p)
                    {
                        if (p->siblings)
                        {
                            stack.push(p->siblings);
                            break;
                        }
                        p = p->parent;
                    }
                }
                if (next->parent)
                {
                    next->parent->removeChild(next);
                }
                else
                {
                    EditableJsonElement* p = this;
                    while (p->parent)
                    {
                        p = p->parent;
                    }
                    while (p->siblings != next)
                    {
                        p = p->siblings;
                    }
                    p->siblings = 0;
                }
                toDelete.add(next);
                if (!stack.getSize())
                {
                    next = 0;
                    break;
                }
                if (next == end)
                {
                    break;
                }
                next = stack.pop();
            }
            if (next == end)
            {
                Text* tmp = next->content.getTeilText(endIndex);
                result->append(*tmp);
            }
            for (EditableJsonElement* del : toDelete)
            {
                del->disconnect();
                del->release();
            }
            Array<EditableJsonElement*> afterList;
            while (stack.getSize())
            {
                afterList.add(stack.pop());
            }
            int p = 0;
            setContent(*result, p, afterList);
        }
        else
        {
            setContent(*result);
            result->release();
            return;
        }
    }
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zBefore(
    EditableJsonElement* zRoot, bool onlyVisible, int* lineCount)
{
    if (this == zRoot)
    {
        return 0;
    }
    EditableJsonElement* parent = this->parent;
    EditableJsonElement* current = parent ? parent->children : zRoot;
    EditableJsonElement* last = parent;
    while (current)
    {
        if (current == this)
        {
            break;
        }
        last = current;
        current = current->siblings;
    }
    if (last && last->children != this && (!last->hidden || !onlyVisible))
    {
        current = last->lastChild;
        while (current)
        {
            last = current;
            if (current->children)
            {
                if ((!current->hidden || !onlyVisible))
                {
                    current = current->lastChild;
                }
                else if (*lineCount)
                {
                    EditableJsonElement* e = current->children;
                    while (e)
                    {
                        int lc = 0;
                        e->lineCount(true, false, 0, lc);
                        *lineCount -= lc;
                        e = e->siblings;
                    }
                    break;
                }
            }
            else
            {
                break;
            }
        }
    }
    else if (last && last->hidden && onlyVisible && lineCount)
    {
        EditableJsonElement* e = last->children;
        while (e)
        {
            int lc = 0;
            e->lineCount(true, false, 0, lc);
            *lineCount -= lc;
            e = e->siblings;
        }
    }
    return last;
}

EditableJsonElement* Framework::JSON::EditableJsonElement::zAfter(
    bool onlyVisible, int* lineCount)
{
    EditableJsonElement* zElement = this;
    if (zElement->children)
    {
        if (!zElement->hidden || !onlyVisible)
        {
            return zElement->children;
        }
        else if (lineCount)
        {
            EditableJsonElement* e = zElement->children;
            while (e)
            {
                int lc = 0;
                e->lineCount(true, false, 0, lc);
                *lineCount += lc;
                e = e->siblings;
            }
        }
    }
    if (zElement->siblings)
    {
        return zElement->siblings;
    }
    while (zElement->parent)
    {
        zElement = zElement->parent;
        if (zElement->siblings)
        {
            return zElement->siblings;
        }
    }
    return 0;
}

JsonEditor::JsonEditor(UIInit uiInit)
    : DrawableBackground(),
      uiInit(uiInit)
{
    valueValidator = Regex::parse("^-?[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$");
    validator = 0;
    content = 0;
    renderStart = {0, 0};
    renderStartLine = 0;
    lineCount = 0;
    cursorPos.x = -1;
    cursorPos.y = -1;
    textCursor = {0, 0};
    selectionStart = {0, 0};
    renderStartOffset = 0;
    selectionEnd = {0, 0};
    textRenderer = new TextRenderer();
    textRenderer->setFontSize(12);
    textRenderer->setLineSpacing(2);
    textRenderer->setCharSpacing(1);
    pressed = 0;
    time = 0;
    drag = 0;
    drawCursor = 0;
    dragSart = {-1, -1};
    pressedPos = {-1, -1};
    dragStartPos = {0, -1};
    timeSicePress = 0.0;
    lastClickCursorPos = {0, 0};
    tps = 0;
    renderings = 0;
    renderedLines = 0;
    renderStopLine = 0;
    errorDescription = uiInit.createTextField(uiInit.initParam);
    errorDescription->setStyle(TextField::Style::Text | TextField::Style::Center
                               | TextField::Style::Border
                               | TextField::Style::Background
                               | TextField::Style::BAlpha);
    errorDescription->removeStyle(TextField::Style::Visible);
    errorDescription->setFontColor(0xFFFFFFFF);
    errorDescription->setBorderColor(0xFFA0A0A0);
    errorDescription->setBackgroundColor(0xA0000000);
    hasSyntaxError = false;
}

JsonEditor::~JsonEditor()
{
    if (content) content->release();
    if (validator) validator->release();
    textRenderer->release();
    errorDescription->release();
}

void Framework::JSON::JsonEditor::doMouseEvent(MouseEvent& me, bool userRet)
{
    LOCK({&cs});
    rend |= cursorPos.x != me.mx || cursorPos.y != me.my;
    cursorPos.x = me.mx;
    cursorPos.y = me.my;
    if (me.id == ME_RLeft)
    {
        pressedPos = cursorPos;
        if (timeSicePress < 0.5)
        {
            if (lastClickCursorPos.line == textCursor.line
                && lastClickCursorPos.column == textCursor.column
                && lastClickCursorPos.line && lastClickCursorPos.column > 0)
            {
                EditableJsonElement* current = textCursor.line;
                int start = 0;
                int end = 0;
                current->getWordBounds(textCursor.column, &start, &end);
                selectionStart = {current, start};
                selectionEnd = {current, end};
                unifyPosition(selectionEnd);
                textCursor = selectionEnd;
            }
        }
        lastClickCursorPos = textCursor;
        pressed = true;
        drag = false;
        rend = 1;
        time = 0;
        timeSicePress = 0.0;
    }
    if (me.id == ME_PLeft || (me.id == ME_Enter && getMouseState(M_Left)))
    {
        if (me.mx >= getInnerWidth() - 15)
        {
            int line = (int)(me.my / ((double)getInnerHeight() / lineCount));
            if (line >= lineCount)
            {
                line = lineCount - 1;
            }
            scrollToLine(line + 1, Center);
        }
        if (!drag)
        {
            drag = true;
            textCursor = getScreenPosition(cursorPos.x, cursorPos.y);
            selectionStart = textCursor;
            selectionEnd = textCursor;
            dragSart = cursorPos;
            dragStartPos = textCursor;
            rend = 1;
            time = 0;
        }
    }
    if (me.id == ME_Move)
    {
        if (drag)
        {
            if (dragSart.x >= getInnerWidth() - 15)
            {
                int line
                    = (int)(me.my / ((double)getInnerHeight() / lineCount));
                if (line >= lineCount)
                {
                    line = lineCount - 1;
                }
                scrollToLine(line + 1, Center);
            }
            else
            {
                EditorPosition pos
                    = getScreenPosition(cursorPos.x, cursorPos.y);
                if (pos.line == dragStartPos.line)
                {
                    if (pos.column < dragStartPos.column)
                    {
                        selectionStart = pos;
                        selectionEnd = dragStartPos;
                    }
                    else if (pos.column > dragStartPos.column)
                    {
                        selectionStart = dragStartPos;
                        selectionEnd = pos;
                    }
                }
                else
                {
                    if (cursorPos.y < dragSart.y)
                    {
                        selectionStart = pos;
                        selectionEnd = dragStartPos;
                    }
                    else if (cursorPos.y > dragSart.y)
                    {
                        selectionStart = dragStartPos;
                        selectionEnd = pos;
                    }
                }
                textCursor = pos;
            }
        }
    }
    if (me.id == ME_UScroll)
    {
        if (renderStart.column > 0)
        {
            const char* content = renderStart.line->getContent();
            int index = renderStart.column - 2;
            while (index > 0 && content[index] != '\n')
            {
                index--;
            }
            if (content[index] == '\n')
            {
                renderStart.column = index + 1;
                rend = 1;
                renderStartLine--;
                unifyPosition(renderStart);
                return;
            }
        }
        while (true)
        {
            EditableJsonElement* next
                = renderStart.line->zBefore(content, true, &renderStartLine);
            if (next)
            {
                renderStart.line = next;
                const char* content = next->getContent();
                int index = next->getContent().getLength() - 1;
                while (index > 0 && content[index] != '\n')
                {
                    index--;
                }
                if (content[index] == '\n')
                {
                    renderStart.column = index + 1;
                    rend = 1;
                    renderStartLine--;
                    unifyPosition(renderStart);
                    return;
                }
            }
            else
            {
                renderStart.column = 0;
                rend = 1;
                renderStartLine = 1;
                return;
            }
        }
    }
    if (me.id == ME_DScroll)
    {
        const char* content = renderStart.line->getContent();
        int length = renderStart.line->getContent().getLength();
        int index = renderStart.column;
        while (index < length && content[index] != '\n')
        {
            index++;
        }
        if (content[index] == '\n')
        {
            renderStart.column = index + 1;
            rend = 1;
            renderStartLine++;
            unifyPosition(renderStart);
            return;
        }
        while (true)
        {
            EditableJsonElement* next
                = renderStart.line->zAfter(true, &renderStartLine);
            if (next)
            {
                renderStart.line = next;
                const char* content = next->getContent();
                int length = next->getContent().getLength();
                int index = 0;
                while (index < length && content[index] != '\n')
                {
                    index++;
                }
                if (content[index] == '\n')
                {
                    renderStart.column = index + 1;
                    rend = 1;
                    renderStartLine++;
                    unifyPosition(renderStart);
                    return;
                }
            }
            else
            {
                return;
            }
        }
    }
}

EditorPosition Framework::JSON::JsonEditor::getScreenPosition(
    int localX, int localY)
{
    if (!renderStart.line) return {0, 0};
    int y = 0;
    int lineNumberWidth = 0;
    for (int i = lineCount; i > 0; i /= 10)
    {
        lineNumberWidth++;
    }
    lineNumberWidth = lineNumberWidth * textRenderer->getMaxCharWidth()
                    + textRenderer->getCharSpacing() * (lineNumberWidth - 1);
    int x = lineNumberWidth + 26;
    EditableJsonElement* current = renderStart.line;
    int index = renderStart.column;
    EditableJsonElement* last = current;
    while (y < gr.y && current)
    {
        int length = current->getContent().getLength();
        const char* content = current->getContent();
        for (int i = index; i < length; i++)
        {
            if (y >= localY - textRenderer->getRowHeight()
                         - textRenderer->getLineSpacing()
                && x >= localX - textRenderer->getCharWidth(content[i]) / 2
                            - textRenderer->getCharSpacing())
            {
                EditorPosition result = {current, i};
                unifyPosition(result);
                return result;
            }
            if (content[i] == '\n')
            {
                if (y >= localY - textRenderer->getRowHeight()
                             - textRenderer->getLineSpacing())
                {
                    EditorPosition result = {current, i};
                    unifyPosition(result);
                    return result;
                }
                y += textRenderer->getRowHeight()
                   + textRenderer->getLineSpacing();
                x = lineNumberWidth + 26;
            }
            else
            {
                x += textRenderer->getCharWidth(content[i])
                   + textRenderer->getCharSpacing();
            }
        }
        last = current;
        current = current->zAfter(true, 0);
        index = 0;
    }
    return {last, last->getContent().getLength()};
}

void Framework::JSON::JsonEditor::deleteSelection()
{
    if (selectionStart.line && selectionEnd.line)
    {
        selectionStart.line->removeUntil(
            selectionStart.column, selectionEnd.line, selectionEnd.column);
        selectionEnd = selectionStart;
        textCursor = selectionStart;
        fixTree(selectionStart.line);
        if (dragStartPos.line)
        {
            dragStartPos = selectionStart;
        }
        if (lastClickCursorPos.line)
        {
            lastClickCursorPos = selectionStart;
        }
    }
}

void Framework::JSON::JsonEditor::unifyPosition(EditorPosition& pos)
{
    while (pos.line && pos.column >= pos.line->getContent().getLength())
    {
        if (pos.line->zFirstChildren() && pos.line->isVisible())
        {
            pos = {pos.line->zFirstChildren(),
                pos.column - pos.line->getContent().getLength()};
        }
        else if (pos.line->zMextSibling())
        {
            pos = {pos.line->zMextSibling(),
                pos.column - pos.line->getContent().getLength()};
        }
        else
        {
            EditableJsonElement* p = pos.line->zParent();
            while (p)
            {
                if (p->zMextSibling())
                {
                    pos = {p->zMextSibling(), 0};
                    break;
                }
                p = p->zParent();
            }
            if (!p)
            {
                pos.column = pos.line->getContent().getLength();
                break;
            }
        }
    }
}

void Framework::JSON::JsonEditor::fixTree(EditableJsonElement* zElement)
{
    EditableJsonElement* before = zElement->zBefore(content, false, 0);
    int beforeLength = before ? before->getContent().getLength() : 0;
    if (zElement->hasError() && before)
    {
        Text content = before->getContent();
        before->setContent(content);
        if (before->getContent().getLength() != beforeLength)
        {
            before->makeVisible();
        }
    }
    if (textCursor.line == zElement)
    {
        textCursor.column += beforeLength;
        textCursor.line = before ? before : zElement;
        unifyPosition(textCursor);
    }
    if (renderStart.line == zElement)
    {
        renderStart.column += beforeLength;
        renderStart.line = before ? before : zElement;
        unifyPosition(renderStart);
    }
}

void Framework::JSON::JsonEditor::setFont(Font* font)
{
    textRenderer->setFontZ(font);
}

void Framework::JSON::JsonEditor::setFontSize(int size)
{
    textRenderer->setFontSize(size);
    textRenderer->setLineSpacing(size / 6);
    textRenderer->setCharSpacing(size / 8);
}

void JsonEditor::setContent(Text content)
{
    if (this->content)
    {
        this->content->release();
        this->content = 0;
        this->renderStart = {0, 0};
    }
    this->content = new EditableJsonElement(
        dynamic_cast<Regex::Automata<char>*>(valueValidator->getThis()));
    content.replace("\r", "");
    content.replace("\t", "    ");
    this->content->setContent(content);
    textCursor = {this->content, 0};
    selectionStart = {this->content, 0};
    selectionEnd = {this->content, 0};
    format();
}

void Framework::JSON::JsonEditor::setContent(JSONValue* content)
{
    setContent(content->toString());
    content->release();
}

void Framework::JSON::JsonEditor::format()
{
    if (content)
    {
        content->format();
        lineCount = 0;
        content->lineCount(true, true, 0, lineCount);
    }
}

void Framework::JSON::JsonEditor::setValidator(
    Validator::DataValidator* validator)
{
    if (this->validator) this->validator->release();
    this->validator = validator;
    // if (content) validate(); TODO: validate attributes
}

void Framework::JSON::JsonEditor::doKeyboardEvent(KeyboardEvent& te)
{
    LOCK({&cs});
    if (!textCursor.line)
    {
        return;
    }
    bool shift = getKeyState(T_Shift);
    bool strg = getKeyState(T_Strg);
    if (te.id == TE_Press)
    {
        switch (te.virtualKey)
        {
        case T_Tab:
            {
                Text illegalStarts = "[]{},\": ";
                if (shift)
                {
                    bool lastStr
                        = textCursor.line->getContent().getLength()
                                > textCursor.column
                            ? textCursor.line->getContent()[textCursor.column]
                                  == '"'
                            : false;
                    int nextColumn = textCursor.column - 1;
                    EditableJsonElement* nextLine = textCursor.line;
                    while (nextLine)
                    {
                        if (nextColumn < 0)
                        {
                            nextLine = nextLine->zBefore(content, true, 0);
                            if (!nextLine)
                            {
                                return;
                            }
                            nextColumn = nextLine->getContent().getLength();
                        }
                        int start = 0;
                        int end = 0;
                        nextLine->getWordBounds(nextColumn, &start, &end);
                        if ((start != end
                                && !illegalStarts.has(
                                    nextLine->getContent()[start]))
                            || (lastStr
                                && nextLine->getContent()[nextColumn] == '"'))
                        {
                            if (lastStr
                                && nextLine->getContent()[nextColumn] == '"')
                            {
                                start = end;
                            }
                            if (selectionStart.column != start
                                || selectionStart.line != nextLine
                                || selectionEnd.column != end
                                || selectionEnd.line != nextLine)
                            {
                                selectionStart = {nextLine, start};
                                selectionEnd = {nextLine, end};
                                unifyPosition(selectionEnd);
                                textCursor = selectionEnd;
                                scrollToLine(textCursor, Top);
                                te.processed = true;
                                time = 0;
                                rend = 1;
                                return;
                            }
                        }
                        lastStr = nextLine->getContent()[nextColumn] == '"';
                        nextColumn--;
                    }
                }
                else
                {
                    bool lastStr
                        = textCursor.line->getContent().getLength()
                                > textCursor.column
                            ? textCursor.line->getContent()[textCursor.column]
                                  == '"'
                            : false;
                    int nextColumn = textCursor.column + 1;
                    EditableJsonElement* nextLine = textCursor.line;
                    while (nextLine)
                    {
                        if (nextColumn > nextLine->getContent().getLength())
                        {
                            nextLine = nextLine->zAfter(true, 0);
                            if (!nextLine)
                            {
                                return;
                            }
                            nextColumn = 0;
                        }
                        int start = 0;
                        int end = 0;
                        nextLine->getWordBounds(nextColumn, &start, &end);
                        if (((start != end
                                 && !illegalStarts.has(
                                     nextLine->getContent()[start]))
                                || (lastStr
                                    && nextLine->getContent()[nextColumn]
                                           == '"'))
                            && (selectionStart.column != start
                                || selectionStart.line != nextLine
                                || selectionEnd.column != end
                                || selectionEnd.line != nextLine))
                        {
                            selectionStart = {nextLine, start};
                            selectionEnd = {nextLine, end};
                            unifyPosition(selectionEnd);
                            textCursor = selectionEnd;
                            scrollToLine(textCursor, Bottom);
                            te.processed = true;
                            time = 0;
                            rend = 1;
                            return;
                        }
                        lastStr = nextLine->getContent()[nextColumn] == '"';
                        nextColumn++;
                    }
                }
            }
            return;
        case T_Entf:
            if (selectionStart.line == selectionEnd.line
                && selectionStart.column == selectionEnd.column)
            {
                if (textCursor.column
                    < textCursor.line->getContent().getLength())
                {
                    Text content = textCursor.line->getContent();
                    content.remove(textCursor.column, textCursor.column + 1);
                    textCursor.line->setContent(content);
                    fixTree(textCursor.line);
                }
            }
            else
            {
                deleteSelection();
            }
            break;
        case T_BackSpace:
            if (selectionStart.line == selectionEnd.line
                && selectionStart.column == selectionEnd.column)
            {
                if (textCursor.column > 0)
                {
                    Text content = textCursor.line->getContent();
                    content.remove(textCursor.column - 1, textCursor.column);
                    textCursor.line->setContent(content);
                    textCursor.column--;
                    fixTree(textCursor.line);
                }
                else
                {
                    EditableJsonElement* before
                        = textCursor.line->zBefore(content, false, 0);
                    if (before)
                    {
                        before->makeVisible();
                        Text content = before->getContent();
                        content.remove(
                            content.getLength() - 1, content.getLength());
                        before->setContent(content);
                        textCursor = {before, content.getLength()};
                        fixTree(before);
                        scrollToLine(textCursor, Top);
                    }
                }
            }
            else
            {
                deleteSelection();
            }
            break;
        case T_Enter:
            {
                deleteSelection();
                Text content = textCursor.line->getContent();
                content.insert(textCursor.column, "\n");
                textCursor.column += 1;
                textCursor.line->setContent(content);
                fixTree(textCursor.line);
                scrollToLine(textCursor, Bottom);
            }
            break;
        case T_Links:
            {
                int nextColumn = textCursor.column - 1;
                EditableJsonElement* nextLine = textCursor.line;
                while (nextColumn < 0)
                {
                    nextLine = textCursor.line->zBefore(content, true, 0);
                    if (!nextLine)
                    {
                        return;
                    }
                    nextColumn = nextLine->getContent().getLength() - 1;
                }
                if (strg)
                {
                    int start = 0;
                    nextLine->getWordBounds(nextColumn, &start, 0);
                    nextColumn = start;
                }
                if (shift)
                {
                    if (textCursor.line == selectionStart.line
                        && textCursor.column == selectionStart.column)
                    {
                        selectionStart = {nextLine, nextColumn};
                        unifyPosition(selectionStart);
                        textCursor = selectionStart;
                    }
                    else
                    {
                        selectionEnd = {nextLine, nextColumn};
                        unifyPosition(selectionEnd);
                        textCursor = selectionEnd;
                    }
                }
                else
                {
                    textCursor = {nextLine, nextColumn};
                    unifyPosition(textCursor);
                    selectionStart = textCursor;
                    selectionEnd = textCursor;
                }
                scrollToLine(textCursor, Top);
                te.processed = true;
                time = 0;
                rend = 1;
                return;
            }
        case T_Oben:
            {
                EditableJsonElement* current = textCursor.line;
                int count = 0;
                bool found = 0;
                int index = textCursor.column - 1;
                const char* content = current->getContent();
                while (current)
                {
                    while (index < 0)
                    {
                        current = current->zBefore(this->content, true, 0);
                        if (!current)
                        {
                            break;
                        }
                        content = current->getContent();
                        index = current->getContent().getLength() - 1;
                    }
                    if (!current)
                    {
                        break;
                    }
                    if (content[index] == '\n')
                    {
                        if (found)
                        {
                            break;
                        }
                        found = 1;
                    }
                    if (!found)
                    {
                        count++;
                    }
                    index--;
                }
                if (!current)
                {
                    break;
                }
                index++;
                while (current && count > 0)
                {
                    while (index >= current->getContent().getLength())
                    {
                        current = current->zAfter(true, 0);
                        if (!current)
                        {
                            break;
                        }
                        content = current->getContent();
                        index = 0;
                    }
                    if (!current)
                    {
                        break;
                    }
                    if (content[index] == '\n')
                    {
                        break;
                    }
                    count--;
                    index++;
                }
                if (!current)
                {
                    break;
                }
                if (shift)
                {
                    if (textCursor.line == selectionStart.line
                        && textCursor.column == selectionStart.column)
                    {
                        selectionStart = {current, index};
                        unifyPosition(selectionStart);
                        textCursor = selectionStart;
                    }
                    else
                    {
                        selectionEnd = {current, index};
                        unifyPosition(selectionEnd);
                        textCursor = selectionEnd;
                    }
                }
                else
                {
                    textCursor = {current, index};
                    unifyPosition(textCursor);
                    selectionStart = textCursor;
                    selectionEnd = textCursor;
                }
                scrollToLine(textCursor, Top);
                te.processed = true;
                time = 0;
                rend = 1;
                return;
            }
        case T_Rechts:
            {
                int nextColumn = textCursor.column + 1;
                EditableJsonElement* nextLine = textCursor.line;
                if (nextColumn > nextLine->getContent().getLength())
                {
                    nextLine = textCursor.line->zAfter(true, 0);
                    if (!nextLine)
                    {
                        return;
                    }
                    nextColumn = 0;
                }
                if (strg)
                {
                    int end = 0;
                    nextLine->getWordBounds(nextColumn, 0, &end);
                    nextColumn = end;
                }
                if (shift)
                {
                    if (textCursor.line == selectionEnd.line
                        && textCursor.column == selectionEnd.column)
                    {
                        selectionEnd = {nextLine, nextColumn};
                        unifyPosition(selectionEnd);
                        textCursor = selectionEnd;
                    }
                    else
                    {
                        selectionStart = {nextLine, nextColumn};
                        unifyPosition(selectionStart);
                        textCursor = selectionStart;
                    }
                }
                else
                {
                    textCursor = {nextLine, nextColumn};
                    unifyPosition(textCursor);
                    selectionStart = textCursor;
                    selectionEnd = textCursor;
                }
                scrollToLine(textCursor, Bottom);
                te.processed = true;
                time = 0;
                rend = 1;
                return;
            }
        case T_Unten:
            {
                EditableJsonElement* current = textCursor.line;
                int count = 0;
                int index = textCursor.column - 1;
                const char* content = current->getContent();
                while (current)
                {
                    while (index < 0)
                    {
                        current = current->zBefore(this->content, true, 0);
                        if (!current)
                        {
                            break;
                        }
                        content = current->getContent();
                        index = current->getContent().getLength() - 1;
                    }
                    if (!current)
                    {
                        break;
                    }
                    if (content[index] == '\n')
                    {
                        break;
                    }
                    count++;
                    index--;
                }
                bool found = 0;
                current = textCursor.line;
                index = textCursor.column;
                content = current->getContent();
                while (current && (count > 0 || !found))
                {
                    while (index >= current->getContent().getLength())
                    {
                        current = current->zAfter(true, 0);
                        if (!current)
                        {
                            break;
                        }
                        content = current->getContent();
                        index = 0;
                    }
                    if (found)
                    {
                        count--;
                    }
                    if (content[index] == '\n')
                    {
                        if (found)
                        {
                            break;
                        }
                        found = 1;
                    }
                    index++;
                }
                if (shift)
                {
                    if (textCursor.line == selectionEnd.line
                        && textCursor.column == selectionEnd.column)
                    {
                        selectionEnd = {current, index};
                        unifyPosition(selectionEnd);
                        textCursor = selectionEnd;
                    }
                    else
                    {
                        selectionStart = {current, index};
                        unifyPosition(selectionStart);
                        textCursor = selectionStart;
                    }
                }
                else
                {
                    textCursor = {current, index};
                    unifyPosition(textCursor);
                    selectionStart = textCursor;
                    selectionEnd = textCursor;
                }
                scrollToLine(textCursor, Bottom);
                te.processed = true;
                time = 0;
                rend = 1;
                return;
            }
        default:
            if (strg)
            {
                if (te.virtualKey == 'c' || te.virtualKey == 'C')
                {
                    Text content = getSelectedContent();
                    TextKopieren(content);
                    return;
                }
                else if (te.virtualKey == 'x' || te.virtualKey == 'X')
                {
                    Text content = getSelectedContent();
                    TextKopieren(content);
                    deleteSelection();
                    scrollToLine(textCursor, Top);
                    return;
                }
                else if (te.virtualKey == 'v' || te.virtualKey == 'V')
                {
                    deleteSelection();
                    EditableJsonElement* changed = textCursor.line;
                    Text content = changed->getContent();
                    const char* inserted = TextInsert();
                    content.insert(textCursor.column, inserted);
                    textCursor.column += textLength(inserted);
                    unifyPosition(textCursor);
                    scrollToLine(textCursor, Bottom);
                    break;
                }
                else if (te.virtualKey == 'a' || te.virtualKey == 'A')
                {
                    selectionStart = {content, 0};
                    EditableJsonElement* element = content;
                    while (element->zMextSibling())
                    {
                        element = element->zMextSibling();
                    }
                    while (element->zLastChildren())
                    {
                        element = element->zLastChildren();
                    }
                    selectionEnd = {element, element->getContent().getLength()};
                    textCursor = selectionEnd;
                    te.processed = true;
                    time = 0;
                    rend = 1;
                    scrollToLine(textCursor, Bottom);
                    return;
                }
                else if (te.virtualKey == 'f' || te.virtualKey == 'F')
                {
                    format();
                    return;
                }
            }
            if (isWritable(te.key[0]))
            {
                deleteSelection();
                Text content = textCursor.line->getContent();
                content.insert(textCursor.column, te.key);
                textCursor.column += textLength(te.key);
                textCursor.line->setContent(content);
                fixTree(textCursor.line);
            }
            else
            {
                return;
            }
        }
        selectionStart = textCursor;
        selectionEnd = textCursor;
        te.processed = true;
        lineCount = 0;
        content->lineCount(true, true, 0, lineCount);
    }
    time = 0;
    rend = 1;
}

bool Framework::JSON::JsonEditor::tick(double tickVal)
{
    LOCK({&cs});
    time += tickVal;
    timeSicePress += tickVal;
    if (time > 1.0)
    {
        tps = renderings / time;
        time = 0.0;
        renderings = 0;
    }
    rend |= drawCursor != (time < 0.5);
    drawCursor = time < 0.5;
    errorDescription->tick(tickVal);
    return DrawableBackground::tick(tickVal);
}

void Framework::JSON::JsonEditor::render(Image& rObj)
{
    LOCK({&cs});
    renderings++;
    renderedLines = 0;
    errorDescription->removeStyle(TextField::Style::Visible);
    DrawableBackground::render(rObj);
    if (textRenderer->zFont() && content
        && rObj.setDrawOptions(pos + Point(getBorderWidth(), getBorderWidth()),
            Point(getInnerWidth(), getInnerHeight())))
    {
        if (!renderStart.line)
        {
            renderStart = {content, 0};
            renderStartLine = 1;
        }
        int y = 0;
        int lineNumberWidth = 0;
        for (int i = lineCount; i > 0; i /= 10)
        {
            lineNumberWidth++;
        }
        lineNumberWidth
            = lineNumberWidth * textRenderer->getMaxCharWidth()
            + textRenderer->getCharSpacing() * (lineNumberWidth - 1);
        bool selected = false;
        EditableJsonElement* element = content;
        while (element)
        {
            if (element == selectionStart.line)
            {
                if (element != renderStart.line)
                {
                    selected = true;
                }
                else
                {
                    if (selectionStart.column < renderStart.column)
                    {
                        selected = true;
                    }
                }
            }
            if (element == selectionEnd.line)
            {
                if (element != renderStart.line)
                {
                    selected = false;
                    break;
                }
                else
                {
                    if (selectionEnd.column < renderStart.column)
                    {
                        selected = false;
                    }
                }
            }
            if (element == renderStart.line)
            {
                break;
            }
            element = element->zAfter(false, 0);
        }
        int line = renderStartLine;
        int x = lineNumberWidth + 26;
        EditableJsonElement* current = renderStart.line;
        EditableJsonElement* highlightStop = 0;
        int index = renderStart.column;
        bool treeBranchRendered = false;
        bool highlighted = false;
        int numberWidth = textRenderer->getTextWidth(Text(line));
        textRenderer->renderText(
            5 + lineNumberWidth - numberWidth, y, Text(line), rObj, 0xFF707070);
        bool whiteSpaceOnly = true;
        while (y < gr.y && current)
        {
            const Text& content = current->getContent();
            int column = index;
            for (int i = index; i < content.getLength() && y < gr.y;
                i++, column++)
            {
                if (selectionStart.line == current
                    && selectionStart.column == i)
                {
                    selected = true;
                }
                if (selectionEnd.line == current && selectionEnd.column == i)
                {
                    selected = false;
                }
                int color = current->getColor(i);
                int cursorX = x - 1;
                if (textCursor.line == current && textCursor.column == i
                    && drawCursor)
                {
                    rObj.drawLineV(
                        cursorX, y, textRenderer->getFontSize(), 0xFFC0C0C0);
                }
                if (content[i] == '\n')
                {
                    column = -1;
                    highlighted = false;
                    if (!treeBranchRendered)
                    {
                        // | in tree view
                        rObj.drawLineV(lineNumberWidth + 13,
                            y
                                - (line > 1 ? textRenderer->getFontSize() / 6
                                            : 0),
                            textRenderer->getFontSize()
                                + (line > 1 ? textRenderer->getFontSize() / 6
                                            : 0),
                            0xFF808080);
                        if (highlightStop)
                        {
                            // hover effect in tree view
                            rObj.fillRegion(lineNumberWidth + 10,
                                y - textRenderer->getFontSize() / 6,
                                7,
                                textRenderer->getFontSize()
                                    + textRenderer->getFontSize() / 6,
                                0xFF505050);
                        }
                    }
                    if (selected)
                    {
                        rObj.fillRegion(x,
                            y,
                            textRenderer->getTextWidth(" "),
                            textRenderer->getRowHeight()
                                + textRenderer->getLineSpacing(),
                            0xFF502020);
                    }
                    x = lineNumberWidth + 26;
                    y += textRenderer->getRowHeight()
                       + textRenderer->getLineSpacing();
                    whiteSpaceOnly = true;
                    line++;
                    renderedLines++;
                    treeBranchRendered = false;
                    int numberWidth = textRenderer->getTextWidth(Text(line));
                    textRenderer->renderText(5 + lineNumberWidth - numberWidth,
                        y,
                        Text(line),
                        rObj,
                        0xFF707070);
                }
                else
                {
                    textRenderer->renderChar(x,
                        y,
                        content[i],
                        rObj,
                        color,
                        false,
                        selected,
                        0xFF502020);
                }
                if (cursorPos.x > cursorX && cursorPos.x <= x
                    && cursorPos.y >= y
                    && cursorPos.y <= y + textRenderer->getRowHeight())
                {
                    if (current->hasError(i))
                    {
                        const SyntaxError& error = current->getError(i);
                        errorDescription->setText(errors[error.getErrorType()]);
                        errorDescription->setSize(
                            errorDescription->getNeededWidth() + 6,
                            errorDescription->getNeededHeight() + 6);
                        errorDescription->setPosition(
                            cursorPos.x, cursorPos.y + 20);
                        if (errorDescription->getX()
                                + errorDescription->getWidth()
                            > getInnerWidth())
                        {
                            errorDescription->setX(
                                getInnerWidth() - errorDescription->getWidth()
                                - 5);
                        }
                        if (errorDescription->getY()
                                + errorDescription->getHeight()
                            > getInnerHeight())
                        {
                            errorDescription->setY(
                                getInnerHeight() - errorDescription->getHeight()
                                - 5);
                        }
                        errorDescription->addStyle(TextField::Style::Visible);
                    }
                }
                if (column % 4 == 0 && content[i] == ' ' && whiteSpaceOnly)
                {
                    rObj.drawLineV(
                        cursorX + 1 + textRenderer->getTextWidth(" ") / 2,
                        y + 2,
                        textRenderer->getFontSize() - 4,
                        0xFF353535);
                }
                whiteSpaceOnly &= content[i] == ' ' || content[i] == '\n';
            }
            if (selectionStart.line == current
                && selectionStart.column == content.getLength())
            {
                selected = true;
            }
            if (selectionEnd.line == current
                && selectionEnd.column == content.getLength())
            {
                selected = false;
            }
            if (textCursor.line == current
                && textCursor.column == content.getLength() && drawCursor)
            {
                rObj.drawLineV(
                    x - 1, y, textRenderer->getFontSize(), 0xFFC0C0C0);
            }
            if (current->zFirstChildren())
            {
                if (pressed && pressedPos.x >= lineNumberWidth + 10
                    && pressedPos.x <= lineNumberWidth + 16
                    && pressedPos.y >= y + textRenderer->getFontSize() / 2 - 4
                    && pressedPos.y <= y + textRenderer->getFontSize() / 2 + 2)
                {
                    pressed = false;
                    current->setHidden(!current->isHidden());
                }
                if (cursorPos.x >= lineNumberWidth + 10
                    && cursorPos.x <= lineNumberWidth + 16
                    && cursorPos.y >= y + textRenderer->getFontSize() / 2 - 4
                    && cursorPos.y <= y + textRenderer->getFontSize() / 2 + 2
                    && !current->isHidden())
                {
                    highlightStop = current->zLastChildren();
                }
                if (current->isHidden())
                {
                    if (!treeBranchRendered)
                    {
                        rObj.fillRegion(lineNumberWidth + 10,
                            y + textRenderer->getFontSize() / 2 - 4,
                            6,
                            6,
                            0xFF000000);
                        rObj.drawLine(
                            Point(lineNumberWidth + 10,
                                y + textRenderer->getFontSize() / 2 - 4),
                            Point(lineNumberWidth + 16,
                                y + textRenderer->getFontSize() / 2 - 1),
                            0xFF808080);
                        rObj.drawLine(
                            Point(lineNumberWidth + 10,
                                y + textRenderer->getFontSize() / 2 + 2),
                            Point(lineNumberWidth + 16,
                                y + textRenderer->getFontSize() / 2 - 1),
                            0xFF808080);
                    }
                    for (char c : " ... ")
                    {
                        textRenderer->renderChar(x,
                            y,
                            c,
                            rObj,
                            0xFF505050,
                            false,
                            selected,
                            0xFF502020);
                    }
                    if (current->getOpeningControllChar() == '{')
                    {
                        textRenderer->renderChar(x,
                            y,
                            '}',
                            rObj,
                            0xFF505050,
                            false,
                            selected,
                            0xFF502020);
                    }
                    else if (current->getOpeningControllChar() == '[')
                    {
                        textRenderer->renderChar(x,
                            y,
                            ']',
                            rObj,
                            0xFF505050,
                            false,
                            selected,
                            0xFF502020);
                    }
                }
                else
                {
                    if (!treeBranchRendered)
                    {
                        rObj.fillRegion(lineNumberWidth + 10,
                            y + textRenderer->getFontSize() / 2 - 4,
                            6,
                            6,
                            0xFF000000);
                        rObj.drawLine(
                            Point(lineNumberWidth + 10,
                                y + textRenderer->getFontSize() / 2 - 4),
                            Point(lineNumberWidth + 13,
                                y + textRenderer->getFontSize() / 2 + 2),
                            0xFF808080);
                        rObj.drawLine(
                            Point(lineNumberWidth + 16,
                                y + textRenderer->getFontSize() / 2 - 4),
                            Point(lineNumberWidth + 13,
                                y + textRenderer->getFontSize() / 2 + 2),
                            0xFF808080);
                    }
                }
                treeBranchRendered = true;
            }
            if (!current->zMextSibling() && current->zParent())
            {
                // |_ in tree view
                rObj.drawLineH(lineNumberWidth + 14,
                    y + textRenderer->getFontSize() - 1,
                    3,
                    0xFF808080);
            }
            rObj.drawLineV(x,
                y,
                textRenderer->getFontSize(),
                0xFF30C030); // TODO: debug tree seperator
            if (current == highlightStop)
            {
                highlightStop = 0;
                if (!treeBranchRendered)
                {
                    // hover effect in tree view
                    rObj.fillRegion(lineNumberWidth + 10,
                        y - textRenderer->getFontSize() / 6,
                        7,
                        textRenderer->getFontSize()
                            + textRenderer->getFontSize() / 6,
                        0xFF505050);
                    highlighted = true;
                }
            }
            current = current->zAfter(true, &line);
            index = 0;
        }
        if (!treeBranchRendered && !highlighted)
        {
            // | in tree view
            rObj.drawLineV(lineNumberWidth + 13,
                y - (line > 1 ? textRenderer->getFontSize() / 6 : 0),
                textRenderer->getFontSize()
                    + (line > 1 ? textRenderer->getFontSize() / 6 : 0),
                0xFF808080);
        }
        EditableJsonElement* resnderStopElement = current;
        renderStopLine = line;
        textRenderer->renderText(5,
            y + textRenderer->getRowHeight() + textRenderer->getLineSpacing(),
            Text("FPS: ") + Text(tps),
            rObj,
            0xFFFFFFFF);
        bool visible = false;
        double sy = 0.0;
        double yOffset = (double)getInnerHeight() / lineCount;
        current = content;
        EditableJsonElement* hiddenStop = 0;
        while (current)
        {
            if (hiddenStop == current)
            {
                hiddenStop = 0;
            }
            if (current == renderStart.line)
            {
                visible = true;
            }
            if (current == resnderStopElement)
            {
                visible = false;
            }
            int f = 0xFF303030;
            if (visible)
            {
                f = 0xFFA0A0A0;
            }
            if (hiddenStop)
            {
                f = 0xFF505050;
            }
            if (current->hasError())
            {
                f = 0xFFFF0000;
            }
            double size = current->lineCount() * yOffset;
            if ((int)(sy + size) > (int)sy || current->hasError())
            {
                rObj.fillRegion(getInnerWidth() - 15,
                    (int)sy,
                    15,
                    (int)(sy + MAX(yOffset, 1)),
                    f);
            }
            if (current->isHidden())
            {
                if (!hiddenStop)
                {
                    hiddenStop = current->zAfter(true, 0);
                }
            }
            current = current->zAfter(false, 0);
            sy += size;
        }
        errorDescription->render(rObj);
        rObj.releaseDrawOptions();
    }
}

Text Framework::JSON::JsonEditor::getContent()
{
    return content ? content->getRecursiveContent() : Text("");
}

Text Framework::JSON::JsonEditor::getSelectedContent()
{
    Text result = "";
    if (selectionStart.line && selectionEnd.line)
    {
        if (selectionStart.line == selectionEnd.line)
        {
            Text* tmp = selectionStart.line->getContent().getTeilText(
                selectionStart.column, selectionEnd.column);
            result.append(*tmp);
            tmp->release();
        }
        else
        {
            Text* tmp = selectionStart.line->getContent().getTeilText(
                selectionStart.column,
                selectionStart.line->getContent().getLength());
            result.append(*tmp);
            tmp->release();
            Stack<EditableJsonElement*> stack(0);
            stack.push(selectionStart.line);
            while (stack.getSize())
            {
                EditableJsonElement* current = stack.pop();
                if (current->zMextSibling())
                {
                    stack.push(current->zMextSibling());
                }
                else if (stack.getSize() == 0 && current->zParent())
                {
                    EditableJsonElement* parent = current->zParent();
                    while (parent)
                    {
                        if (parent->zMextSibling())
                        {
                            stack.push(current->zParent()->zMextSibling());
                            break;
                        }
                        parent = parent->zParent();
                    }
                }
                if (current->zFirstChildren())
                {
                    stack.push(current->zFirstChildren());
                }
                if (current == selectionEnd.line)
                {
                    break;
                }
                if (current != selectionStart.line)
                {
                    result += current->getContent();
                }
            }
            tmp = selectionEnd.line->getContent().getTeilText(
                0, selectionEnd.column);
            result.append(*tmp);
            tmp->release();
        }
    }
    return result;
}

JSONValue* Framework::JSON::JsonEditor::getValidContent()
{
    return nullptr; // TODO
}

void Framework::JSON::JsonEditor::scrollToLine(int line, ScrollTargetPos pos)
{
    if (pos == Top || pos == Bottom)
    {
        if (line >= renderStartLine && line < renderStopLine)
        {
            return; // line is already visible
        }
    }
    EditableJsonElement* element = content;
    if (line == 1)
    {
        scrollToLine(line, {content, 0}, pos);
        return;
    }
    int l = 1;
    int column = 0;
    while (element)
    {
        int lineCount = element->lineCount();
        if (lineCount + l >= line)
        {
            column = element->getContent().positionOf('\n', line - l - 1) + 1;
            break;
        }
        l += lineCount;
        EditableJsonElement* tmp = element->zAfter(true, &l);
        if (l >= line)
        {
            column = element->getContent().positionOf('\n', lineCount - 1) + 1;
            break;
        }
        element = tmp;
    }
    EditorPosition target = {element, column};
    unifyPosition(target);
    scrollToLine(line, target, pos);
}

void Framework::JSON::JsonEditor::scrollToLine(
    EditorPosition target, ScrollTargetPos pos)
{
    if (!target.line || !target.line->isVisible())
    {
        return;
    }
    int lineNumber = 0;
    if (!content->lineCount(true, true, target.line, lineNumber))
    {
        Text* part = target.line->getContent().getTeilText(0, target.column);
        lineNumber += part->countOf('\n');
        part->release();
        if (pos == Top || pos == Bottom)
        {
            if (lineNumber >= renderStartLine && lineNumber < renderStopLine)
            {
                return; // line is already visible
            }
        }
        scrollToLine(lineNumber, target, pos);
    }
}

void Framework::JSON::JsonEditor::scrollToLine(
    int lineNum, EditorPosition target, ScrollTargetPos pos)
{
    if (!target.line || !target.line->isVisible())
    {
        return;
    }
    if (pos == Top || pos == Bottom)
    {
        if (lineNum >= renderStartLine && lineNum < renderStopLine)
        {
            return; // line is already visible
        }
    }
    if (pos == Top)
    {
        renderStart = target;
        const char* content = renderStart.line->getContent();
        while (
            renderStart.column > 0 && content[renderStart.column - 1] != '\n')
        {
            renderStart.column--;
        }
        renderStartLine = lineNum;
    }
    else
    {
        int linesUntilStart
            = pos == Bottom ? renderedLines - 1 : renderedLines / 2 - 1;
        if (linesUntilStart >= lineNum)
        {
            renderStart = {content, 0};
            renderStartLine = 1;
            return;
        }
        EditableJsonElement* element = target.line;
        EditableJsonElement* before = element;
        while (linesUntilStart >= 0)
        {
            if (!before)
            {
                break;
            }
            element = before;
            int newLines = 0;
            if (element == target.line)
            {
                Text* part
                    = element->getContent().getTeilText(0, target.column);
                newLines = part->countOf('\n');
                part->release();
            }
            else
            {
                newLines = element->lineCount();
            }
            if (newLines > linesUntilStart)
            {
                renderStart = {element,
                    element->getContent().positionOf(
                        '\n', newLines - linesUntilStart - 1)
                        + 1};
                unifyPosition(renderStart);
                renderStartLine = lineNum - linesUntilStart;
                return;
            }
            lineNum -= newLines;
            linesUntilStart -= newLines;
            before = element->zBefore(this->content, true, &lineNum);
        }
        renderStart = {element, 0};
        renderStartLine = lineNum;
    }
}
