// echofilehdrObj.cpp : Implementation of CechofilehdrObj

#include "stdafx.h"
#include "echofilehdrObj.h"

#include "..\wmsoapmsg\wmsoapmsg_i.c"
#include "..\wmsoapmsg\wmsoapmsg.h"
#include "..\wmsoapstruct\wmsoapstruct.h"
#include "..\wmsoapstruct\wmsoapstruct_i.c"
#include "..\soap_source\DIMEPayload.h"
#include "comdef.h"
#include <string>
using namespace std;

static wchar_t *g_pwszHeaderNS = L"http://whitemesa.net/echofile/header";

// CechofilehdrObj

STDMETHODIMP CechofilehdrObj::OnProcessHeader(VARIANT SOAPMsgInterface, VARIANT_BOOL *pResult)
{
	// get message interface ptr
	IDispatch *pIDispatch = SOAPMsgInterface.pdispVal;
	Iwmsoapmsg2 *pIwmsoapmsg;
	HRESULT hRes = pIDispatch->QueryInterface(IID_Iwmsoapmsg2, (void **)&pIwmsoapmsg);
	if (hRes != S_OK)
	{
		// trouble
		*pResult = VARIANT_FALSE;
		return S_OK;
	}
	// ok
	*pResult = VARIANT_TRUE;
	VARIANT_BOOL bResult;
	pIwmsoapmsg->IsRequestPhase(&bResult);
	// check message phase
	if (bResult == VARIANT_FALSE)
	{
		// this is response phase... echo request headers in response
		BSTR bstrTargetActorURI = SysAllocString(L"");
		BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
		BSTR bstrLocalName = SysAllocString(L"outputDataFile");
		vector<_variant_t>::iterator iter;
		for (iter = m_arrHeaders.begin();
				iter != m_arrHeaders.end();
				iter++)
		{
	        // get pointer to struct object
	        IDispatch *pIDispatch = (*iter).pdispVal;
	        if (pIDispatch == NULL)
	        {
		        return E_POINTER;
	        }
	        Iwmsoapstruct *pIwmsoapstruct;
	        HRESULT res = pIDispatch->QueryInterface(IID_Iwmsoapstruct, (void **)&pIwmsoapstruct);
	        if (FAILED(res))
	        {
		        return E_NOINTERFACE;
	        }
	        _variant_t varTemp;
	        VARIANT_BOOL bResult;
	        wstring wstrFilename;
	        BSTR bstrMember1 = SysAllocString(L"fileName");
	        BSTR bstrMember2 = SysAllocString(L"fileData");
	        // now get struct members
	        pIwmsoapstruct->GetMember(bstrMember1, &varTemp, &bResult);
	        if (bResult == VARIANT_FALSE)
	        {
		        return E_FAIL;
	        }
	        wstrFilename = varTemp.bstrVal;
	        varTemp.Clear();
	        pIwmsoapstruct->GetMember(bstrMember2, &varTemp, &bResult);
	        if (bResult == VARIANT_FALSE)
	        {
		        return E_FAIL;
	        }
	        // release interface ptr
	        pIwmsoapstruct->Release();
	        // now get file data
	        VARIANT varOutputFile;
	        VariantInit(&varOutputFile);
	        // test vartype to see what we have
	        if (varTemp.vt == VT_UNKNOWN)
	        {
		        // binary data sent as DIME attachment
		        IUnknown *pIUnknownIn = varTemp.punkVal;
		        IStorage *pIStorageIn;
		        HRESULT hRes = pIUnknownIn->QueryInterface(IID_IStorage, (void **)&pIStorageIn);
		        if (FAILED(hRes))
		        {
			        return E_NOINTERFACE;
		        }
		        DIMEPayload *pPayloadIn = new DIMEPayload(  pIStorageIn,
													        string(""),
													        string(""),
													        DIME_TYPENAME_FORMAT_UNKNOWN);
		        pIStorageIn->Release();
		        if (pPayloadIn == NULL)
		        {
			        return E_FAIL;
		        }
		        // now create storage for output
		        IStorage *pIStorageOut;
		        hRes = StgCreateDocfile(NULL,
								        STGM_DELETEONRELEASE | STGM_DIRECT | STGM_READWRITE| STGM_CREATE | STGM_SHARE_EXCLUSIVE,
								        0,
								        &pIStorageOut);
		        if (FAILED(hRes))
		        {
			        return E_FAIL;
		        }
		        DIMEPayload *pPayloadOut = new DIMEPayload( pIStorageOut,
													        string(""),
													        string(""),
													        DIME_TYPENAME_FORMAT_UNKNOWN);
		        if (pPayloadOut == NULL)
		        {
			        pIStorageOut->Release();
			        return E_FAIL;
		        }
		        // now copy contents
		        char szTemp[4096];
		        unsigned long ulNumBytes = 0;
		        unsigned long ulBytesWritten = 0;
		        pPayloadIn->OpenForRead();
		        pPayloadOut->OpenForWrite();
		        do
		        {
			        pPayloadIn->Read(szTemp, 4096, &ulNumBytes);
			        pPayloadOut->Write(szTemp, ulNumBytes, &ulBytesWritten);
		        } while (ulNumBytes == 4096);
		        pPayloadIn->Close();
		        pPayloadOut->Close();
		        delete pPayloadIn;
		        delete pPayloadOut;
		        varOutputFile.punkVal = pIStorageOut;
		        varOutputFile.vt = VT_UNKNOWN;
	        }
	        else
	        {
		        // binary sent as type base64Binary, passed in as (VT_ARRAY | VT_UI1)
		        SafeArrayCopy(varTemp.parray, &varOutputFile.parray);
		        varOutputFile.vt = (VT_ARRAY | VT_UI1);
	        }
	        // instantiate struct object
	        Iwmsoapstruct *pIwmsoapstructOut;
	        res = CoCreateInstance( CLSID_wmsoapstruct,
									        NULL, CLSCTX_SERVER,
									        IID_Iwmsoapstruct,
									        (void **) &pIwmsoapstructOut);
	        if (FAILED(res))
	        {
		        return E_FAIL;
	        }
	        varTemp.Clear();
	        // filename
	        varTemp = wstrFilename.c_str();
	        pIwmsoapstructOut->SetMember(bstrMember1, varTemp, &bResult);
	        // data
	        pIwmsoapstructOut->SetMember(bstrMember2, varOutputFile, &bResult);
	        VariantClear(&varOutputFile);

	        SysFreeString(bstrMember1);
	        SysFreeString(bstrMember2);
	        // now get IDispatch pointer
	        IDispatch *pIDispatchOut;
	        res = pIwmsoapstructOut->QueryInterface(IID_IDispatch, (void **)&pIDispatchOut);
	        if (FAILED(res))
	        {
		        pIwmsoapstructOut->Release();
		        return E_NOINTERFACE;
	        }
	        // release
	        pIwmsoapstructOut->Release();
	        // set up variant
	        _variant_t varOut;
	        varOut.vt = VT_DISPATCH;
	        varOut.punkVal = pIDispatchOut;
			// now add the header to response message
			pIwmsoapmsg->AddHeaderElem( bstrNamespaceURI,
										bstrLocalName,
										varOut,
										VARIANT_FALSE,
										bstrTargetActorURI,
										&bResult);
		}
		SysFreeString(bstrLocalName);
		SysFreeString(bstrNamespaceURI);
		SysFreeString(bstrTargetActorURI);
		// done with message interface
		pIwmsoapmsg->Release();
		// finished
		return S_OK;
	}
	// this is the request phase... get any "inputDataFile" request header blocks
	long lPosition = 0;
	_variant_t varTemp;

	BSTR bstrNamespaceURI = SysAllocString(g_pwszHeaderNS);
	BSTR bstrLocalName = SysAllocString(L"inputDataFile");
	while (true)
	{
		pIwmsoapmsg->GetHeaderElem( bstrNamespaceURI,
									bstrLocalName,
									&varTemp,
									&bResult);
		if (bResult == VARIANT_TRUE)
		{
			// store it
			m_arrHeaders.push_back(_variant_t(varTemp));
			varTemp.Clear();
		}
		else
		{
			break;
		}
	}
	SysFreeString(bstrLocalName);
	SysFreeString(bstrNamespaceURI);
	pIwmsoapmsg->Release();
	// done for now, we'll be called again in response phase
	return S_OK;
}

STDMETHODIMP CechofilehdrObj::OnTestMUHeaderBlock(BSTR bstrNamespace, BSTR bstrLocalName, VARIANT_BOOL *pResult)
{
    *pResult = VARIANT_FALSE;
    if (wcscmp(bstrNamespace, g_pwszHeaderNS) == 0)
    {
        if (wcscmp(bstrLocalName, L"inputDataFile") == 0)
        {
            *pResult = VARIANT_TRUE;
            return S_OK;
        }
    }
    return S_OK;
}
