#include "ToolTip.h"
#include "TextFeld.h"
#include "Text.h"
#include "AlphaFeld.h"
#include "Bild.h"
#include "MausEreignis.h"
#include "Schrift.h"
#include "Bildschirm.h"
#include "Rahmen.h"
#include "Scroll.h"

using namespace Framework;

// Inhalt der ToolTip Klasse aus ToolTip.h
// Konstruktor
ToolTip::ToolTip( Bildschirm *zScreen )
    : ZeichnungHintergrund(),
    size( 0, 0 ),
    animationSpeed( 250 ),
    warten( 1 ),
    wartenCount( 0 ),
    tval( 0 ),
    mausIn( 0 ),
    alpha( 0 ),
    sichtbar( 0 ),
    zeichnen( 0 ),
    bildschirm( zScreen ),
    onShow( 0 ),
    onHide( 0 )
{
    style = Style::MEIgnoreInside | Style::MEIgnoreParentInside | Style::MEIgnoreSichtbar | Style::MEIgnoreVerarbeitet | Style::Erlaubt;
    members = new RCArray< Zeichnung >();
    bildschirm->addToolTip( (ToolTip*)this->getThis() );
    setMausEreignis( _ret1ME );
}

// Destruktor
ToolTip::~ToolTip()
{
    members->release();
}

