#include "telnetd.hpp"
#include "telnetd_cli.hpp"

TelnetDaemon::TelnetDaemon(TCore* acore,  QObject *parent)
: inherited(parent)
, core(acore)
{
}

void TelnetDaemon::cli_init(){
    cli_api = std::make_unique<CLITelnetDaemon>( name() , *this);
    cli_api->registerCmd();
}

TelnetDaemon::~TelnetDaemon(){
    core->logf( ILogger::vINFO, "daemon %s closed\n", name());
}

const char* TelnetDaemon::name(){
    if (_name.empty()){
        _name = str_printf("%u", serverPort());
    }
    return _name.c_str();
}

bool TelnetDaemon::listen(const QHostAddress &address, quint16 port){
    bool ok = inherited::listen(address, port); 
    core->logf(ILogger::vINFO, (ok)? "daemon %s listen on %s:%u\n" 
                                   : "daemon %s failed to listen %s:%u\n"
                            , name() 
                            , address.toString().toStdString().c_str(), port
               );
    if (ok)
        cli_init();
    else
        close();
    return ok;
}

void TelnetDaemon::close(){
    core->logf( ILogger::vINFO, "daemon %s close\n", name());
    inherited::close();
}

TelnetDaemon::service_t* TelnetDaemon::new_service( unsigned id, qintptr handle){
    //core->logf( ILogger::vINFO, "daemon %s[%u] incoming sock %u\n"
    //            , name(), id, handle);
    return new TelnetShell( handle, str_printf("telnet%u", id), core );
}

void TelnetDaemon::destroy(){
    close();
    deleteLater();
}

void TelnetDaemon::shutdown(){
    terminate_all();
    destroy();
}

bool TelnetDaemon::event(::QEvent *ev){
	if (ev->type() == evShutdown.type()){
		shutdown();
		return true;
	}
	else if (ev->type() == evDestroy.type()){
		destroy();
		return true;
	}
	return QObject::event(ev);
}

TelnetDaemon::QEvent	TelnetDaemon::evDestroy;
TelnetDaemon::QEvent	TelnetDaemon::evShutdown;



//----------------------------------------------------------------------------
TelnetShell::TelnetShell(portid port, const std::string& shell_name
						, TCore* acore)
:inherited(port, shell_name, acore)
, core(acore)
, info_cli("info", this, &TelnetShell::cli_info)
{
	info_cli.registerCmd( &shell() );
	static const char* info_help = "info\t- show info on this shell connection\n";
	info_cli.help_banner = info_help;

	core->logf( ILogger::vINFO, "%s start on sock %u for remote %s:%u\n"
	            , name.c_str(), port
	            , _port.peerAddress().toString().toStdString().c_str()
	            , _port.peerPort()
	            );
}

TelnetShell::~TelnetShell()
{
	core->logf( ILogger::vINFO, "%s closed for remote %s:%u\n"
	            , name.c_str()
	            , _port.peerAddress().toString().toStdString().c_str()
	            , _port.peerPort()
	            );
}

int TelnetShell::cli_info(CLI_shell* shell, cli::const_line line){
	shell->printf("%s: listen port:%u for remote %s:%u\n"
	              , name.c_str()
	              , _port.localPort()
				  , _port.peerAddress().toString().toStdString().c_str()
				  , _port.peerPort()
	              );
	(void)line;
	return 0;
}

