unit uAlbums;
// (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,
  ComCtrls, StdCtrls, Buttons, ExtCtrls, Menus, jpeg;

type
  TFormAlbums = class(TForm)
    Panel1: TPanel;
    PanelAlbums: TPanel;
    Label1: TLabel;
    PanelTracks: TPanel;
    ListViewTracks: TListView;
    TreeViewAlbums: TTreeView;
    PopupMenuRateTracks: TPopupMenu;
    N1: TMenuItem;
    RateSelectedSuperb1: TMenuItem;
    RateSelectedGood1: TMenuItem;
    RateSelectedNeutral1: TMenuItem;
    RateSelectedBad1: TMenuItem;
    RateSelectedAwful1: TMenuItem;
    Splitter1: TSplitter;
    MnuEnqueueTrack: TMenuItem;
    MnuEnqueueAlbum: TMenuItem;
    MnuTrackProperty: TMenuItem;
    N2: TMenuItem;
    PopupMenuAlbums: TPopupMenu;
    Refresh1: TMenuItem;
    Properties1: TMenuItem;
    EnqueueAlbum1: TMenuItem;
    N3: TMenuItem;
    Panel2: TPanel;
    Splitter2: TSplitter;
    imageAlbum: TImage;
    labelAlbumName: TLabel;
    labelAlbumArtist: TLabel;
    pnlQueue: TPanel;
    Splitter3: TSplitter;
    lstQueue: TListView;
    PopupQueue: TPopupMenu;
    MenuItem1: TMenuItem;
    MenuItem2: TMenuItem;
    Unqueue1: TMenuItem;
    EnqueuetopX1: TMenuItem;
    N4: TMenuItem;
    Gototrack1: TMenuItem;
    timerCover: TTimer;
    procedure BtnLoadAlbumsClick(Sender: TObject);
    procedure PanelAlbumsResize(Sender: TObject);
    procedure Panel1Resize(Sender: TObject);
    procedure PanelTracksResize(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure TreeViewAlbumsChange(Sender: TObject; Node: TTreeNode);
    procedure TreeViewAlbumsEnter(Sender: TObject);
    procedure ListViewTracksEnter(Sender: TObject);
    procedure BtnEnqueueClick(Sender: TObject);
    procedure BtnRenameClick(Sender: TObject);
    procedure RateCurrent1Click(Sender: TObject);
    procedure RateSelected1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure btnTrackinfoEditClick(Sender: TObject);
    procedure ListViewTracksDblClick(Sender: TObject);
    procedure TreeViewAlbumsDblClick(Sender: TObject);
    procedure MnuEnqueueTrackClick(Sender: TObject);
    procedure MnuEnqueueAlbumClick(Sender: TObject);
    procedure MnuTrackPropertyClick(Sender: TObject);
    procedure EnqueueAlbum1Click(Sender: TObject);
    procedure RefreshQueue1Click(Sender: TObject);
	 procedure Properties1Click(Sender: TObject);
	 procedure Refresh1Click(Sender: TObject);
	 procedure LoadQueue;
	 procedure ShowQueue;
	 procedure OnQueueChange;
	 procedure OnQueueTrackChange(AlbumID,TrackID : Integer);
    procedure Unqueue1Click(Sender: TObject);
    procedure EnqueuetopX1Click(Sender: TObject);
    procedure Gototrack1Click(Sender: TObject);

    procedure timerCoverTimer(Sender: TObject);

  private
    { Private declarations }
    AlbumIDs         : Array of Array of Integer; // [AuthorIdx, AlbumIdx]
    SelectedAlbumID  : Integer;
    ActWinPart       : (awpAlbums, awpTracks);
  public
    { Public declarations }
    procedure LoadAlbums();
    procedure ShowAlbums();
    procedure ActualizeAlbumInTreeView(AlbumID:Integer);
    procedure LoadTracks(AlbumID:Integer);
    procedure ShowTracks(AlbumID:Integer);

    procedure FocusAlbum(AlbumID:Integer);
    procedure FocusTrack(AlbumID, TrackID:Integer);

    procedure SaveSizesAndPositions();
    procedure RestoreSizesAndPositions();

    procedure OnAlbumChange(AlbumID:Integer);
    procedure OnTrackChange(AlbumID,TrackID:Integer);
    procedure OnReset();
  end;

var
  FormAlbums: TFormAlbums;

implementation

uses MServClients, Defs, uRenameAlbum, uRenameTrack, MServCDatas, uMain,
  uEnqueueTopX;


const
 // lvfTrackName    = 0;
//  lvfRating       = 1;
//  lvfLength       = 2;
//  lvfTrackID      = 3;
//  lvfLengthInSecs = 4;
	lvfTrackName   = 0;
	lvfLength		=1;
	lvfRating		=2;
	lvfGenre			=3;
	lvfTrackAuthor	=4;
	//lvftrackID		=4;
	lvfLengthInSecs=5;

{$R *.DFM}

procedure TFormAlbums.LoadAlbums();
begin
  MServClient.CacheAlbums;
end;

procedure TFormAlbums.ShowAlbums();
var
  i                                   : Integer;
  CurrentAlbumAuthor, LastAlbumAuthor : String;
begin
  TreeViewAlbums.Items.BeginUpdate;
  try
    TreeViewAlbums.Items.Clear;
    SetLength(AlbumIDs,0);

    TreeViewAlbums.ShowRoot:=True;
    TreeViewAlbums.Items.Add(nil,'MServ Albums');
    TreeViewAlbums.Selected:=TreeViewAlbums.Items[0];

    LastAlbumAuthor:='';
    for i:=0 to High(MServClient.MServCData.Albums) do begin
      CurrentAlbumAuthor:=MServClient.MServCData.Albums[i].AlbumAuthor;
      if LastAlbumAuthor<>CurrentAlbumAuthor then begin
        SetLength(AlbumIDs,High(AlbumIDs)+2);
        SetLength(AlbumIDs[High(AlbumIDs)],0);

        TreeViewAlbums.Items.AddChild(TreeViewAlbums.Items[0], CurrentAlbumAuthor);

        LastAlbumAuthor:=CurrentAlbumAuthor;
      end; // if LastAlbumAuthor<>CurrentAlbumAuthor then begin

      SetLength(AlbumIDs[High(AlbumIDs)],High(AlbumIDs[High(AlbumIDs)])+2);
      AlbumIDs[High(AlbumIDs),High(AlbumIDs[High(AlbumIDs)])]:=MServClient.MServCData.Albums[i].AlbumID;
      TreeViewAlbums.Items.AddChild(TreeViewAlbums.Items[0].GetLastChild, MServClient.MServCData.Albums[i].AlbumName);
    end; // for i:=0 to High(MServClient.MServCData.Albums) do begin

    TreeViewAlbums.Items[0].Expand(False);
  finally
	 TreeViewAlbums.Items.EndUpdate;
  end;
end;

procedure TFormAlbums.LoadTracks(AlbumID:Integer);
begin
  MServClient.CacheTracks(AlbumID);
end;

procedure TFormAlbums.FocusAlbum(AlbumID:Integer);
var
  AuthorIdx, AlbumIdx        : Integer;                     
  m, n                       : Integer;
//  tmpTopItemIdx              : Integer;
begin
  try
    AuthorIdx:=-1;
    AlbumIdx:=-1;
    for m:=0 to High(AlbumIDs) do begin
      for n:=0 to High(AlbumIDs[m]) do begin
        if AlbumIDs[m,n]=AlbumID then begin
          AuthorIdx:=m;
          AlbumIdx:=n;
          Break;
        end;
      end; // for n:=0 to High(AlbumIDs[m]) do begin
    end; // for m:=0 to High(AlbumIDs) do begin

    if AlbumIdx<0 then raise Exception.Create('#5: not found!');

//    tmpTopItemIdx:=TreeViewAlbums.TopItem.AbsoluteIndex;

    TreeViewAlbums.Items[0].Item[AuthorIdx].Item[AlbumIdx].Selected:=True;

{
    for m:=0 to TreeViewAlbums.Items.Count-1 do begin
      if TreeViewAlbums.Items[m].AbsoluteIndex=tmpTopItemIdx then begin
        TreeViewAlbums.TopItem:=TreeViewAlbums.Items[m];
        Break;
      end;
    end; // for i:=0 to TreeViewAlbums.Items.Count-1 do begin
}

    TreeViewAlbums.Selected.MakeVisible();

//    TreeViewAlbums.OnChange(TreeViewAlbums, nil);

    TreeViewAlbums.SetFocus();

  except
    on E:Exception do raise Exception.Create('TFormAlbums.FocusAlbum (AlbumID='+IntToStr(AlbumID)+'): '+E.Message);
  end;
end;

procedure TFormAlbums.FocusTrack(AlbumID, TrackID:Integer);
var
  i                       : Integer;
begin
  try
    FocusAlbum(AlbumID);

    for i:=0 to ListViewTracks.Items.Count-1 do begin
      if StrToInt(ListViewTracks.Items[i].Caption)=TrackID then begin
        ListViewTracks.Selected:=nil;
        ListViewTracks.Selected:=ListViewTracks.Items[i];
        ListViewTracks.ItemFocused:=ListViewTracks.Selected;
        ListViewTracks.Selected.MakeVisible(False);
      end;
    end; // for i:=0 to ListViewTracks.Items.Count-1 do begin

    ListViewTracks.SetFocus();

  except
    on E:Exception do raise Exception.Create('TFormAlbums.FocusTrack: '+E.Message);
  end;
end;

procedure TFormAlbums.ShowTracks(AlbumID:Integer);
var
  AlbumIdx,i     : Integer;
begin
  ListViewTracks.Items.BeginUpdate;
  try
    ListViewTracks.Items.Clear;
	 if AlbumID<0 then Exit;

	 AlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);
	 if AlbumIdx<0 then
		raise Exception.Create('No Album with ID='+IntToStr(AlbumID)+' in cache!');
	 if High(MServClient.MServCData.Albums[AlbumIdx].Tracks)<0 then begin
		LoadTracks(AlbumID);
	 end;

	 for i:=0 to High(MServClient.MServCData.Albums[AlbumIdx].Tracks) do begin
		with ListViewTracks.Items.Add do begin
			Caption:=IntToStr(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].TrackID);
			SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].TrackName);
			SubItems.Add(SecsToHourMinStr(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].Length));
			SubItems.Add(CMServRatingStr[MServClient.MServCData.Albums[AlbumIdx].Tracks[i].Rating]);
			SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].Genre);
			SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].TrackAuthor);
			SubItems.Add(IntToStr(MServClient.MServCData.Albums[AlbumIdx].Tracks[i].Length));
      end;
    end; // for i:=0 to High(MServClient.MServCData.Albums[AlbumIdx].Tracks) do begin
  finally
    ListViewTracks.Items.EndUpdate;
  end;
