{service insertion code}
unit mApiCardM;

interface

uses windows,messages;

type
  tmApiCard = class
  private
    function  GetDescription:PAnsiChar; 
    function  GetResultType :PAnsiChar; 
    procedure SetCurrentService(item:PAnsiChar);
    function  GetWindowStatus:boolean;
  public
    constructor Create(fname:PAnsiChar; lparent:HWND=0);
    destructor Destroy; override;
    procedure FillList(combo:HWND; mode:integer=0);

    function NameFromList(cb:HWND):PAnsiChar;
    function HashToName(ahash:longword):PAnsiChar;
    function FillParams(wnd:HWND{;item:PAnsiChar};wparam:boolean):PAnsiChar;
    function GetParam(wparam:boolean):PAnsiChar;
    procedure Show;//(item:PAnsiChar);

    property Description:PAnsiChar read GetDescription;
    property ResultType :PAnsiChar read GetResultType;
    property Service    :PAnsiChar write SetCurrentService;
    property Event      :PAnsiChar write SetCurrentService;
    property IsShown    :boolean   read GetWindowStatus;
  private
    storage:pointer;
    current:pointer;
    namespace: array [0.. 63] of AnsiChar;
    parent,
    HelpWindow:HWND;
    isServiceHelp:boolean;

    procedure Update(item:PAnsiChar=nil);
  end;

function CreateServiceCard(parent:HWND=0):tmApiCard;
function CreateEventCard  (parent:HWND=0):tmApiCard;

implementation

{
  mirutils unit is for ConvertFileName function only
  m_api is for TranslateW and TrandlateDialogDefault
}
uses common,io,m_api,mirutils,memini,wrapper;

{$r mApiCard.res}

{$include i_card_const.inc}

const
  WM_UPDATEHELP = WM_USER+100;

const
  BufSize = 2048;

const
  ApiHlpFile = 'plugins\services.ini';
{
  ServiceHlpFile = 'plugins\services.ini';
  EventsHlpFile  = 'plugins\events.ini';
}
function tmApiCard.GetResultType:PAnsiChar;
var
  buf:array [0..2047] of AnsiChar;
  p:PAnsiChar;
begin
  if storage<>nil then
  begin
    StrCopy(buf,GetParamSectionStr(current,'return',''));
    p:=@buf;
    while p^ in sWordOnly do inc(p);
    p^:=#0;
    StrDup(result,@buf);
  end
  else
    result:=nil;
end;

function tmApiCard.GetDescription:PAnsiChar;
begin
  if storage<>nil then
  begin
    StrDup(result,GetParamSectionStr(current,'descr',''));
  end
  else
    result:=nil;
end;

function tmApiCard.GetWindowStatus:boolean;
begin
  result:=HelpWindow<>0;
end;

function tmApiCard.GetParam(wparam:boolean):PAnsiChar;
var
  paramname:PAnsiChar;
begin
  if storage=nil then
  begin
    result:=nil;
    exit;
  end;
  if wparam then
    paramname:='wparam'
  else
    paramname:='lparam';

  StrDup(result,GetParamSectionStr(current,paramname,''));
end;

function tmApiCard.FillParams(wnd:HWND{;item:PAnsiChar};wparam:boolean):PAnsiChar;
var
  buf :array [0..2047] of AnsiChar;
  bufw:array [0..2047] of WideChar;
  j:integer;
  p,pp,pc:PAnsiChar;
  tmp:PWideChar;
  paramname:PAnsiChar;
