#include "UIMLView.h"

#include "Bild.h"
#include "Bildschirm.h"
#include "Fenster.h"
#include "Knopf.h"
#include "Rahmen.h"
#include "Schrift.h"
#include "Scroll.h"
#include "Tabelle.h"
#include "TextFeld.h"
#include "XML.h"

using namespace Framework;

UIMLElement::UIMLElement()
    : ReferenceCounter()
{}

UIMLElement::~UIMLElement() {}

//! wendet die layout parameter zu einer Zeichnung an
void UIMLElement::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    int width = z.getBreite();
    int height = z.getHeight();
    if (element.hasAttribute("width"))
    {
        Text w = element.getAttributeValue("width");
        if (!w.istGleich("auto"))
        {
            width = (int)w;
            if (w.getText()[w.getLength() - 1] == '%')
                width = (int)((pWidth / 100.0) * width);
        }
    }
    if (element.hasAttribute("height"))
    {
        Text h = element.getAttributeValue("height");
        if (!h.istGleich("auto"))
        {
            height = (int)h;
            if (h.getText()[h.getLength() - 1] == '%')
                height = (int)((pHeight / 100.0) * height);
        }
    }
    z.setSize(width, height);
    if (element.hasAttribute("align-left"))
    {
        Text la = element.getAttributeValue("align-left");
        int x = 0;
        if (la.istGleich("start"))
            x = 0;
        else if (la.istGleich("end"))
            x = pWidth;
        else if (la.istGleich("center"))
            x = pWidth / 2 - width / 2;
        else
        {
            XML::Editor ed
                = element.zParent()->selectChildsByAttribute("id", la);
            generalLayouter.layout(*ed.begin().val(),
                *generalLayouter.zZeichnungById(la),
                pWidth,
                pHeight,
                generalLayouter);
            Zeichnung* laz = generalLayouter.zZeichnungById(la);
            if (laz) x = laz->getX() + laz->getBreite();
        }
        if (element.hasAttribute("margin-left"))
        {
            Text mt = element.getAttributeValue("margin-left");
            int m = (int)mt;
            if (mt.getText()[mt.getLength() - 1] == '%')
                m = (int)((pWidth / 100.0) * m);
            x += m;
        }
        z.setX(x);
    }
    else if (element.hasAttribute("align-right"))
    {
        Text ra = element.getAttributeValue("align-right");
        int x = 0;
        if (ra.istGleich("start"))
            x = -z.getBreite();
        else if (ra.istGleich("end"))
            x = pWidth - z.getBreite();
        else if (ra.istGleich("center"))
            x = pWidth / 2 - width / 2;
        else
        {
            XML::Editor ed
                = element.zParent()->selectChildsByAttribute("id", ra);
            generalLayouter.layout(*ed.begin().val(),
                *generalLayouter.zZeichnungById(ra),
                pWidth,
                pHeight,
                generalLayouter);
            Zeichnung* raz = generalLayouter.zZeichnungById(ra);
            if (raz) x = raz->getX() - z.getBreite();
        }
        if (element.hasAttribute("margin-right"))
        {
            Text mt = element.getAttributeValue("margin-right");
            int m = (int)mt;
            if (mt.getText()[mt.getLength() - 1] == '%')
                m = (int)((pWidth / 100.0) * m);
            x -= m;
        }
        z.setX(x);
    }
    if (element.hasAttribute("align-top"))
    {
        Text ta = element.getAttributeValue("align-top");
        int y = 0;
        if (ta.istGleich("start"))
            y = 0;
        else if (ta.istGleich("end"))
            y = pHeight;
        else if (ta.istGleich("center"))
            y = pHeight / 2 - height / 2;
        else
        {
            XML::Editor ed
                = element.zParent()->selectChildsByAttribute("id", ta);
            generalLayouter.layout(*ed.begin().val(),
                *generalLayouter.zZeichnungById(ta),
                pWidth,
                pHeight,
                generalLayouter);
            Zeichnung* taz = generalLayouter.zZeichnungById(ta);
            if (taz) y = taz->getY() + taz->getHeight();
        }
        if (element.hasAttribute("margin-top"))
        {
            Text mt = element.getAttributeValue("margin-top");
            int m = (int)mt;
            if (mt.getText()[mt.getLength() - 1] == '%')
                m = (int)((pHeight / 100.0) * m);
            y += m;
        }
        z.setY(y);
    }
    else if (element.hasAttribute("align-bottom"))
    {
        Text ba = element.getAttributeValue("align-bottom");
        int y = 0;
        if (ba.istGleich("start"))
            y = -z.getHeight();
        else if (ba.istGleich("end"))
            y = pHeight - z.getHeight();
        else if (ba.istGleich("center"))
            y = pHeight / 2 - height / 2;
        else
        {
            XML::Editor ed
                = element.zParent()->selectChildsByAttribute("id", ba);
            generalLayouter.layout(*ed.begin().val(),
                *generalLayouter.zZeichnungById(ba),
                pWidth,
                pHeight,
                generalLayouter);
            Zeichnung* baz = generalLayouter.zZeichnungById(ba);
            if (baz) y = baz->getY() - z.getHeight();
        }
        if (element.hasAttribute("margin-bottom"))
        {
            Text mt = element.getAttributeValue("margin-bottom");
            int m = (int)mt;
            if (mt.getText()[mt.getLength() - 1] == '%')
                m = (int)((pHeight / 100.0) * m);
            y -= m;
        }
        z.setY(y);
    }
    int x = z.getX();
    int y = z.getY();
    if (element.hasAttribute("x"))
    {
        Text xt = element.getAttributeValue("x");
        x = (int)xt;
        if (xt.getText()[xt.getLength() - 1] == '%')
            x = (int)((pWidth / 100.0) * x);
    }
    if (element.hasAttribute("y"))
    {
        Text yt = element.getAttributeValue("y");
        y = (int)yt;
        if (yt.getText()[yt.getLength() - 1] == '%')
            y = (int)((pHeight / 100.0) * y);
    }
    z.setPosition(x, y);
    pWidth = z.getInnenBreite();
    pHeight = z.getInnenHeight();
    // recursive layout
    for (auto i = element.getChilds(); i; i++)
        generalLayouter.layout(*i.val(),
            *generalLayouter.zZeichnungById(i->getAttributeValue("id")),
            pWidth,
            pHeight,
            generalLayouter);
}