end;

procedure TFormAlbums.BtnLoadAlbumsClick(Sender: TObject);
begin
  LoadAlbums;
  ShowAlbums;
end;

procedure TFormAlbums.Panel1Resize(Sender: TObject);
begin
  PanelAlbums.Width:=Panel1.ClientWidth div 3;
end;

procedure TFormAlbums.PanelAlbumsResize(Sender: TObject);
begin
  TreeViewAlbums.Width:=(Sender as TPanel).ClientWidth-16;
  TreeViewAlbums.Height:=(Sender as TPanel).ClientHeight-16-Label1.Height;
end;

procedure TFormAlbums.PanelTracksResize(Sender: TObject);
begin
  //ListViewTracks.Width:=(Sender as TPanel).ClientWidth-16;
  //ListViewTracks.Height:=(Sender as TPanel).ClientHeight-16-Label2.Height;
end;

procedure TFormAlbums.FormShow(Sender: TObject);
begin
  Panel1.OnResize(Panel1);
  PanelAlbums.OnResize(PanelAlbums);
  PanelTracks.OnResize(PanelTracks);
	 MServClient.OnQueueChange:=OnQueueChange;
end;

procedure TFormAlbums.TreeViewAlbumsChange(Sender: TObject; Node: TTreeNode);
var
	AlbumIdx	: Integer;
	bufCDCover: String;
	StrStream:TStringStream;
	FilStream:TFileStream;
	ll:integer;