begin
  if storage=nil then
  begin
    result:=nil;
    exit;
  end;
  if wparam then
    paramname:='wparam'
  else
    paramname:='lparam';

  StrCopy(buf,GetParamSectionStr(current,paramname,''));
  StrDup(result,@buf);

  if wnd=0 then
    exit;

  SendMessage(wnd,CB_RESETCONTENT,0,0);
  if buf[0]<>#0 then
  begin
    p:=@buf;
    GetMem(tmp,BufSize*SizeOf(WideChar));
    repeat
      pc:=StrScan(p,'|');
      if pc<>nil then
        pc^:=#0;

      if (p^ in ['0'..'9']) or ((p^='-') and (p[1] in ['0'..'9'])) then
      begin
        j:=0;
        pp:=p;
        repeat
          bufw[j]:=WideChar(pp^);
          inc(j); inc(pp);
        until (pp^=#0) or (pp^=' ');
        if pp^<>#0 then
        begin
          bufw[j]:=' '; bufw[j+1]:='-'; bufw[j+2]:=' '; inc(j,3);
          FastAnsiToWideBuf(pp+1,tmp);
          StrCopyW(bufw+j,TranslateW(tmp));
          SendMessageW(wnd,CB_ADDSTRING,0,lparam(@bufw));
        end
        else
          SendMessageA(wnd,CB_ADDSTRING,0,lparam(p));
      end
      else
      begin
        FastAnsiToWideBuf(p,tmp);
        SendMessageW(wnd,CB_ADDSTRING,0,lparam(TranslateW(tmp)));
        if (p=@buf) and (StrCmp(p,'structure')=0) then
          break;
      end;
      p:=pc+1;
    until pc=nil;
    FreeMem(tmp);
  end;
  SendMessage(wnd,CB_SETCURSEL,0,0);
end;

function tmApiCard.HashToName(ahash:longword):PAnsiChar;
var
  p,pp:PAnsiChar;
begin
  result:=nil;
  if storage<>nil then
  begin
    p:=GetSectionList(storage,namespace);
    pp:=p;
    while p^<>#0 do
    begin
      if ahash=Hash(p,StrLen(p)) then
      begin
        StrDup(result,p);
      end;
      while p^<>#0 do inc(p); inc(p);
    end;
    FreeSectionList(pp);
  end;
end;

function tmApiCard.NameFromList(cb:HWND):PAnsiChar;
var
  buf:array [0..255] of AnsiChar;
  pc:PAnsiChar;
  idx:integer;
begin
  pc:=GetDlgText(cb,true);
  idx:=SendMessage(cb,CB_GETCURSEL,0,0);
  if idx<>CB_ERR then
  begin
    SendMessageA(cb,CB_GETLBTEXT,idx,lparam(@buf));
    // edit field is text from list
    if StrCmp(pc,@buf)=0 then
    begin
      mFreeMem(pc);
      result:=HashToName(CB_GetData(cb,idx));
      exit;
    end;
  end;
  // no select or changed text
  result:=pc;
end;

procedure tmApiCard.FillList(combo:HWND; mode:integer=0);
var
  tmpbuf:array [0..127] of AnsiChar;
  p,pp,pc:PAnsiChar;
  idx:integer;
begin
  if storage<>nil then
  begin
    SendMessage(combo,CB_RESETCONTENT,0,0);
    p:=GetSectionList(storage,namespace);
    pp:=p;
    while p^<>#0 do
    begin
      case mode of
        1: begin // just constant name
          pc:=GetParamStr(storage,p,'alias',nil,namespace);
          if pc=nil then
            pc:=p;
        end;
        2: begin // value (name)
          pc:=StrCopyE(tmpbuf,p);
          pc^:=' '; inc(pc);
          pc^:='('; inc(pc);
          pc:=StrCopyE(pc,GetParamStr(storage,p,'alias',nil,namespace));
          pc^:=')'; inc(pc);
          pc^:=#0;
          pc:=@tmpbuf;
        end;
        3: begin // name 'value'
          pc:=@tmpbuf;
          pc:=StrCopyE(pc,GetParamStr(storage,p,'alias',nil,namespace));
          pc^:=' '; inc(pc);
          pc^:=''''; inc(pc);
          pc:=StrCopyE(pc,p);
          pc^:=''''; inc(pc);
          pc^:=#0;
          pc:=@tmpbuf;
        end;
      else // just constant value
        pc:=p;
      end;
      idx:=SendMessageA(combo,CB_ADDSTRING,0,lparam(pc));
      SendMessageA(combo,CB_SETITEMDATA,idx,Hash(p,StrLen(p)));
      while p^<>#0 do inc(p); inc(p);
    end;
    FreeSectionList(pp);
    SendMessage(combo,CB_SETCURSEL,-1,0);
  end;
end;

function ServiceHelpDlg(Dialog:HWND;hMessage:uint;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
var
  buf:PAnsiChar;
  tmp:PWideChar;
  card:tmApiCard;
begin
  result:=0;
  case hMessage of
    WM_CLOSE: begin
      card:=tmApiCard(GetWindowLongPtr(Dialog,GWLP_USERDATA{DWLP_USER}));
      card.HelpWindow:=0;
      DestroyWindow(Dialog); //??
    end;

    WM_INITDIALOG: begin
      TranslateDialogDefault(Dialog);
      result:=1;
    end;

    WM_COMMAND: begin
      if (wParam shr 16)=BN_CLICKED then
      begin
        case loword(wParam) of
          IDOK,IDCANCEL: begin
            card:=tmApiCard(GetWindowLongPtr(Dialog,GWLP_USERDATA{DWLP_USER}));
            card.HelpWindow:=0;
            DestroyWindow(Dialog);
          end;
        end;
      end;
    end;

    WM_UPDATEHELP: begin
      with tmApiCard(lParam) do
      begin
        if (storage<>nil) and (lParam<>0) and (current<>nil) then
        begin
          GetMem(buf,BufSize);
          GetMem(tmp,BufSize*SizeOf(WideChar));

          SetDlgItemTextA(Dialog,IDC_HLP_SERVICE,GetSectionName(current));

          SetDlgItemTextA(Dialog,IDC_HLP_ALIAS,
              GetParamSectionStr(current,'alias',''));
          
          FastAnsiToWideBuf(GetParamSectionStr(current,'return','Undefined'),tmp);
          SetDlgItemTextW(Dialog,IDC_HLP_RETURN,TranslateW(tmp));

          FastAnsiToWideBuf(GetParamSectionStr(current,'descr','Undefined'),tmp);
          SetDlgItemTextW(Dialog,IDC_HLP_EFFECT,TranslateW(tmp));

          FastAnsiToWideBuf(GetParamSectionStr(current,'plugin',''),tmp);
          SetDlgItemTextW(Dialog,IDC_HLP_PLUGIN,TranslateW(tmp));

          // Parameters
          StrCopy(buf,GetParamSectionStr(current,'wparam','0'));
          if StrScan(buf,'|')<>nil then
          begin
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_WPARAML),SW_SHOW);
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_WPARAM ),SW_HIDE);
            FillParams(GetDlgItem(Dialog,IDC_HLP_WPARAML),true);
          end
          else
          begin
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_WPARAML),SW_HIDE);
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_WPARAM ),SW_SHOW);
            FastAnsiToWideBuf(buf,tmp);
            SetDlgItemTextW(Dialog,IDC_HLP_WPARAM,TranslateW(tmp));
          end;

          StrCopy(buf,GetParamSectionStr(current,'lparam','0'));
          if StrScan(buf,'|')<>nil then
          begin
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_LPARAML),SW_SHOW);
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_LPARAM ),SW_HIDE);
            FillParams(GetDlgItem(Dialog,IDC_HLP_LPARAML),false);
          end
          else
          begin
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_LPARAML),SW_HIDE);
            ShowWindow(GetDlgItem(Dialog,IDC_HLP_LPARAM ),SW_SHOW);
            FastAnsiToWideBuf(buf,tmp);
            SetDlgItemTextW(Dialog,IDC_HLP_LPARAM,TranslateW(tmp));
          end;

          FreeMem(tmp);
          FreeMem(buf);
        end
        else
        begin
          SetDlgItemTextW(Dialog,IDC_HLP_SERVICE,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_ALIAS  ,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_PLUGIN ,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_RETURN ,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_EFFECT ,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_WPARAM ,nil);
          SetDlgItemTextW(Dialog,IDC_HLP_LPARAM ,nil);
          SendDlgItemMessage(Dialog,IDC_HLP_WPARAML,CB_RESETCONTENT,0,0);
          SendDlgItemMessage(Dialog,IDC_HLP_LPARAML,CB_RESETCONTENT,0,0);
          ShowWindow(GetDlgItem(Dialog,IDC_HLP_WPARAML),SW_HIDE);
          ShowWindow(GetDlgItem(Dialog,IDC_HLP_LPARAML),SW_HIDE);
        end;
      end;
    end;
  end;
