#include <main.h>
#include <Fenster.h>
#include <Bildschirm.h>
#include <RenderThread.h>
#include <TextFeld.h>
#include <iostream>
#include <Schrift.h>
#include <DateiSystem.h>
#include "TestThread.h"
#include <Network.h>

// Output
template <class charT, class traits = std::char_traits<charT> >
class CDG_CoutRerouteStr : public std::basic_streambuf<charT, traits>
{
private:
    Framework::TextFeld * tf;
public:
    CDG_CoutRerouteStr( Framework::TextFeld *tf )
    {
        this->tf = tf;
    };
protected:
    std::streamsize xsputn( const charT * pChar, std::streamsize n )
    {
        Framework::Text tmp( pChar );
        tf->lockZeichnung();
        if( tmp.getText()[ 0 ] == 1 && tf->zText()->getText()[ tf->zText()->getLength() - 2 ] == 1 )
        {
            int anz = tf->zText()->anzahlVon( 1 );
            tf->zText()->ersetzen( tf->zText()->positionVon( 1, anz - 2 ), tf->zText()->getLength(), tmp );
        }
        else
            tf->zText()->append( pChar );
        tf->setRender();
        tf->updateVScroll();
        if( tf->zText()->anzahlVon( '\n' ) > 1000 )
            tf->zText()->remove( 0, tf->zText()->positionVon( '\n' ) + 1 );
        tf->unlockZeichnung();
        return strlen( pChar );
    }

    typedef typename traits::int_type int_type;
    int_type overflow( int_type ch ) override
    {
        tf->zText()->append( (char)ch );
        return 1;
    }
}; 

template <class charT, class traits = std::char_traits<charT> >
class CDG_CerrRerouteStr : public std::basic_streambuf<charT, traits>
{
private:
    Framework::TextFeld * tf;
public:
    CDG_CerrRerouteStr( Framework::TextFeld *tf )
    {
        this->tf = tf;
    };
protected:
    std::streamsize xsputn( const charT * pChar, std::streamsize n )
    {
        tf->lockZeichnung();
        tf->zText()->append( "\r0xFFFF0000" );
        tf->zText()->append( pChar );
        tf->zText()->append( "\r0xFFFFFFFF" );
        tf->setRender();
        tf->updateVScroll();
        tf->updateHScroll();
        if( tf->zText()->anzahlVon( '\n' ) > 1000 )
            tf->zText()->remove( 0, tf->zText()->positionVon( '\n' ) + 1 );
        tf->unlockZeichnung();
        return strlen( pChar );
    }

    typedef typename traits::int_type int_type;
    int_type overflow( int_type ch ) override
    {
        tf->zText()->append( "\r0xFFFF0000" );
        tf->zText()->append( (char)ch );
        tf->zText()->append( "\r0xFFFFFFFF" );
        return 1;
    }
};

int Framework::Start( Framework::Startparam p )
{
    Network::Start( 100 );
    WNDCLASS wc = Framework::F_Normal( p.hinst );
    wc.lpszClassName = "Server System Checker";
    WFenster frame;
    frame.erstellen( WS_OVERLAPPEDWINDOW, wc );
    Punkt pos( 100, 100 );
    frame.setPosition( pos );
    frame.setSize( 600, 400 );
    frame.setMausAktion( _ret1ME );
    frame.setTastaturAktion( []( void *param, void *obj, TastaturEreignis te ) -> bool
    {
        if( te.id == TE_Release )
            std::cin.putback( te.taste );
        return 1;
    } );
    frame.setVSchließAktion( []( void*, void*f )
    {
        StopNachrichtenSchleife( ( (WFenster*)f )->getFensterHandle() );
    } );
    frame.setAnzeigeModus( 1 );
    frame.setNSchließAktion( []( void *param, void *object )
    {
        StopNachrichtenSchleife( ( (WFenster*)object )->getFensterHandle() );
    } );

    Bildschirm3D screen( frame.getThis() );
    frame.setBildschirm( screen.getThis() );
    screen.update();

    RenderTh thread;
    thread.setBildschirm( screen.getThis() );
    thread.beginn();

    LTDSDatei d;
    d.setPfad( new Text( "console.ltds" ) );
    d.leseDaten();
    Schrift *schrift = d.ladeSchrift();

    TextFeld console;
    console.setStyle( TextFeld::Style::Scroll | TextFeld::Style::Mehrfarbig | TextFeld::Style::Mehrzeilig | TextFeld::Style::Sichtbar );
    console.setSize( screen.getBackBufferSize() );
    console.setSchriftFarbe( 0xFFFFFFFF );
    console.setSchriftZ( schrift );
    console.setMausEreignis( _ret1ME );
    console.setText( "" );
    screen.addMember( &console );

    // output umleiten...
    CDG_CoutRerouteStr<char> str( &console );
    std::streambuf* old_buffer = std::cout.rdbuf();
    std::cout.rdbuf( &str );
    CDG_CerrRerouteStr<char> err( &console );
    std::streambuf* old_errbuffer = std::cerr.rdbuf();
    std::cerr.rdbuf( &err );

    TestThread tests;

    StartNachrichtenSchleife();

    tests.abbrechen();
    tests.warteAufThread( 10000 );
    tests.ende();
    
    std::cout.rdbuf( old_buffer );
    std::cerr.rdbuf( old_errbuffer );

    thread.beenden();

    frame.setBildschirm( 0 );
    frame.zerstören();

    Network::Exit();

    return 0;
}