/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2008 OMC Denmark ApS.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ieicc_utils.h"
#include "conv_utils.h"
#include "obj_utils.h"
#include "templates.i"
#include "utils/macros.h"

#include "edkcode.h"

inline BRUTUS::BDEFINE brutus_flags(const ULONG Flags)
{
	ULONG flags = Flags;
	BRUTUS::BDEFINE retval = 0;

	if (flags & SYNC_UNICODE) {
		retval |= BRUTUS::BRUTUS_SYNC_UNICODE;
		FLAGS_OFF(DWORD, flags, SYNC_UNICODE);
	}
	if (flags & SYNC_ASSOCIATED) {
		retval |= BRUTUS::BRUTUS_SYNC_ASSOCIATED;
		FLAGS_OFF(DWORD, flags, SYNC_ASSOCIATED);
	}
	if (flags & SYNC_NO_DELETIONS) {
		retval |= BRUTUS::BRUTUS_SYNC_NO_DELETIONS;
		FLAGS_OFF(DWORD, flags, SYNC_NO_DELETIONS);
	}
	if (flags & SYNC_READ_STATE) {
		retval |= BRUTUS::BRUTUS_SYNC_READ_STATE;
		FLAGS_OFF(DWORD, flags, SYNC_READ_STATE);
	}
	if (flags & SYNC_NORMAL) {
		retval |= BRUTUS::BRUTUS_SYNC_NORMAL;
		FLAGS_OFF(DWORD, flags, SYNC_NORMAL);
	}

	if (flags) {
		char msg[128] = {0};
		sprintf_s(msg, sizeof(msg), "Unknown flag(s) from MAPI : %X", flags);
		BRUTUS_LOG_BUG(msg);
	}

	return retval;
}

STDMETHODIMP CExchangeImportContentsChanges::GetLastError(HRESULT hResult,
							  ULONG ulFlags,
							  LPMAPIERROR FAR * lppMAPIError)
{
	BRUTUS::BRESULT br;
	HRESULT hr;

	if (!hresult_to_bresult(hResult, br)) {
		BRUTUS_LOG_BUG("Could not convert HRESULT into BRESULT");
		hr = E_FAIL;
	}

	CORBA::ULong flags = brutus_flags(ulFlags);
	BRUTUS::MAPIERROR_var b_error;

	try {
		br = brutus_obj_->GetLastError(br,
					       flags,
					       b_error.out());
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::GetLastError()");
		return E_FAIL;
	}

	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}
	if(!mapierror_brutus_to_mapi(b_error,
				     NULL,
				     *lppMAPIError)) {
		BRUTUS_LOG_BUG("Could not convert BRUTUS::MAPIERROR into MAPIERROR");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::Config(LPSTREAM lpStream,
						    ULONG ulFlags)
{
	BRUTUS::IStream_var brutus_stream = BRUTUS::IStream::_nil();

	stream_ = lpStream;
	if (stream_) {
		stream_->AddRef();
		brutus_stream = create_object<BRUTUS_IStream_i, BRUTUS::IStream, LPSTREAM>
			(stream_, poa_.in(), mapi_session_);
	}

	CORBA::ULong flags = brutus_flags(ulFlags);

	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->Config(brutus_stream.in(),
					 flags);
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::Config()");
		return E_FAIL;
	}
	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::UpdateState(LPSTREAM lpStream)
{
	BRUTUS::IStream_var brutus_stream = BRUTUS::IStream::_nil();
	if (lpStream) {
		lpStream->AddRef();
		brutus_stream = create_object<BRUTUS_IStream_i, BRUTUS::IStream, LPSTREAM>
			(lpStream, poa_.in(), mapi_session_);
	}

	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->UpdateState(brutus_stream.in());
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::UpdateState()");
		return E_FAIL;
	}
	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::ImportMessageChange(ULONG cValue,
								 LPSPropValue lpPropArray,
								 ULONG ulFlags,
								 LPMESSAGE * lppMessage)
{
	BRUTUS::seq_SPropValue brutus_propvalue_array;
	if (!spropvalue_array_mapi_to_brutus(cValue, lpPropArray, brutus_propvalue_array, mapi_session_, false, poa_.in()))
		return EC_EDK_E_OUTOFMEMORY;

	BRUTUS::BDEFINE flags = brutus_flags(ulFlags);

	LPMESSAGE mapi_message = NULL;
	BRUTUS::IMessage_var brutus_message = BRUTUS::IMessage::_nil();

	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->ImportMessageChange(brutus_propvalue_array,
						      flags,
						      brutus_message.out());
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::ImportMessageChange()");
		return E_FAIL;
	}

	*lppMessage = mapi_message; // FIXME

	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::ImportMessageDeletion(ULONG ulFlags,
								   LPENTRYLIST lpSourceEntryList)
{
	if (!lpSourceEntryList)
		return EC_EDK_E_INVALIDARG;

	BRUTUS::BDEFINE flags = brutus_flags(ulFlags);
	BRUTUS::SBinaryArray brutus_bin_array;

	if (!sbinary_array_mapi_to_brutus(lpSourceEntryList, brutus_bin_array))
		return EC_EDK_E_OUTOFMEMORY;

	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->ImportMessageDeletion(flags,
							brutus_bin_array);
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::ImportMessageDeletion()");
		return E_FAIL;
	}

	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::ImportPerUserReadStateChange(ULONG cElements,
									  LPREADSTATE lpReadState)
{
	BRUTUS::seq_READSTATE_var read_state;
	if (!readstate_array_mapi_to_brutus(cElements, lpReadState, read_state.out()))
		return EC_EDK_E_OUTOFMEMORY;

	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->ImportPerUserReadStateChange(read_state.in());
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::ImportPerUserReadStateChange()");
		return E_FAIL;
	}

	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}