end;

procedure tmApiCard.SetCurrentService(item:PAnsiChar);
begin
  if (item=nil) or (item^=#0) then
    current:=nil
  else
    current:=SearchSection(storage,item,namespace);
end;

procedure tmApiCard.Update(item:PAnsiChar=nil);
begin
  SendMessage(HelpWindow,WM_UPDATEHELP,0,LPARAM(self));
end;

procedure tmApiCard.Show;
var
  note,
  title:PWideChar;
begin
  if HelpWindow=0 then
  begin
    HelpWindow:=CreateDialogW(hInstance,'IDD_MAPIHELP',//MAKEINTRESOURCEW(IDD_HELP),
                parent,@ServiceHelpDlg);
    if HelpWindow<>0 then
    begin
      SetWindowLongPtr(HelpWindow,GWLP_USERDATA{DWLP_USER},LONG_PTR(Self));
      if isServiceHelp then
      begin
        title:='Miranda service help';
        note :='''<proto>'' in service name will be replaced by protocol name for contact handle in parameter';
      end
      else
      begin
        title:='Miranda event help';
        note :='';
      end;
      SendMessageW(HelpWindow,WM_SETTEXT,0,LPARAM(TranslateW(title)));

      SendMessageW(GetDlgItem(HelpWindow,IDC_HLP_NOTE),WM_SETTEXT,0,LPARAM(TranslateW(note)));
    end;
  end
  else
  begin
{
    if parent<>GetParent(HelpWindow) then
      SetParent(HelpWindow,parent);
}
  end;
//  if title<>nil then
//    SendMessageW(HelpWindow,WM_SETTEXT,0,TranslateW(title));

  Update(current);
end;

constructor tmApiCard.Create(fname:PAnsiChar; lparent:HWND=0);
var
  INIFile: array [0..511] of AnsiChar;
begin
  inherited Create;

  StrCopy(@INIFile,fname);
  HelpWindow:=0;
  current:=nil;
  if fname<>nil then
  begin
    ConvertFileName(fname,@INIFile);
  //  CallService(MS_UTILS_PATHTOABSOLUTE,
  //    WPARAM(PAnsiChar(ServiceHlpFile)),LPARAM(INIFile));
    if GetFSize(PAnsiChar(@INIFile))=0 then
    begin
      INIFile[0]:=#0;
    end;
    parent:=lparent;
  end;
  storage:=OpenStorage(PAnsiChar(@INIFile));
end;

destructor tmApiCard.Destroy;
begin
  CloseStorage(storage);

  inherited;
end;

function CreateServiceCard(parent:HWND=0):tmApiCard;
begin
  result:=tmApiCard.Create(ApiHlpFile,parent);
  result.isServiceHelp:=true;
  StrCopy(result.namespace,'Service');
end;

function CreateEventCard(parent:HWND=0):tmApiCard;
begin
  result:=tmApiCard.Create(ApiHlpFile,parent);
  result.isServiceHelp:=false;
  StrCopy(result.namespace,'Event');
end;


//initialization
//finalization
end.