#pragma once

#include "Array.h"
#include "Trie.h"
#include "UIInitialization.h"
#include "Zeichnung.h"

namespace Framework
{
    class Text;
    class ObjTabelle;
    class Schrift;
    class Bildschirm;
    class UIMLContainer;

    namespace XML
    {
        class Element;
    }

    class UIMLElement : public virtual ReferenceCounter
    {
    public:
        DLLEXPORT UIMLElement();
        DLLEXPORT virtual ~UIMLElement();
        //! prüft, ob dieses UIML Element für ein bestimmtes xml Element
        //! zuständig ist
        virtual bool isApplicableFor(XML::Element& element) = 0;
        //! erstellt eine neue Zeichnung zu einem gegebenen xml Element
        virtual Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory)
            = 0;
        //! wendet die layout parameter zu einer Zeichnung an
        DLLEXPORT virtual void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter);
    };

    class UIMLContainer : public UIMLElement
    {
    public:
        DLLEXPORT UIMLContainer();
        DLLEXPORT virtual ~UIMLContainer();
        virtual Zeichnung* zZeichnungById(const char* id) = 0;
        virtual Zeichnung* getZeichnungById(const char* id) = 0;
        virtual const UIInit& getFactory() = 0;
    };

    class UIMLTextField : public UIMLElement
    {
    public:
        DLLEXPORT UIMLTextField();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLButton : public UIMLElement
    {
    public:
        DLLEXPORT UIMLButton();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLCheck : public UIMLElement
    {
    public:
        DLLEXPORT UIMLCheck();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLText : public UIMLElement
    {
    public:
        DLLEXPORT UIMLText();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLTextArea : public UIMLElement
    {
    public:
        DLLEXPORT UIMLTextArea();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLTable : public UIMLElement
    {
    public:
        DLLEXPORT UIMLTable();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    class UIMLFrame : public UIMLElement
    {
    public:
        DLLEXPORT UIMLFrame();
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
    };

    /**
      KSG UIML Standart
      possible XML elements:
        - uimlview (the root element of uiml),
        - class (only as direct child of uimlview),
        - textfield,
        - button,
        - check, (KontrollKnopf)
        - text,
        - textarea,
        - table (allowed child elements: tr),
        - tr (allowed child elements: textfield, button, table, text, textarea,
      frame),
        - frame (allowed child elements: textfield, button, table, text,
      textarea, frame). possible global XML attributes:
        - id (string should be unique),
        - x (integer, optional % char at end),
        - y (integer, optional % char at end),
        - width (integer, optional % char at end) or auto keyword,
        - height (integer, optional % char at end) or auto keyword,
        - margin (integer, optional % char at end),
        - margin-left (integer, optional % char at end),
        - margin-top (integer, optional % char at end),
        - margin-right (integer, optional % char at end),
        - margin-bottom (integer, optional % char at end),
        - align-left (string (id values of other elements or keywords: start,
      end, center)),
        - align-top (string (id values of other elements or keywords: start,
      end, center)),
        - align-bottom ((string (id values of other elements or keywords: start,
      end, center)),
        - align-right (string (id values of other elements or keywords: start,
      end, center)),
        - tooltip (string),
        - style (hex __int64),
        - class (string (id of class element))

        attribute die sich gegenseitig ausschließen:
        - align-left / align-right
        - align-top / align-bottom

      spezific attributes:
         - font-size (textfield, text, textarea, button)
         - text-align (textfield, text, textarea)
         - text-align-horizontal (textfield, text, textarea)
         - text-align-vertical (textfield, text, textarea)

      example:
        \code
        <view>
          <textfield id="element_at_top_left" align-left="start",
      align-top="start", margin-left="5", margin-top="5" width="90%"
      height="30"/> <table id="element_below_textfield" align-left="start",
      aliign-top="element_at_top_left", margin-left="5", margin-top="5"
      width="90%" height="300"> <tr> <button id="a_button_in_a_table"/>
              <textfield id="a_textfield_in_a_table"/>
            </tr>
          </table>
        </view>
        \endcode
    */
    class UIMLView : public ZeichnungHintergrund,
                     public UIMLContainer
    {
    private:
        RCArray<UIMLElement> knownElements;
        UIInit init;
        Trie<Zeichnung>* members;
        XML::Element* dom;
        int nextId;

        //! Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch
        //! aufgerufen. \param me Das Ereignis
        DLLEXPORT virtual void doMausEreignis(
            MausEreignis& me, bool userRet) override;

    public:
        //! Erstellt eine UIML View
        DLLEXPORT UIMLView();
        //! Erstellt eine UIML View zu einem UIML Text
        //! \param uiml Ein xml element gemät des KSG UIML standarts
        //! \param screen Ein zeiger für den Belschirm auf dem die tooltips
        //! angezeigt werden sollen \param schrift Die schrift mit der der Text
        //! gezeichnet werden soll
        DLLEXPORT UIMLView(XML::Element* uiml, UIInit& init);
        //! Erstellt eine UIML View zu einem UIML Text
        //! \param uiml Ein xml text gemät des KSG UIML standarts
        //! \param screen Ein zeiger für den Belschirm auf dem die tooltips
        //! angezeigt werden sollen \param schrift Die schrift mit der der Text
        //! gezeichnet werden soll
        DLLEXPORT UIMLView(Text uiml, UIInit& init);
        DLLEXPORT ~UIMLView();
        //! entfernt alle bekannten elemente, die im uiml verwendet werden
        //! können
        DLLEXPORT void removeAllKnownElements();
        //! fügt ein neues bekanntes element hinzu, dass danach im uiml
        //! verwendet werden kann.
        DLLEXPORT void addKnownElement(UIMLElement* element);
        //! prüft, ob ein xml Element ein bekanntes uiml Element ist;
        DLLEXPORT bool isKnownElement(XML::Element* zElement);
        //! setzt den inhalt der view
        //! \param uiml Ein xml element gemät des KSG UIML standarts
        DLLEXPORT void setUIML(XML::Element* uiml);
        //! setzt den inhalt der view
        //! \param uiml Ein xml text gemät des KSG UIML standarts
        DLLEXPORT void setUIML(Text uiml);
        //! aktualisiert größe und position aller Zeichnungen gemäß den
        //! spezifikationen in UIML
        DLLEXPORT void layout();
        //! fügt ein element hinzu
        //! \param uiml Ein xml text gemät des KSG UIML standarts, welcher das
        //! neue Objekt darstellt \return id des neuen Elements
        DLLEXPORT Text addMember(Text uiml);
        //! fügt ein element zu einem Elternelement hinzu (funktioniert momentan
        //! nur mit frame Objekten) \param uiml Ein xml text gemät des KSG UIML
        //! standarts, welcher das neue Objekt darstellt \return id des neuen
        //! Elements
        DLLEXPORT Text addMember(Text uiml, Text parentId);
        //! entfernt ein element
        //! \param id id des Elements
        DLLEXPORT void removeMember(Text id);
        //! Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat
        //! \param id die id der Zeichnung
        DLLEXPORT Zeichnung* zZeichnungById(const char* id) override;
        //! Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat
        //! \param id die id der Zeichnung
        DLLEXPORT Zeichnung* getZeichnungById(const char* id) override;
        //! Verarbeitet ein Tastatur Ereignis. Wird vom Framework automatisch
        //! aufgerufen \param te Das Ereignis
        DLLEXPORT virtual void doTastaturEreignis(TastaturEreignis& te);
        //! Updated den Zeichenhintergrund
        //! \param 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
        DLLEXPORT bool tick(double tickVal) override;
        //! Zeichnet den Hintergrund eines Zeichnunges nach rObj
        DLLEXPORT void render(Bild& rObj) override;
        //! 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)
        DLLEXPORT XML::Element* zDom() const;
        //! Gibt den Dom Tree zurück
        //! Änderungen am Dom Tree sollten vermieden werden (nur änderungen von
        //! attributen einzelner elemente sind erlaubt)
        DLLEXPORT XML::Element* getDom() const;
        DLLEXPORT bool isApplicableFor(XML::Element& element) override;
        DLLEXPORT Zeichnung* parseElement(
            XML::Element& element, UIMLContainer& generalFactory) override;
        DLLEXPORT void layout(XML::Element& element,
            Zeichnung& z,
            int pWidth,
            int pHeight,
            UIMLContainer& generalLayouter) override;
        DLLEXPORT const UIInit& getFactory() override;
        //! calculates the needed size for all content elements to be visible
        DLLEXPORT Punkt calculateContentSize();
    };
} // namespace Framework