UIMLContainer::UIMLContainer()
    : UIMLElement()
{}

UIMLContainer::~UIMLContainer() {}

UIMLTextField::UIMLTextField()
    : UIMLElement()
{}

bool UIMLTextField::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("textfield");
}

Zeichnung* UIMLTextField::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    TextFeld* t = generalFactory.getFactory().createTextFeld(
        generalFactory.getFactory().initParam);
    t->addStyle(TextFeld::Style::TextFeld);
    return t;
}

void UIMLTextField::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    z.setStyle(TextFeld::Style::HCenter,
        element.hasAttribute("text-align-horizontal")
            && element.getAttributeValue("text-align-horizontal")
                   .istGleich("center"));
    z.setStyle(TextFeld::Style::VCenter,
        element.hasAttribute("text-align-vertical")
            && element.getAttributeValue("text-align-vertical")
                   .istGleich("center"));
    if (element.hasAttribute("font-size"))
        ((TextFeld*)&z)
            ->setSchriftSize(
                (unsigned char)(int)element.getAttributeValue("font-size"));
    z.setStyle(TextFeld::Style::Editierbar,
        !element.hasAttribute("disabled")
            || (element.getAttributeValue("disabled").getLength() != 0
                && !element.getAttributeValue("disabled").istGleich("true")));
    ((TextFeld*)&z)->setText(element.getText());
    if (element.hasAttribute("width"))
    {
        Text w = element.getAttributeValue("width");
        if (w.istGleich("auto"))
        {
            z.setWidth(((TextFeld*)&z)->getNeededWidth());
        }
    }
    if (element.hasAttribute("height"))
    {
        Text h = element.getAttributeValue("height");
        if (h.istGleich("auto"))
        {
            z.setHeight(((TextFeld*)&z)->getNeededHeight());
        }
    }
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

UIMLButton::UIMLButton()
    : UIMLElement()
{}

bool UIMLButton::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("button");
}

Zeichnung* UIMLButton::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    Knopf* k = generalFactory.getFactory().createKnopf(
        generalFactory.getFactory().initParam);
    return k;
}

