{ A. Nasır Şentürk 2006 }
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GdipApi, GdipObj, DirectDraw, StdCtrls, ExtCtrls, InterThr, TextUtil,
  ConstDef, VarDates, TrayUtil, Menus, IniFiles, WinInet, XPMan, SyncObjs,
  InfoWind, ActnList, DateUtils, AboutDlg;

type
  TMainForm = class(TForm)
    ExitBtn: TButton;
    HideBtn: TButton;
    WeatherLbl: TLabel;
    BackgrndLbl: TLabel;
    TemperatureLbl: TLabel;
    CityNameLbl: TLabel;
    InfoTextLbl: TLabel;
    GridLbl: TLabel;
    Day1Lbl: TLabel;
    Day2Lbl: TLabel;
    Day3Lbl: TLabel;
    Day4Lbl: TLabel;
    Day5Lbl: TLabel;
    MoonLbl: TLabel;
    TrayPopup: TPopupMenu;
    TrayExitMenu: TMenuItem;
    TrayHideMenu: TMenuItem;
    TrayShowMenu: TMenuItem;
    OptionsBtn: TButton;
    CheckTimer: TTimer;
    XPManifest1: TXPManifest;
    VersionTimer: TTimer;
    LoadedTimer: TTimer;
    ShortPopup: TPopupMenu;
    FavoritesMenu: TMenuItem;
    N1: TMenuItem;
    N2: TMenuItem;
    AboutMenu: TMenuItem;
    ShowInfoMenu: TMenuItem;
    N3: TMenuItem;
    ExitMainMenu: TMenuItem;
    RefreshMenu: TMenuItem;
    OptionsMenu: TMenuItem;
    MainActionList: TActionList;
    ExitAction: TAction;
    ShowInfoAction: TAction;
    OptionsAction: TAction;
    HideAction: TAction;
    ShowAction: TAction;
    RefreshAction: TAction;
    AboutAction: TAction;
    N4: TMenuItem;
    TrayOptionsMenu: TMenuItem;
    N5: TMenuItem;
    TrayShowInfoMenu: TMenuItem;
    N6: TMenuItem;
    TrayAboutMenu: TMenuItem;
    TrayRefreshMenu: TMenuItem;
    N7: TMenuItem;
    AddLocAction: TAction;
    AddLocMenu: TMenuItem;
    TrayAddLocMenu: TMenuItem;
    TrayFavoritesMenu: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure CheckTimerTimer(Sender: TObject);
    procedure VersionTimerTimer(Sender: TObject);
    procedure LoadedTimerTimer(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ShortPopupPopup(Sender: TObject);
    procedure ExitActionExecute(Sender: TObject);
    procedure ShowInfoActionExecute(Sender: TObject);
    procedure OptionsActionExecute(Sender: TObject);
    procedure HideActionExecute(Sender: TObject);
    procedure ShowActionExecute(Sender: TObject);
    procedure RefreshActionExecute(Sender: TObject);
    procedure AboutActionExecute(Sender: TObject);
    procedure TrayPopupPopup(Sender: TObject);
    procedure AddLocActionExecute(Sender: TObject);
  private
    { Private declarations }
    Updating: Boolean;
    Moving: Boolean;
    Opacity: Byte;

    MainBuffer: TGPBitmap;
    DrawCanvas: TGPGraphics;
    {
    ButtonsBuffer: TGPBitmap;
    ButtonsCanvas: TGPGraphics;
    }
    OptionsImage,
    CloseImage,
    HideImage,
    TopImage,
    MidImage,
    BaseImage,
    OvTopImage,
    OvMidImage,
    OvBaseImage,
    ReflectionImage: TGPBitmap;
    EarthImage,
    SunImage,
    NoneImage: TGPBitmap;
    GridImage: TGPBitmap;

    DayState: TDayState;

    LastBuildDateStr: string;

    LocCityStr: string;
    LocRegionStr: string;
    LocCountryStr: string;
    {
    UnitTemperatureStr: string;
    UnitDistanceStr: string;
    UnitPressureStr: string;
    UnitSpeedStr: string;
    }
    CityID: string;
    IPAddress: string;

    SunriseStr: string;
    SunsetStr: string;
    LatitudeStr: string;
    LongitudeStr: string;

    WindChillStr: string;
    WindDirectionStr: string;
    WindSpeedStr: string;

    HumidityStr: string;
    VisibilityStr: string;
    {
    PressureStr: string;
    RisingStr: string;
    }
    PubDateStr: string;

    CondTextStr: string;
    CondCodeStr: string;
    CondTempStr: string;
    CondDateStr: string;

    ForecastDays : array[0..MaxForecast - 1] of string;
    ForecastLows : array[0..MaxForecast - 1] of string;
    ForecastHighs: array[0..MaxForecast - 1] of string;
    ForecastCodes: array[0..MaxForecast - 1] of string;
    ForecastDates: array[0..MaxForecast - 1] of string;
    ForecastTexts: array[0..MaxForecast - 1] of string;

    DateStr: WideString;
    HijriDateStr: WideString;

    UnitValue: string;
    TrayIcon: TTrayIcon;

    AutoUpdate: Boolean;
    UpdatePeriod: Cardinal;
    ShowTrayIcon: Boolean;

    FormCreated: Boolean;

    IsStarted: Boolean;

    BackScale: Single;

    Favorites: TStringList;

    CheckVerThread: TInternetThread;
    CheckVerXML: WideString;
    VersionStr: string;

    WeatherXML: WideString;
    WeatherThread: TInternetThread;

    IPAddressXML: WideString;
    IPAddrThread: TInternetThread;

    InfoTextForm: TInfoTextForm;
    Distance: TPoint;

    AboutForm: TAboutForm;

    IsDateShift: Boolean;
    FormatSettings: TFormatSettings;
    procedure AllocateHandle;
    procedure ReleaseHandle;
  protected
    procedure CMRestore(var Message: TMessage); message CM_RESTORE;
    procedure WMWeatherDone(var Message: TMessage); message WM_WEATHERDONE;
    procedure WMCheckVerDone(var Message: TMessage); message WM_CHECKVERDONE;
    procedure WMIPAddrDone(var Message: TMessage); message WM_IPADDRDONE;
    procedure WMMove(var Message: TWMMove); message WM_MOVE;
  public
    IsActive: Boolean;
    ConnectionStatus: TConnectionStatus;
    BackgroundStyle: TBackgroundStyle;
    BackColor: Cardinal;
    GlassEffect: Boolean;
    GlassOpacity: Byte;
    ShowIP,
    ShowDate,
    ShowHijri,
    ShowSituation,
    ShowSunInfo,
    ShowWind,
    ShowHumidity,
    ShowVisibility,
    ShowChill,
    ShowWeatherText,
    EnableFadeEffect,
    ShowInfoText,
    StayOnTop,
    FirstUsage: Boolean;
    InfoText: WideString;
    InfoTextHeight: Integer;
    { Public declarations }
    procedure UpdateLayered;
    procedure UpdateMainWindow;
    procedure UpdateBackground;
    procedure DoActivate(Sender: TObject);
    procedure DoDeactivate(Sender: TObject);
    procedure InternetUpdate;
    procedure ParseWeatherXML;
    procedure ParseIPAddressXML;
    procedure ParseCheckVerXML;
    procedure ParseDocumentDateTime;
    procedure PaintBackground;
    procedure PaintButtons;
    procedure PaintSunOrMoon;
    procedure PaintEarth;
    procedure PaintSun;
    procedure PaintMoon(Phase: Integer);
    procedure PaintNone;
    procedure PaintWeatherBig;
    procedure PaintCityName;
    procedure PaintTemperature;
    procedure PaintInfoText;
    procedure PaintGridImage;
    procedure PaintForecasts;
    procedure PaintForecastsDay(Index: Integer);
    procedure PaintTinyMoon;
    procedure LoadOptions;
    procedure SaveOptions;
    procedure DisableEvents;
    procedure EnableEvents;
    function GetMoonPhase: Integer;
    function GetMoonPhasePercent(const TheDate: TDateTime): Integer;
    function GetConnectionText: WideString;
    function GetInfoText: WideString;
    function GetHijriText: WideString;
    function GetWindText: WideString;
    function GetWindDirectionText: WideString;
    function GetWeatherText: WideString;
    function GetVisibilityText: WideString;
    function GetDateTime: WideString;
    function GetSunText: WideString;
    function GetIPAddress: WideString;
    procedure CheckNewVersion;
    procedure FadeInEffect(const Step, Wait, Max: Integer);
    procedure FadeOutEffect(const Step, Wait, Min: Integer);
    procedure HideMainForm;
    procedure ShowMainForm;
    procedure DoShowHint(var HintStr: string; var CanShow: Boolean; var HintInfo: THintInfo);
    procedure PrepareInfoText;
    function GetInfoTextHeight: Integer;
    procedure ChooseFavorite(Sender: TObject);
    procedure FetchIPAddress;
    function GetHintText: WideString;
    function GetTrayHintText: WideString;
    function GetSituationText: WideString;
    function GetTemperatureText: WideString;
    procedure ToggleInfoTextForm(Value: Boolean);
    procedure ResetData;
    procedure UpdateActionsState;
    procedure ShowOptionsDialog(const PageIndex: Integer);
    procedure DrawImageTo(Graphics: TGPGraphics; X, Y, W, H: Single;
      Image: TGPBitmap; Alpha: Byte = $FF);
    function UTCTimeToSystemTime(const UTCTime: string;
      var SystemTime: TSystemTime): Boolean;
    function DocTimeToSystemTime(const DocTime: string;
      var SystemTime: TSystemTime): Boolean;
    function GetDocumentTimeText: string;
    procedure UpdateFormStyle;
  end;

var
  MainForm: TMainForm;

implementation

uses ActiveX, ComObj, OptnsDlg, ShelApix;

{$R *.dfm}

procedure TMainForm.AllocateHandle;
begin
  MainBuffer := TGPBitmap.Create(Width, Height, PixelFormat32bppARGB);
  DrawCanvas := TGPGraphics.Create(MainBuffer);
end;

procedure TMainForm.FormCreate(Sender: TObject);
var
  I: Integer;
begin

  WideGetLocaleMonthDayNames(MakeLCID(
      MakeLangID(LANG_TURKISH, SUBLANG_DEFAULT),
    SORT_DEFAULT));

  GetLocaleFormatSettings(
    MakeLCID(
      MakeLangID(LANG_TURKISH, SUBLANG_DEFAULT),
    SORT_DEFAULT),
    FormatSettings);

  FormCreated := False;

  BackScale := 1.25;

  GridLbl.Visible := False;

  Application.ShowHint := True;
  Application.OnShowHint := DoShowHint;

  TrayIcon := TTrayIcon.Create(Self);
  TrayIcon.Hint := 'Hava Cıva!';
  TrayIcon.Icon := Application.Icon;
  TrayIcon.PopupMenu := TrayPopup;
  TrayIcon.OnDblClick := ShowActionExecute;//RefreshActionExecute;
  TrayIcon.BalloonTitle := 'Hava Cıva!';
  TrayIcon.BalloonFlags := bfInfo;
  TrayIcon.BalloonHint := sBalloonHintMsg;

  VersionTimer.Enabled := IniFile.ReadBool(sGeneral, sCheckNewVersion, True);

  for I := 0 to MaxForecast - 1 do ForecastDays[I] := '';

  DayState := dsNone;

  Application.OnActivate := MainForm.DoActivate;
  Application.OnDeactivate := MainForm.DoDeactivate;

  if GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_LAYERED = 0 then
    SetWindowLong(Handle, GWL_EXSTYLE,
      GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);

  CloseImage := TGPBitmap.Create('.\Contents\Resources\UI\Close.png');
  HideImage := TGPBitmap.Create('.\Contents\Resources\UI\Less.png');
  OptionsImage := TGPBitmap.Create('.\Contents\Resources\UI\Options.png');
  GridImage := TGPBitmap.Create('.\Contents\Resources\UI\Grid.png');

  TopImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Top.png');
  MidImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Mid.png');
  BaseImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Base.png');

  OvTopImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Top Overlay.png');
  OvMidImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Mid Overlay.png');
  OvBaseImage := TGPBitmap.Create('.\Contents\Resources\Colorize\Base Overlay.png');
  ReflectionImage := TGPBitmap.Create('.\Contents\Resources\UI\Reflection.png');

  EarthImage := TGPBitmap.Create('.\Contents\Resources\Big\Earth.png');
  SunImage := TGPBitmap.Create('.\Contents\Resources\Big\Sun.png');
  NoneImage := TGPBitmap.Create('.\Contents\Resources\Big\None.png');

  LoadOptions;

  UnitValue := 'c';

  if EnableFadeEffect then Opacity := OpacityMin
  else Opacity := OpacityMax;

  UpdateLayered;

  InternetUpdate;

  TrayIcon.Visible := ShowTrayIcon;

  CheckTimer.Enabled := AutoUpdate;
  CheckTimer.Interval := UpdatePeriod;

  LoadedTimer.Enabled := True;

  FormCreated := True;

  Favorites := TStringList.Create;

  InfoTextForm := TInfoTextForm.Create(Self);

  AboutForm := TAboutForm.Create(Self);

end;

procedure TMainForm.ReleaseHandle;
begin
  if Assigned(MainBuffer) then FreeAndNil(MainBuffer);
  if Assigned(DrawCanvas) then FreeAndNil(DrawCanvas);
end;

procedure TMainForm.UpdateLayered;
begin
  Updating := True;
  try

    ReleaseHandle;
    AllocateHandle;
    UpdateActionsState;
    PrepareInfoText;
    PaintBackground;
    PaintGridImage;
    PaintForecasts;
    PaintTemperature;
    PaintCityName;
    PaintSunOrMoon;
    PaintWeatherBig;
    //PaintInfoText;
    PaintButtons;

    UpdateMainWindow;

  finally
    Updating := False;
  end;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  AboutForm.Free;
  InfoTextForm.Free;
  Favorites.Free;
  NoneImage.Free;
  SunImage.Free;
  EarthImage.Free;
  ReflectionImage.Free;
  OvTopImage.Free;
  OvMidImage.Free;
  OvBaseImage.Free;
  TopImage.Free;
  MidImage.Free;
  BaseImage.Free;
  IPAddrThread.Free;
  CheckVerThread.Free;
  WeatherThread.Free;
  GridImage.Free;
  OptionsImage.Free;
  HideImage.Free;
  CloseImage.Free;
  ReleaseHandle;
  TrayIcon.Free;
  SaveOptions;
end;

procedure TMainForm.UpdateMainWindow;
var
  ScrDC, MemDC: HDC;
  BitmapHandle, PrevBitmap: HBITMAP;
  BlendFunc: _BLENDFUNCTION;
  Size: TSize;
  P, S: TPoint;
begin

  ScrDC := CreateCompatibleDC(0);
  MemDC := CreateCompatibleDC(ScrDC);

  MainBuffer.GetHBITMAP(0, BitmapHandle);
  PrevBitmap := SelectObject(MemDC, BitmapHandle);
  Size.cx := Width;
  Size.cy := Height;
  P := Point(Left, Top);
  S := Point(0, 0);

  with BlendFunc do
  begin
    BlendOp := AC_SRC_OVER;
    BlendFlags := 0;
    SourceConstantAlpha := Opacity;
    AlphaFormat := AC_SRC_ALPHA;
  end;

  UpdateLayeredWindow(Handle, ScrDC, @P, @Size, MemDC, @S, 0,
    @BlendFunc, ULW_ALPHA);

  SelectObject(MemDC, PrevBitmap);
  DeleteObject(BitmapHandle);

  DeleteDC(MemDC);
  DeleteDC(ScrDC);

end;

procedure TMainForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  R: TRect;
begin

  if Assigned(InfoTextForm) then
  begin
    Distance.X := InfoTextForm.Left - Self.Left;
    Distance.Y := InfoTextForm.Top - Self.Top;
  end;

  if not IsActive then
  begin
    IsActive := True;
    UpdateFormStyle;
    UpdateLayered;
  end;

  if Button = mbLeft then
  begin
    Moving := True;
    ReleaseCapture;
    SendMessage( Handle, WM_SYSCOMMAND, SC_DRAGMOVE, 0 );
    GetWindowRect(Handle, R);
    Left := R.Left;
    Top := R.Top;
    Moving := False;
    UpdateLayered;
  end;
  
end;

procedure TMainForm.DoActivate(Sender: TObject);
begin
  //IsActive := True;
  //UpdateLayered;
end;

procedure TMainForm.DoDeactivate(Sender: TObject);
begin
  IsActive := False;
  UpdateLayered;
end;

procedure TMainForm.InternetUpdate;
begin

  if Assigned(WeatherThread) then begin
    if not WeatherThread.Terminated then Exit;
  end;

  ConnectionStatus := csConnecting;
  UpdateLayered;
  if Assigned(WeatherThread) then FreeAndNil(WeatherThread);
  WeatherThread := TInternetThread.Create( True, Self,
    ForecastURL + CityID + '_' + UnitValue + '.xml', WM_WEATHERDONE );
  try
    WeatherThread.Resume;
    FetchIPAddress;
  except
    FreeAndNil(WeatherThread);
    ConnectionStatus := csException;
  end;
end;

procedure TMainForm.PaintBackground;
var
  AColor: Cardinal;
  AOpacity: Integer;
  Scale: Single;

  procedure PaintColorizedOverlay;
  var
    Image: TGPBitmap;
    X, Y: Single;
    Attr: TGPImageAttributes;
    ScaledHeight: Cardinal;
  begin
    X := BackgrndLbl.Left;
    Y := BackgrndLbl.Top;
    Image := OvTopImage;
    DrawCanvas.DrawImage(Image, X, Y, Image.GetWidth, Image.GetHeight);

    DrawCanvas.DrawImage(ReflectionImage, X + 7, Y + 3,
      ReflectionImage.GetWidth, ReflectionImage.GetHeight);

    Y := Y + Image.GetHeight;
    Image := OvMidImage;

    Attr := TGPImageAttributes.Create;
    try
      Attr.SetWrapMode(WrapModeTile);
      ScaledHeight := Round(Image.GetHeight * Scale);// + InfoTextHeight);
      DrawCanvas.SetInterpolationMode(InterpolationModeDefault);

      DrawCanvas.DrawImage(Image,
        MakeRect(X, Y, Image.GetWidth, ScaledHeight),
        0, 0, Image.GetWidth, 0.978 * Image.GetHeight, // Neden 0.978?
        UnitPixel,                                // Mecburen. Yoksa scale edince altta cizgi cikiyor.
        Attr);                                    // Neden cigi cikiyor?
                                                  // Bilmem. GDI+ scale edince alta soft bir golge veriyor.
      Y := Y + ScaledHeight;
      Image := OvBaseImage;
      DrawCanvas.DrawImage(Image, X, Y, Image.GetWidth, Image.GetHeight);

    finally
      Attr.Free;
    end;

  end;

  procedure PaintColorized(Color: Cardinal; Alpha: Byte);
  const
    CMatrix: ColorMatrix = (
      (1.0, 0.0, 0.0, 0.0, 1.0),
      (0.0, 1.0, 0.0, 0.0, 0.0),
      (0.0, 0.0, 1.0, 0.0, 0.0),
      (0.0, 0.0, 0.0, 1.0, 0.0),
      (0.0, 0.0, 0.0, 0.0, 1.0)
    );
  var
    Image: TGPBitmap;
    X, Y: Single;
    Attr: TGPImageAttributes;
    Matrix: ColorMatrix;
    ScaledHeight: Cardinal;
    Brush: TGPSolidBrush;
  begin

    Matrix := CMatrix;

    Matrix[3, 3] := (Alpha / 255);
    Matrix[0, 0] := 2 * (GetRValue(Color) / 255);
    Matrix[1, 1] := 2 * (GetGValue(Color) / 255);
    Matrix[2, 2] := 2 * (GetBValue(Color) / 255);

    Attr := TGPImageAttributes.Create;
    try
      Attr.SetWrapMode(WrapModeTile);
      Attr.SetColorMatrix(Matrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);

      X := BackgrndLbl.Left;
      Y := BackgrndLbl.Top;

      Brush := TGPSolidBrush.Create(aclRed);
      try
        //DrawCanvas.FillRectangle(Brush, MakeRect(0, 0, Self.Width, Self.Height));
      finally
        Brush.Free;
      end;

      Image := TopImage;

      DrawCanvas.DrawImage(Image,
        MakeRect(X, Y, Image.GetWidth, Image.GetHeight),  // dest rect
        0, 0, Image.GetWidth, Image.GetHeight,       // source rect
        UnitPixel,
        Attr);

      Y := Y + Image.GetHeight;
      Image := MidImage;
      ScaledHeight := Round(Image.GetHeight * Scale);// + InfoTextHeight);

      DrawCanvas.DrawImage(Image,
        MakeRect(X, Y, Image.GetWidth, ScaledHeight),  // dest rect
        0, 0, Image.GetWidth, Image.GetHeight,       // source rect
        UnitPixel,
        Attr);

      Y := Y + ScaledHeight;
      Image := BaseImage;
      
      DrawCanvas.DrawImage(Image,
        MakeRect(X, Y, Image.GetWidth, Image.GetHeight),  // dest rect
        0, 0, Image.GetWidth, Image.GetHeight,       // source rect
        UnitPixel,
        Attr);

      PaintColorizedOverlay;

    finally
      Attr.Free;
    end;

  end;

begin

  if BackgroundStyle <> bsNone then
  begin
    case BackgroundStyle of
      bsTinyGlass:
        begin
          AColor := clBlack;
          AOpacity := 0;
        end;
      bsDarkGlass:
        begin
          AColor := clBlack;
          AOpacity := 120;
        end;
      bsCoffeeMilk:
        begin
          AColor := RGB(128, 64, 0);
          AOpacity := 255;
        end;
      else begin
        AColor := BackColor;
        if GlassEffect then AOpacity := GlassOpacity
        else AOpacity := $FF;
      end;
    end;

    Scale := BackScale;
    PaintColorized(AColor, AOpacity);

  end;

end;

procedure TMainForm.PaintSunOrMoon;
var
  Sunrise, Sunset: TDateTime;
  MoonPhase: Integer;
  WeatherCodeInt: Integer;
  SysTime: TSystemTime;
  FetchedTime: TDateTime;
begin

  if WeatherLbl.Visible then
  begin

    Sunrise := StrToTimeDef(SunriseStr, -1);
    Sunset  := StrToTimeDef(SunsetStr, -1);

    if (Sunrise > -1) and (Sunset > -1) then
    begin

      FetchedTime := -1;
      if UTCTimeToSystemTime(CondDateStr, SysTime) then
        FetchedTime := TimeOf(SystemTimeToDateTime(SysTime));

      if (FetchedTime >= Sunrise) and (FetchedTime < Sunset) then
        DayState := dsDayTime
      else
        DayState := dsNightTime;
    end else DayState := dsNone;

    MoonPhase := GetMoonPhase;
    if MoonPhase < 0 then MoonPhase := 0;

    WeatherCodeInt := StrToIntDef(CondCodeStr, -1);

    if WeatherCodeInt = 3200 then WeatherCodeInt := 32;

    if (WeatherCodeInt >= 0) and (WeatherCodeInt < MaxWeatherIcons) then
    begin
      if WeatherIcons[WeatherCodeInt].SoM then
      begin
        case DayState of
          dsDayTime   : PaintSun;
          dsNightTime : PaintMoon(MoonPhase);
        else PaintEarth;
        end;
      end
      else PaintNone;
    end
    else PaintEarth;
    
  end;

end;

procedure TMainForm.PaintWeatherBig;
var
  Image: TGPBitmap;
  ImageName: string;
  WeatherCodeInt: Integer;
begin

  if WeatherLbl.Visible then
  begin
    WeatherCodeInt := StrToIntDef(CondCodeStr, -1);
    //WeatherCodeInt := 6;
    if (WeatherCodeInt >= 0) and (WeatherCodeInt < MaxWeatherIcons) then
      ImageName := '.\Contents\Resources\Big\' + WeatherIcons[WeatherCodeInt].Weather + '.png'
    else ImageName := '.\Contents\Resources\Big\None.png';

    Image := TGPBitmap.Create(ImageName);
    try
      {
      DrawImageTo(DrawCanvas, WeatherLbl.Left, WeatherLbl.Top,
        Image.GetWidth, Image.GetHeight, Image, 180);
      }
      DrawCanvas.DrawImage(Image, WeatherLbl.Left, WeatherLbl.Top,
        Image.GetWidth, Image.GetHeight);
    finally
      Image.Free;
    end;
    
  end;
end;

procedure TMainForm.PaintCityName;
var
  oRect, R: TGPRectF;
  WideText: WideString;
begin
  if CityNameLbl.Visible then
  begin

    WideText := GetConnectionText;

    CityNameLbl.Caption := WideText;

    GdiPlusMeasureString(DrawCanvas, WideText, oRect, CityNameLbl.Font,
      StringAlignmentFar);

    CityNameLbl.ClientWidth := Round(oRect.Width) + 1;
    CityNameLbl.ClientHeight := Round(oRect.Height) + 1;
    CityNameLbl.Left := BackgrndLbl.Left + BackgrndLbl.ClientWidth -
      CityNameLbl.ClientWidth - 16;

    R := MakeRectF(CityNameLbl.BoundsRect);
    GdiPlusDrawText(DrawCanvas, WideText, R, CityNameLbl.Font,
      StringAlignmentFar, aclWhite);

  end;
end;

procedure TMainForm.PaintTemperature;
var
  oRect, R: TGPRectF;
  WideText: WideString;
begin
  if TemperatureLbl.Visible then
  begin

    WideText := GetTemperatureText;

    if WideText <> '' then
    begin

      TemperatureLbl.Caption := WideText;//CondTempStr + #0176;

      GdiPlusMeasureString(DrawCanvas, WideText, oRect,
        TemperatureLbl.Font, StringAlignmentFar);

      TemperatureLbl.ClientWidth := Round(oRect.Width) + 1;
      TemperatureLbl.ClientHeight := Round(oRect.Height) + 1;
      TemperatureLbl.Left := BackgrndLbl.Left + BackgrndLbl.ClientWidth -
        TemperatureLbl.ClientWidth - 4;

      R := MakeRectF(TemperatureLbl.BoundsRect);
      GdiPlusDrawText(DrawCanvas, WideText, R, TemperatureLbl.Font,
        StringAlignmentFar, aclWhite);

    end;
  end;
end;

procedure TMainForm.PaintGridImage;
begin
  if GridLbl.Visible then
  begin
    DrawCanvas.DrawImage(GridImage, GridLbl.Left, GridLbl.Top,
      GridImage.GetWidth, GridImage.GetHeight);
  end;
end;

procedure TMainForm.PaintForecasts;
begin
  PaintForecastsDay(0);
  PaintForecastsDay(1);
  PaintForecastsDay(2);
  PaintForecastsDay(3);
  PaintForecastsDay(4);
  PaintTinyMoon;
end;

procedure TMainForm.PaintForecastsDay(Index: Integer);
var
  ForecastLabel: TLabel;
  oRect, R: TGPRectF;
  Image: TGPBitmap;
  WideText: WideString;
  TempFont: TFont;
  SysTime: TSystemTime;
begin

  ForecastLabel := nil;

  case Index of
    0: ForecastLabel := Day1Lbl;
    1: ForecastLabel := Day2Lbl;
    2: ForecastLabel := Day3Lbl;
    3: ForecastLabel := Day4Lbl;
    4: ForecastLabel := Day5Lbl;
  end;

  if (ForecastLabel <> nil) and (ForecastLabel.Visible) then
  begin

    if ForecastDays[Index] <> '' then
    begin

      UTCTimeToSystemTime(CondDateStr, SysTime);

      if Index = 0 then begin
        if (SysTime.wHour < 2) or (SysTime.wHour > 15) then
          WideText := 'BU GECE'
        else WideText := 'BUGÜN';
      end
      else if Index = 1 then WideText := 'YARIN'
      else begin
        if IsDateShift then
          WideText := EnglishDayToTurkishDay(NextEnglishDay(ForecastDays[Index]))
        else WideText := EnglishDayToTurkishDay(ForecastDays[Index]);
      end;

      GdiPlusMeasureString(DrawCanvas, WideText, oRect, ForecastLabel.Font,
        StringAlignmentCenter);

      R := MakeRectF(ForecastLabel.BoundsRect);
      R.Y := R.Y - 14;
      GdiPlusDrawText(DrawCanvas, WideText, R, ForecastLabel.Font,
        StringAlignmentCenter, aclWhite);
    end;

    TempFont := TFont.Create;
    try
      {
      TempFont.Assign(ForecastLabel.Font);
      TempFont.Size := 10;
      TempFont.Style := [fsBold];
      }

      TempFont.Name := 'Arial';
      TempFont.Size := 10;
      TempFont.Style := [fsBold];

      if ForecastHighs[Index] <> '' then
      begin

        WideText := ForecastHighs[Index] + #0176;

        GdiPlusMeasureString(DrawCanvas, WideText, oRect, TempFont,
          StringAlignmentCenter);

        R := MakeRectF(ForecastLabel.BoundsRect);
        OffsetRectF(R, -14.0, 26.0);
        GdiPlusDrawText(DrawCanvas, WideText, R, TempFont,
          StringAlignmentCenter, aclWhite);

      end;

      if ForecastLows[Index] <> '' then
      begin

        TempFont.Size := 9;

        WideText := ForecastLows[Index] + #0176;

        GdiPlusMeasureString(DrawCanvas, WideText, oRect, TempFont,
          StringAlignmentCenter);

        R := MakeRectF(ForecastLabel.BoundsRect);
        OffsetRectF(R, 14.0, 26.0);
        GdiPlusDrawText(DrawCanvas, WideText, R, TempFont,
          StringAlignmentCenter, MakeColor(200, 255, 255, 255));
      end;

    finally
      TempFont.Free;
    end;

    if ForecastCodes[Index] <> '' then
    begin

      if not ForecastLabel.ShowHint then ForecastLabel.ShowHint := True;
      ForecastLabel.Hint := WeatherIcons[StrToIntDef(ForecastCodes[Index], 49)].Turkish;

      Image := TGPBitmap.Create('.\Contents\Resources\Tiny\' +
        TinyWeatherIcons[StrToIntDef(ForecastCodes[Index], 0)] + '.png');
      try
        DrawCanvas.DrawImage(Image, ForecastLabel.Left, ForecastLabel.Top,
          Image.GetWidth, Image.GetHeight);
      finally
        Image.Free;
      end;
    end;

  end;

end;

procedure TMainForm.PaintTinyMoon;
var
  oRect, R: TGPRectF;
  Image: TGPBitmap;
  WideText: WideString;
  MoonPhase: Integer;
  TempFont: TFont;
begin

  if MoonLbl.Visible then
  begin

    if SunriseStr <> '' then
    begin

      WideText := 'AY';

      MoonPhase := GetMoonPhase();
      if MoonPhase < 0 then MoonPhase := 0;

      MoonLbl.Hint := PhaseNamesTurkish[MoonPhase];

      Image := TGPBitmap.Create('.\Contents\Resources\Tiny\Moons\' +
        IntToStr(MoonPhase) + '.png');
      try
        DrawCanvas.DrawImage(Image, MoonLbl.Left, MoonLbl.Top,
          Image.GetWidth, Image.GetHeight);
      finally
        Image.Free;
      end;

      GdiPlusMeasureString(DrawCanvas, WideText, oRect, MoonLbl.Font,
        StringAlignmentCenter);

      R := MakeRectF(MoonLbl.BoundsRect);
      R.Y := R.Y - 14;
      GdiPlusDrawText(DrawCanvas, WideText, R, MoonLbl.Font,
        StringAlignmentCenter, aclWhite);

      TempFont := TFont.Create;
      try

        TempFont.Name := 'Arial';
        TempFont.Size := 10;
        TempFont.Style := [fsBold];

        MoonPhase := GetMoonPhasePercent(SysUtils.Now);
        
        WideText := '%' + IntToStr(MoonPhase);

        GdiPlusMeasureString(DrawCanvas, WideText, oRect, TempFont,
          StringAlignmentCenter);

        R := MakeRectF(MoonLbl.BoundsRect);
        OffsetRectF(R, 0.0, 26.0);
        GdiPlusDrawText(DrawCanvas, WideText, R, TempFont,
          StringAlignmentCenter, aclWhite);

      finally
        TempFont.Free;
      end;

    end;

  end;

end;

function TMainForm.GetMoonPhase: Integer;
begin
  Result := Round(GetMoonPhasePercent(SysUtils.Date) * 0.279);
end;

procedure TMainForm.CMRestore(var Message: TMessage);
begin
  Application.Restore;
  if not Self.Visible then begin
    ShowMainForm;
    if ShowInfoText then InfoTextForm.ShowForm;
  end;
end;

procedure TMainForm.WMWeatherDone(var Message: TMessage);
begin
  WeatherXML := WeatherThread.ResponseText;
  if Assigned(WeatherThread) then FreeAndNil(WeatherThread);
  //Sleep(1000);
  if Message.LParam = 0 then
  begin
    if (not IsStarted) and (EnableFadeEffect) then
    begin
      while BackScale < 4.00 do begin
        BackScale := BackScale + 0.25;
        UpdateBackground;
        Sleep(2);
      end;
    end else BackScale := 4.00;
    IsStarted := True;
    ConnectionStatus := csConnected;
    ResetData;
    ParseWeatherXML;
    ParseDocumentDateTime;
    GridLbl.Visible := True;
    DateStr := GetDateTime;
    HijriDateStr := GetHijriText;
    //ParseLongDateTime(CondDateStr, FetchedDate, FetchedTime);
  end
  else
    ConnectionStatus := csNotConnected;
  UpdateLayered;
  InfoTextForm.UpdateLayered;
  if ShowInfoText and Self.Visible then
    InfoTextForm.ShowForm;
  TrayIcon.Hint := GetTrayHintText;
end;

procedure TMainForm.LoadOptions;
begin
  Left := IniFile.ReadInteger(sAppearance, sLeft, 300);
  Top := IniFile.ReadInteger(sAppearance, sTop, 300);
  LocCityStr := IniFile.ReadString(sLocation, sCityName, 'Istanbul');
  CityID := IniFile.ReadString(sLocation, sCityID, 'TUXX0014');
  BackgroundStyle := TBackgroundStyle(IniFile.ReadInteger(sAppearance, sBackground,
    Ord(bsDarkGlass)));
  AutoUpdate := IniFile.ReadBool(sGeneral, sAutoUpdate, True);
  EnableFadeEffect := IniFile.ReadBool(sGeneral, sFadeEffect, True);
  case IniFile.ReadInteger(sGeneral, sUpdatePeriod, 2) of
    1: UpdatePeriod := 10 * MinuteMs;
    2: UpdatePeriod := 15 * MinuteMs;
    3: UpdatePeriod := 30 * MinuteMs;
    4: UpdatePeriod := HourMs;
    5: UpdatePeriod := 2 * HourMs;
  else
    UpdatePeriod := 5 * MinuteMs;
  end;
  CheckTimer.Interval := UpdatePeriod;
  ShowTrayIcon := IniFile.ReadBool(sGeneral, sShowTrayIcon, True);
  
  TrayIcon.Visible := ShowTrayIcon;
  HideBtn.Visible := TrayIcon.Visible;

  GlassEffect := IniFile.ReadBool(sAppearance, sGlassEffect, False);
  GlassOpacity := IniFile.ReadInteger(sAppearance, sGlassOpacity, 150);
  BackColor := IniFile.ReadInteger(sAppearance, sBackColor, $808080);

  ShowIP := IniFile.ReadBool(sAppearance, sShowIP, True);
  ShowSunInfo := IniFile.ReadBool(sAppearance, sShowSunInfo, False);
  ShowSituation := IniFile.ReadBool(sAppearance, sShowSituation, False);
  ShowDate := IniFile.ReadBool(sAppearance, sShowDate, False);

  ShowHijri := IniFile.ReadBool(sAppearance, sShowHijri, False);
  ShowWind := IniFile.ReadBool(sAppearance, sShowWind, False);
  ShowVisibility := IniFile.ReadBool(sAppearance, sShowVisibility, False);
  ShowHumidity := IniFile.ReadBool(sAppearance, sShowHumidity, False);
  ShowChill := IniFile.ReadBool(sAppearance, sShowChill, False);
  ShowWeatherText := IniFile.ReadBool(sAppearance, sShowWeatherText, True);
  ShowInfoText := IniFile.ReadBool(sAppearance, sShowInfoText, True);

  FirstUsage := IniFile.ReadBool(sGeneral, sFirstUsage, True);

  TemperatureLbl.Font.Name := IniFile.ReadString(sAppearance, sTempFontName, 'Arial');
  CityNameLbl.Font.Name := IniFile.ReadString(sAppearance, sCityFontName, 'Arial');

  ShowInfoAction.Checked := ShowInfoText;

  StayOnTop := IniFile.ReadBool(sGeneral, sAlwaysTop, False);

  // Note:	It is not advisable to change FormStyle at runtime.
  
  if StayOnTop then
    SetWindowPos(Self.Handle, HWND_TOP or HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED)
  else
    SetWindowPos(Self.Handle, HWND_NOTOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED);

  if Assigned(InfoTextForm) then
    InfoTextForm.UpdateFormStyle;

end;

procedure TMainForm.SaveOptions;
begin
  IniFile.WriteInteger(sAppearance, sLeft, Left);
  IniFile.WriteInteger(sAppearance, sTop, Top);
  IniFile.WriteString(sLocation, sCityName, LocCityStr);
  IniFile.WriteString(sLocation, sCityID, CityID);
  IniFile.WriteInteger(sAppearance, sInfoTextLeft, InfoTextForm.Left);
  IniFile.WriteInteger(sAppearance, sInfoTextTop, InfoTextForm.Top);
  IniFile.WriteBool(sAppearance, sShowInfoText, ShowInfoText);
  if FirstUsage then IniFile.WriteBool(sGeneral, sFirstUsage, False);
  IniFile.UpdateFile;
end;

function TMainForm.GetConnectionText: WideString;
begin
  case ConnectionStatus of
    csConnecting   : Result := sConnecting;
    csNotConnected : Result := sNotConnected;
    csException    : Result := sException;
  else
    Result := LocCityStr;
  end;
end;

procedure TMainForm.CheckTimerTimer(Sender: TObject);
begin
  if ConnectionStatus <> csConnecting then
    InternetUpdate;
end;

procedure TMainForm.DisableEvents;
begin
  CheckTimer.Enabled := False;
end;

procedure TMainForm.EnableEvents;
begin
  CheckTimer.Enabled := AutoUpdate;
end;

function TMainForm.GetInfoText: WideString;

  procedure AddWideText(const Item, FormatStr: WideString);
  begin
    if Item <> '' then
      Result := Result + WideFormat(FormatStr, [Item]);
  end;

begin
  Result := '';
  if ShowWeatherText then
    AddWideText(GetWeatherText, '%s'#13#10);
  if ShowSunInfo then
    AddWideText(GetSunText, '%s'#13#10);
  if ShowSituation then
    AddWideText(GetSituationText, '%s'#13#10);
  if ShowWind then
    AddWideText(GetWindText, '%s'#13#10);
  if ShowHumidity then
    AddWideText(HumidityStr, 'Nem oranı: %%%s'#13#10);
  if ShowVisibility then
    AddWideText(GetVisibilityText, 'Görüş mesafesi: %s'#13#10);
  if ShowChill then
    AddWideText(WindChillStr, 'Hissedilen sıcaklık: %s'#0176#13#10);
  if ShowDate then
    AddWideText(DateStr, '%s'#13#10);
    //AddWideText(CondDateStr, '%s'#13#10);
  if ShowHijri then
    AddWideText(HijriDateStr, '%s'#13#10);
  if ShowIP then
    AddWideText(GetIPAddress, 'IP: %s'#13#10);
    
  if (Result <> '') and (Length(Result) > 1) and
     (Result[Length(Result)] = #10) then
    Delete(Result, Length(Result) - 1, 2);

end;

function TMainForm.GetHijriText: WideString;
var
  stg, sth: TSystemTime;
begin
  Result := '';
  if ConnectionStatus <> csConnected then Exit;
  GetLocalTime(stg);
  if GregorianTimeToHijriTime(stg, sth) = S_OK then
    Result := WideFormatHijriDate(sth);
end;

function TMainForm.GetWindText: WideString;
begin
  Result := '';
  if (WindDirectionStr <> '') and (WindSpeedStr <> '') then
  begin
    if WindSpeedStr <> '0' then
      Result := WideFormat('Rüzgar: %s, %s km/s', [GetWindDirectionText, WindSpeedStr])
    else
      Result := 'Rüzgar: Yok';
  end;
end;

function TMainForm.GetWindDirectionText: WideString;
var
  DirectionNum: Integer;
begin
  Result := '';
  DirectionNum := StrToIntDef(WindDirectionStr, -1);
  if DirectionNum < 0 then Exit;
  case DirectionNum of
       0..23: Result := 'Kuzey';
      24..68: Result := 'Kuzey Doğu';
     69..113: Result := 'Doğu';
    114..158: Result := 'Güney Doğu';
    159..203: Result := 'Güney';
    204..248: Result := 'Güney Batı';
    249..293: Result := 'Batı';
    294..338: Result := 'Kuzey Batı';
  else
    Result := 'Kuzey';
  end;
end;

function TMainForm.GetWeatherText: WideString;
var
  CondCodeInt: Integer;
begin
  Result := '';
  if CondCodeStr <> '' then
  begin
    CondCodeInt := StrToIntDef(CondCodeStr, 3200);
    if CondCodeInt = 3200 then CondCodeInt := 49;
    Result := WeatherIcons[CondCodeInt].Turkish;
  end;
end;

function TMainForm.GetVisibilityText: WideString;
var
  Visibility: Single;
begin
  Visibility := StrToFloatDef(VisibilityStr, -1.0);
  Visibility := Visibility / 100;
  if Visibility < 0 then Result := ''
  else if Visibility >= 320 then Result := 'Sınırsız'
       else Result := FormatFloat('0.00 km', Visibility);
end;

procedure TMainForm.VersionTimerTimer(Sender: TObject);
begin
  CheckNewVersion;
end;

procedure TMainForm.CheckNewVersion;
begin

  if Assigned(CheckVerThread) then
    if not CheckVerThread.Terminated then Exit;

  VersionTimer.Enabled := False;

  if Assigned(CheckVerThread) then FreeAndNil(CheckVerThread);
  CheckVerThread := TInternetThread.Create( True, Self,
    MyHomePage + 'version.asp?fmt=xml', WM_CHECKVERDONE );
  try
    CheckVerThread.Resume;
  except
    FreeAndNil(CheckVerThread);
  end;

end;

procedure TMainForm.LoadedTimerTimer(Sender: TObject);
begin
  LoadedTimer.Enabled := False;
  ShowMainForm;
  //if ShowInfoText then InfoTextForm.ShowForm;
  if FirstUsage then TrayIcon.ShowBalloonHint;
end;

procedure TMainForm.FadeInEffect(const Step, Wait, Max: Integer);
begin
  if not EnableFadeEffect then Exit;
  while Opacity < Max do
  begin
    if Opacity + Step >= Max then
    begin
      //Application.ProcessMessages;
      Opacity := Max;
      UpdateMainWindow;
      Break;
    end;
    Opacity := Opacity + Step;
    UpdateMainWindow;
    Sleep(Wait);
  end;
end;

procedure TMainForm.FadeOutEffect(const Step, Wait, Min: Integer);
begin
  if not EnableFadeEffect then Exit;
  while Opacity > Min do
  begin
    if Opacity - Step <= Min then
    begin
      //Application.ProcessMessages;
      Opacity := Min;
      UpdateMainWindow;
      Break;
    end;
    Opacity := Opacity - Step;
    UpdateMainWindow;
    Sleep(Wait);
  end;
end;

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  InfoTextForm.HideForm;
  HideMainForm;
end;

procedure TMainForm.HideMainForm;
begin
  if EnableFadeEffect then
    FadeOutEffect(OpacityStep, OpacityWait, OpacityMin);
  Self.Hide;
end;

procedure TMainForm.ShowMainForm;
begin
  Self.Show;
  if EnableFadeEffect then
    FadeInEffect(OpacityStep, OpacityWait, OpacityMax);
end;

procedure TMainForm.DoShowHint(var HintStr: string;
  var CanShow: Boolean; var HintInfo: THintInfo);
begin
  if HintInfo.HintControl = WeatherLbl then
    HintInfo.HintStr := GetInfoText;
end;

procedure TMainForm.ParseIPAddressXML;
var
  xmlPage, Elem: OleVariant;
begin
  // showip.org sitesinde xml datanin basinda anlamini bilmedigim 3 karakter var.
  IPAddressXML := System.Copy(IPAddressXML, Pos('<?xml', IPAddressXML), MaxInt);

  if IPAddressXML = '' then Exit;
  
  xmlPage := CreateOleObject('Microsoft.XMLDOM');
  try
    if not VarIsClear(xmlPage) then
    begin
      if xmlPage.LoadXml(IPAddressXML) then
      begin
        {
        // ipaddr
        Elem := xmlPage.documentElement.selectSingleNode('/root/ipaddr');
        try
          if not VarIsClear(Elem) then
            IPAddress := Elem.Text;
        finally
          Elem := Unassigned;
        end;
        }
        // ip
        Elem := xmlPage.documentElement.selectSingleNode('/data/ip');
        try
          if not VarIsClear(Elem) then
            IPAddress := Elem.Text;
        finally
          Elem := Unassigned;
        end;
      end;
    end;
  finally
    xmlPage := Unassigned;
  end;

end;

procedure TMainForm.PrepareInfoText;
begin
  InfoText := GetInfoText;
  InfoTextHeight := GetInfoTextHeight;
end;

function TMainForm.GetInfoTextHeight: Integer;
var
  R: TGPRectF;
begin
  GdiPlusMeasureString(DrawCanvas, InfoText, R, InfoTextLbl.Font,
    StringAlignmentCenter);
  Result := Round(R.Height);
end;

procedure TMainForm.PaintInfoText;
var
  oRect, R: TGPRectF;
  oBrush: TGPSolidBrush;
  WideText: WideString;
begin
  if InfoTextLbl.Visible then
  begin

    WideText := InfoText;

    if WideText <> '' then
    begin
      GdiPlusMeasureString(DrawCanvas, WideText, oRect, InfoTextLbl.Font, StringAlignmentCenter);

      InfoTextLbl.ClientWidth := Round(oRect.Width) + 1;
      InfoTextLbl.ClientHeight := Round(oRect.Height) + 1;
      InfoTextHeight := Round(oRect.Height) + 1;

      R := MakeRectF(InfoTextLbl.BoundsRect);
      R.X := InfoTextLbl.Left;
      R.Y := InfoTextLbl.Top;
      R.Width := 183;
      //R.Height := 50;

      oBrush := TGPSolidBrush.Create(MakeColor(51, 0, 0, 0));
      try
        //DrawCanvas.FillRectangle(oBrush, R);
      finally
        oBrush.Free;
      end;

      OffsetRectF(R, -1.0, -1.0);
      GdiPlusDrawText(DrawCanvas, WideText, R, InfoTextLbl.Font,
        StringAlignmentCenter, aclWhite);

    end;
  end;
end;

procedure TMainForm.UpdateBackground;
begin
  Updating := True;
  try
    ReleaseHandle;
    AllocateHandle;
    PaintBackground;
    PaintEarth;
    UpdateMainWindow;
  finally
    Updating := False;
  end;
end;

procedure TMainForm.PaintButtons;
begin

  if IsActive then begin
    if ExitBtn.Visible then
      DrawCanvas.DrawImage(CloseImage, ExitBtn.Left, ExitBtn.Top,
        CloseImage.GetWidth, CloseImage.GetHeight);
    if HideBtn.Visible then
      DrawCanvas.DrawImage(HideImage, HideBtn.Left, HideBtn.Top,
        HideImage.GetWidth, HideImage.GetHeight);
    if OptionsBtn.Visible then
      DrawCanvas.DrawImage(OptionsImage, OptionsBtn.Left, OptionsBtn.Top,
        OptionsImage.GetWidth, OptionsImage.GetHeight);
  end;
end;

function TMainForm.GetDateTime: WideString;
begin
  if ConnectionStatus <> csConnected then Result := ''
  else
    //Result := FormatDateTime(SysUtils.LongDateFormat, SysUtils.Now, FormatSettings);
    Result := WideFormatDate(SysUtils.Now(), FormatSettings);
end;

function TMainForm.GetSunText: WideString;
begin
  Result := '';
  if (SunriseStr <> '') and (SunsetStr <> '') then
    Result := WideFormat('GD: %s, GB: %s',
      [FormatDateTime(ShortTimeFormat, StrToTime(SunriseStr)),
      FormatDateTime(ShortTimeFormat, StrToTime(SunsetStr))]);
end;

procedure TMainForm.PaintEarth;
begin
  if WeatherLbl.Visible then
  begin
    DrawCanvas.DrawImage(EarthImage, WeatherLbl.Left, WeatherLbl.Top,
      EarthImage.GetWidth, EarthImage.GetHeight);
  end;
end;

procedure TMainForm.ShortPopupPopup(Sender: TObject);
var
  Item: TMenuItem;
  Index: Integer;
begin
  FavoritesMenu.Clear;
  IniFile.ReadSectionValues(sFavorites, Favorites);
  if Favorites.Count > 0 then begin
    Favorites.Sort;
    for Index := 0 to Favorites.Count - 1 do
    begin
      Item := TMenuItem.Create(Self);
      Item.Caption := Favorites.Names[Index];
      Item.OnClick := ChooseFavorite;
      FavoritesMenu.Add(Item);
    end;
  end
  else begin
    Item := TMenuItem.Create(Self);
    Item.Caption := 'Favori Listesi Boş';
    Item.Enabled := False;
    FavoritesMenu.Add(Item);
  end;
end;

procedure TMainForm.ChooseFavorite(Sender: TObject);
var
  Item: TMenuItem;
  ACityID: string;
begin
  if ConnectionStatus = csConnecting then Exit;
  Item := Sender as TMenuItem;
  ACityID := IniFile.ReadString(sFavorites, Item.Caption, '');
  if ACityID <> '' then begin
    CityID := ACityID;
    InternetUpdate;
  end;
end;

procedure TMainForm.WMCheckVerDone(var Message: TMessage);
begin
  CheckVerXML := CheckVerThread.ResponseText;
  if Assigned(CheckVerThread) then FreeAndNil(CheckVerThread);
  if Message.LParam = 0 then
  begin
    ParseCheckVerXML;
    if (VersionStr <> '') and (CompareText(sCurrVersion, VersionStr) < 0) then
      if MessageDlg(WideFormat(sUpdateMessage, [VersionStr]), mtInformation,
        [mbYes, mbNo], 0) = mrYes then
          ShellExecute(Self.Handle, 'open', MyHomePage + 'downloads.asp#havaciva',
            nil, nil, SW_SHOWNORMAL);

  end;
end;

procedure TMainForm.ParseCheckVerXML;
var
  xmlPage, Elem: OleVariant;
begin

  if CheckVerXML = '' then Exit;

  xmlPage := CreateOleObject('Microsoft.XMLDOM');
  try
    if not VarIsClear(xmlPage) then
    begin
      if xmlPage.LoadXml(CheckVerXML) then
        begin
        // version/havaciva
        Elem := xmlPage.documentElement.selectSingleNode('/version/havaciva');
        try
          if not VarIsClear(Elem) then
            VersionStr := Elem.Text;
        finally
          Elem := Unassigned;
        end;
      end;
    end;
  finally
    xmlPage := Unassigned;
  end;

end;

procedure TMainForm.FetchIPAddress;
begin

  if Assigned(IPAddrThread) then begin
    if not IPAddrThread.Terminated then Exit;
  end;

  if Assigned(IPAddrThread) then FreeAndNil(IPAddrThread);
  {
  IPAddrThread := TInternetThread.Create( True, Self,
    MyHomePage + 'showip.asp?fmt=xml', WM_IPADDRDONE );
  }
  IPAddrThread := TInternetThread.Create( True, Self,
    ShowIPSite + 'xml.aspx', WM_IPADDRDONE ); // yada rss.aspx
  try
    IPAddrThread.Resume;
  except
    FreeAndNil(IPAddrThread);
  end;
  
end;

procedure TMainForm.WMIPAddrDone(var Message: TMessage);
begin
  IPAddressXML := IPAddrThread.ResponseText;
  if Assigned(IPAddrThread) then FreeAndNil(IPAddrThread);
  if Message.LParam = 0 then
    ParseIPAddressXML;
  //TrayIcon.Hint := GetTrayHintText;
  InfoTextForm.UpdateLayered;
end;

function TMainForm.GetHintText: WideString;
begin
  Result := GetWeatherText + #13#10 + CondTempStr + #0176;
end;

procedure TMainForm.PaintSun;
begin
  if WeatherLbl.Visible then
  begin
    {
    DrawImageTo(DrawCanvas, WeatherLbl.Left, WeatherLbl.Top,
      SunImage.GetWidth, SunImage.GetHeight, SunImage, 140);
    }
    DrawCanvas.DrawImage(SunImage, WeatherLbl.Left, WeatherLbl.Top,
      SunImage.GetWidth, SunImage.GetHeight);
  end;
end;

procedure TMainForm.PaintMoon(Phase: Integer);
var
  Image: TGPBitmap;
  ImageName: string;
begin

  if Phase < 0 then Exit;

  if WeatherLbl.Visible then
  begin
    ImageName := '.\Contents\Resources\Moons\' + IntToStr(Phase) + '.png';
    Image := TGPBitmap.Create(ImageName);
    try
      DrawCanvas.DrawImage(Image, WeatherLbl.Left, WeatherLbl.Top,
        Image.GetWidth, Image.GetHeight);
    finally
      Image.Free;
    end;
  end;

end;

procedure TMainForm.PaintNone;
begin
  if WeatherLbl.Visible then
  begin
    DrawCanvas.DrawImage(NoneImage, WeatherLbl.Left, WeatherLbl.Top,
      NoneImage.GetWidth, NoneImage.GetHeight);
  end;
end;

function TMainForm.GetIPAddress: WideString;
begin
  if ConnectionStatus = csConnected then
  begin
    if IPAddress <> '' then Result := IPAddress
    else Result := 'Araştırılıyor...';
    end
  else Result := GetConnectionText;
end;

function TMainForm.GetTrayHintText: WideString;
const
  sHavaCiva: WideString = 'Hava Cıva!';
  
  procedure AddWideText(const Item, FormatStr: WideString);
  begin
    if Item <> '' then
      Result := Result + WideFormat(FormatStr, [Item]) + ', ';
  end;

begin
  if ConnectionStatus = csConnected then
  begin
    AddWideText(LocCityStr, '%s');
    AddWideText(GetWeatherText, '%s');
    AddWideText(GetTemperatureText, '%s');
    if (Result <> '') and (Length(Result) > 1) and
       (Result[Length(Result) - 1] = ',') then
      Delete(Result, Length(Result) - 1, 2);
    if Result <> '' then
      Result := sHavaCiva + ' - ' + Result
    else Result := sHavaCiva;
  end else Result := 'Hava Cıva! - ' + GetConnectionText;
end;

function TMainForm.GetSituationText: WideString;
begin
  Result := '';
  if (LatitudeStr <> '') and (LongitudeStr <> '') then
    Result := WideFormat('E: %s'#0176', B: %s'#0176, [LatitudeStr, LongitudeStr] );
end;

function TMainForm.GetTemperatureText: WideString;
begin
  if CondTempStr <> '' then
    Result := CondTempStr + #0176
  else Result := '';
end;

procedure TMainForm.ToggleInfoTextForm(Value: Boolean);
begin
  ShowInfoAction.Checked := Value;
  ShowInfoText := Value;
  if ShowInfoText then InfoTextForm.ShowForm
  else InfoTextForm.HideForm;
  IniFile.WriteBool(sAppearance, sShowInfoText, ShowInfoText);
  IniFile.UpdateFile;
end;

procedure TMainForm.ParseWeatherXML;
var
  xmlPage, Elem, ElemList, NodeMap: OleVariant;
  I: Integer;
begin

  if WeatherXML = '' then Exit;

  xmlPage := CreateOleObject('Microsoft.XMLDOM');
  try

    if not VarIsClear(xmlPage) then
    begin

      if xmlPage.LoadXML(WeatherXML) then
      begin
        // lastBuildDate
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/lastBuildDate');
        try
          if not VarIsClear(Elem) then
            LastBuildDateStr := Elem.Text;
        finally
          Elem := Unassigned;
        end;

        // yweather:location
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/yweather:location');
        try
          if not VarIsClear(Elem) then
          begin
            NodeMap := Elem.attributes;
            try
              LocCityStr := NodeMap.getNamedItem('city').Text;
              LocRegionStr := NodeMap.getNamedItem('region').Text;
              LocCountryStr := NodeMap.getNamedItem('country').Text;
            finally
              NodeMap := Unassigned;
            end;
          end;
        finally
          Elem := Unassigned;
        end;

        // yweather:wind
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/yweather:wind');
        try
          if not VarIsClear(Elem) then
          begin
            NodeMap := Elem.attributes;
            try
              WindChillStr := NodeMap.getNamedItem('chill').Text;
              WindDirectionStr := NodeMap.getNamedItem('direction').Text;
              WindSpeedStr := NodeMap.getNamedItem('speed').Text;
            finally
              NodeMap := Unassigned;
            end;
          end;
        finally
          Elem := Unassigned;
        end;

        // yweather:atmosphere
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/yweather:atmosphere');
        try
          if not VarIsClear(Elem) then
          begin
            NodeMap := Elem.attributes;
            try
              HumidityStr := NodeMap.getNamedItem('humidity').Text;
              VisibilityStr := NodeMap.getNamedItem('visibility').Text;
            finally
              NodeMap := Unassigned;
            end;
          end;
        finally
          Elem := Unassigned;
        end;

        // yweather:astronomy
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/yweather:astronomy');
        try
          if not VarIsClear(Elem) then
          begin
            NodeMap := Elem.attributes;
            try
              SunriseStr := NodeMap.getNamedItem('sunrise').Text;
              SunsetStr := NodeMap.getNamedItem('sunset').Text;
            finally
              NodeMap := Unassigned;
            end;
          end;
        finally
          Elem := Unassigned;
        end;

        // geo:lat
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/item/geo:lat');
        try
          if not VarIsClear(Elem) then
            LatitudeStr := Elem.Text;
        finally
          Elem := Unassigned;
        end;

        // geo:long
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/item/geo:long');
        try
          if not VarIsClear(Elem) then
            LongitudeStr := Elem.Text;
        finally
          Elem := Unassigned;
        end;

        // pubDate
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/item/pubDate');
        try
          if not VarIsClear(Elem) then
            PubDateStr := Elem.Text;
        finally
          Elem := Unassigned;
        end;

        // yweather:condition
        Elem := xmlPage.documentElement.selectSingleNode('/rss/channel/item/yweather:condition');
        try
          if not VarIsClear(Elem) then
          begin
            NodeMap := Elem.attributes;
            try
              CondTextStr := NodeMap.getNamedItem('text').Text;
              CondCodeStr := NodeMap.getNamedItem('code').Text;
              CondTempStr := NodeMap.getNamedItem('temp').Text;
              CondDateStr := NodeMap.getNamedItem('date').Text;
            finally
              NodeMap := Unassigned;
            end;
          end;
        finally
          Elem := Unassigned;
        end;

        // yweather:forecast
        ElemList := xmlPage.documentElement.selectNodes('/rss/channel/item/yweather:forecast');
        try
          if (not VarIsClear(ElemList)) and (ElemList.Length > 0) then
          begin
            for I := 0 to ElemList.Length - 1 do
            begin
              NodeMap := ElemList.Item[I].attributes;
              try
                ForecastLows[I]  := NodeMap.getNamedItem('low').Text;
                ForecastDays[I]  := NodeMap.getNamedItem('day').Text;
                ForecastHighs[I] := NodeMap.getNamedItem('high').Text;
                ForecastTexts[I] := NodeMap.getNamedItem('text').Text;
                ForecastCodes[I] := NodeMap.getNamedItem('code').Text;
                ForecastDates[I] := NodeMap.getNamedItem('date').Text;
              finally
                NodeMap := Unassigned;
              end;
            end;
          end;
        finally
          ElemList := Unassigned;
        end;
      end; // end of "if xmlPage.LoadXML(WeatherXML) then"
    end; // end of "if not VarIsClear(xmlPage) then"
  finally
    xmlPage := Unassigned;
  end;
end;

procedure TMainForm.ResetData;
var
  I: Integer;
begin

  SunriseStr := '';
  SunsetStr := '';
  LatitudeStr := '';
  LongitudeStr := '';

  WindChillStr := '';
  WindDirectionStr := '';
  WindSpeedStr := '';

  LastBuildDateStr := '';

  LocCityStr := '';
  LocRegionStr := '';
  LocCountryStr := '';

  HumidityStr := '';
  VisibilityStr := '';
  {
  PressureStr := '';
  RisingStr := '';
  }
  PubDateStr := '';

  CondTextStr := '';
  CondCodeStr := '';
  CondTempStr := '';
  CondDateStr := '';
  
  for I := 0 to MaxForecast - 1 do
  begin
    ForecastDays[I] := '';
    ForecastLows[I] := '';
    ForecastHighs[I] := '';
    ForecastCodes[I] := '';
    ForecastDates[I] := '';
    ForecastTexts[I] := '';
  end;

  IsDateShift := False;

end;

procedure TMainForm.WMMove(var Message: TWMMove);
begin
  inherited;
  if Assigned(InfoTextForm) then
  begin
    InfoTextForm.Left := Self.Left + Distance.X;
    InfoTextForm.Top := Self.Top + Distance.Y;
  end;
end;

procedure TMainForm.ExitActionExecute(Sender: TObject);
begin
  Close;
end;

procedure TMainForm.ShowInfoActionExecute(Sender: TObject);
begin
  ShowInfoAction.Checked := not ShowInfoAction.Checked;
  ToggleInfoTextForm(ShowInfoAction.Checked);
end;

procedure TMainForm.OptionsActionExecute(Sender: TObject);
begin
  ShowOptionsDialog(-1);
end;

procedure TMainForm.HideActionExecute(Sender: TObject);
begin
  HideMainForm;
  InfoTextForm.HideForm;
end;

procedure TMainForm.ShowActionExecute(Sender: TObject);
begin
  SetForeGroundWindow( Self.Handle);
  ShowMainForm;
  if ShowInfoText then InfoTextForm.ShowForm;
end;

procedure TMainForm.RefreshActionExecute(Sender: TObject);
begin
  if ConnectionStatus <> csConnecting then
  begin
    DisableEvents;
    InternetUpdate;
    EnableEvents;
  end;
end;

procedure TMainForm.AboutActionExecute(Sender: TObject);
begin
  {
  MessageDlg('Hava Cıva! 1.0b'#13#10'Test sürümü'#13#10#13#10'freedelphi@hotmail.com',
    mtInformation, [mbOK], 0);
  }
  AboutForm.ShowForm;
end;

procedure TMainForm.TrayPopupPopup(Sender: TObject);
var
  Item: TMenuItem;
  Index: Integer;
begin
  TrayFavoritesMenu.Clear;
  IniFile.ReadSectionValues(sFavorites, Favorites);
  if Favorites.Count > 0 then begin
    Favorites.Sort;
    for Index := 0 to Favorites.Count - 1 do
    begin
      Item := TMenuItem.Create(Self);
      Item.Caption := Favorites.Names[Index];
      Item.OnClick := ChooseFavorite;
      TrayFavoritesMenu.Add(Item);
    end;
  end
  else begin
    Item := TMenuItem.Create(Self);
    Item.Caption := 'Favori Listesi Boş';
    Item.Enabled := False;
    TrayFavoritesMenu.Add(Item);
  end;
end;

procedure TMainForm.AddLocActionExecute(Sender: TObject);
begin
  ShowOptionsDialog(2);
end;

procedure TMainForm.UpdateActionsState;
begin

  HideBtn.Enabled := IsActive and (ConnectionStatus <> csConnecting);
  ExitBtn.Enabled := IsActive and (ConnectionStatus <> csConnecting);
  OptionsBtn.Enabled := IsActive and (ConnectionStatus <> csConnecting);

  HideBtn.Visible := TrayIcon.Visible and (ConnectionStatus <> csConnecting);
  ExitBtn.Visible := IsActive and (ConnectionStatus <> csConnecting);
  OptionsBtn.Visible := IsActive and (ConnectionStatus <> csConnecting);

  OptionsAction.Enabled := ConnectionStatus <> csConnecting;
  HideAction.Enabled := TrayIcon.Visible and (ConnectionStatus <> csConnecting);
  ExitAction.Enabled := ConnectionStatus <> csConnecting;

  RefreshAction.Enabled := ConnectionStatus <> csConnecting;
  AddLocAction.Enabled := ConnectionStatus <> csConnecting;
  
end;

procedure TMainForm.ShowOptionsDialog(const PageIndex: Integer);
var
  OptionsForm: TOptionsForm;
begin
  DisableEvents;
  SaveOptions;
  OptionsForm := TOptionsForm.Create(Self);
  try
    if (PageIndex >= 0) and (PageIndex < OptionsForm.PageControl1.PageCount) then
      OptionsForm.PageControl1.ActivePageIndex := PageIndex;
    if OptionsForm.ShowModal = mrOk then
    begin
      LoadOptions;
      if OptionsForm.CityChanged then InternetUpdate
      else UpdateLayered;
      InfoTextForm.UpdateLayered;
      if ShowInfoText then InfoTextForm.ShowForm
      else InfoTextForm.HideForm;
    end;
  finally
    OptionsForm.Free;
    EnableEvents;
  end;
end;

function TMainForm.GetMoonPhasePercent(const TheDate: TDateTime): Integer;
const
  Synodic  = 29.53058867;
  MsPerDay = 24 * 60 * 60 * 1000;
var
  BaseDate: TDateTime;
  Phase: Double;
  Diff: Int64;
begin
  // Source: http://aa.usno.navy.mil/data/docs/MoonPhase.html
  // Istanbul'da Yeni Ay olustugu tarih ve saat (y,m,d,h,m): 2006, 6, 25, 18, 05
  // Orjinal data 2 saat geridedir (16:05). Istanbul +2 saat ileride!
  BaseDate := DateUtils.EncodeDateTime(2006, 6, 25, 18, 05, 0, 0);
  Diff := MilliSecondsBetween(TheDate, BaseDate);
  Phase := Diff / (Synodic * MsPerDay);
  Phase := Phase * 100;
  while Phase > 100 do Phase := Phase - 100;
  if Phase < 0 then Phase := 50;
  if Phase = 0 then Phase := 100;
  Result := Trunc(Phase);
end;

procedure TMainForm.DrawImageTo(Graphics: TGPGraphics; X, Y, W, H: Single;
  Image: TGPBitmap; Alpha: Byte);
const
  CMatrix: ColorMatrix = (
    (1.0, 0.0, 0.0, 0.0, 0.0),
    (0.0, 1.0, 0.0, 0.0, 0.0),
    (0.0, 0.0, 1.0, 0.0, 0.0),
    (0.0, 0.0, 0.0, 1.0, 0.0),
    (0.0, 0.0, 0.0, 0.0, 1.0)
  );
var
  Attr: TGPImageAttributes;
  Matrix: ColorMatrix;
begin

  Matrix := CMatrix;

  Matrix[3, 3] := (Alpha / 255);

  Attr := TGPImageAttributes.Create;
  try
    Attr.SetWrapMode(WrapModeTile);
    Attr.SetColorMatrix(Matrix, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);

    Graphics.DrawImage(Image,
      MakeRect(X, Y, W, H),  // dest rect
      0, 0, Image.GetWidth, Image.GetHeight, // source rect
      UnitPixel,
      Attr);

  finally
    Attr.Free;
  end;

end;

procedure TMainForm.ParseDocumentDateTime;
var
  DocSysTime, BuildSysTime: TSystemTime;

  procedure IncHour(var Hour: Word);
  begin
    if Hour = 23 then Hour := 0
    else Inc(Hour);
  end;

begin
  if DocTimeToSystemTime(GetDocumentTimeText(), DocSysTime) then
  begin

    if DocSysTime.wHour < 6 then begin
      IsDateShift := False;
      Exit;
    end;

    UTCTimeToSystemTime(LastBuildDateStr, BuildSysTime);
    if BuildSysTime.wMinute > 45 then
      IncHour(BuildSysTime.wHour);

    if BuildSysTime.wHour >= (DocSysTime.wHour - 6) then
      IsDateShift := False
    else IsDateShift := True;
    
  end;
end;

function TMainForm.UTCTimeToSystemTime(const UTCTime: string;
  var SystemTime: TSystemTime): Boolean;
var
  Parser: TParser;
  Stream: TStringStream;
  AMPM: string;
begin
  Result := False;
  if UTCTime = '' then Exit;
  // Mon, 27 Nov 2006 10:20 pm EET
  Stream := TStringStream.Create(UTCTime);
  try
    Parser := TParser.Create(Stream);
    try
      FillChar(SystemTime, SizeOf(TSystemTime), 0);
      AMPM := '';
      if Parser.Token = toSymbol then
        SystemTime.wDayOfWeek := ShortDayStrToInt(Parser.TokenString); // Haftanin Gunu: "Mon"
      Parser.NextToken;
      if Parser.Token = ',' then
        Parser.NextToken;
      if Parser.Token = toInteger then // Sayi olarak Gun: "27"
        SystemTime.wDay := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = toSymbol then // Yazi olarak ay: "Nov"
        SystemTime.wMonth := ShortMonthStrToInt(Parser.TokenString);
      Parser.NextToken;
      if Parser.Token = toInteger then // Sayi olarak yil: "2006"
        SystemTime.wYear := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = toInteger then // Saat: "10"
        SystemTime.wHour := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = ':' then // Saat ayraci
        Parser.NextToken;
      if Parser.Token = toInteger then // Dakika: "20"
        SystemTime.wMinute := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = toSymbol then // am/pm
        AMPM := LowerCase(Parser.TokenString);
      Parser.NextToken;

      if (SystemTime.wHour = 12) and (AMPM = 'am') then
        SystemTime.wHour := 0
      else if (SystemTime.wHour = 12) and (AMPM = 'pm') then
        SystemTime.wHour := 12
      else if AMPM = 'pm' then
        SystemTime.wHour := SystemTime.wHour + 12;
      Result := True;    
    finally
      Parser.Free;
    end;
  finally
    Stream.Free;
  end;
end;

function TMainForm.DocTimeToSystemTime(const DocTime: string;
  var SystemTime: TSystemTime): Boolean;
var
  Parser: TParser;
  Stream: TStringStream;
begin
  // Mon Nov 27 12:47:19 PST 2006
  Result := False;
  if DocTime = '' then Exit;
  Stream := TStringStream.Create(DocTime);
  try
    Parser := TParser.Create(Stream);
    try
      FillChar(SystemTime, SizeOf(TSystemTime), 0);
      if Parser.Token = toSymbol then
        SystemTime.wDayOfWeek := ShortDayStrToInt(Parser.TokenString); // Haftanin Gunu: "Mon"
      Parser.NextToken;
      if Parser.Token = toSymbol then // Yazi olarak ay: "Nov"
        SystemTime.wMonth := ShortMonthStrToInt(Parser.TokenString);
      Parser.NextToken;
      if Parser.Token = toInteger then // Sayi olarak Gun: "27"
        SystemTime.wDay := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = toInteger then // Saat: "12"
        SystemTime.wHour := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = ':' then // Saat ayraci
        Parser.NextToken;
      if Parser.Token = toInteger then // Dakika: "47"
        SystemTime.wMinute := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = ':' then // Dakika ayraci
        Parser.NextToken;
      if Parser.Token = toInteger then // Saniye: "19"
        SystemTime.wSecond := Parser.TokenInt;
      Parser.NextToken;
      if Parser.Token = toSymbol then // "PST"
        Parser.NextToken;
      if Parser.Token = toInteger then // Sayi olarak yil: "2006"
        SystemTime.wYear := Parser.TokenInt;
      Result := True;
    finally
      Parser.Free;
    end;
  finally
    Stream.Free;
  end;
end;

function TMainForm.GetDocumentTimeText: string;
const
  SearchText = 'compressed/chunked ';
var
  StartPos, EndPos: Integer;
  TempText: string;
begin
  Result := '';
  if WeatherXML = '' then Exit;
  StartPos := System.Pos(SearchText, WeatherXML);
  if StartPos >= 0 then
  begin
    TempText := System.Copy(WeatherXML, StartPos + Length(SearchText), MaxInt);
    EndPos := System.Pos(' -->', TempText) - 1;
    if EndPos >= 0 then
      Result := System.Copy(TempText, 1, EndPos);
  end;
end;

procedure TMainForm.UpdateFormStyle;
begin
  if StayOnTop then
    SetWindowPos(Self.Handle, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED)
  else
    SetWindowPos(Self.Handle, HWND_NOTOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE or SWP_NOSIZE or SWP_FRAMECHANGED);
end;

end.
