#include "connection.h"
#include <QStateMachine>
#include <QTcpSocket>
#include <QHostAddress>
#include <QState>
#include <QFinalState>
/**
  ValidState
  ErrorState
  ExitState

  StartState m_sourceSocket::connected() -> SendVersion ( send version 3.8 to m_sourceSocket )
  SendVersion m_sourceSocket::readyRead() -> SourceSecurityHandshake ( read version from m_sourceSocket )
  SourceSecurityHandshake this::handshakeGood() -> SourceAuthHandshakeState ( send VNCAuth type to m_sourceSocket )
  SourceSecurityHandshake this::handshakeBad() -> FinalState ( send reason )
  SourceAuthHandshakeState m_sourceSocket::readyRead() -> CheckAuthState ( read auth response from m_sourceSocket )
  CheckAuthState this::authSuccessful() -> TargetConnectState ( connect m_targetSocket to selected host )
  CheckAuthState this::authFailure() -> FinalState ( send reason )
  TargetConnectState m_targetSocket::readyRead() -> TargetVersionHandshakeState ( read version from m_targetSocket )
  TargetConnectState m_targetSocket::error() -> FinalState
  TargetVersionHandshakeState this::versionGood() -> TargetSecurityHandshakeState ( send back version 3.8 to m_targetSocket )
  TargetVersionHandshakeState this::versionBad() -> FinalState
  TargetSecurityHandshakeState m_targetSocket::readyRead() -> targetReadSecurityTypesState ( read security types from m_targetSocket )
  targetReadSecurityTypesState this::useVNCAuth() -> TargetSendVNCAuthState ( send back VNCAuth )
  targetReadSecurityTypesState this::useNone() -> TargetSendAuthNone ( send back AuthNone )
  TargetSendVNCAuthState m_targetSocket::readyRead() -> TargetReadAuthChallenge ( send back password hash using challenge )
  TargetSendAuthNone m_targetSocket::readyRead() -> TargetReadSecurityResult
  TargetReadAuthChallenge m_targetSocket::readyRead() -> TargetReadSecurityResult
  TargetReadSecurityResult this::success()  -> SendTargetClientInit ( send back that we are not shared, set target init, check for bytes on the m_sourceSocket )
  TargetReadSecurityResult this::failure() -> FinalState
  SendTargetClientInit this::sourceBytesAvailable() -> DiscardSourceClientInit ( if not source init read client init message and discard it, set source init )
  SendTargetClientInit this::initialized() -> JoinedState
  SendTargetClientInit m_sourceSocket::readyRead() -> DiscardSourceClientInit ( if not source init read client init message and discard it, set source init )
  DiscardSourceClientInit this::initialized() -> JoinedState ( check to see bytes at m_sourceSocket or m_targetSocket )
  JoinedState this::sourceBytesAvailable() -> ForwardSourceToTarget
  JoinedState this::targetBytesAvailable() -> ForwardTargetToSource
  JoinedState m_source::readyRead() -> ForwardSourceToTarget
  JoinedState m_target::readyRead() -> ForwardTargetToSource
  ForwardSourceToTarget m_source::readyRead() -> ForwardSourceToTarget
  ForwardSourceToTarget m_target::readyRead() -> ForwardTargetToSource
  ForwardTargetToSource m_source::readyRead() -> ForwardSourceToTarget
  ForwardTargetToSource m_target::readyRead() -> ForwardTargetToSource

  */