begin
  SelectedAlbumID:=-1;
  if TreeViewAlbums.Selected=nil then Exit;

  if TreeViewAlbums.Selected.Level=2 then begin
    SelectedAlbumID:=
      AlbumIDs[TreeViewAlbums.Selected.Parent.Index,TreeViewAlbums.Selected.Index];
  end;

  ShowTracks(SelectedAlbumID); // leert die ListView, wenn AlbumID<0
	if SelectedAlbumID<0 then begin
		LabelAlbumName.Caption:='';
		LabelAlbumArtist.Caption:='';
		imageAlbum.Hide;
	end
	else begin
		AlbumIdx:=MServClient.MServCData.GetAlbumIdx(SelectedAlbumID);
		if (LabelAlbumName.Caption<>MServClient.MServCData.Albums[AlbumIdx].AlbumName) or
			(LabelAlbumArtist.Caption<>MServClient.MServCData.Albums[AlbumIdx].AlbumAuthor) then begin
				 // a different album.
				LabelAlbumName.Caption:=MServClient.MServCData.Albums[AlbumIdx].AlbumName;
				LabelAlbumArtist.Caption:=MServClient.MServCData.Albums[AlbumIdx].AlbumAuthor;
				try
					// Lets load a cover!
					MServClient.GetCover(SelectedAlbumID,bufCDCover);
					StrStream := TStringStream.Create(bufCDCover);
					ll:=Length(bufCDCover);
					FilStream := TFileStream.Create('C:\tt.jpg',fmCreate);
					FilStream.CopyFrom(StrStream,ll);
					FilStream.free;
					StrStream.free;

					imageAlbum.Picture.LoadFromFile('C:\tt.jpg');

					imageAlbum.Show;
				except
					imageAlbum.Picture.LoadFromFile('nocover.jpg');
				end;
		end;
	end;
