unit uSearch;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, ExtCtrls, StdCtrls, Buttons, Defs;

type TLastFocusedLV = (lflvNone, lflvAlbums, lflvTracks);
const CLastFocusedLV : Array[TLastFocusedLV] of String = ('lflvNone', 'lflvAlbums', 'lflvTracks');


type
  TFormSearch = class(TForm)
    PanelTop: TPanel;
    PanelTracks: TPanel;
    PanelBottom: TPanel;
    ListViewTracks: TListView;
    LabelSearchTerm: TLabel;
    EditSearchTerm: TEdit;
    PanelAlbums: TPanel;
    ListViewAlbums: TListView;
    CheckBoxSearchAlbums: TCheckBox;
    CheckBoxSearchTracks: TCheckBox;
    BtnSearch: TBitBtn;
    BtnGoTo: TBitBtn;
    BtnEnqueue: TBitBtn;
    Splitter1: TSplitter;
    procedure FormDestroy(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure EditSearchTermEnter(Sender: TObject);
    procedure EditSearchTermExit(Sender: TObject);
    procedure CheckBoxSearchAlbumsEnter(Sender: TObject);
    procedure CheckBoxSearchAlbumsExit(Sender: TObject);
    procedure ListViewAlbumsEnter(Sender: TObject);
    procedure ListViewAlbumsExit(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure CheckBoxSearchAlbumsClick(Sender: TObject);
    procedure CheckBoxSearchTracksClick(Sender: TObject);
    procedure EditSearchTermChange(Sender: TObject);
    procedure ListViewAlbumsChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure BtnSearchClick(Sender: TObject);
    procedure ListViewAlbumsDblClick(Sender: TObject);
    procedure BtnGoToClick(Sender: TObject);
    procedure BtnEnqueueClick(Sender: TObject);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
    LastFocusedLV : TLastFocusedLV;

    procedure SetControlsEnabled();
  public
    { Public declarations }
    procedure SaveSizesAndPositions();
    procedure RestoreSizesAndPositions();

    procedure Execute();
  end;

var
  FormSearch: TFormSearch;

procedure FormSearch_Use();

implementation

uses MServClients, MServCDatas, uAlbums;

{$R *.DFM}

const
  LVC_Albums_AlbumName    = 0;
  LVC_Albums_AlbumID      = 1;

  LVC_Tracks_AlbumName    = 0;
  LVC_Tracks_TrackAuthor  = 1;
  LVC_Tracks_TrackName    = 2;
  LVC_Tracks_Rating       = 3;
  LVC_Tracks_Length       = 4;
  LVC_Tracks_AlbumID      = 5;
  LVC_Tracks_TrackID      = 6;
  LVC_Tracks_LengthInSecs = 7;

procedure FormSearch_Use();
begin
  try
    if not Assigned(FormSearch) then
      Application.CreateForm(TFormSearch, FormSearch);
      
  except
    on E:Exception do raise Exception.Create('FormSearch_Use: '+E.Message);
  end;
end;


procedure TFormSearch.Execute();
begin
  try
    RestoreSizesAndPositions();
    
    Self.Show();
    EditSearchTerm.SetFocus();
    EditSearchTerm.SelectAll();
  except
    on E:Exception do raise Exception.Create('TFormSearch.Execute: '+E.Message);
  end;
end;


procedure TFormSearch.SaveSizesAndPositions();
procedure DoSaveForm(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;

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
  DoSaveForm(Self, 'PositionsSizes', 'FormSearch.');
  DoSaveListViewParams(ListViewAlbums,'PositionsSizes','FormSearch.ListViewAlbums.');
  DoSaveListViewParams(ListViewTracks,'PositionsSizes','FormSearch.ListViewTracks.');
  IniFile.WriteString('PositionsSizes','FormSearch.PanelAlbums.Height',IntToStr(PanelAlbums.Height));
end;

procedure TFormSearch.RestoreSizesAndPositions();

procedure DoRestoreForm(Form:TForm;const SectionName,KeyPrefix:String);
var
  s    : String;
begin
  s:=IniFile.ReadString(SectionName,KeyPrefix+'WindowState','0');
  if s='wsMinimized' then Form.WindowState:=wsMinimized;

  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;

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
  DoRestoreForm(Self, 'PositionsSizes', 'FormSearch.');

  DoRestoreListViewParams(ListViewAlbums,'PositionsSizes','FormSearch.ListViewAlbums.');
  DoRestoreListViewParams(ListViewTracks,'PositionsSizes','FormSearch.ListViewTracks.');

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



procedure TFormSearch.FormDestroy(Sender: TObject);
begin
  FormSearch:=nil;
end;

procedure TFormSearch.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
end;

procedure TFormSearch.EditSearchTermEnter(Sender: TObject);
begin
  BtnSearch.Default:=True;
end;

procedure TFormSearch.EditSearchTermExit(Sender: TObject);
begin
  BtnSearch.Default:=False;
end;

procedure TFormSearch.CheckBoxSearchAlbumsEnter(Sender: TObject);
begin
  BtnSearch.Default:=True;
end;

procedure TFormSearch.CheckBoxSearchAlbumsExit(Sender: TObject);
begin
  BtnSearch.Default:=False;
end;

procedure TFormSearch.ListViewAlbumsEnter(Sender: TObject);
var
  LV               : TListView;
begin
  LV:=Sender as TListView;
  try
    if not (LV.Tag in [0..2]) then raise Exception.Create('Tag out of range!');

    LastFocusedLV:=TLastFocusedLV(LV.Tag);

    SetControlsEnabled();

    if BtnGoTo.Enabled then BtnGoTo.Default:=True
                       else BtnEnqueue.Default:=True;
  except
    on E:Exception do raise Exception.Create('TFormSearch.ListViewAlbumsEnter ('+LV.Name+'): '+E.Message);
  end;
end;

procedure TFormSearch.ListViewAlbumsExit(Sender: TObject);
begin
  BtnGoTo.Default:=False;
  BtnEnqueue.Default:=False;
end;

procedure TFormSearch.FormCreate(Sender: TObject);
begin
  LastFocusedLV:=lflvNone;
end;

procedure TFormSearch.SetControlsEnabled();
begin
  try
    BtnSearch.Enabled:=EditSearchTerm.Text<>'';
    BtnGoTo.Enabled:=
      ((LastFocusedLV=lflvAlbums) and (ListViewAlbums.SelCount=1)) or
      ((LastFocusedLV=lflvTracks) and (ListViewTracks.SelCount=1));
    BtnEnqueue.Enabled:=
      ((LastFocusedLV=lflvAlbums) and (ListViewAlbums.SelCount>0)) or
      ((LastFocusedLV=lflvTracks) and (ListViewTracks.SelCount>0));

    if ListViewAlbums.Focused or ListViewTracks.Focused then begin
      BtnGoTo.Default:=False;
      BtnEnqueue.Default:=False;
      
      if BtnGoTo.Enabled then BtnGoTo.Default:=True
                         else BtnEnqueue.Default:=True;
    end; // if ListViewAlbums.Focused or ListViewTracks.Focused then begin
  except
    on E:Exception do raise Exception.Create('TFormSearch.SetControlsEnabled: '+E.Message);
  end;
end;

procedure TFormSearch.CheckBoxSearchAlbumsClick(Sender: TObject);
var
  CB                  : TCheckBox;
begin
  CB:=Sender as TCheckBox;
  if not (CB.Checked or CheckBoxSearchTracks.Checked) then CheckBoxSearchTracks.Checked:=True;
end;

procedure TFormSearch.CheckBoxSearchTracksClick(Sender: TObject);
var
  CB                  : TCheckBox;
begin
  CB:=Sender as TCheckBox;
  if not (CB.Checked or CheckBoxSearchAlbums.Checked) then CheckBoxSearchAlbums.Checked:=True;
end;

procedure TFormSearch.EditSearchTermChange(Sender: TObject);
begin
  SetControlsEnabled();
end;

procedure TFormSearch.ListViewAlbumsChange(Sender: TObject;
  Item: TListItem; Change: TItemChange);
begin
  SetControlsEnabled();
end;

procedure TFormSearch.BtnSearchClick(Sender: TObject);
var
  i                    : Integer;
  AlbumID, TrackID     : Integer;
  AlbumIdx, TrackIdx   : Integer;
begin
  try
    ListViewAlbums.Items.BeginUpdate;
    try
      ListViewTracks.Items.BeginUpdate;
      try

        ListViewAlbums.Items.Clear;
        ListViewTracks.Items.Clear;

        if CheckBoxSearchAlbums.Checked then begin
          MServClient.SearchAlbums(EditSearchTerm.Text);

          for i:=0 to High(MServClient.MServCData.FoundAlbums) do begin
            AlbumID:=MServClient.MServCData.FoundAlbums[i].AlbumID;
            AlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);
            with ListViewAlbums.Items.Add do begin
              Caption:=MServClient.MServCData.Albums[AlbumIdx].AlbumAuthor;
              SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].AlbumName);
              SubItems.Add(IntToStr(AlbumID));
            end;
          end;
        end; // if CheckBoxSearchAlbums.Checked then begin


        if CheckBoxSearchTracks.Checked then begin
          MServClient.SearchTracks(EditSearchTerm.Text);

          for i:=0 to High(MServClient.MServCData.FoundTracks) do begin
            AlbumID:=MServClient.MServCData.FoundTracks[i].AlbumID;
            AlbumIdx:=MServClient.MServCData.GetAlbumIdx(AlbumID);

            TrackID:=MServClient.MServCData.FoundTracks[i].TrackID;
            TrackIdx:=MServClient.MServCData.Albums[AlbumIdx].GetTrackIdx(TrackID);

            with ListViewTracks.Items.Add do begin
              Caption:=MServClient.MServCData.Albums[AlbumIdx].AlbumAuthor;
              SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].AlbumName);
              SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor);
              SubItems.Add(MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].TrackName);
              SubItems.Add(CMServRatingStr[MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Rating]);
              SubItems.Add(SecsToHourMinStr(MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Length));
              SubItems.Add(IntToStr(AlbumID));
              SubItems.Add(IntToStr(TrackID));
              SubItems.Add(IntToStr(MServClient.MServCData.Albums[AlbumIdx].Tracks[TrackIdx].Length));
            end;
          end;
        end; // if CheckBoxSearchTracks.Checked then begin

      finally
        ListViewTracks.Items.EndUpdate;
      end;
    finally
      ListViewAlbums.Items.EndUpdate;
    end;

    if (ListViewAlbums.Items.Count<=0) and (ListViewTracks.Items.Count<=0) then
      Application.MessageBox(PChar('Nothing found for search string "'+EditSearchTerm.Text+'"!'), 'Search', mb_OK or mb_IconInformation);

    SetControlsEnabled();
  except
    on E:Exception do raise Exception.Create('TFormSearch.BtnSearchClick: '+E.Message);
  end;
