#include "FlowSshNetIncludes.h"
#include "FlowSshNet.h"


#if defined(_DEBUG) && defined(_CRTDBG_MAP_ALLOC)
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif



namespace Bitvise {
namespace FlowSshNet {


// ProgressHandlerCpp

void ProgressHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void ProgressHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::ProgressHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();	
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }	
}

void ProgressHandlerCpp::OnProgress(unsigned int taskSpecificStep)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnProgress(taskSpecificStep);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ProgressHandlerCpp::OnSuccess()
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnSuccess();
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ProgressHandlerCpp::OnError(unsigned int taskSpecificStep, std::wstring const& auxInfo)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(taskSpecificStep, Helper::WStrToNetStr(auxInfo));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ForwardingHandlerCpp

void ForwardingHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void ForwardingHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::ForwardingHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();	
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }	
}

void ForwardingHandlerCpp::OnSuccess(unsigned int listPort)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnSuccess(listPort);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ForwardingHandlerCpp::OnError(FlowSshCpp::ForwardingErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::ForwardingErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ClientCpp

void ClientCpp::OnSshVersion(std::wstring const& version)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnSshVersion(Helper::WStrToNetStr(version));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

bool ClientCpp::OnHostKey(FlowSshCpp::RefPtr<FlowSshCpp::PublicKey> publicKey)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return false;

		AutoKeepAlive keepAlive(flowSshNet);
		return flowSshNet->Raise_OnHostKey(gcnew FlowSshNet::PublicKey(publicKey));
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

void ClientCpp::OnKexDone(unsigned __int64 kexNr, bool incoming, std::wstring const& kexAlg, std::wstring const& encAlg, std::wstring const& macAlg, std::wstring const& cmprAlg)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;
		
		flowSshNet->Raise_OnKexDone(kexNr, incoming, Helper::WStrToNetStr(kexAlg), Helper::WStrToNetStr(encAlg), Helper::WStrToNetStr(macAlg), Helper::WStrToNetStr(cmprAlg));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

bool ClientCpp::OnFurtherAuth(FlowSshCpp::Client::FurtherAuth& furtherAuth)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return false;

		AutoKeepAlive keepAlive(flowSshNet);
		return flowSshNet->Raise_OnFurtherAuth(gcnew FlowSshNet::FurtherAuth(&furtherAuth));
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

bool ClientCpp::OnPasswordChange(FlowSshCpp::Client::PasswordChange& passwordChange)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return false;

		AutoKeepAlive keepAlive(flowSshNet);
		return flowSshNet->Raise_OnPasswordChange(gcnew FlowSshNet::PasswordChange(&passwordChange));
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

void ClientCpp::OnBanner(std::wstring const& banner)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnBanner(Helper::WStrToNetStr(banner));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientCpp::OnSessionIdReply(unsigned int code)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnSessionIdReply(code);
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientCpp::OnServerNotice(unsigned int severity, std::wstring const& facility, std::wstring const& status, std::wstring const& description)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		AutoKeepAlive keepAlive(flowSshNet);
		flowSshNet->Raise_OnServerNotice(severity, Helper::WStrToNetStr(facility), Helper::WStrToNetStr(status), Helper::WStrToNetStr(description));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

bool ClientCpp::OnHostKeySync(FlowSshCpp::RefPtr<FlowSshCpp::PublicKey> publicKey, bool keyVerified)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return false;

		AutoKeepAlive keepAlive(flowSshNet);
		return flowSshNet->Raise_OnHostKeySync(gcnew FlowSshNet::PublicKey(publicKey), keyVerified);
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

void ClientCpp::OnForwardingLog(FlowSshCpp::RefPtrConst<FlowSshCpp::ForwardingLog> const& log)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnForwardingLog(ForwardingLog::Create(log));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientCpp::OnDisconnect(unsigned int reason, std::wstring const& desc)
{
	try
	{
		FlowSshNet::ClientBase^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;
		
		flowSshNet->Raise_OnDisconnect(static_cast<DisconnectReason>(reason), Helper::WStrToNetStr(desc));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ReceiveHandlerCpp

void ReceiveHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void ReceiveHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::ReceiveHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ReceiveHandlerCpp::OnReceive(bool stdErr, unsigned char const* dataPtr, unsigned int dataSize, bool eof)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnReceive(stdErr, Helper::UnsignedCharsToByteArray(dataPtr, dataSize), eof);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ReceiveHandlerCpp::OnError()
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError();
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ClientSessionChannelCpp

void ClientSessionChannelCpp::OnExitStatus(FlowSshC_ExitStatus const& status)
{
	try
	{
		FlowSshNet::ClientSessionChannel^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;
		
		flowSshNet->Raise_OnExitStatus(gcnew ExitStatus(status));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientSessionChannelCpp::OnExitSignal(FlowSshCpp::ClientSessionChannel::ExitSignal const& signal)
{
	try
	{
		FlowSshNet::ClientSessionChannel^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnExitSignal(gcnew FlowSshNet::ExitSignal(signal));
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientSessionChannelCpp::OnChannelClose()
{
	try
	{
		FlowSshNet::ClientSessionChannel^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnChannelClose();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// RealPathHandlerCpp

void RealPathHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void RealPathHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::RealPathHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void RealPathHandlerCpp::OnRealPath(std::wstring const& realPath)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnRealPath(Helper::WStrToNetStr(realPath));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void RealPathHandlerCpp::OnError(FlowSshCpp::SftpErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::SftpErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// StatHandlerCpp

void StatHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void StatHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::StatHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void StatHandlerCpp::OnStat(FlowSshCpp::FileAttrs const& fileAttrs)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnStat(gcnew FlowSshNet::FileAttrs(fileAttrs));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void StatHandlerCpp::OnError(FlowSshCpp::SftpErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::SftpErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// SftpHandler

void SftpHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void SftpHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::SftpHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void SftpHandlerCpp::OnSuccess()
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnSuccess();
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void SftpHandlerCpp::OnError(FlowSshCpp::SftpErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::SftpErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ListHandlerCpp

void ListHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void ListHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::ListHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

bool ListHandlerCpp::OnList(std::vector<FlowSshCpp::FileInfo> const& fileInfos, bool endOfList)
{
	try
	{
		if (m_flowSshNetDisposed) return false;

		unsigned int nrFileInfos = static_cast<unsigned int>(fileInfos.size());
		array<FlowSshNet::FileInfo^>^ fileInfosNet = gcnew array<FlowSshNet::FileInfo^>((int)nrFileInfos);

		for (unsigned int c = 0; c < nrFileInfos; c++)
		{
			FlowSshNet::FileInfo^ fileInfo = gcnew FlowSshNet::FileInfo(fileInfos[c]);
			fileInfosNet[(int)c] = fileInfo;
		}
		return m_flowSshNet->Raise_OnList(fileInfosNet, endOfList);
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

void ListHandlerCpp::OnError(FlowSshCpp::ListErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::ListErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// TransferHandlerCpp

void TransferHandlerCpp::OnStart()
{
	__super::OnStart();
	m_flowSshNet = m_flowSshNet_weak;
}

void TransferHandlerCpp::OnDone()
{
	try
	{
		FlowSshNet::TransferHandler^ flowSshNet = m_flowSshNet.ReleaseTarget();
		if (m_flowSshNetDisposed) return;

		flowSshNet->Base_Raise_OnDone();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

bool TransferHandlerCpp::OnTransfer(bool done, FlowSshC_TransferStat const& transferStat)
{
	try
	{
		if (m_flowSshNetDisposed) return false;
		return m_flowSshNet->Raise_OnTransfer(done, gcnew FlowSshNet::TransferStat(transferStat));
	}
	catch (System::Exception^ e)
	{
		SshNet::Raise_OnExceptionInEvent(nullptr, true, e);
		return false;
	}
}

void TransferHandlerCpp::OnError(FlowSshCpp::TransferErr const& error)
{
	try
	{
		if (m_flowSshNetDisposed) return;
		m_flowSshNet->Raise_OnError(gcnew FlowSshNet::TransferErr(error));
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


// ClientSftpChannel

void ClientSftpChannelCpp::OnSftpVersion(unsigned int version)
{
	try
	{
		FlowSshNet::ClientSftpChannel^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnSftpVersion(version);
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}

void ClientSftpChannelCpp::OnChannelClose() 
{
	try
	{
		FlowSshNet::ClientSftpChannel^ flowSshNet = m_flowSshNet_weak;
		if (flowSshNet == nullptr || m_flowSshNetDisposed) return;

		flowSshNet->Raise_OnChannelClose();
		GC::KeepAlive(flowSshNet);
	}
	catch (System::Exception^ e) { SshNet::Raise_OnExceptionInEvent(nullptr, true, e); }
}


} // namespace FlowSshNet
} // namespace Bitvise