end;

procedure TFormAlbums.TreeViewAlbumsEnter(Sender: TObject);
begin
  //CheckBox1.Checked:=True;
  ActWinPart:=awpAlbums;
end;

procedure TFormAlbums.ListViewTracksEnter(Sender: TObject);
begin
  //CheckBox1.Checked:=False;
  ActWinPart:=awpTracks;
end;

procedure TFormAlbums.BtnEnqueueClick(Sender: TObject);
var
  i          : Integer;
begin
  if SelectedAlbumID<0 then Exit;
  //if CheckBox1.Checked then begin
	 // Album einqueuen
	 MServClient.Enqueue(SelectedAlbumID,-1);
  //end // if CheckBox1.Checked then begin
  //else begin
  // if not CheckBox1.Checked then begin
  // einzelne Tracks einqueuen
  //	 for i:=0 to ListViewTracks.Items.Count-1 do begin
	//	if ListViewTracks.Items[i].Selected then begin
  //		  MServClient.Enqueue(
	//		 SelectedAlbumID,
			 StrToInt(ListViewTracks.Items[i].Caption)
	//	  );
	//	end;
	// end; // for i:=0 to ListView1.Items.Count-1 do begin

  //end; // if not CheckBox1.Checked then begin
end;

procedure TFormAlbums.BtnRenameClick(Sender: TObject);
begin
	MnuTrackPropertyClick(Sender);
end;

procedure TFormAlbums.ActualizeAlbumInTreeView(AlbumID:Integer);
var
  AuthorIdx, AlbumIdx  : Integer;
  tmpSelectedAlbumID   : Integer;
//  tmpTopItemIdx        : Integer;
//  i                    : Integer;

procedure Get2DimIdx(AlbumID:Integer;var AuthorIdx,AlbumIdx:Integer);
var
  n,i                  : Integer;
begin
  AuthorIdx:=-1;
  AlbumIdx:=-1;

  for n:=0 to High(AlbumIDs) do begin
    for i:=0 to High(AlbumIDs[n]) do begin
      if AlbumIDs[n,i]=AlbumID then begin
        AuthorIdx:=n;
        AlbumIdx:=i;
        Break;
      end;
    end; // for i:=0 to High(AlbumIDs[n]) do begin
    if AlbumIdx>=0 then Break;
  end; // for n:=0 to High(AlbumIDs) do begin
end;

begin
//  Get2DimIdx(AlbumID,AuthorIdx,AlbumIdx);

  tmpSelectedAlbumID:=SelectedAlbumID;
//  tmpTopItemIdx:=TreeViewAlbums.TopItem.AbsoluteIndex;

  TreeViewAlbums.Items.BeginUpdate;
  try

    ShowAlbums;

    if tmpSelectedAlbumID>=0 then begin
      Get2DimIdx(tmpSelectedAlbumID,AuthorIdx,AlbumIdx);
      TreeViewAlbums.Items[0].Item[AuthorIdx].Item[AlbumIdx].Selected:=True;
    end;