Connection::Connection(QAbstractSocket *source, QObject *parent) :
    QObject(parent), m_sourceSocket(source)
{
    m_targetSocket = new QTcpSocket(this);
    m_connectionStateMachine = new QStateMachine(this);
    QState *validState = new QState(m_connectionStateMachine);
    QState *errorState = new QState(m_connectionStateMachine);
    QFinalState *exitState = new QFinalState(m_connectionStateMachine);

    validState->addTransition(m_sourceSocket, SIGNAL(error(QAbstractSocket::SocketError)), errorState );
    validState->addTransition(m_targetSocket, SIGNAL(error(QAbstractSocket::SocketError)), errorState );
    validState->addTransition(m_sourceSocket, SIGNAL(disconnected()), exitState );
    validState->addTransition(m_targetSocket, SIGNAL(disconnected()), exitState );
    errorState->addTransition(errorState, SIGNAL(finished()), exitState );

    connect( errorState, SIGNAL(entered()), this, SLOT(onErrorState()));
    connect( exitState, SIGNAL(entered()), this, SLOT(onExitState()));

    QState *handshakeState = new QState( QState::ParallelStates, validState );
    QState *joinedState = new QState( validState );
    handshakeState->addTransition(handshakeState, SIGNAL(finished()), joinedState );

    QState *sourceHandshakeState = new QState( handshakeState );
    QState *targetHandshakeState = new QState( handshakeState );

    QState *sourceSendVersionState = new QState( sourceHandshakeState );
    QState *sourceHandshakeVersionState = new QState( sourceHandshakeState );
    QState *sourceSendSecurityTypesState = new QState( sourceHandshakeState );
    QState *sourceSecurityHandshakeState = new QState( sourceHandshakeState );
    QState *sourceSendChallengeState = new QState( sourceHandshakeState );
    QState *sourceAuthHandshakeState = new QState( sourceHandshakeState );
    QState *sourceCheckAuthState = new QState( sourceHandshakeState );
    QState *sourceSendAuthResultState = new QState( sourceHandshakeState );
    QFinalState *sourceDiscardClientInitState = new QFinalState( sourceHandshakeState );
    QFinalState *sourceSendErrorResponseState = new QFinalState( sourceHandshakeState );
    connect( sourceSendVersionState, SIGNAL(entered()), this, SLOT(onSourceSendVersionState()));
    connect( sourceHandshakeVersionState, SIGNAL(entered()), this, SLOT(onSourceHandshakeVersionState()));
    connect( sourceSendSecurityTypesState, SIGNAL(entered()), this, SLOT(onSourceSendSecurityTypesState()));
    connect( sourceSecurityHandshakeState, SIGNAL(entered()),this, SLOT(onSourceSecurityHandshakeState()));
    connect( sourceSendChallengeState, SIGNAL(entered()), this, SLOT(onSourceSendChallengeState()));
    connect( sourceSendErrorResponseState, SIGNAL(entered()), this, SLOT(onSourceSendErrorResponseState()));
    connect( sourceAuthHandshakeState, SIGNAL(entered()),this, SLOT(onSourceAuthHandshakeState()));
    connect( sourceCheckAuthState, SIGNAL(entered()),this, SLOT(onSourceCheckAuthState()));
    connect( sourceSendAuthResultState, SIGNAL(entered()), this, SLOT(onSourceSendAuthResultState()));
    connect( sourceDiscardClientInitState, SIGNAL(entered()),this, SLOT(onSourceDiscardClientInitState()));
    sourceSendVersionState->addTransition( m_sourceSocket, SIGNAL(readyRead()), sourceHandshakeVersionState);
    sourceHandshakeVersionState->addTransition( this, SIGNAL(sourceVersionHandshakeSuccess()), sourceSendSecurityTypesState );
    sourceHandshakeVersionState->addTransition( this, SIGNAL(sourceVersionHandshakeFailure()), exitState );
    sourceSendSecurityTypesState->addTransition( m_sourceSocket, SIGNAL(readyRead()), sourceSecurityHandshakeState);
    sourceSecurityHandshakeState->addTransition( this, SIGNAL(sourceSecurityHandshakeSuccess()), sourceSendChallengeState );
    sourceSecurityHandshakeState->addTransition( this, SIGNAL(sourceSecurityHandshakeFailure()), sourceSendErrorResponseState );
    sourceSendChallengeState->addTransition(m_sourceSocket, SIGNAL(readyRead()), sourceCheckAuthState );
    sourceCheckAuthState->addTransition( this, SIGNAL(sourceAuthSuccess()), sourceSendAuthResultState );
    sourceCheckAuthState->addTransition( this, SIGNAL(sourceAuthFailure()), sourceSendErrorResponseState );
    sourceSendAuthResultState->addTransition( m_sourceSocket, SIGNAL(readyRead()), sourceDiscardClientInitState );

    QState *targetConnectState = new QState( targetHandshakeState );
    QState *targetVersionHandshakeState = new QState( targetHandshakeState );
    QState *targetSendVersionResponseState = new QState( targetHandshakeState );
    QState *targetSecurityHandshakeState = new QState( targetHandshakeState );
    QState *targetReadSecurityTypeState = new QState( targetHandshakeState );
    QState *targetSendVNCAuthState = new QState( targetHandshakeState );
    QState *targetSendAuthNoneState = new QState( targetHandshakeState );
    QState *targetReadAuthChallengeState = new QState( targetHandshakeState );
    QState *targetReadSecurityResultState = new QState( targetHandshakeState );
    QFinalState *targetSendClientInitState = new QFinalState( targetHandshakeState );
    connect( targetConnectState, SIGNAL(entered()), this, SLOT(onTargetConnectState()));
    connect( targetVersionHandshakeState, SIGNAL(entered()), this, SLOT(onTargetVersionHandshakeState()));
    connect( targetSendVersionResponseState, SIGNAL(entered()), this, SLOT(onTargetSendVersionResponseState()));
    connect( targetSecurityHandshakeState, SIGNAL(entered()), this, SLOT(onTargetSecurityHandshakeState()));
    connect( targetReadSecurityTypeState, SIGNAL(entered()), this, SLOT(onTargetReadSecurityTypeState()));
    connect( targetSendVNCAuthState, SIGNAL(entered()), this, SLOT(onTargetSendVNCAuthState()));
    connect( targetSendAuthNoneState, SIGNAL(entered()), this, SLOT(onTargetSendAuthNoneState()));
    connect( targetReadAuthChallengeState, SIGNAL(entered()), this, SLOT(onTargetReadAuthChallengeState()));
    connect( targetReadSecurityResultState, SIGNAL(entered()), this, SLOT(onTargetReadSecurityResultState()));
    connect( targetSendClientInitState, SIGNAL(entered()), this, SLOT(onTargetSendClientInitState()));
    targetConnectState->addTransition( m_targetSocket, SIGNAL(readyRead()), targetVersionHandshakeState );
    targetVersionHandshakeState->addTransition( this, SIGNAL(targetVersionHandshakeSuccess()), targetSendVersionResponseState );
    targetVersionHandshakeState->addTransition( this, SIGNAL(targetVersionHandshakeFailure()), errorState);
    targetSendVersionResponseState->addTransition( m_targetSocket, SIGNAL(readyRead()), targetSecurityHandshakeState );
    targetSecurityHandshakeState->addTransition( m_targetSocket, SIGNAL(readyRead()), targetReadSecurityTypeState );
    targetReadSecurityTypeState->addTransition( this, SIGNAL(targetUsesVNCAuth()), targetSendVNCAuthState );
    targetReadSecurityTypeState->addTransition( this, SIGNAL(targetUsesNoAuth()), targetSendAuthNoneState );
    targetReadSecurityTypeState->addTransition( this, SIGNAL(targetUsesUnsupportedAuth()), errorState );
    targetSendVNCAuthState->addTransition(m_targetSocket, SIGNAL(readyRead()), targetReadAuthChallengeState );
    targetReadAuthChallengeState->addTransition(m_targetSocket, SIGNAL(readyRead()), targetReadSecurityResultState );
    targetSendAuthNoneState->addTransition(m_targetSocket, SIGNAL(readyRead()), targetReadSecurityResultState );
    targetReadSecurityResultState->addTransition(this, SIGNAL(targetAuthSuccess()), targetSendClientInitState );
    targetReadSecurityResultState->addTransition( this, SIGNAL(targetAuthFailure()), errorState );

    QState *forwardSourceToTargetState = new QState( joinedState );
    QState *forwardTargetToSourceState = new QState( joinedState );
    connect( forwardSourceToTargetState, SIGNAL(entered()), this, SLOT(onForwardSourceToTargetState()));
    connect( forwardTargetToSourceState, SIGNAL(entered()), this, SLOT(onForwardTargetToSourceState()));
    forwardSourceToTargetState->addTransition( m_targetSocket, SIGNAL(readyRead()), forwardTargetToSourceState );
    forwardSourceToTargetState->addTransition( m_sourceSocket, SIGNAL(readyRead()), forwardSourceToTargetState );
    forwardTargetToSourceState->addTransition( m_sourceSocket, SIGNAL(readyRead()), forwardSourceToTargetState );
    forwardTargetToSourceState->addTransition( m_targetSocket, SIGNAL(readyRead()), forwardTargetToSourceState );
    joinedState->setInitialState( forwardTargetToSourceState );

    connect( m_connectionStateMachine, SIGNAL(finished()), this, SLOT(deleteLater()));

    validState->setInitialState( sourceSendVersionState );
    m_connectionStateMachine->setInitialState( validState );
    m_connectionStateMachine->start();
}

