library SudoScan;

{$mode objfpc}{$H+}

uses
  Classes, strutils, sysutils, character
  { you can add units after this };
  
//Fonction InStr renvoie la position d'une sous-chaine Needle dans une chaine Chaine
//  On peut préciser la position de départ Debut dans la chaine.
//  Renvoie 0 si Needle non trouvée.       
Function InStr(Debut: Integer; Chaine: AnsiString; Needle: AnsiString): Integer;
  var
    f: PChar;
    res: Integer;
  begin
    f := @Chaine[Debut];
    res := Pos(Needle, f);
    if res = 0 then
      result := 0
    else
      Result := res + Debut - 1;
  end;

//Fonction blktfr transfère un bloc de caractères orig vers un pointeur de caractères dest
Function blktfr(dest: PChar; orig: AnsiString): PChar;
var
  c: Integer;
begin
  for c:=1 to length(orig) do begin
    dest^ := orig[c]; dest := dest + 1;
  end;
  Result := dest;
end;

//Effectue l'analyse de la page web codeSource et rempli Reponse avec le résultat de l'analyse
//  Reponse est un tableau de caractères de 400 caractères initialisé à chr(0) fourni par l'application appelante
procedure procedeEsudoku(codeSource: AnsiString; var Reponse:Array of char);
  var
  k: Char;
  tablo: array[0..80] of char;
  m, col, lig: Integer;
  posi, situetd, situevalue, offset, lastp: Integer;
  q: PChar;
  txprem, txinput, txtd, txvalue, txsudoku, txnumero, txdiv: AnsiString;
  txAnnul: AnsiString;
begin
  for m:=0 to 80 do tablo[m]:='0';
  txAnnul:='0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,';
  txAnnul:= txAnnul + '0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,';
  txAnnul := txAnnul + 'page web sudoku inconnue'; //variable à renvoyer en cas d'incompréhension;
  
  if Instr(1, codeSource, 'class=tableau') <> 0 then txprem := 'class=tableau'
  else if Instr(1, codeSource, 'class="tableau"') <> 0 then txprem := 'class="tableau"'
  else if Instr(1, codeSource, 'id=grille') <> 0 then txprem := 'id=grille'
  else if Instr(1, codeSource, 'id="grille"') <> 0 then txprem := 'id="grille"'
  else if Instr(1, codeSource, 'id="grille-sudoku"') <> 0 then txprem := 'id="grille-sudoku"'
  else begin blktfr(Reponse, txAnnul); exit; end; //Tiens! un nouveau qu'on ne connait pas?

  posi := Instr(1, codeSource, txprem); // lancer la recherche du tableau
  if Instr(posi, codeSource, 'value="') <> 0 then begin  // et initialise...
    txvalue := 'value="'; offset := 7; end
  else begin txvalue := 'value='; offset := 6; end;  //... quelques variables
  if Instr(posi, codeSource, '<INPUT') <> 0 then txinput := '<INPUT'
  else txinput := '<input';
  if Instr(posi, codeSource, '</TD') <> 0 then txtd := '</TD' //... encore
  else txtd := '</td';
  txsudoku := 'sudoku['; //... et encore

// Remplissage du tableau tablo qui représente les 81 cases du sudoku
  if posi <> 0 then begin
    posi := Instr(posi, codeSource, txinput); // Recherche la position de <INPUT
    for m:=0 to 80 do begin
      if  posi = 0 then break;
      lastp := posi; // conserve cette position pour un usage ultérieur
      situetd := Instr(posi, codeSource, txtd); // chercher </td
      situevalue := Instr(posi, codeSource, txvalue); // chercher value=
      if (situevalue <> 0) and (situevalue < situetd) then begin
        k := codeSource[situevalue + offset];
        if k = '"' then k:='0'; // prévoir le cas : value=""
        situevalue := Instr(posi, codeSource, txsudoku); // rech sudoku[l][c]
        lig := StrToInt(codeSource[situevalue + 7]);
        col := StrToInt(codesource[situevalue + 10]);
        tablo[lig * 9 + col] := k;
      end;
      posi := Instr(posi+1, CodeSource, txinput); //rech du <INPUT suivant
    end;
  end;
  if posi = 0 then begin blktfr(Reponse, txAnnul); exit; end; // c'est la cata...

  q := @Reponse[0]; // transferer tous les chiffres du tablo dans la réponse Reponse
  for m:=0 to 80 do begin
    q^ := tablo[m]; q := q + 1;
    q^ := ','; q := q + 1;
  end;

// Recherche de la référence du Sudoku
  if Instr(lastp, codeSource, '</DIV') <> 0 then txdiv := '</DIV'
  else txdiv := '</div';
  if Instr(lastp, codeSource, 'id="numero"') <> 0 then txnumero := 'id="numero"'
  else if Instr(lastp, codeSource, 'id=numero') <> 0 then txnumero := 'id=numero'
  else begin blktfr(q, 'e-sudoku-Numéro_inconnu'); exit; end;

  posi := Instr(lastp, codeSource, txnumero); //rech id=numero
  while not IsNumber(codeSource[posi]) do Inc(posi); //rech du 1er car numérique
  situetd := Instr(posi, codeSource, txdiv); //on limite le texte à la rencontre de </DIV
  q := blktfr(q, 'e-sudoku-');
  for m := posi to situetd - 2 do begin
    q^ := codeSource[m]; q := q + 1; //transfere la référence du sudoku dans la réponse
  end;
  q^ := chr(0);
end;

procedure gridLoading(codeSource, Titre: AnsiString; var Reponse:Array of char); stdcall; export;
begin
  if titre = 'e-sudoku' then begin procedeEsudoku(codeSource, Reponse); end
  else begin
    txAnnul:='0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,';
    txAnnul:= txAnnul +'0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,';
    blktfr(Reponse, txAnnul+'Titre du site non trouvé');
  end;
end;

exports
  gridLoading;

begin
end.