{
    for i:=0 to TreeViewAlbums.Items.Count-1 do begin
      if TreeViewAlbums.Items[i].AbsoluteIndex=tmpTopItemIdx then begin
        TreeViewAlbums.TopItem:=TreeViewAlbums.Items[i];
        Break;
      end;
    end; // for i:=0 to TreeViewAlbums.Items.Count-1 do begin
}
  finally
    TreeViewAlbums.Items.EndUpdate;
  end;

{
  if TreeViewAlbums.Items[0].Item[AuthorIdx].Count<>1 then begin
    tmpSelectedAlbumID:=SelectedAlbumID;
    tmpTopItemIdx:=TreeViewAlbums.TopItem.AbsoluteIndex;

    ShowAlbums;

    if tmpSelectedAlbumID>=0 then begin
      Get2DimIdx(tmpSelectedAlbumID,AuthorIdx,AlbumIdx);
      TreeViewAlbums.Items[0].Item[AuthorIdx].Item[AlbumIdx].Selected:=True;
    end;

    for i:=0 to TreeViewAlbums.Items.Count-1 do begin
      if TreeViewAlbums.Items[i].AbsoluteIndex=tmpTopItemIdx then begin
        TreeViewAlbums.TopItem:=TreeViewAlbums.Items[i];
        Break;
      end;
    end; // for i:=0 to TreeViewAlbums.Items.Count-1 do begin

  end
  else begin
    if AlbumIdx>=0 then begin
      MSCDAlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);
      TreeViewAlbums.Items[0].Item[AuthorIdx].Text:=
        MServClient.MServCData.Albums[MSCDAlbumIdx].AlbumAuthor;

      TreeViewAlbums.Items[0].Item[AuthorIdx].Item[AlbumIdx].Text:=
        MServClient.MServCData.Albums[MSCDAlbumIdx].AlbumName;
    end; // if AlbumIdx>=0 then begin
  end;
}

end;

procedure TFormAlbums.SaveSizesAndPositions();
procedure DoSaveListViewParams(LV:TListView;const SectionName,KeyPrefix:String);
var
  Key, Value  : String;
  i           : Integer;
begin
  for i:=0 to LV.Columns.Count-1 do begin
    Key:=KeyPrefix+'ColWidth'+IntToStr(i);
    Value:=IntToStr(LV.Columns[i].Width);
    IniFile.WriteString(SectionName,Key,Value);
  end; // for i:=0 to LV.Columns.Count-1 do begin
end;

begin
  DoSaveListViewParams(ListViewTracks,'PositionsSizes','FormAlbums.ListViewTracks.');
  IniFile.WriteString('PositionsSizes','FormAlbums.PanelAlbums.Width',IntToStr(PanelAlbums.Width));
end;

procedure TFormAlbums.RestoreSizesAndPositions();
procedure DoRestoreListViewParams(LV:TListView;const SectionName,KeyPrefix:String);
var
  Key, Value  : String;
  i           : Integer;
begin
  for i:=0 to LV.Columns.Count-1 do begin
    Key:=KeyPrefix+'ColWidth'+IntToStr(i);
    Value:=IniFile.ReadString(SectionName,Key,IntToStr(LV.Columns[i].Width));
    LV.Columns[i].Width:=StrToInt(Value);
  end; // for i:=0 to LV.Columns.Count-1 do begin
end;

var
  s  : String;
begin
  DoRestoreListViewParams(ListViewTracks,'PositionsSizes','FormAlbums.ListViewTracks.');

  s:=IniFile.ReadString('PositionsSizes','FormAlbums.PanelAlbums.Width','');
  try
    PanelAlbums.Width:=StrToInt(s);
  except
    // nix
  end;
end;


procedure TFormAlbums.OnAlbumChange(AlbumID:Integer);
begin
  ActualizeAlbumInTreeView(AlbumID);
end;

procedure TFormAlbums.OnTrackChange(AlbumID,TrackID:Integer);
var
  Idx, i              : Integer;
  AlbumIdx, TrackIdx  : Integer;