void Connection::onSourceSendVersionState()
{


}

void Connection::onSourceSecurityHandshakeState()
{


}

void Connection::onSourceSendSecurityTypesState()
{


}

void Connection::onSourceSendErrorResponseState()
{


}

void Connection::onSourceSendChallengeState()
{


}

void Connection::onSourceAuthHandshakeState()
{


}

void Connection::onSourceCheckAuthState()
{


}

void Connection::onSourceSendAuthResultState()
{


}

void Connection::onSourceDiscardClientInitState()
{


}


void Connection::onTargetConnectState()
{


}

void Connection::onTargetVersionHandshakeState()
{


}

void Connection::onTargetSendVersionResponseState()
{


}

void Connection::onTargetSecurityHandshakeState()
{


}

void Connection::onTargetReadSecurityTypeState()
{


}

void Connection::onTargetSendVNCAuthState()
{


}

void Connection::onTargetSendAuthNoneState()
{


}

void Connection::onTargetReadAuthChallengeState()
{


}

void Connection::onTargetReadSecurityResultState()
{


}

void Connection::onTargetSendClientInitState()
{


}


void Connection::onForwardSourceToTargetState()
{


}

void Connection::onForwardTargetToSourceState()
{


}

void Connection::onErrorState()
{

}

void Connection::onExitState()
{

}