void UIMLButton::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    if (element.hasAttribute("font-size"))
        ((Knopf*)&z)
            ->setSchriftSize(
                (unsigned char)(int)element.getAttributeValue("font-size"));
    ((Knopf*)&z)->setText(element.getText());
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

UIMLCheck::UIMLCheck()
    : UIMLElement()
{}

bool UIMLCheck::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("check");
}

Zeichnung* UIMLCheck::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    KontrollKnopf* k = generalFactory.getFactory().createKontrollKnopf(
        generalFactory.getFactory().initParam);
    return k;
}

void UIMLCheck::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    ((KontrollKnopf*)&z)->setText(element.getText());
    ((KontrollKnopf*)&z)->setSText(element.getText());
    z.setStyle(
        KontrollKnopf::Style::Selected, element.hasAttribute("selected"));
    if (element.hasAttribute("font-size"))
        ((KontrollKnopf*)&z)
            ->setSSize(
                (unsigned char)(int)element.getAttributeValue("font-size"));
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

UIMLText::UIMLText()
    : UIMLElement()
{}

bool UIMLText::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("text");
}

Zeichnung* UIMLText::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    TextFeld* t = generalFactory.getFactory().createTextFeld(
        generalFactory.getFactory().initParam);
    t->addStyle(TextFeld::Style::Text);
    return t;
}

void UIMLText::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    z.setStyle(TextFeld::Style::HCenter,
        element.hasAttribute("text-align-horizontal")
            && element.getAttributeValue("text-align-horizontal")
                   .istGleich("center"));
    z.setStyle(TextFeld::Style::VCenter,
        element.hasAttribute("text-align-vertical")
            && element.getAttributeValue("text-align-vertical")
                   .istGleich("center"));
    if (element.hasAttribute("font-size"))
        ((TextFeld*)&z)
            ->setSchriftSize(
                (unsigned char)(int)element.getAttributeValue("font-size"));
    z.setStyle(TextFeld::Style::Editierbar,
        !element.hasAttribute("disabled")
            || (element.getAttributeValue("disabled").getLength() != 0
                && !element.getAttributeValue("disabled").istGleich("true")));
    ((TextFeld*)&z)->setText(element.getText());
    if (element.hasAttribute("width"))
    {
        Text w = element.getAttributeValue("width");
        if (w.istGleich("auto"))
        {
            z.setWidth(((TextFeld*)&z)->getNeededWidth());
        }
    }
    if (element.hasAttribute("height"))
    {
        Text h = element.getAttributeValue("height");
        if (h.istGleich("auto"))
        {
            z.setHeight(((TextFeld*)&z)->getNeededHeight());
        }
    }
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

UIMLTextArea::UIMLTextArea()
    : UIMLElement()
{}

bool UIMLTextArea::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("textarea");
}

Zeichnung* UIMLTextArea::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    TextFeld* t = generalFactory.getFactory().createTextFeld(
        generalFactory.getFactory().initParam);
    t->addStyle(TextFeld::Style::TextGebiet);
    return t;
}

void UIMLTextArea::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    z.setStyle(TextFeld::Style::HCenter,
        element.hasAttribute("text-align-horizontal")
            && element.getAttributeValue("text-align-horizontal")
                   .istGleich("center"));
    z.setStyle(TextFeld::Style::VCenter,
        element.hasAttribute("text-align-vertical")
            && element.getAttributeValue("text-align-vertical")
                   .istGleich("center"));
    if (element.hasAttribute("font-size"))
        ((TextFeld*)&z)
            ->setSchriftSize(
                (unsigned char)(int)element.getAttributeValue("font-size"));
    z.setStyle(TextFeld::Style::Editierbar,
        !element.hasAttribute("disabled")
            || (element.getAttributeValue("disabled").getLength() != 0
                && !element.getAttributeValue("disabled").istGleich("true")));
    ((TextFeld*)&z)->setText(element.getText());
    ((TextFeld*)&z)
        ->zTextRenderer()
        ->textFormatieren(((TextFeld*)&z)->zText(), z.getInnenBreite());
    if (element.hasAttribute("width"))
    {
        Text w = element.getAttributeValue("width");
        if (w.istGleich("auto"))
        {
            z.setWidth(((TextFeld*)&z)->getNeededWidth());
        }
    }
    if (element.hasAttribute("height"))
    {
        Text h = element.getAttributeValue("height");
        if (h.istGleich("auto"))
        {
            z.setHeight(((TextFeld*)&z)->getNeededHeight());
        }
    }
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