STDMETHODIMP CExchangeImportContentsChanges::ImportMessageMove(ULONG cbSourceKeySrcFolder,
							       BYTE FAR * pbSourceKeySrcFolder,
							       ULONG cbSourceKeySrcMessage,
							       BYTE FAR * pbSourceKeySrcMessage,
							       ULONG cbPCLMessage,
							       BYTE FAR * pbPCLMessage,
							       ULONG cbSourceKeyDestMessage,
							       BYTE FAR * pbSourceKeyDestMessage,
							       ULONG cbChangeNumDestMessage,
							       BYTE FAR * pbChangeNumDestMessage)
{
	BRUTUS::seq_octet_var brutus_pbSourceKeySrcFolder;
	BRUTUS::seq_octet_var brutus_pbSourceKeySrcMessage;
	BRUTUS::seq_octet_var brutus_pbPCLMessage;
	BRUTUS::seq_octet_var brutus_pbSourceKeyDestMessage;
	BRUTUS::seq_octet_var brutus_pbChangeNumDestMessage;

	bool retv;
	retv = seq_octet_mapi_to_brutus(cbSourceKeySrcFolder,
					pbSourceKeySrcFolder,
					brutus_pbSourceKeySrcFolder);
	if (!retv)
		return EC_EDK_E_OUTOFMEMORY;

	retv = seq_octet_mapi_to_brutus(cbSourceKeySrcMessage,
					pbSourceKeySrcMessage,
					brutus_pbSourceKeySrcMessage);
	if (!retv)
		return EC_EDK_E_OUTOFMEMORY;

	retv = seq_octet_mapi_to_brutus(cbPCLMessage,
					pbPCLMessage,
					brutus_pbPCLMessage);
	if (!retv)
		return EC_EDK_E_OUTOFMEMORY;

	retv = seq_octet_mapi_to_brutus(cbSourceKeyDestMessage,
					pbSourceKeyDestMessage,
					brutus_pbSourceKeyDestMessage);
	if (!retv)
		return EC_EDK_E_OUTOFMEMORY;

	retv = seq_octet_mapi_to_brutus(cbChangeNumDestMessage,
					pbChangeNumDestMessage,
					brutus_pbChangeNumDestMessage);
	if (!retv)
		return EC_EDK_E_OUTOFMEMORY;


	BRUTUS::BRESULT br;
	try {
		br = brutus_obj_->ImportMessageMove(brutus_pbSourceKeySrcFolder.in(),
						    brutus_pbSourceKeySrcMessage.in(),
						    brutus_pbPCLMessage.in(),
						    brutus_pbSourceKeyDestMessage.in(),
						    brutus_pbChangeNumDestMessage.in());
	}
	catch (...) {
		BRUTUS_LOG_BUG("Exception caught from client in CExchangeImportContentsChanges::ImportMessageMove()");
		return E_FAIL;
	}
	HRESULT hr;
	if (!bresult_to_hresult(br, hr)) {
		BRUTUS_LOG_BUG("Could not convert BRESULT into HRESULT");
		hr = E_FAIL;
	}

	return hr;
}