begin
  try
    if SelectedAlbumID<>AlbumID then Exit;

    AlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);
    if AlbumIdx<0 then raise Exception.Create('no album with ID='+IntToStr(AlbumID)+' in cache!');

    if High(MServClient.MServCData.Albums[AlbumIdx].Tracks)<0 then begin
      MServClient.CacheTracks(AlbumID);
    end;

    TrackIdx:=MServClient.MServCData.Albums[AlbumIdx].GetTrackIdx(TrackID);
    if TrackIdx<0 then raise Exception.Create('no track with ID='+IntToStr(TrackID)+' in Album #'+IntToStr(AlbumID)+' in cache!');

    Idx:=-1;
    for i:=0 to ListViewTracks.Items.Count-1 do begin
      if StrToInt(ListViewTracks.Items[i].Caption)=TrackID then begin
        Idx:=i;
        Break;
      end;
    end; // for i:=0 to ListViewTracks.Items.Count-1 do begin

    if Idx>=0 then begin
		ListViewTracks.Items[Idx].SubItems[lvfTrackAuthor]:=
		  MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor;
		ListViewTracks.Items[Idx].SubItems[lvfTrackName]:=
		  MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackName;
		ListViewTracks.Items[Idx].SubItems[lvfRating]:=
		  CMServRatingStr[MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Rating];
		ListViewTracks.Items[Idx].SubItems[lvfGenre]:=
		  MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Genre;


	 end; // if Idx>=0 then begin
  except
    on E:Exception do raise Exception.Create('TFormAlbums.OnTrackChange: '+E.Message);
  end;
end;

procedure TFormAlbums.OnReset();
begin
  LoadAlbums;
  ShowAlbums;
end;

procedure TFormAlbums.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);
    Exit;
  end;
end;

procedure TFormAlbums.RateSelected1Click(Sender: TObject);
var
  Rating                  : TMServRating;
  ResI                    : Integer;
  ResS                    : String;
  i                       : Integer;
  AlbumID, TrackID        : Integer;
begin
  if SelectedAlbumID<0 then Exit;

  Rating:=TMServRating((Sender as TMenuItem).Tag-10);

  AlbumID:=SelectedAlbumID;
  for i:=0 to ListViewTracks.Items.Count-1 do begin
    if ListViewTracks.Items[i].Selected then begin
      TrackID:=StrToInt(ListViewTracks.Items[i].Caption);
      if not MServClient.Rate(AlbumID,TrackID,Rating,ResI,ResS) then begin
        MessageDlg('Unable to rate selected track (AlbumID='+IntToStr(AlbumID)+', TrackID='+IntToStr(TrackID)+')! Reason: ['+IntToStr(ResI)+'] '+ResS,mtError,[mbOK],0);
        Exit;
      end;
    end; // if ListViewTracks.Items[i].Selected then begin
  end; // for i:=0 to ListViewTracks.Items.Count-1 do begin
end;

procedure TFormAlbums.FormDestroy(Sender: TObject);
begin
  FormAlbums:=nil;
end;

procedure TFormAlbums.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  //if Key=VK_F2 then BtnRename.OnClick(BtnRename);
  //if Key=VK_F4 then BtnEnqueue.OnClick(BtnEnqueue);
  //if Key=VK_F5 then BtnLoadAlbums.OnClick(BtnLoadAlbums);
end;

procedure TFormAlbums.btnTrackinfoEditClick(Sender: TObject);
var
  i          : Integer;
begin
	if SelectedAlbumID<0 then Exit;
	for i:=0 to ListViewTracks.Items.Count-1 do begin
		if ListViewTracks.Items[i].Selected then begin
			ShowMessage('hello! ');
		end;
	end; // for i:=0 to ListView1.Items.Count-1 do begin
end;

procedure TFormAlbums.ListViewTracksDblClick(Sender: TObject);
var
  i          : Integer;
begin
	if SelectedAlbumID<0 then Exit;
	for i:=0 to ListViewTracks.Items.Count-1 do begin
		if ListViewTracks.Items[i].Selected then begin
		  MServClient.Enqueue(
			 SelectedAlbumID,
			 StrToInt(ListViewTracks.Items[i].Caption)
		  );
		end;
	end; // for i:=0 to ListView1.Items.Count-1 do begin
end;

procedure TFormAlbums.TreeViewAlbumsDblClick(Sender: TObject);
var
	AlbumIdx : Integer;
begin
	if SelectedAlbumID<0 then Exit;
	// Album einqueuen
	MServClient.Enqueue(SelectedAlbumID,-1);
	AlbumIdx:=MServClient.MServCData.GetAlbumIdx(SelectedAlbumID);
	FormMain.StatusBar1.Panels[1].Text:='Album ' + MServClient.MServCData.Albums[AlbumIdx].AlbumName + ' Queued';
end;