UIMLTable::UIMLTable()
    : UIMLElement()
{}

bool UIMLTable::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("table");
}

Zeichnung* UIMLTable::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    ObjTabelle* t = generalFactory.getFactory().createObjTabelle(
        generalFactory.getFactory().initParam);
    int index = 0;
    for (auto i = element.getChilds(); i; i++)
    {
        Text id;
        if (i->hasAttribute("id"))
            id = i->getAttributeValue("id");
        else
        {
            id = Text("_") += index++;
            i->setAttribute("id", id);
        }
        if (i->getName().istGleich("tr"))
        {
            t->addZeile(id);
            Text line = id;
            int c = 1;
            for (auto j = i->getChilds(); j; j++)
            {
                Zeichnung* z
                    = generalFactory.parseElement(*i.val(), generalFactory);
                if (t->getSpaltenAnzahl() < c) t->addSpalte(Text(c - 1));
                if (z)
                    t->setZeichnungZ(Text(c - 1),
                        line,
                        dynamic_cast<Zeichnung*>(z->getThis()));
                c++;
            }
        }
    }
    return t;
}

void UIMLTable::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    z.setStyle(ObjTabelle::Style::HScroll,
        element.hasAttribute("scroll")
            && element.getAttributeValue("scroll").istGleich("horizontal"));
    z.setStyle(ObjTabelle::Style::VScroll,
        element.hasAttribute("scroll")
            && element.getAttributeValue("scroll").istGleich("vertical"));
    z.setStyle(ObjTabelle::Style::scroll,
        element.hasAttribute("scroll")
            && element.getAttributeValue("scroll").istGleich("both"));
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
    ObjTabelle* objT = (ObjTabelle*)&z;
    if (objT->getZeilenAnzahl() > 0)
    {
        if (element.hasAttribute("line-height"))
        {
            int height = (int)element.getAttributeValue("line-height");
            for (int i = 0; i < objT->getZeilenAnzahl(); i++)
                objT->setZeilenHeight(i, height);
        }
        for (int i = 0; i < objT->getSpaltenAnzahl(); i++)
        {
            if (objT->zZeichnung(i, 0))
                objT->setSpaltenBreite(i, objT->zZeichnung(i, 0)->getBreite());
        }
    }
}

UIMLFrame::UIMLFrame()
    : UIMLElement()
{}

bool UIMLFrame::isApplicableFor(XML::Element& element)
{
    return element.getName().istGleich("frame");
}

Zeichnung* UIMLFrame::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    Fenster* f = generalFactory.getFactory().createFenster(
        generalFactory.getFactory().initParam);
    for (auto i = element.getChilds(); i; i++)
    {
        Zeichnung* z = generalFactory.parseElement(*i.val(), generalFactory);
        if (z) f->addMember(dynamic_cast<Zeichnung*>(z->getThis()));
    }
    return f;
}

void UIMLFrame::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    if (element.hasAttribute("title"))
        ((Fenster*)&z)->setTitel(element.getAttributeValue("title"));
    if (element.hasAttribute("title-height"))
        ((Fenster*)&z)
            ->zTTextFeld()
            ->setSize(((Fenster*)&z)->zTTextFeld()->getBreite(),
                (int)element.getAttributeValue("title-height"));
    UIMLElement::layout(element, z, pWidth, pHeight, generalLayouter);
}

// Erstellt eine UIML View
UIMLView::UIMLView()
    : ZeichnungHintergrund()
{
    style = Style::MEIgnoreInside | Style::MEIgnoreParentInside
          | Style::MEIgnoreSichtbar | Style::MEIgnoreVerarbeitet;
    members = new Trie<Zeichnung>();
    dom = 0;
    nextId = 0;
    memset(&init, 0, sizeof(UIInit));
    addKnownElement(new UIMLTextField());
    addKnownElement(new UIMLButton());
    addKnownElement(new UIMLCheck());
    addKnownElement(new UIMLText());
    addKnownElement(new UIMLTextArea());
    addKnownElement(new UIMLTable());
    addKnownElement(new UIMLFrame());
}

