unit U_HintW;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Registry, ShellAPI, FastStrings, Dialogs, StdCtrls, OleCtrls, SHDocVw, ucCustomizedWebBrowser, ActiveX,
  IdCoderMIME, Menus, ExtCtrls;

type

  TVariantArray = array of Variant;

  TCustomizedWebBrowser = class(ucCustomizedWebBrowser.TCustomizedWebBrowser)
  protected
    procedure InvokeEvent(DispID: TDispID; var Params: TDispParams); override;
  end;

  TF_HintW = class(TForm)
    WebBrowser: TCustomizedWebBrowser;
    PopupMenu1: TPopupMenu;
    Timer1: TTimer;
    Panel1: TPanel;
    CustomizedWebBrowser1: TCustomizedWebBrowser;
    procedure WebBrowserBeforeNavigate2(Sender: TObject;
      const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
      Headers: OleVariant; var Cancel: WordBool);
    procedure WebBrowserEnter(Sender: TObject);
    function WebBrowserPressAccelerator(Sender: TObject;
      const lpMsg: tagMSG): Boolean;
    procedure WebBrowserDocumentComplete(Sender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
    procedure WebBrowserNavigateComplete2(Sender: TObject;
      const pDisp: IDispatch; var URL: OleVariant);
    procedure WebBrowserMenuPopup(Sender: TObject; X, Y: Integer;
      ID: Cardinal);
    procedure Timer1Timer(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  protected
    FBNext: String;
    FBBack: String;
    FBFirst: String;
    FTplPath: String;
    FMainForm: TForm;
    procedure AssignEmptyDocument;
    procedure Go(Url: string);
    procedure GoStat(Url: string);
    procedure HideHints;
    function LoadFromStream(const AStream: TStream): HRESULT;
    function LoadFromStrings(const AStrings: TStrings): HRESULT;
    function LoadFromString(const S: string): HRESULT;
    function LoadFromFile(const FileName: string): HRESULT;
    procedure LoadNavButton(var aBtCode: String; const aTplDir, aTpl, aDefText: String);
    procedure StepWizard(aDirection: Integer);
  public
    FCurrStep: Integer;
    FStepCount: Integer;
    function GetPathTpl(aRelative: Boolean=false): String;
    procedure FirstWizard;
    procedure NextWizard;
    procedure BackWizard;
    procedure StartWizard;
  end;

  procedure CheckAndShowHint(aUrl: string; aProgIdent: string; aMainForm: TForm = nil; DaysCheck: integer = 7; CheckNeedOpen: boolean = True);

  procedure SendStat(aUrlStat, aProgIdent, prog_full_ver_str, prog_ver, build_or_date, req_code, answ_code: string; is_trial, is_flash: boolean);

const
  RegRootKey = HKEY_CURRENT_USER;

var
  F_HintW: TF_HintW;
  WasNavError: boolean;
  Reg: TRegistry = nil;
  NumTime: integer;

implementation

uses IdCoder;

{$R *.dfm}


{ TF_HintW }

procedure SendStat(aUrlStat, aProgIdent, prog_full_ver_str, prog_ver, build_or_date, req_code, answ_code: string; is_trial, is_flash: boolean);
var
  aFullURL: string;
  IdEncoderMIME: TIdEncoderMIME;
begin
  if assigned(F_HintW) then
    FreeAndNil(F_HintW);
  if Not assigned(F_HintW) then
    Application.CreateForm(TF_HintW, F_HintW);

  try
    IdEncoderMIME := TIdEncoderMIME.Create(nil);
    aFullURL := aUrlStat + '?ProgIdent=' + IdEncoderMIME.EncodeString(aProgIdent);
    aFullURL := aFullURL + '&prog_full_ver_str=' + IdEncoderMIME.EncodeString(prog_full_ver_str);
    aFullURL := aFullURL + '&prog_ver=' + IdEncoderMIME.EncodeString(prog_ver);
    aFullURL := aFullURL + '&build_or_date=' + IdEncoderMIME.EncodeString(build_or_date);
    aFullURL := aFullURL + '&req_code=' + IdEncoderMIME.EncodeString(req_code);
    aFullURL := aFullURL + '&answ_code=' + IdEncoderMIME.EncodeString(answ_code);
    aFullURL := aFullURL + '&is_trial=' + IdEncoderMIME.EncodeString(inttostr(byte(is_trial)));
    aFullURL := aFullURL + '&is_flash=' + IdEncoderMIME.EncodeString(inttostr(byte(is_flash)));
  finally
    IdEncoderMIME.Free;
  end;
  F_HintW.GoStat(aFullURL);
end;

procedure CheckAndShowHint(aUrl: string; aProgIdent: string; aMainForm: TForm = nil; DaysCheck: integer = 7; CheckNeedOpen: boolean = True);
var
  LastDate: integer;
  NeedOpen: boolean;
  vRefresh : OleVariant;
begin
  NumTime := 0;
  if Not Assigned(Reg) then
    Reg := TRegistry.Create;
  Reg.RootKey := RegRootKey;
  if (DaysCheck > 0) and CheckNeedOpen then
  begin
    try
      if Reg.OpenKey('\Software\Expertsoft\Hints\' + aProgIdent, True) then
      begin
        if Reg.ValueExists('DontShow') then
        begin
          if Reg.ReadBool('DontShow') then
          begin
            Reg.CloseKey;
            exit;
          end;
        end;
      end;
    except
    end;
  end;

  NeedOpen := True;
  if CheckNeedOpen then
  begin
    NeedOpen := False;
    LastDate := 0;
    if Reg.OpenKey('\Software\Expertsoft\Hints\' + aProgIdent, True) then
    begin
      try
        if Reg.ValueExists('Date') then
        begin
          LastDate := Reg.ReadInteger('Date');
        end;
      except
        LastDate := 0;
      end;
    end;
    if Now - LastDate >= DaysCheck then
      NeedOpen := True
  end;
  if NeedOpen then
  begin
    if assigned(F_HintW) then
    begin
      if F_HintW.Caption = aUrl then
        FreeAndNil(F_HintW);
    end;

    if Not assigned(F_HintW) then
      Application.CreateForm(TF_HintW, F_HintW);

    F_HintW.FMainForm := aMainForm;
    //if F_HintW.Caption = '' then
    begin
      F_HintW.Caption := aUrl;
      F_HintW.CustomizedWebBrowser1.Visible := False;
      F_HintW.CustomizedWebBrowser1.Height := 1;
      F_HintW.CustomizedWebBrowser1.Width := 1;
      F_HintW.CustomizedWebBrowser1.left := -1;
      F_HintW.CustomizedWebBrowser1.top := -1;
      if F_HintW.FMainForm <> nil then
      begin
        F_HintW.Left := aMainForm.Left + aMainForm.Width - F_HintW.Width - (GetSystemMetrics(SM_CXBORDER) + 2);
        F_HintW.Top := aMainForm.Top + aMainForm.Height - F_HintW.Height - (GetSystemMetrics(SM_CXBORDER) + 2);
       end;
      //F_HintW.WebBrowser.Navigate(aUrl);
      //F_HintW.WebBrowser.Stop;  тормозит
      F_HintW.Go(aUrl);
      //F_HintW.Show;
    end;  
  end;
end;

procedure TCustomizedWebBrowser.InvokeEvent(DispID: TDispID;
  var Params: TDispParams);
const
  DISPID_NAVIGATEERROR = 271;
  INET_E_RESOURCE_NOT_FOUND = -2146697211;
var
  Code: Integer;
  ParamCount, I: Integer;
  VarArray: TVariantArray;
begin
  inherited;
  if DispID = DISPID_NAVIGATEERROR then
  begin
    ParamCount := Params.cArgs;
    SetLength(VarArray, ParamCount);
    for I := Low(VarArray) to High(VarArray) do
      VarArray[High(VarArray) - I] := OleVariant(Params.rgvarg^[I]);
    { StatusCode }
    Code := VarArray[3];
    if (Code = INET_E_RESOURCE_NOT_FOUND) or  (Code = 404) then
    begin
      //ShowMessage('Not found!');
      WasNavError := True;
    end;
  end;
end;


procedure TF_HintW.AssignEmptyDocument;
begin
  Go('about:blank');
end;

procedure TF_HintW.BackWizard;
begin
  StepWizard(-1);
end;

procedure TF_HintW.Go(Url: string);
var
  Flags, TargetFrameName, PostData, Headers: OleVariant;
begin
  WasNavError := False;
  Flags := 0;
  TargetFrameName := 0;
  Postdata := 0;
  Headers := 0;
  if (Trim(Url) <> '') then
    WebBrowser.Navigate(Url, Flags, TargetFrameName, PostData, Headers);
end;

procedure TF_HintW.GoStat(Url: string);
var
  Flags, TargetFrameName, PostData, Headers: OleVariant;
begin
  WasNavError := False;
  Flags := 0;
  TargetFrameName := 0;
  Postdata := 0;
  Headers := 0;
  if (Trim(Url) <> '') then
    CustomizedWebBrowser1.Navigate(Url, Flags, TargetFrameName, PostData, Headers);
end;

procedure TF_HintW.HideHints;
begin
//
end;

function TF_HintW.LoadFromFile(const FileName: string): HRESULT;
var
   Stream: TStream;
begin
   Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
   try
      Result := LoadFromStream(Stream);
   finally
      Stream.Free;
   end;
end;


function TF_HintW.LoadFromStream(const AStream: TStream): HRESULT;
begin
  if not Assigned(WebBrowser.Document) then
      AssignEmptyDocument;
   AStream.seek(0, 0);
   Result := (WebBrowser.Document as IPersistStreamInit).Load(TStreamadapter.Create(AStream));
end;

function TF_HintW.LoadFromStrings(const AStrings: TStrings): HRESULT;
var
   M: TMemoryStream;
begin
   if not Assigned(WebBrowser.document) then
      AssignEmptyDocument;
   M := TMemoryStream.Create;
   try
      AStrings.SaveToStream(M);
      Result := LoadFromStream(M);
   except
      Result := S_False;
   end;
   M.free;
end;

function TF_HintW.LoadFromString(const S: string): HRESULT;
var
   Strings: TStringList;
begin
   Strings := TStringList.Create;
   try
      Strings.Text := S;
      Result := LoadFromStrings(Strings);
   finally
      FreeAndNil(Strings);
   end;
end;

function TF_HintW.GetPathTpl(aRelative: Boolean=false): String;
begin
  Result := '\HintBox\';
end;

procedure TF_HintW.FirstWizard;
begin
  StepWizard(1-FCurrStep);
end;

procedure TF_HintW.NextWizard;
begin
  StepWizard(1);
end;

procedure TF_HintW.StartWizard;
begin
end;

procedure TF_HintW.StepWizard(aDirection: Integer);
begin
//  LoadFromString(tplBegin + Tpl +TplNav + tplEnd);
end;

function SplitString(const AStr, ASeparator: string; AIncludeEmptySections: Boolean): TStringList;
var
  i: Integer;
  LenStr: Integer;
  BuffStr: String;
  SepLookIdx: Integer;
  SepBuff: String;
  IsFullSep: Boolean;
begin
  Result := TStringList.Create;
  BuffStr := '';
  LenStr := Length(AStr);
  SepLookIdx := 1;
  SepBuff := '';

  for i := 1 to LenStr do
  begin
    IsFullSep := false;
    if AStr[i] = ASeparator[SepLookIdx] then
    begin
      if SepLookIdx = Length(ASeparator) then
      begin
        IsFullSep := true;
        SepLookIdx := 1;
        SepBuff := '';
      end
      else
      begin
        SepBuff := SepBuff + AStr[i];
        Inc(SepLookIdx);
        Continue; //// CONTINUE ////
      end;
    end
    else
    begin
      // Сброс буФера сплитера
      if SepLookIdx > 1 then
      begin
        BuffStr := BuffStr + SepBuff;
        SepLookIdx := 1;
        SepBuff := '';
      end;
    end;

    if Not IsFullSep then
      BuffStr := BuffStr + AStr[i];
    if IsFullSep or (i=LenStr) then
      if (BuffStr <> '') or AIncludeEmptySections then
      begin
        Result.Add(BuffStr);
        BuffStr := '';

        // если последний символ - разделитель, то добавляем пустую строку
        if AIncludeEmptySections then
          if IsFullSep and (i=LenStr) then
            Result.Add('');
      end;
  end;
end;


procedure TF_HintW.WebBrowserBeforeNavigate2(Sender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
var
  PosAbout: Integer;
  UrlParts: TStringList;
  UrlCmd: String;
  ovElem: OleVariant;
  Str: String;

  //SprComponentType: TNBComponentType;
  FileName: String;

  function DefineWorkList: Boolean;
  begin
    Result := true;
  end;

begin
  if (URL <> 'about:blank') then
  begin
    URL := FastReplace(URL, 'about:blank', 'about:', false);
    PosAbout := Pos('about:shell:', URL);
    if PosAbout = 1 then
    begin
      URL := FastReplace(URL, 'about:shell:', 'about:', false);
      UrlParts := SplitString(Copy(URL, Length('about:')+1, Length(URL)-(Length('about:'))), #255, false);
      if UrlParts.Count > 0 then
      begin
        UrlCmd := UrlParts[0];
        ShellExecute(Handle, 'open', PChar(UrlCmd), nil, nil, SW_MAXIMIZE);
      end;
      Cancel := true;
    end
    else
    begin
      PosAbout := Pos('about:', URL);
      if PosAbout = 1 then
      begin
        UrlParts := SplitString(Copy(URL, Length('about:')+1, Length(URL)-(Length('about:'))), '_', false);
        if UrlParts.Count > 0 then
        begin
          UrlCmd := UrlParts[0];
          if UrlCmd = 'actClose' then
          begin
            Close;
          end
          else if UrlCmd = 'actToolTip' then
          begin
            if UrlParts.Count > 1 then
            begin
              ovElem := WebBrowser.OleObject.document.getElementbyId('ttContent'+UrlParts[1]); 
              if ovElem.tagName = 'SPAN' then
              begin
                Str := ovElem.InnerHTML;
                Str := FastReplace(Str, 'about:blank', 'about:', false);
              end
              else
              if ovElem.tagName = 'IMG' then
              begin
                FileName := ovElem.href;
                FileName := FastReplace(FileName, 'about:blank', 'about:', false);
                FileName := Copy(FileName, Length('about:')+1, Length(URL)-(Length('about:')));
                try
                except
                end;
              end;
            end;
          end
          else
          if UrlCmd = 'actNewProj' then
          begin
            //FSCS_Main.aNew.Execute
          end;
        end;
        Cancel := true;
      end;
    end;  
  end;
end;

procedure TF_HintW.WebBrowserEnter(Sender: TObject);
begin
//  HideHints;
end;

function TF_HintW.WebBrowserPressAccelerator(Sender: TObject;
  const lpMsg: tagMSG): Boolean;
begin
  //
end;

procedure TF_HintW.LoadNavButton(var aBtCode: String; const aTplDir, aTpl, aDefText: String);
var
  btPath: String;
begin
  if aBtCode = '' then
  begin
    btPath := aTplDir + aTpl;
    //if FileExists(btPath) then
    //  aBtCode := GetFileContents(btPath)
    //else
    //  aBTCode := aDefText;
  end;
end;

procedure TF_HintW.WebBrowserDocumentComplete(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
var
  str1: string;
begin
  if WasNavError then
  begin
    Close;
    exit;
  end;
  str1 := WebBrowser.OleObject.Document.All.Tags('title').Item(0).InnerHtml;
  if pos('HTTP 404', str1) <= 0 then
    Show
  else
    exit;

  Timer1.Enabled := True;

  try
    if Reg.CurrentPath <> '' then
    begin
      try
        Reg.WriteInteger('Date', Trunc(Now));
      except
      end;
    end;
  except
  end;
end;

procedure Explode(var a: array of string; Border, S: string; MaxLen: integer);
var
  S2: string;
  i: Integer;
begin
  i  := 0;
  S2 := S + Border;
  repeat
    a[i] := Copy(S2, 0,Pos(Border, S2) - 1);
    Delete(S2, 1,Length(a[i] + Border));
    Inc(i);
    if i > MaxLen then
      break;
  until S2 = '';
end;

procedure TF_HintW.WebBrowserNavigateComplete2(Sender: TObject;
  const pDisp: IDispatch; var URL: OleVariant);
var
  str1: string;
  i: integer;
  A: array of String;
begin
  F_HintW.WebBrowser.Ctl3D := False;
  F_HintW.webbrowser.Left := - (GetSystemMetrics(SM_CXBORDER) + 1);
  F_HintW.webbrowser.Top := - (GetSystemMetrics(SM_CYBORDER) + 1);
  F_HintW.webbrowser.Height := F_HintW.Height + (GetSystemMetrics(SM_CYBORDER) + 1) * 2;
  F_HintW.webbrowser.Width := F_HintW.Width + (GetSystemMetrics(SM_CXBORDER) + 1) * 2;

  if not WasNavError then
  begin
    try
      str1 := WebBrowser.OleObject.Document.Title;
      SetLength(A, 3);
      Explode(A, '_', str1, 3);
      F_HintW.Width := strtoint(A[1]);
      F_HintW.Height := strtoint(A[2]);
      if F_HintW.FMainForm <> nil then
      begin
        F_HintW.Left := FMainForm.Left + FMainForm.Width - F_HintW.Width - (GetSystemMetrics(SM_CXBORDER) + 2);
        F_HintW.Top := FMainForm.Top + FMainForm.Height - F_HintW.Height - (GetSystemMetrics(SM_CXBORDER) + 2);
      end;
      F_HintW.webbrowser.Left := - (GetSystemMetrics(SM_CXBORDER) + 1);
      F_HintW.webbrowser.Top := - (GetSystemMetrics(SM_CYBORDER) + 1);
      F_HintW.webbrowser.Height := F_HintW.Height + (GetSystemMetrics(SM_CYBORDER) + 1) * 2;
      F_HintW.webbrowser.Width := F_HintW.Width + (GetSystemMetrics(SM_CXBORDER) + 1) * 2;
    except
    end;
    Show;

  end;  
end;

procedure TF_HintW.WebBrowserMenuPopup(Sender: TObject; X, Y: Integer;
  ID: Cardinal);
begin
  //
end;

procedure TF_HintW.Timer1Timer(Sender: TObject);
begin
  NumTime := NumTime + 1;
  F_HintW.Show;
  if NumTime > 5 then
    Timer1.Enabled := False;
end;

procedure TF_HintW.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if Timer1.Enabled then
    CanClose := False;
end;

end.
