{
    This file is part of the Web Service Toolkit
    Copyright (c) 2006 by Inoussa OUEDRAOGO

    This file is provide under modified LGPL licence
    ( the files COPYING.modifiedLGPL and COPYING.LGPL).
    

    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.
}
unit server_service_soap;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, TypInfo, DOM,
  base_service_intf, server_service_intf, server_service_imputils,
  base_soap_formatter;

Type

  { TSOAPFormatter }

{$M+}
  TSOAPFormatter = class(TSOAPBaseFormatter,IFormatterBase,IFormatterResponse)
  private
    FCallProcedureName : string;
    FCallTarget : String;
    FCallContext : ICallContext;
  public

    procedure BeginCallResponse(Const AProcName,ATarget:string);
    procedure EndCallResponse();

    procedure BeginCallRead(ACallContext : ICallContext);
    function GetCallProcedureName():String;
    function GetCallTarget():String;

    procedure BeginExceptionList(
      const AErrorCode : string;
      const AErrorMsg  : string
    );
    procedure EndExceptionList();
  End;

  procedure Server_service_RegisterSoapFormat();
  
implementation

Const NAMESPACE_SEPARATOR = ':';
function ExtractNamespacePart( Const AQualifiedName : string):String;
Var
  i : Integer;
begin
  Result := '';
  i := Pos(NAMESPACE_SEPARATOR,AQualifiedName);
  If ( i <= 0 ) Then
    Exit;
  Result := Copy(AQualifiedName,1,Pred(i));
end;

function ExtractNamePart(Const AQualifiedName : string):String;
Var
  i : Integer;
begin
  i := Pos(NAMESPACE_SEPARATOR,AQualifiedName);
  If ( i <= 0 ) Then
    i := 0;
  Result := Copy(AQualifiedName,Succ(i),MaxInt);
end;

{ TSOAPFormatter }

procedure TSOAPFormatter.BeginCallResponse(Const AProcName,ATarget:string);
begin
{  Clear();
  BeginScope('Envelope',sSOAP_ENV,'SOAP-ENV');
    AddScopeAttribute('xmlns:xsi',sXSI_NS);
    AddScopeAttribute('xmlns:'+sXSD, sXSD_NS);
    AddScopeAttribute('xmlns:'+sSOAP_ENC_ABR, sSOAP_ENC);
    BeginScope('Body',sSOAP_ENV);
        BeginScope(AProcName + 'Response',ATarget);
}
  Clear();
  Prepare();
    WriteHeaders(FCallContext);
    BeginScope('Body',sSOAP_ENV);
        BeginScope(AProcName + 'Response',ATarget);
end;

procedure TSOAPFormatter.EndCallResponse();
begin
      EndScope(); //BeginScope(AProcName,ATarget);
    EndScope();   //BeginScope('Body','http://schemas.xmlsoap.org/soap/envelope/');
  EndScope();     //BeginScope('Envelope','http://schemas.xmlsoap.org/soap/envelope/','SOAP-ENV');
end;

procedure TSOAPFormatter.BeginCallRead(ACallContext : ICallContext);
Var
  envNd : TDOMElement;
  hdrNd, bdyNd, mthdNd, tmpNode : TDOMNode;
  s,nsShortName,eltName : string;
  doc : TXMLDocument;
begin
  FCallContext := ACallContext;
  ClearStack();
  doc := GetXmlDoc();
  If FindAttributeByValueInNode(sSOAP_ENV,doc.DocumentElement,nsShortName) Then Begin
    nsShortName := Copy(nsShortName,1 + Pos(':',nsShortName),MaxInt);
    If Not IsStrEmpty(nsShortName) Then
      nsShortName := nsShortName + ':';
  End Else
    nsShortName := '';
  eltName := nsShortName + 'Envelope';
  envNd := doc.DocumentElement;
  If Not SameText(eltName,envNd.NodeName) Then
    Error('XML root node must be "Envelope".');
  PushStack(envNd).SetNameSpace(sSOAP_ENV);

  bdyNd := envNd.FirstChild;
  If Not Assigned(bdyNd) Then
    Error('Node not found : "Body".');

  eltName := nsShortName + 'Body';
  if not SameText(bdyNd.NodeName,eltName) then begin
    eltName := nsShortName + 'Header';
    hdrNd := bdyNd;
    bdyNd := hdrNd.NextSibling;
    if SameText(hdrNd.NodeName,eltName) then begin
      PushStack(hdrNd,stArray).SetNameSpace(sSOAP_ENV);
      ReadHeaders(FCallContext);
      PopStack().Free();
    end;
  end;
  
  eltName := nsShortName + 'Body';
  If Not Assigned(bdyNd) Then
    Error('Node not found : "Body".');
  PushStack(bdyNd).SetNameSpace(sSOAP_ENV);
  If Not Assigned(bdyNd.FirstChild) Then
    Error('Method Node not found.');
  mthdNd := bdyNd.FirstChild;
  PushStack(mthdNd);
  s := mthdNd.NodeName;
  nsShortName := ExtractNamespacePart(s);
  If IsStrEmpty(nsShortName) Then
    Error('Method Node must have a qualified name.');
  FCallProcedureName := ExtractNamePart(s);
  If IsStrEmpty(FCallProcedureName) Then
    Error('No Method name.');
  tmpNode := mthdNd.Attributes.GetNamedItem(sXML_NS + ':' + nsShortName);
  If Not Assigned(tmpNode) Then
    Error('Call target attribute not found.');
  FCallTarget := tmpNode.NodeValue;
end;

function TSOAPFormatter.GetCallProcedureName(): String;
begin
  Result := FCallProcedureName;
end;

function TSOAPFormatter.GetCallTarget(): String;
begin
  Result := FCallTarget;
end;

procedure TSOAPFormatter.BeginExceptionList(
  const AErrorCode: string;
  const AErrorMsg: string
);
Var
  c,m :string;
begin
  If IsStrEmpty(AErrorCode) Then
    c := 'SOAP-ENV:Server'
  Else
    c := AErrorCode;
  If IsStrEmpty(AErrorMsg) Then
    m := 'Server Error'
  Else
    m := AErrorMsg;
  Clear();
  BeginScope('Envelope',sSOAP_ENV,'SOAP-ENV');
    AddScopeAttribute('xmlns:xsi',sXSI_NS);
    AddScopeAttribute('xmlns:'+sXSD, sXSD_NS);
    BeginScope('Body',sSOAP_ENV);
      BeginScope('Fault',sSOAP_ENV);
        Put('faultcode',TypeInfo(string),c);
        Put('faultstring',TypeInfo(string),m);
end;

procedure TSOAPFormatter.EndExceptionList();
begin
      EndScope(); //BeginScope('Fault',sSOAP_ENV);
    EndScope();   //BeginScope('Body','http://schemas.xmlsoap.org/soap/envelope/');
  EndScope();     //BeginScope('Envelope','http://schemas.xmlsoap.org/soap/envelope/','SOAP-ENV');
end;

procedure Server_service_RegisterSoapFormat();
begin
  GetFormatterRegistry().Register(sSOAP_CONTENT_TYPE,TSimpleItemFactory.Create(TSOAPFormatter) as IItemFactory);
  RegisterStdTypes();
end;

end.