// Erstellt eine UIML View zu einem UIML Text
//  uiml: Ein xml element gemät des ksg uiml standarts
UIMLView::UIMLView(XML::Element* uiml, UIInit& init)
    : UIMLView()
{
    this->init = init;
    setUIML(uiml);
}

// Erstellt eine UIML View zu einem UIML Text
//  uiml: Ein xml text gemät des ksg uiml standarts
UIMLView::UIMLView(Text uiml, UIInit& init)
    : UIMLView()
{
    this->init = init;
    setUIML(uiml);
}

UIMLView::~UIMLView()
{
    if (dom) dom->release();
    members->release();
}

// Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch aufgerufen.
//  me: Das Ereignis
void UIMLView::doMausEreignis(MausEreignis& me, bool userRet)
{
    if (dom)
    {
        bool verarbeitet = me.verarbeitet;
        me.verarbeitet |= hatStyleNicht(Style::Sichtbar);
        bool insideParent = me.insideParent;
        if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet
            || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y
            || !userRet)
            me.insideParent = 0;
        int rbr = 0;
        if (hatStyle(Style::Rahmen) && rahmen) rbr = rahmen->getRBreite();
        me.mx -= rbr;
        me.my -= rbr;
        if (hatStyle(Style::VScroll) && vertikalScrollBar)
            me.my += vertikalScrollBar->getScroll();
        if (hatStyle(Style::HScroll) && horizontalScrollBar)
            me.mx += horizontalScrollBar->getScroll();
        if (dom)
        {
            for (auto i = dom->getChilds(); i; i++)
            { // TODO render elements backwards
                Zeichnung* z = members->z(i->getAttributeValue("id"),
                    i->getAttributeValue("id").getLength());
                if (z) z->doPublicMausEreignis(me);
            }
        }
        me.mx += rbr;
        me.my += rbr;
        if (hatStyle(Style::VScroll) && vertikalScrollBar)
            me.my -= vertikalScrollBar->getScroll();
        if (hatStyle(Style::HScroll) && horizontalScrollBar)
            me.mx -= horizontalScrollBar->getScroll();
        if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet
            || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y
            || !userRet)
            me.insideParent = insideParent;
        else
            me.verarbeitet = 1;
        if (hatStyleNicht(Style::Sichtbar)) me.verarbeitet = verarbeitet;
    }
}

//! entfernt alle bekannten elemente, die im uiml verwendet werden können
void UIMLView::removeAllKnownElements()
{
    knownElements.leeren();
}

//! fügt ein neues bekanntes element hinzu, dass danach im uiml verwendet werden
//! kann.
void UIMLView::addKnownElement(UIMLElement* element)
{
    knownElements.add(element);
}

//! prüft, ob ein xml Element ein bekanntes uiml Element ist;
bool UIMLView::isKnownElement(XML::Element* zElement)
{
    for (UIMLElement* element : knownElements)
    {
        if (element->isApplicableFor(*zElement)) return 1;
    }
    return 0;
}

// setzt den inhalt der view
//  uiml: Ein xml element gemät des ksg uiml standarts
void UIMLView::setUIML(XML::Element* uiml)
{
    if (dom) dom->release();
    dom = uiml;
    members->leeren();
    nextId = 0;
    if (dom)
    {
        for (auto i = dom->getChilds(); i; i++)
        {
            parseElement(*i.val(), *this);
        }
    }
}

// setzt den inhalt der view
//  uiml: Ein xml text gemät des ksg uiml standarts
void UIMLView::setUIML(Text uiml)
{
    setUIML(new XML::Element(uiml));
}

// Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat
//  id: die id der Zeichnung
Zeichnung* UIMLView::zZeichnungById(const char* id)
{
    return members->z(id, textLength(id));
}

// Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat
//  id: die id der Zeichnung
Zeichnung* UIMLView::getZeichnungById(const char* id)
{
    return members->get(id, textLength(id));
}

// aktualisiert größe und position aller Zeichnungen gemäß den spezifikationen
// in UIML
void UIMLView::layout()
{
    if (dom)
    {
        for (auto i = dom->getChilds(); i; i++)
        {
            Text id = i->getAttributeValue("id");
            Zeichnung* z = zZeichnungById(id);
            if (z)
            {
                layout(*i.val(),
                    *z,
                    this->getInnenBreite(),
                    this->getInnenHeight(),
                    *this);
            }
        }
    }
}

