unit uMain;
// (C) by Marco Schulze <marco@nightlabs.com>
// [YMD] 2001-03-07
// published under GPL (GNU Public Licence)

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, ExtCtrls, StdCtrls, Buttons, Defs, fraQueue, ComCtrls,
  JvExControls, JvComponent,  JvXPButtons, JvXPCore,
  JvButton, JvTransparentButton, ImgList;

const
  WM_TRAYICONEVENT = WM_USER+1; //Taskbar message


type
  TFormMain = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    Login1: TMenuItem;
    Logout1: TMenuItem;
    N1: TMenuItem;
    Exit1: TMenuItem;
    Controls1: TMenuItem;
    Play1: TMenuItem;
    Pause1: TMenuItem;
    Stop1: TMenuItem;
    Next1: TMenuItem;
    Repeat1: TMenuItem;
    N3: TMenuItem;
    Reset1: TMenuItem;
    Search1: TMenuItem;
    ChangePassword1: TMenuItem;
    N4: TMenuItem;
    Timer1: TTimer;
    Panel1: TPanel;
    Timer2: TTimer;
    LabelAlbumAuthor: TLabel;
    LabelAlbumName: TLabel;
    LabelTrackName: TLabel;
    LabelRating: TLabel;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Panel2: TPanel;
    Label4: TLabel;
    LabelTrackLength: TLabel;
    LabelPosition: TLabel;
    tbtnPlay: TJvTransparentButton2;
    ilButtonToolbar: TImageList;
    tbtnStop: TJvTransparentButton2;
    tbtnNext: TJvTransparentButton2;
    tbtnRepeat: TJvTransparentButton2;
    tbtnPause: TJvTransparentButton2;
    PopupStatusBar: TPopupMenu;
    RateSuperb1: TMenuItem;
    RateCurrentGood1: TMenuItem;
    RatecurrentNeutral1: TMenuItem;
    RateCurrentBad1: TMenuItem;
    RateCurrentAwful1: TMenuItem;
    StatusBar1: TStatusBar;
    N2: TMenuItem;
    GotoTrack1: TMenuItem;
    tbtnPlaylist: TJvTransparentButton2;
    Panel5: TPanel;
    Panel3: TPanel;
    AutoGoto1: TMenuItem;
    Fil1: TMenuItem;
    SetFilter1: TMenuItem;
    Resetfilter1: TMenuItem;
    Randomplay1: TMenuItem;
    Factor1: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure Logout1Click(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Cascade1Click(Sender: TObject);
    procedure Queue1Click(Sender: TObject);
    procedure Albums1Click(Sender: TObject);
    procedure SaveSizesandPositions1Click(Sender: TObject);
    procedure RestoreSizesandPositions1Click(Sender: TObject);
    procedure Login1Click(Sender: TObject);
    procedure Reset1Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure WinSearchClick(Sender: TObject);
    procedure Search1Click(Sender: TObject);
    procedure ChangePassword1Click(Sender: TObject);
	 procedure Timer2Timer(Sender: TObject);
	 procedure ShowStatus(SetOnlyPosition:Boolean);
	 procedure tbtnMouseEnter(Sender: TObject);
	 procedure tbtnMouseLeave(Sender: TObject);
    procedure tbtnNextMouseEnter(Sender: TObject);
    procedure tbtnNextMouseLeave(Sender: TObject);
    procedure tbtnRepeatMouseEnter(Sender: TObject);
    procedure tbtnRepeatMouseLeave(Sender: TObject);
    procedure tbtnPlayClick(Sender: TObject);
    procedure tbtnPauseClick(Sender: TObject);
    procedure tbtnNextClick(Sender: TObject);
    procedure tbtnStopClick(Sender: TObject);
	 procedure tbtnRepeatClick(Sender: TObject);
	 procedure Statusbar_OnStatusChange;
	 procedure Statusbar_OnReset;
    procedure RateCurrent1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure TrackDblClick(Sender: TObject);
    procedure tbtnPlaylistClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure AutoGoto1Click(Sender: TObject);
    procedure Randomplay1Click(Sender: TObject);
    procedure SetFilter1Click(Sender: TObject);
  private
    { Private declarations }
    DoInitializationInOnShow : Boolean;
  public
    { Public declarations }
    procedure TrayIconShow(ModeAddNotify:Byte;Msg:String);
    procedure SetTrayIconHint;

    procedure OnStatusChange;
    procedure OnAlbumChange(AlbumID:Integer);
    procedure OnTrackChange(AlbumID,TrackID : Integer);
    procedure SaveSizesAndPositions();
    procedure RestoreSizesAndPositions();
    procedure AfterLoggedIn();
    procedure OnReset();

    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SysCommand;
    procedure OnTrayIconEvent(var Msg: TMessage); Message WM_TRAYICONEVENT;

    procedure OnTrayIconMouseMove(var Msg: TMessage);
    procedure OnTrayIconLButtonDown(var Msg: TMessage);
    procedure OnTrayIconLButtonUp(var Msg: TMessage);
    procedure OnTrayIconLButtonDblClk(var Msg: TMessage);
    procedure OnTrayIconRButtonDown(var Msg: TMessage);
    procedure OnTrayIconRButtonUp(var Msg: TMessage);
    procedure OnTrayIconRButtonDblClk(var Msg: TMessage);
  end;

var
  FormMain: TFormMain;

implementation

uses ShellApi, MServClients, MServCDatas, uLogin, uAlbums, uQueue,  IniFiles,
  uSearch, uFormChangePW, uFilter;

{$R *.DFM}

const
  StatusRefreshPeriod = 60; // Sekunden

procedure TFormMain.FormCreate(Sender: TObject);
var
  IniFileStr     : String;
begin
  try
    DoInitializationInOnShow:=True;

    MServClient:=TMServClient.Create;

    FormAlbums:=nil;
    //FormQueue:=nil;

    IniFileStr:=Application.ExeName;

    while (Copy(IniFileStr,Length(IniFileStr),1)<>'.') and (IniFileStr<>'') do
      Delete(IniFileStr,Length(IniFileStr),1);

    IniFileStr:=IniFileStr+'ini';

    IniFile:=TIniFile.Create(IniFileStr);
  except
    on E:Exception do raise Exception.Create('TFormMain.FormCreate: '+E.Message);
  end;
end;

procedure TFormMain.Exit1Click(Sender: TObject);
begin
  SaveSizesandPositions();
  MServClient.Disconnect;
  Close;
end;

procedure TFormMain.Logout1Click(Sender: TObject);
begin
  MServClient.Disconnect;
  StatusBar1.Panels[0].Text:='Disconnected.';

  MServClient.OnStatusChange:=OnStatusChange;
  MServClient.OnAlbumChange:=OnAlbumChange;
  MServClient.OnTrackChange:=OnTrackChange;
  MServClient.OnReset:=OnReset;

  if Assigned(FormSearch) then
    FormSearch.Free;

  if Assigned(FormAlbums) then
    FormAlbums.Free;

  //if Assigned(FormQueue) then
  //  FormQueue.Free;



  TrayIconShow(0, Caption);
end;

function NullStr(in_Num, in_Len: integer): string;
begin
  Result := IntToStr(in_Num);
  while length(Result)<in_Len do
    Result := '0' + Result;
end;

procedure _GetFileVersion(aFile: String; var FileVersionMS, FileVersionLS:
LongInt);
var
  VSize     : LongInt;                                     { Size of the Version Block }
  Vhandle   : Cardinal;                                    { Version Handle }
  Vinfo     : PChar;                                       { Char Pointer }
  Vitem     : Pointer;                                     { Item Pointer }
  Rc        : Boolean;                                     { Result Code }
  NtFn      : array [0..255] of Char;                      { Ascii Buffer }
  LenRes    : UINT;                                        { Resource Length }
  FFi       : PVSFixedFileInfo;                            { Ver Info structure }
begin
  FileVersionMS := 0;
  FileVersionLS := 0;
  StrPCopy(NtFn,aFile);
  Vitem := @NtFn;                                          { Set Pointer to char buffer }
  VSize := GetFileVersionInfoSize(NtFn,Vhandle);           { Get Version Size }
  if VSize = 0 then Exit;                                  { If None, then Exit }
  GetMem(Vinfo,Word(VSize));                               { Grab some Memory }
  try
    Rc := GetFileVersionInfo(NtFn,
                       Vhandle,
                       VSize,
                       Vinfo);                              { Get the Version Block }
    if Not Rc then Exit;                                    { If We Failed then Get out of here }

    Rc := VerQueryValue(Vinfo,
                        '\',
                        Vitem,
                        LenRes);                            { Get First Val }
    if Not Rc then begin end;
    FFi := Vitem;                                           { Set Struncture }

    FileVersionMS := FFi^.dwFileVersionMS;
    FileVersionLS := FFi^.dwFileVersionLS;
  finally
    FreeMem(Vinfo,Vsize);                                   { Free the memory }
  end;
end;

function GetFileVersion(aFile: String): String;
var
  FileVersionMS,
  FileVersionLS: LongInt;
begin
  Result := '';
  _GetFileVersion(aFile, FileVersionMS, FileVersionLS);
  if ((FileVersionMS = 0) and (FileVersionLS = 0)) then
    Result := IntToStr(FileAge(aFile)) {keine Versionsinfos vorhanden}
  else
{    Result := NullStr(HIWORD(FileVersionMS),3) +
              '.' +
              NullStr(LOWORD(FileVersionMS),3) +
              '.' +
              NullStr(HIWORD(FileVersionLS),3) +
              '.' +
              NullStr(LOWORD(FileVersionLS),3); }
    Result := NullStr(HIWORD(FileVersionMS),0) +
              '.' +
              NullStr(LOWORD(FileVersionMS),2) +
              '.' +
              NullStr(HIWORD(FileVersionLS),2) +
              '.' +
              NullStr(LOWORD(FileVersionLS),3);
end;

procedure TFormMain.FormShow(Sender: TObject);
var
  s        : String;
  HOwner   : HWnd;
begin
  if DoInitializationInOnShow then begin
    DoInitializationInOnShow:=False;

    Caption:=Caption + ' ver ' + GetFileVersion(Application.ExeName);

    // TrayIcon anzeigen
    TrayIconShow(1,Caption);

    // normalen Taskbar-Eintrag verstecken...
    HOwner:=GetWindow(Handle,GW_OWNER);
    ShowWindow(HOwner,SW_HIDE);

    Logout1Click(Sender);
    RestoreSizesandPositions();

    s:=AnsiLowerCase(IniFile.ReadString('Options','AutoLogin','no'));
    if s='yes' then begin
      if FormLogin.Execute(True) then begin
        AfterLoggedIn;
      end;
    end // if s='yes' then begin
    else s:='no';
    IniFile.WriteString('Options','AutoLogin',s);

    if FormAlbums<>nil then begin
			s:=AnsiLowerCase(IniFile.ReadString('Options','MinimizeOnStart','no'));
			if s='yes' then begin
			  Timer1.Enabled:=True;
			end // if s='yes' then begin
			else begin
			  s:='no';
			  Timer1.Free;
			  Timer1:=nil;
			end;
			IniFile.WriteString('Options','MinimizeOnStart',s);
	 end; // if FormAlbums<>nil then begin
	 Timer2.Enabled:=True;
	 Statusbar_OnReset;
  end; // if DoInitializationInOnShow then begin
end;

procedure TFormMain.OnTrackChange(AlbumID,TrackID : Integer);
begin
  if FormAlbums<>nil then FormAlbums.OnTrackChange(AlbumID,TrackID);
  if FormAlbums<>nil then FormAlbums.OnQueueTrackChange(AlbumID,TrackID);
  //if FormQueue<>nil then FormQueue.OnTrackChange(AlbumID,TrackID);

  if (MServClient.MServCData.Status.AlbumID = AlbumID) and
     (MServClient.MServCData.Status.TrackID = TrackID) then begin


	  Statusbar_OnStatusChange();
  end;


  SetTrayIconHint;
end;

procedure TFormMain.OnAlbumChange(AlbumID:Integer);
begin
  if FormAlbums<>nil then FormAlbums.OnAlbumChange(AlbumID);
end;

procedure TFormMain.FormDestroy(Sender: TObject);
var
  NotifyIconData : TNotifyIconData;
begin
  try

    if Assigned(MServClient) then begin
      MServClient.Free();
      MServClient:=nil;
    end;

    if Assigned(IniFile) then begin
      IniFile.Free;
      IniFile:=nil;
    end;

    // Tray-Icon löschen...
    FillChar(NotifyIconData,Sizeof(NotifyIconData),0);
    NotifyIconData.cbSize := Sizeof(NotifyIconData);
    NotifyIconData.Wnd    := Self.Handle;
    NotifyIconData.uFlags := NIF_MESSAGE
      or NIF_ICON
      or NIF_TIP;
    NotifyIconData.uCallbackMessage := WM_TRAYICONEVENT;
    NotifyIconData.hIcon := Application.Icon.Handle;
    NotifyIconData.szTip := 'Punkt';
    Shell_NotifyIcon(NIM_DELETE, @NotifyIconData);
  except
    on E:Exception do raise Exception.Create('TFormMain.FormDestroy: '+E.Message);
  end;
end;

procedure TFormMain.Cascade1Click(Sender: TObject);
begin
  Cascade;
end;

procedure TFormMain.Queue1Click(Sender: TObject);
begin
  //if FormQueue<>nil then
  //  FormQueue.Show;
end;

procedure TFormMain.Albums1Click(Sender: TObject);
begin
  if FormAlbums<>nil then
    FormAlbums.Show;
end;

procedure TFormMain.SaveSizesAndPositions();
procedure DoSave(Form:TForm;const SectionName,KeyPrefix:String);
var
  s    : String;
begin
  s:='wsNormal';
  if Form.WindowState=wsMinimized then s:='wsMinimized';
  if Form.WindowState=wsMaximized then s:='wsMaximized';
  IniFile.WriteString(SectionName,KeyPrefix+'WindowState',s);

  IniFile.WriteString(SectionName,KeyPrefix+'Left',IntToStr(Form.Left));
  IniFile.WriteString(SectionName,KeyPrefix+'Top',IntToStr(Form.Top));
  IniFile.WriteString(SectionName,KeyPrefix+'Width',IntToStr(Form.Width));
  IniFile.WriteString(SectionName,KeyPrefix+'Height',IntToStr(Form.Height));
end;

begin
  DoSave(FormMain,'PositionsSizes','FormMain.');

  if FormAlbums=nil then Exit;

  DoSave(FormAlbums,'PositionsSizes','FormAlbums.');
  //DoSave(FormQueue,'PositionsSizes','FormQueue.');


  FormAlbums.SaveSizesAndPositions;
  //FormQueue.SaveSizesAndPositions;

  if Assigned(FormSearch) then
	 FormSearch.SaveSizesAndPositions;
end;

procedure TFormMain.SaveSizesandPositions1Click(Sender: TObject);
begin
  SaveSizesandPositions();
end;

procedure TFormMain.RestoreSizesAndPositions();
procedure DoRestore(Form:TForm;const SectionName,KeyPrefix:String);
var
  s    : String;
begin
  s:=IniFile.ReadString(SectionName,KeyPrefix+'WindowState','0');
  if s='wsMinimized' then begin
    if Form=FormMain then
      s:='wsNormal'
    else
      Form.WindowState:=wsMinimized;
  end;

  if s='wsMaximized' then Form.WindowState:=wsMaximized;

  if s='wsNormal' then begin
    Form.WindowState:=wsNormal;
    Form.Left:=StrToInt(IniFile.ReadString(SectionName,KeyPrefix+'Left','0'));
    Form.Top:=StrToInt(IniFile.ReadString(SectionName,KeyPrefix+'Top','0'));
    Form.Width:=StrToInt(IniFile.ReadString(SectionName,KeyPrefix+'Width','500'));
    Form.Height:=StrToInt(IniFile.ReadString(SectionName,KeyPrefix+'Height','300'));
  end;
end;

begin
  DoRestore(FormMain,'PositionsSizes','FormMain.');

  if FormAlbums=nil then Exit;

  //DoRestore(FormAlbums,'PositionsSizes','FormAlbums.');
  FormAlbums.WindowState:=wsMaximized;
  
  //DoRestore(FormQueue,'PositionsSizes','FormQueue.');

  //FormAlbums.RestoreSizesAndPositions;
  //FormQueue.RestoreSizesAndPositions;

  if Assigned(FormSearch) then
	 FormSearch.RestoreSizesAndPositions;
end;

procedure TFormMain.RestoreSizesandPositions1Click(Sender: TObject);
begin
  RestoreSizesAndPositions();
end;

procedure TFormMain.AfterLoggedIn();
begin
//  LabelStatus.Caption:='CurrentUser@CurrentServer: '+MServClient.User.Name+'@'+MServClient.Host.Name;
    StatusBar1.Panels[0].Text:='Logged in: '+MServClient.User.Name+'@'+MServClient.Host.Name;

  Application.CreateForm(TFormAlbums, FormAlbums);
  FormAlbums.LoadAlbums;
  FormAlbums.ShowAlbums;

  //Application.CreateForm(TFormQueue, FormQueue);
  //FormQueue.ShowQueue;

  RestoreSizesAndPositions();

  OnStatusChange;
end;

procedure TFormMain.Login1Click(Sender: TObject);
begin
  if FormLogin.Execute(False) then begin
    AfterLoggedIn;
  end;
end;

procedure TFormMain.Reset1Click(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Reset(ResI,ResS) then begin
    MessageDlg('Unable to reset! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
  end;
end;

procedure TFormMain.OnReset();
begin
  if FormAlbums<>nil then FormAlbums.OnReset();
  //if FormQueue<>nil then FormQueue.OnReset();

  Statusbar_OnReset;
end;

procedure TFormMain.SetTrayIconHint;
var
  AlbumIdx, TrackIdx     : Integer;
  TrayIconMsg            : String;
  TrackAuthor, TrackName : String;

procedure GetAlbumIdxTrackIdx;
begin
  AlbumIdx:=MServClient.MServCData.GetAlbumIdx(MServClient.MServCData.Status.AlbumID);
  if AlbumIdx<0 then begin
    TrackIdx:=-1;
    Exit;
  end;
  TrackIdx:=MServClient.MServCData.Albums[AlbumIdx].GetTrackIdx(MServClient.MServCData.Status.TrackID);
end;

procedure Shorten(AvailableCharCount : Integer);
var
  AHasBeenShortened, NHasBeenShortened : Boolean;
begin
  AHasBeenShortened:=False;
  NHasBeenShortened:=False;

  while Length(TrackAuthor)+Length(TrackName)>AvailableCharCount do begin
    if Length(TrackAuthor)>AvailableCharCount div 2 then begin
      AHasBeenShortened:=True;
      Delete(TrackAuthor,Length(TrackAuthor),1);
    end;
    if Length(TrackName)>AvailableCharCount div 2 then begin
      NHasBeenShortened:=True;
		Delete(TrackName,Length(TrackName),1);
    end;
  end; // while Length(TrackAuthor)+Length(TrackName)>AvailableCharCount do begin

  if AHasBeenShortened then begin
    Delete(TrackAuthor,Length(TrackAuthor)-2,3);
    TrackAuthor:=TrackAuthor+'...';
  end;
  if NHasBeenShortened then begin
    Delete(TrackName,Length(TrackName)-2,3);
    TrackName:=TrackName+'...';
  end;
end;

begin
  TrayIconMsg:='MServClient: ';
  case MServClient.MServCData.Status.Action of
    msaNothingPlaying: TrayIconMsg:=TrayIconMsg+'Nothing Playing';
    msaPlaying: begin
      TrayIconMsg:=TrayIconMsg+'Playing: ';
      GetAlbumIdxTrackIdx;
      TrackAuthor:=MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor;
      TrackName:=MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackName;
      Shorten(60-Length(TrayIconMsg));
      TrayIconMsg:=TrayIconMsg+
        TrackAuthor+
        ' - '+
        TrackName;
    end;
    msaPaused: begin
      TrayIconMsg:=TrayIconMsg+'Paused: ';
      GetAlbumIdxTrackIdx;
      TrackAuthor:=MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor;
      TrackName:=MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackName;
      Shorten(60-Length(TrayIconMsg));
      TrayIconMsg:=TrayIconMsg+
        TrackAuthor+
        ' - '+
        TrackName;
    end;
  end;
  TrayIconShow(0,TrayIconMsg);
end;

procedure TFormMain.OnStatusChange;
begin

	Statusbar_OnStatusChange;
	RandomPlay1.Checked:=MServClient.GetRandomSetting;
	SetTrayIconHint;
end;

procedure TFormMain.OnTrayIconEvent(var Msg: TMessage);
begin
  { Die WM_TaskbarEvent-Message "Msg" gibt in Msg.LParam
    das genaue Ereignis an. Msg.LParam kann folgende Werte für
    Mausereignisse annehmen:

    WM_MouseMove
    WM_LButtonDown
    WM_LButtonUp
    WM_LButtonDblClk
    WM_RButtonDown
    WM_RButtonUp
    WM_RButtonDblClk }

  case Msg.LParam of
    WM_MouseMove: OnTrayIconMouseMove(Msg);
    WM_LButtonDown: OnTrayIconLButtonDown(Msg);
    WM_LButtonUp: OnTrayIconLButtonUp(Msg);
    WM_LButtonDblClk: OnTrayIconLButtonDblClk(Msg);
    WM_RButtonDown: OnTrayIconRButtonDown(Msg);
    WM_RButtonUp: OnTrayIconRButtonUp(Msg);
    WM_RButtonDblClk: OnTrayIconRButtonDblClk(Msg);
  end;
end;

procedure TFormMain.OnTrayIconMouseMove(var Msg: TMessage);
begin
end;

procedure TFormMain.OnTrayIconLButtonDown(var Msg: TMessage);
begin
end;

procedure TFormMain.OnTrayIconLButtonUp(var Msg: TMessage);
begin
  if Visible then Hide
  else begin
    Show;
{    BringToFront;
    SetFocus; }
    Application.BringToFront();
  end;
end;

procedure TFormMain.OnTrayIconLButtonDblClk(var Msg: TMessage);
begin
end;

procedure TFormMain.OnTrayIconRButtonDown(var Msg: TMessage);
begin
end;

procedure TFormMain.OnTrayIconRButtonUp(var Msg: TMessage);
var
  X, Y    : Integer;
begin
  
  X:=Mouse.CursorPos.x;
  Y:=Mouse.CursorPos.y;

  FormMain.PopupStatusbar.Popup(X,Y);
end;

procedure TFormMain.OnTrayIconRButtonDblClk(var Msg: TMessage);
begin
end;

// beim Minimieren keinen breiten Tray-Icon anzeigen
procedure TFormMain.WMSysCommand(var Message: TWMSysCommand);
begin
  if Message.CmdType and $FFF0 = SC_MINIMIZE then
    Self.Visible:=False
  else
    inherited;
end;

procedure TFormMain.TrayIconShow(ModeAddNotify:Byte;Msg:String);
var
  NotifyIconData : TNotifyIconData;
  i              : Integer;

begin
  Fillchar(NotifyIconData,Sizeof(NotifyIconData),0);
  NotifyIconData.cbSize := Sizeof(NotifyIconData);
  NotifyIconData.Wnd    := Handle;
  NotifyIconData.uFlags := NIF_MESSAGE
    or NIF_ICON
    or NIF_TIP;
  NotifyIconData.uCallbackMessage := WM_TRAYICONEVENT;
  NotifyIconData.hIcon := Application.Icon.Handle;
  for i:=0 to High(NotifyIconData.szTip) do begin
    if i+1>Length(Msg) then
      NotifyIconData.szTip[i]:=#0
    else
      NotifyIconData.szTip[i]:=Msg[i+1];
  end; // for i:=0 to High(NotifyIconData.szTip) do begin
  if ModeAddNotify=1 then
    Shell_NotifyIcon(NIM_ADD, @NotifyIconData)
  else
    Shell_NotifyIcon(NIM_MODIFY, @NotifyIconData);
end;

procedure TFormMain.Timer1Timer(Sender: TObject);
begin
  Hide;
  Timer1.Free;
  Timer1:=nil;
end;

procedure TFormMain.WinSearchClick(Sender: TObject);
begin
  if FormSearch<>nil then
    FormSearch.Show;
end;

procedure TFormMain.Search1Click(Sender: TObject);
begin
  FormSearch_Use();
  FormSearch.Execute();
end;

procedure TFormMain.ChangePassword1Click(Sender: TObject);
begin
  try
    if not Assigned(FormAlbums) then begin
      Application.MessageBox('You can only change your password, if you''re logged in! Log in first!', 'Error: Not logged in!', mb_IconStop or mb_OK);
      Exit;
    end;

    FormChangePW.Execute();

  except
    on E:Exception do begin
      E.Message:='TFormMain.ChangePassword1Click: '+E.Message;
      raise;
    end;
  end;
end;

procedure TFormMain.Timer2Timer(Sender: TObject);
begin
	Timer2.Tag:=Timer2.Tag+1;

  if Timer2.Tag>=24*3600 then Timer2.Tag:=0;
  if Timer2.Tag mod StatusRefreshPeriod =0 then begin
		MServClient.ReadStatus;
		ShowStatus(False);
  end;
  ShowStatus(True);       // do a "simple" update
end;

procedure TFormMain.ShowStatus(SetOnlyPosition:Boolean);
var
  DifSecs    : Integer;
  Current    : record
                 AlbumID,
                 TrackID    : Integer;
                 AlbumIdx,
                 TrackIdx   : Integer;
               end;
  i          : Integer;
begin
  try
	 Current.AlbumID:=MServClient.MServCData.Status.AlbumID;
	 Current.TrackID:=MServClient.MServCData.Status.TrackID;
    Current.AlbumIdx:=-1;
    Current.TrackIdx:=-1;

	 //if not SetOnlyPosition then begin
	 //  LabelTracksIncluded.Caption:=IntToStr(MServClient.MServCData.Status.NumberOfTracksIncluded);
	 //  LabelTracksExcluded.Caption:=IntToStr(MServClient.MServCData.Status.NumberOfTracksExcluded);
    //end;

    if Current.AlbumID<0 then begin
      if not SetOnlyPosition then begin
		  LabelAlbumAuthor.Caption:='';
		  LabelAlbumName.Caption:='';

		  //LabelTrackAuthor.Caption:='';
        LabelTrackName.Caption:='';
        LabelTrackLength.Caption:='';
        LabelRating.Caption:='';
        //ListViewRatings.Items.Clear;
      end; // if not SetOnlyPosition then begin
		LabelPosition.Caption:='';
		
	 end // if Current.AlbumID<0 then begin
    else begin
      Current.AlbumIdx:=MServClient.MServCData.GetAlbumIdx(Current.AlbumID);

		if High(MServClient.MServCData.Albums[Current.AlbumIdx].Tracks)<0 then begin
        MServClient.CacheTracks(Current.AlbumID);
      end;
      Current.TrackIdx:=MServClient.MServCData.Albums[Current.AlbumIdx].GetTrackIdx(Current.TrackID);

      DifSecs:=Trunc((Now-MServClient.MServCData.Status.FetchPosDT)* 24 * 3600);
  //    DifSecs:=Timer1.Tag;

		LabelPosition.Caption:=SecsToHourMinStr(
		  MServClient.MServCData.Status.Position+
		  DifSecs
		);

		if not SetOnlyPosition then begin

		  LabelAlbumAuthor.Caption:=
			 MServClient.MServCData.Albums[Current.AlbumIdx].AlbumAuthor;
		  LabelAlbumName.Caption:=
			 MServClient.MServCData.Albums[Current.AlbumIdx].AlbumName;

		  //LabelTrackAuthor.Caption:=
        //  MServClient.MServCData.Albums[Current.AlbumIdx].Tracks[Current.TrackIdx].TrackAuthor;
		  LabelTrackName.Caption:=
			 MServClient.MServCData.Albums[Current.AlbumIdx].Tracks[Current.TrackIdx].TrackName;

        LabelTrackLength.Caption:=SecsToHourMinStr(
          MServClient.MServCData.Albums[Current.AlbumIdx].Tracks[Current.TrackIdx].Length
        );

		  LabelRating.Caption:=CMServRatingStr[MServClient.MServCData.Albums[Current.AlbumIdx].Tracks[Current.TrackIdx].Rating];
		// if follow-mode on, open correspondig album (show info)
		  if AutoGoto1.Checked then
				FormAlbums.FocusTrack(Current.AlbumID,Current.TrackID);

		  //ListViewRatings.Items.BeginUpdate;
		  //try
		  //  ListViewRatings.Items.Clear;
		  //  for i:=0 to High(MServClient.MServCData.Status.Ratings) do begin
		  //    if MServClient.MServCData.Status.Ratings[i].Rating=msrUndefined then
		  //      Continue;

		//		with ListViewRatings.Items.Add do begin
		//		  Caption:=MServClient.MServCData.Status.Ratings[i].UserName;
		 //         SubItems.Add(CMServRatingStr[MServClient.MServCData.Status.Ratings[i].Rating]);
		  //    end; // with ListViewRatings.Items.Add do begin
		  //  end; // for i:=0 to High(MServClient.MServCData.Status.Ratings) do begin
		  //finally
		  //  ListViewRatings.Items.EndUpdate;
        //end;
      end; // if not SetOnlyPosition then begin
    end;
  except
    on E:Exception do raise Exception.Create('TFormStatus.ShowStatus: '+E.Message);
  end;
end;



//------transparent button common stuff--------------------------
procedure TFormMain.tbtnMouseEnter(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DownIndex;
end;

procedure TFormMain.tbtnMouseLeave(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DisabledIndex;
end;

//------transparent button PLAY-----------------------------------
procedure TFormMain.tbtnPlayClick(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Play(ResI,ResS) then begin
	 MessageDlg('Unable to play! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
	 Exit;
  end;
end;

//------transparent button STOP-----------------------------------
procedure TFormMain.tbtnStopClick(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Stop(ResI,ResS) then begin
	 MessageDlg('Unable to stop! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
		MServClient.ReadStatus;
	 ShowStatus(False);
	 Exit;
  end;
end;

//------transparent button PAUSE-----------------------------------
procedure TFormMain.tbtnPauseClick(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Pause(ResI,ResS) then begin
	 MessageDlg('Unable to stop! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
		MServClient.ReadStatus;
	 ShowStatus(False);
	 Exit;
  end;
end;

//------transparent button NEXT (FASTFORWARD)-----------------------------------
procedure TFormMain.tbtnNextClick(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Next(ResI,ResS) then begin
	 MessageDlg('Unable to next! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
	 MServClient.ReadStatus;
    ShowStatus(False);
    Exit;
  end;
end;

procedure TFormMain.tbtnNextMouseEnter(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DownIndex;
end;

procedure TFormMain.tbtnNextMouseLeave(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DisabledIndex;
end;

//------transparent button REPEAT -----------------------------------
procedure TFormMain.tbtnRepeatClick(Sender: TObject);
var
  ResI            : Integer;
  ResS            : String;
begin
  if not MServClient.Repeat_(ResI,ResS) then begin
	 MessageDlg('Unable to repeat current track! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
	 MServClient.ReadStatus;
    ShowStatus(False);
    Exit;
  end;
end;
procedure TFormMain.tbtnRepeatMouseEnter(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DownIndex;
end;

procedure TFormMain.tbtnRepeatMouseLeave(Sender: TObject);
begin
	TJvTransparentButton2(Sender).ActiveIndex:=TJvTransparentButton2(Sender).DisabledIndex;
end;

procedure TFormMain.Statusbar_OnStatusChange;
begin
  ShowStatus(False);
  Timer2.Enabled:=MServClient.MServCData.Status.Action=msaPlaying;
end;

procedure TFormMain.Statusbar_OnReset;
begin
	MServClient.ReadStatus;
	Statusbar_OnStatusChange;
end;    

procedure TFormMain.RateCurrent1Click(Sender: TObject);
var
  Rating     : TMServRating;
  ResI       : Integer;
  ResS       : String;
begin
  Rating:=TMServRating((Sender as TMenuItem).Tag);
  if not MServClient.Rate(-1,-1,Rating,ResI,ResS) then begin
    MessageDlg('Unable to rate current track! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
//    LoadStatus;
//    ShowStatus;
    Exit;
  end;
end;


procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  SaveSizesandPositions();
end;

procedure TFormMain.TrackDblClick(Sender: TObject);
begin
	if (MServClient.MServCData.Status.AlbumID>=0) and
		(MServClient.MServCData.Status.TrackID>=0) then
		FormAlbums.FocusTrack(
		  MServClient.MServCData.Status.AlbumID,
		  MServClient.MServCData.Status.TrackID
		)
end;


procedure TFormMain.tbtnPlaylistClick(Sender: TObject);
begin
	//if FormQueue.Visible then
	//	FormQueue.Hide
	//else
	//	FormQueue.Show;
	if FormAlbums.pnlQueue.Visible then begin
		FormAlbums.Splitter3.Hide;
		FormAlbums.pnlQueue.Hide;
		//FormAlbums.Panel1.Align:=alClient;
	end
	else begin
		FormAlbums.pnlQueue.Show;
		FormAlbums.Splitter3.Show;
	end;
end;

procedure TFormMain.FormResize(Sender: TObject);
begin
	if FormMain.Width>LabelRating.Left+LabelRating.Width+2+Panel3.width then begin
		// its wide enough...
		Panel3.Parent:=Panel1;
		Panel3.Left:=Labelrating.Left+LabelRating.Width+2;
		Panel5.Hide;
	end
	else begin
		Panel3.Parent:=Panel5;
		Panel3.Left:=32;
		Panel5.Show;
	end;
end;

procedure TFormMain.AutoGoto1Click(Sender: TObject);
begin
	if AutoGoto1.Checked then
		AutoGoto1.Checked:=false
	else begin
		AutoGoto1.Checked:=true;
		TrackDblClick(Sender);
	end;
end;

procedure TFormMain.Randomplay1Click(Sender: TObject);
begin
	MServClient.SetRandomSetting(not RandomPlay1.Checked);
	RandomPlay1.Checked:=MServClient.GetRandomSetting;
end;

procedure TFormMain.SetFilter1Click(Sender: TObject);
begin
	FilterSetttingDlg.Execute;
end;

end.
