function dom = createSoapMessage(tns,methodname,values,names,types,style)
%createSoapMessage Create a SOAP message, ready to send to the server.
%   createSoapMessage(NAMESPACE,METHOD,VALUES,NAMES,TYPES,STYLE) creates a SOAP
%   message.  VALUES, NAMES, and TYPES are cell arrays.  NAMES will
%   default to dummy names and TYPES will default to unspecified.  STYLE
%   specifies 'document' or 'rpc' messages ('rpc' is the default).
%
%   Example:
%
%   m = createSoapMessage( ...
%       'urn:xmethodsBabelFish', ...
%       'BabelFish', ...
%       {'en_it','Matthew likes MATLAB.'}, ...
%       {'translationmode','sourcedata'}, ...
%       repmat({'{http://www.w3.org/2001/XMLSchema}string'},1,2));
%   
%   response = callSoapService( ...
%       'http://services.xmethods.net:80/perl/soaplite.cgi', ...
%       'urn:xmethodsBabelFish#BabelFish', ...
%        m);
%
%   results = parseSoapResponse(response)
%
%   See also createClassFromWsdl, callSoapService, parseSoapResponse.

% Matthew J. Simoneau, June 2003
% $Revision: 1.1.6.5 $  $Date: 2004/12/27 23:33:03 $
% Copyright 1984-2004 The MathWorks, Inc.

% Default to made-up names.
if (nargin < 4)
    names = cell(length(values));
    for i = 1:length(values)
        names{i} = sprintf('param%.0f',i);
    end
end
% Default to empty types.
if (nargin < 5)
    types = cell(length(values));
    types(:) = {''};
end
% Default to 'rpc'.
if (nargin < 6)
    style = 'rpc';
end

%   Form the envelope
dom = com.mathworks.xml.XMLUtils.createDocument('http://schemas.xmlsoap.org/soap/envelope/','soap:Envelope');
rootNode = dom.getDocumentElement;
switch style
    case 'rpc'
        rootNode.setAttribute('xmlns:n',tns);
end
rootNode.setAttribute('xmlns:soap','http://schemas.xmlsoap.org/soap/envelope/');
rootNode.setAttribute('xmlns:soapenc','http://schemas.xmlsoap.org/soap/encoding/');
rootNode.setAttribute('xmlns:xs','http://www.w3.org/2001/XMLSchema');
rootNode.setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchema-instance');

% Form the body
soapBody = dom.createElement('soap:Body');
soapBody.setAttribute('soap:encodingStyle','http://schemas.xmlsoap.org/soap/encoding/');

% Method
switch style
    case 'rpc'
        soapMessage = dom.createElement(['n:' methodname]);
    case 'document'
        soapMessage = dom.createElement(methodname);
        soapMessage.setAttribute('xmlns',tns)
end
soapBody.appendChild(soapMessage);

% Add inputs.
populate(dom,soapMessage,values,names,types)

% Add the body
rootNode.appendChild(soapBody);

%===============================================================================
function populate(dom,node,values,names,types)

for i = 1:length(names)
    if isstruct(values{i})
        for j = 1:length(values{i})
            soapStruct = dom.createElement(names{i});
            populate(dom,soapStruct, ...
                struct2cell(values{i}(j)),fieldnames(values{i}(j)), ...
                cell(size(fieldnames(values{i}(j)))));
            node.appendChild(soapStruct);
        end
    elseif iscell(values{i})
        populate(dom,node, ...
            values{i},repmat(names(i),size(values{i})), ...
            cell(size(values{i})));
    else
        input = dom.createElement(names{i});
        if ~isempty(types{i})
            if ~isempty(strmatch('{http://www.w3.org/2001/XMLSchema}',types{i}))
                input.setAttribute('xsi:type',['xs:' types{i}(35:end)]);
            else
                % TODO: Better type handling.
                %fprintf('Could do better with "%s" in "%s".',types{i},names{i})
            end
        end
        textToSend = convertToText(values{i});
        input.appendChild(dom.createTextNode(textToSend));
        node.appendChild(input);
    end
end


%===============================================================================
function s = convertToText(x)
switch class(x)
    case 'char'
        s = x;
    otherwise
        s = mat2str(x);
end