// fügt ein element hinzu
//  uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt
//  darstellt
Text UIMLView::addMember(Text uiml)
{
    XML::Element* e = new XML::Element(uiml);
    if (parseElement(*e, *this)) dom->addChildAtFront(e);
    return e->getAttributeValue("id");
}

// fügt ein element zu einem Elternelement hinzu (funktioniert momentan nur mit
// frame Objekten)
//  uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt
//  darstellt
Text UIMLView::addMember(Text uiml, Text parentId)
{
    XML::Element* e = new XML::Element(uiml);
    XML::Editor ed = dom->selectChildren();
    while (ed.begin())
    {
        XML::Editor ed2 = ed.whereAttributeEquals("id", parentId);
        if (ed2.begin())
        {
            if (ed2.begin()->getName().istGleich("frame"))
            {
                Zeichnung* z = parseElement(*e, *this);
                if (z)
                {
                    dynamic_cast<Fenster*>(
                        members->z(parentId, parentId.getLength()))
                        ->addMember(dynamic_cast<Zeichnung*>(z->getThis()));
                    ed2.begin()->addChild(e);
                }
                return e->getAttributeValue("id");
            }
        }
        ed = ed.selectChildren();
    }
    e->release();
    return "";
}

// entfernt ein element
//  id: id des Elements
void UIMLView::removeMember(Text id)
{
    XML::Editor e = dom->selectChildsByAttribute("id", id);
    e.remove();
    members->remove(id, id.getLength());
}

// Verarbeitet ein Tastatur Ereignis. Wird vom Framework automatisch aufgerufen
//  te: Das Ereignis
void UIMLView::doTastaturEreignis(TastaturEreignis& te)
{
    bool verarbeitet = te.verarbeitet;
    ZeichnungHintergrund::doTastaturEreignis(te);
    te.verarbeitet = verarbeitet;
    if (dom)
    {
        for (auto i = dom->getChilds(); i; i++)
        { // TODO render elements backwards
            Zeichnung* z = members->z(i->getAttributeValue("id"),
                i->getAttributeValue("id").getLength());
            if (z) z->doTastaturEreignis(te);
        }
    }
}

// Updated den Zeichenhintergrund
//  tickVal: Die vergangene Zeit in Sekunden, die seit dem Letzten Aufruf dieser
//  Funktion verstrichen ist return: 1, wenn das Bild neu gezeichnet werden
//  muss. 0 sonnst
bool UIMLView::tick(double tickVal)
{
    if (dom)
    {
        for (auto i = dom->getChilds(); i; i++)
        { // TODO render elements backwards
            Zeichnung* z = members->z(i->getAttributeValue("id"),
                i->getAttributeValue("id").getLength());
            if (z) rend |= z->tick(tickVal);
        }
    }
    return ZeichnungHintergrund::tick(tickVal);
}

// Zeichnet den Hintergrund eines Zeichnunges nach rObj
void UIMLView::render(Bild& rObj)
{
    if (hatStyle(Zeichnung::Style::Sichtbar))
    {
        ZeichnungHintergrund::render(rObj);
        if (dom)
        {
            if (!rObj.setDrawOptions(pos.x + getRahmenBreite(),
                    pos.y + getRahmenBreite(),
                    gr.x + getRahmenBreite() * 2,
                    gr.y + getRahmenBreite() * 2))
                return;
            bool vSc = hatStyle(Style::VScroll) && vertikalScrollBar;
            bool hSc = hatStyle(Style::HScroll) && horizontalScrollBar;
            rObj.addScrollOffset(hSc ? horizontalScrollBar->getScroll() : 0,
                vSc ? vertikalScrollBar->getScroll() : 0);
            for (int i = dom->getChildCount() - 1; i >= 0; i--)
            { // TODO render elements backwards
                XML::Element* e = dom->zChild(i);
                Zeichnung* z = members->z(e->getAttributeValue("id"),
                    e->getAttributeValue("id").getLength());
                if (z) z->render(rObj);
            }
            rObj.releaseDrawOptions();
        }
    }
}