void ToolTip::doMausEreignis( MausEreignis &me, bool userRet )
{
    if( !sichtbar )
        pos.x += me.mx, pos.y += me.my + 15;
    if( hatStyleNicht( Style::Sichtbar ) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet )
    {
        mausIn2 = 0;
        if( !mausIn && sichtbar )
        {
            if( onHide && sichtbar )
                onHide( this );
            sichtbar = 0;
        }
        bool verarbeitet = me.verarbeitet;
        me.verarbeitet |= hatStyleNicht( Style::Sichtbar );
        bool insideParent = me.insideParent;
        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( me.id != ME_Betritt && me.id != ME_Leaves )
        {
            for( int i = members->getEintragAnzahl() - 1; i >= 0; i-- )
                members->z( i )->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();
        me.insideParent = insideParent;
        if( hatStyleNicht( Style::Sichtbar ) )
            me.verarbeitet = verarbeitet;
        return;
    }
    mausIn2 = 1;
    if( sichtbar )
    {
        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();
        for( auto z = members->getIterator(); z; 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( sichtbar )
        me.verarbeitet = 1;
    if( alpha )
        rend = 1;
}

// F�gt eine Zeichnung zum Tooltip hinzu
//  m: die neue Zeichnung
void ToolTip::addMember( Zeichnung *m )
{
    members->add( m );
}

void ToolTip::removeMember( Zeichnung *zM )
{
    int index = 0;
    for( auto i = members->getIterator(); i; i++, index++ )
    {
        if( i._ == zM )
        {
            members->remove( index );
            return;
        }
    }
}

// Entfernt eine Zeichnung vom Tooltip
//  i: der Index der Zeichnung
void ToolTip::removeMember( int i )
{
    members->remove( i );
}

// setzt eine Funktion, die aufgerufen wird, sobald der Tooltip angezeigt wird
//  onShow: Die Funktion
void ToolTip::setShowEvent( std::function< void( ToolTip * ) > onShow )
{
    this->onShow = onShow;
}

// setzt eine Funktion, die aufgerufen wird, sobald der Tooltip nicht mehr angezeigt wird
//  onShow: Die Funktion
void ToolTip::setHideEvent( std::function< void( ToolTip * ) > onHide )
{
    this->onHide = onHide;
}

void ToolTip::setWarten( double warten )
{
    this->warten = warten;
}

void ToolTip::setAnimationSpeed( double speed )
{
    animationSpeed = speed;
}

void ToolTip::setMausIn( bool mausIn )
{
    if( this->mausIn != mausIn )
        rend = 1;
    this->mausIn = mausIn;
    if( !mausIn && !mausIn2 && sichtbar )
    {
        if( sichtbar && onHide )
            onHide( this );
        sichtbar = 0;
    }
}

void ToolTip::wartenReset()
{
    wartenCount = 0;
}

void ToolTip::setZeichnen()
{
    zeichnen = 1;
}

bool ToolTip::tick( double tickVal )
{
    for( auto z = members->getIterator(); z; z++ )
    {
        size.x = MAX( size.x, z->getX() + z->getBreite() + 2 * getRahmenBreite() );
        size.y = MAX( size.y, z->getY() + z->getHeight() + 2 * getRahmenBreite() );
    }
    this->tval += tickVal * animationSpeed;
    int val = (int)this->tval;
    if( val < 1 )
    {
        bool ret = rend;
        rend = 0;
        return ret;
    }
    this->tval -= val;
    if( !sichtbar )
    {
        if( alpha )
        {
            if( alpha - val < 0 )
                alpha = 0;
            else
                alpha = (unsigned char)( alpha - val );
            rend = 1;
        }
        if( mausIn )
        {
            wartenCount += tickVal;
            if( wartenCount >= warten )
            {
                if( onShow )
                    onShow( this );
                sichtbar = 1;
                wartenCount = 0;
                alpha = 0xFF;
                ZeichnungHintergrund::setSize( 0, 0 );
            }
        }
        else
            wartenCount = 0;
    }
    else
    {
        if( getBreite() < size.x )
        {
            ZeichnungHintergrund::setSize( getBreite() + val, getHeight() );
            if( getBreite() > size.x )
                ZeichnungHintergrund::setSize( size.x, getHeight() );
            rend = 1;
        }
        if( getHeight() < size.y )
        {
            ZeichnungHintergrund::setSize( getBreite(), getHeight() + val );
            if( getHeight() > size.y )
                ZeichnungHintergrund::setSize( getBreite(), size.y );
            rend = 1;
        }
    }
    return ZeichnungHintergrund::tick( tickVal );
}

void ToolTip::render( Bild &zRObj )
{
    if( alpha && ( zeichnen || mausIn2 ) )
    {
        zRObj.setAlpha( alpha );
        setPosition( pos );
        if( getX() + getBreite() > zRObj.getBreite() )
            setPosition( getX() - ( getX() + getBreite() - zRObj.getBreite() ), getY() );
        if( getY() + getHeight() > zRObj.getHeight() )
            setPosition( getX(), getY() - ( getY() + getHeight() - zRObj.getHeight() ) );
        ZeichnungHintergrund::render( zRObj );
        Punkt p = pos;
        Punkt s = gr;
        if( hatStyle( ZeichnungHintergrund::Style::Rahmen ) )
        {
            p += Punkt( getRahmenBreite(), getRahmenBreite() );
            s -= Punkt( getRahmenBreite(), getRahmenBreite() ) * 2;
        }
        if( !zRObj.setDrawOptions( p, s ) )
        {
            zRObj.releaseAlpha();
            zeichnen = 0;
            return;
        }
        bool vSc = hatStyle( Style::VScroll ) && vertikalScrollBar;
        bool hSc = hatStyle( Style::HScroll ) && horizontalScrollBar;
        zRObj.addScrollOffset( hSc ? horizontalScrollBar->getScroll() : 0, vSc ? vertikalScrollBar->getScroll() : 0 );
        for( auto z = members->getIterator(); z; z++ )
            z->render( zRObj );
        zRObj.releaseDrawOptions();
        zRObj.releaseAlpha();
        zeichnen = 0;
    }
}

// constant
Bildschirm *ToolTip::zBildschirm() const
{
    return bildschirm;
}

// Gibt ein bestimmten member zur�ck (ohne erh�hten Reference Counter)
//  i: der Index des Members
Zeichnung *ToolTip::zMember( int i ) const
{
    return members->z( i );
}

// Gibt ein bestimmten member zur�ck
//  i: der Index des Members
Zeichnung *ToolTip::getMember( int i ) const
{
    return members->get( i );
}

// Gibt die Anzahl an Zeichnungen zur�ck, die zum Tooltip geh�ren
int ToolTip::getMemberAnzahl() const
{
    return members->getEintragAnzahl();
}

// Erzeugt eine komplette kopie eines tooltip
Zeichnung *ToolTip::dublizieren() const
{
    ToolTip *ret = new ToolTip( bildschirm );
    ret->size = size;
    ret->animationSpeed = animationSpeed;
    ret->warten = warten;
    ret->wartenCount = wartenCount;
    ret->tval = tval;
    ret->mausIn = mausIn;
    ret->alpha = alpha;
    ret->sichtbar = sichtbar;
    ret->zeichnen = zeichnen;
    ret->mausIn2 = mausIn2;
    for( auto z = members->getIterator(); z; z++ )
        ret->addMember( z->getThis() );
    return ret;
}

// Reference Counting
Zeichnung *ToolTip::release()
{
    if( ref == 1 )
    {
        Zeichnung::release();
        return 0;
    }
    else
        Zeichnung::release();
    if( ref == 1 )
    {
        members->leeren();
        if( !bildschirm->removeToolTip( this ) )
            delete this;
    }
    return 0;
}