{
    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.
}
{$INCLUDE wst_global.inc}
unit server_service_xmlrpc;

interface

uses
  Classes, SysUtils, TypInfo,
  {$IFNDEF FPC}xmldom, wst_delphi_xml{$ELSE}DOM{$ENDIF},
  base_service_intf, server_service_intf,
  base_xmlrpc_formatter;

{$INCLUDE wst.inc}
{$INCLUDE wst_delphi.inc}
  
type

{$M+}

  { TXmlRpcFormatter }

  TXmlRpcFormatter = class(TXmlRpcBaseFormatter,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_RegisterXmlRpcFormat();

implementation
{$IFDEF FPC}uses wst_fpc_xml;{$ENDIF}

{ TXmlRpcFormatter }

procedure TXmlRpcFormatter.BeginCallResponse(Const AProcName,ATarget:string);
var
  mthdNode, prmsNode : TDOMNode;
  doc : TXMLDocument;
begin
  Clear();
  doc := Self.GetXmlDoc();
  mthdNode := doc.CreateElement(sMETHOD_RESPONSE);
  doc.AppendChild(mthdNode);
    prmsNode := doc.CreateElement(sPARAMS);
    mthdNode.AppendChild(prmsNode);
    PushStackParams(prmsNode);
end;

procedure TXmlRpcFormatter.EndCallResponse();
begin
  EndScope();
end;

procedure TXmlRpcFormatter.BeginCallRead(ACallContext : ICallContext);
var
  callNode : TDOMElement;
  tmpNode : TDOMNode;
  doc : TXMLDocument;
begin
  FCallContext := ACallContext;
  ClearStack();
  doc := GetXmlDoc();
  callNode := doc.DocumentElement;
  if not SameText(sMETHOD_CALL,callNode.NodeName) then
    Error('XML root node must be "%s".',[sMETHOD_CALL]);

  tmpNode := FindNode(callNode,sMETHOD_NAME);
  if not Assigned(tmpNode) then
    Error('Node not found : "%s".',[sMETHOD_NAME]);
  if not tmpNode.HasChildNodes() then
    Error('"%s" does not provide value node.',[sMETHOD_NAME]);
  FCallProcedureName := Trim(tmpNode.FirstChild.NodeValue);
  
  tmpNode := FindNode(callNode,sPARAMS);
  if not Assigned(tmpNode) then
    Error('Node not found : "%s".',[sPARAMS]);
  PushStackParams(tmpNode);

  //FCallTarget := tmpNode.NodeValue;
end;

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

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

procedure TXmlRpcFormatter.BeginExceptionList(
  const AErrorCode: string;
  const AErrorMsg: string
);
var
  c,m : string;
  i : Integer;
  memberNode, mthdNode, faultNode, structNode,
  valueNode, nameNode,
  internalValueNode, lastValNode : TDOMNode;
  doc : TXMLDocument;
begin
  c := Trim(AErrorCode);
  if not TryStrToInt(c,i) then
    c := '123';
  m := AErrorMsg;
  Clear();
  doc := Self.GetXmlDoc();
  mthdNode := doc.CreateElement(sMETHOD_RESPONSE);
  doc.AppendChild(mthdNode);
    //fault node
    faultNode := doc.CreateElement(sFAULT);
    mthdNode.AppendChild(faultNode);
      // value node
      valueNode := doc.CreateElement(sVALUE);
      faultNode.AppendChild(valueNode);
        // structNode
        structNode := doc.CreateElement(XmlRpcDataTypeNames[xdtStruct]);
        valueNode.AppendChild(structNode);
          //faultCode member node
          memberNode := doc.CreateElement(sMEMBER);
          structNode.AppendChild(memberNode);
            //name node
            nameNode := doc.CreateElement(sNAME);
            memberNode.AppendChild(nameNode);
            nameNode.AppendChild(doc.CreateTextNode(sFAULT_CODE));
            //value node
            internalValueNode := doc.CreateElement(sVALUE);
            memberNode.AppendChild(internalValueNode);
            lastValNode := doc.CreateElement(XmlRpcDataTypeNames[xdtInt]);
            internalValueNode.AppendChild(lastValNode);
            lastValNode.AppendChild(doc.CreateTextNode(c));
          //faultString member node
          memberNode := doc.CreateElement(sMEMBER);
          structNode.AppendChild(memberNode);
            //name node
            nameNode := doc.CreateElement(sNAME);
            memberNode.AppendChild(nameNode);
            nameNode.AppendChild(doc.CreateTextNode(sFAULT_STRING));
            //value node
            internalValueNode := doc.CreateElement(sVALUE);
            memberNode.AppendChild(internalValueNode);
            lastValNode := doc.CreateElement(XmlRpcDataTypeNames[xdtString]);
            internalValueNode.AppendChild(lastValNode);
            lastValNode.AppendChild(doc.CreateTextNode(m));
end;

procedure TXmlRpcFormatter.EndExceptionList();
begin
end;

procedure Server_service_RegisterXmlRpcFormat();
begin
  GetFormatterRegistry().Register(sPROTOCOL_NAME,sXMLRPC_CONTENT_TYPE,TSimpleItemFactory.Create(TXmlRpcFormatter) as IItemFactory);
end;

end.

