program termometeropenweathermap;
{$MODE OBJFPC}{$H+}{$RANGECHECKS ON}

{
    Termometer openweathermap.org
    For GNU/Linux.
    Version: 2.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2025  Artyomov Alexander
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    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.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

uses
  BaseUnix, SysUtils, DateUtils, StrUtils, Math, 
  Unix,Process,classes,fpjson,jsonparser;

const
fn_openweathermap_key:string='openweathermap_key.txt'; // Get from openweathermap.org
fn_openweathermap_city_id:string='openweathermap_city_id.txt';

var
HOMEDIR:string='';
openweathermap_key:string='';
openweathermap_city_id:string='';

{ Обработчик сигнала. Устанавливает флаг timed_out. }
procedure alarm_handler(sig: cint); cdecl;
begin
  // В реальном production-коде не рекомендуется вызывать небезопасные функции внутри обработчика сигнала.
  // Здесь для демонстрации печать допустима, но идеальнее — только атомарные операции/флаги.
//  timed_out := True;
//  writeln('>>> Timer fired (SIGALRM). Флаг timed_out = true');
WriteLn('na');
Halt;
end;

{ C-объявления функций из libc }
function signal(sig: cint; handler: pointer): pointer; cdecl; external 'c' name 'signal';
function alarm(seconds: cint): cint; cdecl; external 'c' name 'alarm';

function Filter(s:string):string;
var f:LongInt;
begin
result := '';
for f := 1 to Length(s) do begin
 case s[f] of
  '0'..'9','-','.': Result := Result+s[f];
 end;
end;
end;

function GetOneLiner(fn: string):string;
var
fp: Text;
l:string;
begin
Assign(fp, fn);
FileMode := 0;
{$I-}
ReSet(fp);
{$I+} if IOResult <> 0 then Exit('');
{$I-}
ReadLn(fp,l);
{$I+} if IOResult <> 0 then Exit('');
{$I-}
Close(fp);
{$I+} if IOResult <> 0 then Exit('');
Exit(l);
end;

function TryOpenWeatherMap(const City: string; out Weather: string): Boolean;
var
  Process: TProcess;
  OutputStream: TMemoryStream;
  Buffer: array[1..2048] of byte;
  BytesRead: LongInt;
  JsonString: string;
  JsonData: TJSONData;
  CityID, TempStr, Description: string;
begin
  Result := False;
  
  // Определяем ID города
//  if Pos('moscow', LowerCase(City)) > 0 then
//    CityID := '524901' // Москва
//  else if (Pos('saint', LowerCase(City)) > 0) or (Pos('petersburg', LowerCase(City)) > 0) then
//    CityID := '498817' // СПб
//  else
//    CityID := '524901'; // По умолчанию Москва
CityID := openweathermap_city_id;

  Process := TProcess.Create(nil);
  OutputStream := TMemoryStream.Create;
  try
    Process.Executable := 'curl';
    Process.Parameters.Add('https://api.openweathermap.org/data/2.5/weather?id=' + CityID + 
                          '&units=metric&appid=' + openweathermap_key{OPENWEATHER_API_KEY}); // Убрали lang=ru
    Process.Options := [poUsePipes];

    Process.Execute;
    while Process.Running or (Process.Output.NumBytesAvailable > 0) do
    begin
      BytesRead := Process.Output.Read(Buffer, SizeOf(Buffer));
      OutputStream.Write(Buffer, BytesRead);
    end;

    SetLength(JsonString, OutputStream.Size);
    OutputStream.Position := 0;
    OutputStream.ReadBuffer(JsonString[1], OutputStream.Size);

    if (Length(JsonString) > 10) and (Pos('temp', JsonString) > 0) then
    begin
      JsonData := GetJSON(JsonString);
      try
        // Форматируем температуру
        TempStr := FormatFloat('0.0', JsonData.FindPath('main.temp').AsFloat);
        
        // Берём описание на английском (например, "light rain")
        Description := JsonData.FindPath('weather[0].main').AsString;
        
        // Переводим основные варианты на русский
        if Description = 'Rain' then Description := 'дождь'
        else if Description = 'Clouds' then Description := 'облачно'
        else if Description = 'Clear' then Description := 'ясно'
        else if Description = 'Snow' then Description := 'снег';
        
        Weather := TempStr;// + '°C, ' + Description;
        Exit(true);
//        Result := True;
//        WriteLn('OpenWeatherMap успешно ответил');
      finally
        JsonData.Free;
      end;
    end;
  finally
    Process.Free;
    OutputStream.Free;
  end;
end;

var
sity,weather:string;
begin
HOMEDIR := GetEnvironmentVariable('HOME');
fn_openweathermap_key := HOMEDIR + '/' + fn_openweathermap_key;
fn_openweathermap_city_id := HOMEDIR + '/' + fn_openweathermap_city_id;
openweathermap_key := GetOneLiner(fn_openweathermap_key);
if openweathermap_key = '' then begin WriteLn(stderr, 'Error: openweathermap_key empty'); WriteLn('na'); Halt; end;
if ParamCount > 0 then openweathermap_city_id := ParamStr(1) else
 openweathermap_city_id := GetOneLiner(fn_openweathermap_city_id);
if openweathermap_city_id = '' then openweathermap_city_id := '524901'; // Moscow

  // Устанавливаем обработчик и запуск таймера
  signal(SIGALRM, @alarm_handler);
  alarm(8); // через 8 секунд придёт SIGALRM

sity:='';
if TryOpenWeatherMap(sity,weather) then begin
 weather := Filter(weather);
 if weather = '' then weather := 'na';
 WriteLn(weather);
end else WriteLn('na');
end.