// Gibt den Dom Tree ohne erhöhten reference counter zurück
// Änderungen am Dom Tree sollten vermieden werden (nur änderungen von
// attributen einzelner elemente sind erlaubt)
XML::Element* UIMLView::zDom() const
{
    return dom;
}

// Gibt den Dom Tree zurück
// Änderungen am Dom Tree sollten vermieden werden (nur änderungen von
// attributen einzelner elemente sind erlaubt)
XML::Element* UIMLView::getDom() const
{
    return dom ? dynamic_cast<XML::Element*>(dom->getThis()) : 0;
}

bool UIMLView::isApplicableFor(XML::Element& element)
{
    for (UIMLElement* e : knownElements)
    {
        if (e->isApplicableFor(element)) return 1;
    }
    return 0;
}

Zeichnung* UIMLView::parseElement(
    XML::Element& element, UIMLContainer& generalFactory)
{
    Text id;
    if (element.hasAttribute("id"))
        id = element.getAttributeValue("id");
    else
    {
        id = Text("_") += nextId++;
        element.setAttribute("id", id);
    }
    Zeichnung* z = members->z(id, id.getLength());
    if (!z)
    {
        // precompute attributes
        if (element.hasAttribute("margin"))
        {
            Text m = element.getAttributeValue("margin");
            if (!element.hasAttribute("margin-left"))
                element.setAttribute("margin-left", m);
            if (!element.hasAttribute("margin-top"))
                element.setAttribute("margin-top", m);
            if (!element.hasAttribute("margin-right"))
                element.setAttribute("margin-right", m);
            if (!element.hasAttribute("margin-bottom"))
                element.setAttribute("margin-bottom", m);
        }
        if (element.hasAttribute("class"))
        {
            Text c = element.getAttributeValue("class");
            while (1)
            {
                Text* t;
                if (c.hat(","))
                    t = c.getTeilText(0, c.positionVon(','));
                else
                    t = new Text(c);
                XML::Editor ce
                    = dom->selectChildsByName("class").whereAttributeEquals(
                        "id", *t);
                for (auto i = ce.begin(); i; i++)
                {
                    for (auto j = i->getAttributeNames(),
                              k = i->getAttributeValues();
                         j && k;
                         j++, k++)
                    {
                        if (!element.hasAttribute(j->getText()))
                            element.setAttribute(j->getText(), i->getText());
                    }
                }
                t->release();
                if (c.hat(","))
                    c.remove(0, c.positionVon(',' + 1));
                else
                    break;
            }
        }
        if (element.hasAttribute("text-align"))
        {
            if (!element.hasAttribute("text-align-horizontal"))
                element.setAttribute("text-align-horizontal",
                    element.getAttributeValue("text-align"));
            if (!element.hasAttribute("text-align-vertical"))
                element.setAttribute("text-align-vertical",
                    element.getAttributeValue("text-align"));
        }
        // create objects
        for (UIMLElement* e : knownElements)
        {
            if (e->isApplicableFor(element))
            {
                z = e->parseElement(element, *this);
                break;
            }
        }
        if (z) members->set(id, id.getLength(), z);
    }
    else
        z->getThis();
    return z;
}

void UIMLView::layout(XML::Element& element,
    Zeichnung& z,
    int pWidth,
    int pHeight,
    UIMLContainer& generalLayouter)
{
    for (UIMLElement* e : knownElements)
    {
        if (e->isApplicableFor(element))
        {
            e->layout(element, z, pWidth, pHeight, *this);
            break;
        }
    }
}

const UIInit& UIMLView::getFactory()
{
    return init;
}

//! calculates the needed size for all content elements to be visible
Punkt UIMLView::calculateContentSize()
{
    Punkt maxP(0, 0);
    for (int i = dom->getChildCount() - 1; i >= 0; i--)
    { // TODO render elements backwards
        XML::Element* e = dom->zChild(i);
        Zeichnung* z = members->z(
            e->getAttributeValue("id"), e->getAttributeValue("id").getLength());
        if (z)
        {
            maxP.x = MAX(maxP.x, z->getPosition().x + z->getBreite());
            maxP.y = MAX(maxP.y, z->getPosition().y + z->getHeight());
        }
    }
    maxP.x += 2 * getRahmenBreite();
    maxP.y += 2 * getRahmenBreite();
    return maxP;
}