procedure TFormAlbums.MnuEnqueueTrackClick(Sender: TObject);
begin
   ListViewTracksDblClick(Sender);
end;

procedure TFormAlbums.MnuEnqueueAlbumClick(Sender: TObject);
begin
	TreeViewAlbumsDblClick(Sender);
end;

procedure TFormAlbums.MnuTrackPropertyClick(Sender: TObject);
begin
  if SelectedAlbumID<0 then Exit;

  if ActWinPart=awpAlbums then begin
	 FormRenameAlbum.Execute(SelectedAlbumID);
  end // if ActWinPart=awpAlbums then begin
  else begin
  // if ActWinPart=awpTracks then begin
	 if ListViewTracks.SelCount<>1 then Exit;

	 FormRenameTrack.Execute(
		SelectedAlbumID,
		StrToInt(ListViewTracks.Selected.Caption)
	 );
  end; // if ActWinPart=awpTracks then begin
end;

procedure TFormAlbums.EnqueueAlbum1Click(Sender: TObject);
begin
 	 TreeViewAlbumsDblClick(Sender);
end;

procedure TFormAlbums.Refresh1Click(Sender: TObject);
begin
  LoadAlbums;
  ShowAlbums;
end;

procedure TFormAlbums.Properties1Click(Sender: TObject);
begin
  if SelectedAlbumID<0 then Exit;
  FormRenameAlbum.Execute(SelectedAlbumID);
end;

//===========================================================================
//=== Queue stuff
//===========================================================================

const
  lqfTrackName    = 0;
  lqfQueuedBy     = 1;
  lqfRating       = 2;
  lqfLength       = 3;
  lqfTrackAuthor	= 4;
  lqfAlbumID      = 5;
  lqfTrackID      = 6;
  lqfLengthInSecs = 7;

procedure TFormAlbums.LoadQueue;
begin
  MServClient.CacheQueue;
end;

procedure TFormAlbums.ShowQueue;
var
  AlbumIdx, TrackIdx : Integer;
  i                  : Integer;
  Tk                 : TTrack;
begin
  if High(MServClient.MServCData.QueueTracks)<0 then begin
    LoadQueue;
  end;

  lstQueue.Items.BeginUpdate;
  try
	 lstQueue.Items.Clear;

    for i:=0 to High(MServClient.MServCData.QueueTracks) do begin
      AlbumIdx:=MServClient.MServCData.GetAlbumIdx(MServClient.MServCData.QueueTracks[i].AlbumID);
      if AlbumIdx<0 then raise Exception.Create('no album cached with AlbumID='+IntToStr(MServClient.MServCData.QueueTracks[i].AlbumID));

      if High(MServClient.MServCData.Albums[AlbumIdx].Tracks)<0 then begin
        MServClient.CacheTracks(MServClient.MServCData.QueueTracks[i].AlbumID);
      end;

      TrackIdx:=MServClient.MServCData.Albums[AlbumIdx].GetTrackIdx(MServClient.MServCData.QueueTracks[i].TrackID);
      if TrackIdx<0 then raise Exception.Create('no track cached with TrackID='+IntToStr(MServClient.MServCData.QueueTracks[i].TrackID)+' in album #'+IntToStr(MServClient.MServCData.QueueTracks[i].AlbumID));

      Tk:=MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx];

		with lstQueue.Items.Add do begin
        Caption:=IntToStr(i+1);
		  SubItems.Add(Tk.TrackName);
        SubItems.Add(MServClient.MServCData.QueueTracks[i].QueuedByUser);
        SubItems.Add(CMServRatingStr[Tk.Rating]);
		  SubItems.Add(SecsToHourMinStr(Tk.Length));
		  SubItems.Add(Tk.TrackAuthor);
        SubItems.Add(IntToStr(Tk.AlbumID));
        SubItems.Add(IntToStr(Tk.TrackID));
        SubItems.Add(IntToStr(Tk.Length));
      end;
    end; // for i:=0 to High(MServClient.MServCData.QueueTracks) do begin

  finally
	 lstQueue.Items.EndUpdate;
  end;

end;

procedure TFormAlbums.RefreshQueue1Click(Sender: TObject);
begin
  LoadQueue;
  ShowQueue;
end;

procedure TFormAlbums.OnQueueChange;
var
  n, i             : Integer;
  SelectedTracks   : Array of record
							  AlbumID,
							  TrackID   : Integer;
							end;