end;

procedure TFormSearch.ListViewAlbumsDblClick(Sender: TObject);
begin
  SetControlsEnabled();
  if BtnGoTo.Default then BtnGoTo.OnClick(BtnGoTo);
  if BtnEnqueue.Default then BtnEnqueue.OnClick(BtnEnqueue); 
end;

procedure TFormSearch.BtnGoToClick(Sender: TObject);
var
  LV                         : TListView;
begin
  try
    if LastFocusedLV=lflvAlbums then LV:=ListViewAlbums
    else if LastFocusedLV=lflvTracks then LV:=ListViewTracks
    else Exit;

    if LV.Selected=nil then Exit;

    FormAlbums.Show;

    if LastFocusedLV=lflvAlbums then
      FormAlbums.FocusAlbum(
        StrToInt(LV.Selected.SubItems[LVC_Albums_AlbumID])
      )
    else
      FormAlbums.FocusTrack(
        StrToInt(LV.Selected.SubItems[LVC_Tracks_AlbumID]),
        StrToInt(LV.Selected.SubItems[LVC_Tracks_TrackID])
      )

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

procedure TFormSearch.BtnEnqueueClick(Sender: TObject);
var
  m                           : Integer;
begin
  try

    if LastFocusedLV=lflvAlbums then begin
      for m:=0 to ListViewAlbums.Items.Count-1 do begin
        if ListViewAlbums.Items[m].Selected then begin
          MServClient.Enqueue(
            StrToInt(ListViewAlbums.Items[m].SubItems[LVC_Albums_AlbumID]),
            -1
          );
        end;
      end; // for m:=0 to ListViewAlbums.Items.Count-1 do begin
    end; // if LastFocusedLV=lflvAlbums then begin

    if LastFocusedLV=lflvTracks then begin
      for m:=0 to ListViewTracks.Items.Count-1 do begin
        if ListViewTracks.Items[m].Selected then begin
          MServClient.Enqueue(
            StrToInt(ListViewTracks.Items[m].SubItems[LVC_Tracks_AlbumID]),
            StrToInt(ListViewTracks.Items[m].SubItems[LVC_Tracks_TrackID])
          );
        end;
      end; // for m:=0 to ListView1.Items.Count-1 do begin
    end; // if LastFocusedLV=lflvTracks then begin

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

procedure TFormSearch.FormKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key=VK_F3 then BtnGoTo.OnClick(BtnGoTo);
  if Key=VK_F4 then BtnEnqueue.OnClick(BtnEnqueue);
end;

procedure TFormSearch.FormShow(Sender: TObject);
begin
  SetControlsEnabled();
end;

initialization
  FormSearch:=nil;
end.