begin
	// take note of selected lines
	SetLength(SelectedTracks,0);
	for i:=0 to lstQueue.Items.Count-1 do begin
		if lstQueue.Items[i].Selected then begin
			SetLength(SelectedTracks,High(SelectedTracks)+2);
			n:=High(SelectedTracks);
			SelectedTracks[n].AlbumID:=StrToInt(lstQueue.Items[i].SubItems[lqfAlbumID]);
			SelectedTracks[n].TrackID:=StrToInt(lstQueue.Items[i].SubItems[lqfTrackID]);

		end; // if ListViewTracks.Items[i].Selected then begin
	end; // for i:=0 to ListViewTracks.Items.Count-1 do begin

	// NOW UPDATE - this will unselect all
	ShowQueue;

	// reselect previously selected lines
	for n:=0 to High(SelectedTracks) do begin
		for i:=0 to lstQueue.Items.Count-1 do begin
			if (SelectedTracks[n].AlbumID=StrToInt(lstQueue.Items[i].SubItems[lqfAlbumID])) and
				(SelectedTracks[n].TrackID=StrToInt(lstQueue.Items[i].SubItems[lqfTrackID])) then begin

				lstQueue.Items[i].Selected:=True;
			end;
		end; // for i:=0 to ListViewTracks.Items.Count-1 do begin
	end; // for n:=0 to High(SelectedTracks) do begin
end;

procedure TFormAlbums.OnQueueTrackChange(AlbumID,TrackID : Integer);
var
  i                  : Integer;
  AlbumIdx, TrackIdx : Integer;
begin
  AlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);
  if AlbumIdx<0 then raise Exception.Create('no album cached with AlbumID='+IntToStr(AlbumID));

  if High(MServClient.MServCData.Albums[AlbumIdx].Tracks)<0 then begin
    MServClient.CacheTracks(AlbumID);
  end;

  TrackIdx:=MServClient.MServCData.Albums[AlbumIdx].GetTrackIdx(TrackID);
  if TrackIdx<0 then raise Exception.Create('no track cached with TrackID='+IntToStr(TrackID)+' in album #'+IntToStr(AlbumID));

  for i:=0 to lstQueue.Items.Count-1 do begin
	 if (StrToInt(lstQueue.Items[i].SubItems[lqfAlbumID])=AlbumID) and
		 (StrToInt(lstQueue.Items[i].SubItems[lqfTrackID])=TrackID) then begin
		lstQueue.Items[i].SubItems[lqfTrackAuthor]:=
		  MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor;

		lstQueue.Items[i].SubItems[lqfTrackName]:=
		  MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackName;

      lstQueue.Items[i].SubItems[lqfRating]:=
        CMServRatingStr[MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Rating];
    end;
  end; // for i:=0 to ListViewTracks.Items.Count-1 do begin
end;


procedure TFormAlbums.Unqueue1Click(Sender: TObject);
var
  i           : Integer;
begin
  if lstQueue.SelCount<1 then Exit;

  for i:=lstQueue.Items.Count-1 downto 0 do begin
	 if lstQueue.Items[i].Selected then begin
		MServClient.Unqueue(
		  StrToInt(lstQueue.Items[i].SubItems[lqfAlbumID]),
		  StrToInt(lstQueue.Items[i].SubItems[lqfTrackID])
		);
	 end; // if ListViewTracks.Items[i].Selected then begin
  end; // for i:=0 to ListViewTracks.Items.Count-1 do begin
end;


procedure TFormAlbums.EnqueuetopX1Click(Sender: TObject);
begin
  FormEnqueueTopX.Execute();
end;

procedure TFormAlbums.Gototrack1Click(Sender: TObject);
var
  i             : Integer;
begin
	for i:=0 to lstQueue.Items.Count-1 do begin
		if lstQueue.Items[i].Selected then begin
			FormAlbums.FocusTrack(
			  StrToInt(lstQueue.Items[i].SubItems[lqfAlbumID]),
			  StrToInt(lstQueue.Items[i].SubItems[lqfTrackID])
			);
			exit;
		end; // if ListViewTracks.Items[i].Selected then begin
	end; // for i:=0
end;


procedure TFormAlbums.timerCoverTimer(Sender: TObject);
begin
	// Now it is time to get the coverfile..
	//...
	//..
	timerCover.Enabled:=false;
end;

initialization
  FormAlbums:=nil;
end.
 