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

interface
type
  TMServRating = (msrAwful,msrBad,msrNeutral,msrGood,msrSuperb,msrUndefined);
  TMServRatings = Array of record
                    UserName : String;
                    Rating   : TMServRating;
                  end;
const
  CMServRatingStr : Array[TMServRating] of String = ('AWFUL', 'BAD', 'NEUTRAL', 'GOOD', 'SUPERB','');
var
  EmptyMServRatings : TMServRatings;

type
	// TTRACK - The TRACK class ============================================
	TTrack = class(TObject)
		constructor Create(AlbumID,TrackID:Integer;const TrackAuthor,TrackName,Genre:String;Rating:TMServRating;Length:Integer);
		destructor Destroy(); override;
	private
	protected
	public
		AlbumID     : Integer;
		TrackID     : Integer;
		TrackAuthor : String;
		TrackName   : String;
		Genre		 	: String;
		Rating      : TMServRating;
		Length      : Integer; // seconds
	end;
	// TALBUM - The ALBUM class ============================================
	TAlbum = class(TObject)
		constructor Create(AlbumID:Integer;const AlbumAuthor,AlbumName:String);
		destructor Destroy(); reintroduce;

		procedure SetTrack(AlbumID,TrackID:Integer;const TrackAuthor,TrackName,Genre:String;Rating:TMServRating;Length:Integer);
		function GetTrackIdx(TrackID:Integer):Integer;
		procedure ClearTracks;
	private
	protected
	public
		AlbumID     : Integer;
		AlbumAuthor : String;
		AlbumName   : String;
		Tracks      : Array of TTrack;
	end;
	//======================================================================

	TMSAction = (msaNothingPlaying, msaPlaying, msaPaused);

	TMServStatus = record
		NumberOfTracksIncluded,
		NumberOfTracksExcluded : Integer;

		Action                 : TMSAction;
		AlbumID, TrackID       : Integer;
		Position               : Integer; // seconds
		FetchPosDT             : TDateTime; // wann wurde diese Position abgefragt?

		Ratings                : TMServRatings;
	end;

	TQueueTrackLink = record
		AlbumID, TrackID   : Integer;
		QueuedByUser       : String;
	end;

	TFoundAlbumLink = record
		AlbumID            : Integer;
	end;

	TFoundTrackLink = record
		AlbumID, TrackID   : Integer;
	end;

	TMServCData = class(TObject)
		constructor Create();
		destructor Destroy(); reintroduce;

		function GetAlbumIdx(AlbumID:Integer):Integer;
		procedure SetAlbum(AlbumID:Integer;const AlbumAuthor,AlbumName:String);
		procedure ClearAlbums;
		procedure ClearQueueTracks;
		procedure ClearFoundAlbums;
		procedure ClearFoundTracks;
		procedure AddToQueue(AlbumID, TrackID : Integer;const QueuedByUser:String);
		procedure AddToFoundAlbums(AlbumID : Integer);
		procedure AddToFoundTracks(AlbumID, TrackID : Integer);
		procedure DeleteFromQueue(AlbumID, TrackID : Integer);
		procedure SetStatus(
		NumberOfTracksIncluded,
		NumberOfTracksExcluded : Integer;
		Action                 : TMSAction;
		AlbumID, TrackID       : Integer;
		Position               : Integer; // seconds
		FetchPosDT             : TDateTime; // wann wurde diese Position abgefragt?);
		Ratings                : TMServRatings
		);
	private
	protected
	public
		Albums          : Array of TAlbum;
		QueueTracks     : Array of TQueueTrackLink;
		Status          : TMServStatus;
		FoundAlbums     : Array of TFoundAlbumLink;
		FoundTracks     : Array of TFoundTrackLink
	end;

function MServRatingStringToMServRating(const S:String):TMServRating;

implementation

uses SysUtils;

function MServRatingStringToMServRating(const S:String):TMServRating;
var
  msr : TMServRating;
begin
  Result:=msrUndefined;

  for msr:=Low(TMServRating) to High(TMServRating) do begin
    if AnsiUpperCase(CMServRatingStr[msr])=AnsiUpperCase(S) then begin
      Result:=msr;
      Break;
    end;
  end;
end;

// Methoden für TTrack:
constructor TTrack.Create(AlbumID,TrackID:Integer;const TrackAuthor,TrackName,Genre:String;Rating:TMServRating;Length:Integer);
begin
  inherited Create();

  Self.AlbumID:=AlbumID;
  Self.TrackID:=TrackID;
  Self.TrackAuthor:=TrackAuthor;
  Self.TrackName:=TrackName;
  Self.Genre:=Genre;
  Self.Rating:=Rating;
  Self.Length:=Length;
end;

destructor TTrack.Destroy();
begin

  inherited Destroy;
end;
// ENDE Methoden für TTrack


// Methoden für TAlbum:
constructor TAlbum.Create(AlbumID:Integer;const AlbumAuthor,AlbumName:String);
begin
  inherited Create();

  Self.AlbumID:=AlbumID;
  Self.AlbumAuthor:=AlbumAuthor;
  Self.AlbumName:=AlbumName;
  SetLength(Tracks,0);
end;

destructor TAlbum.Destroy();
var
  i : Integer;
begin
  for i:=0 to High(Tracks) do begin
    if Tracks[i]<>nil then Tracks[i].Free;
  end; // for i:=0 to High(Tracks) do begin

  inherited Destroy();
end;

function TAlbum.GetTrackIdx(TrackID:Integer):Integer;
var
  i : Integer;
begin
  Result:=-1;

  for i:=0 to High(Tracks) do begin
    if Tracks[i].TrackID=TrackID then begin
      Result:=i;
      Break;
    end;
  end; // for i:=0 to High(Tracks) do begin
end;

procedure TAlbum.SetTrack(AlbumID,TrackID:Integer;const TrackAuthor,TrackName,Genre:String;Rating:TMServRating;Length:Integer);
var
  Idx    : Integer;
begin
  Idx:=GetTrackIdx(TrackID);

  if Idx>=0 then begin
    if TrackAuthor<>'' then Tracks[Idx].TrackAuthor:=TrackAuthor;
	 if TrackName<>'' then Tracks[Idx].TrackName:=TrackName;
	 if Genre<>'' then Tracks[Idx].Genre:=Genre;
    if Rating<>msrUndefined then Tracks[Idx].Rating:=Rating;
    if Length>=0 then Tracks[Idx].Length:=Length;
  end
  else begin
    SetLength(Tracks,High(Tracks)+2);
    Idx:=High(Tracks);
    Tracks[Idx]:=nil;
    try
      Tracks[Idx]:=TTrack.Create(AlbumID,TrackID,TrackAuthor,TrackName,Genre,Rating,Length);
    except
      SetLength(Tracks,High(Tracks));
      raise;
    end;
  end;
end;

procedure TAlbum.ClearTracks;
var
  i : Integer;
begin
  for i:=0 to High(Tracks) do begin
    if Tracks[i]<>nil then Tracks[i].Free;
  end;

  SetLength(Tracks,0);
end;
// ENDE Methoden für TAlbum

// Methoden für TMServData:
constructor TMServCData.Create();
begin
  inherited Create;

  SetLength(Albums,0);
  SetLength(QueueTracks,0);
  SetLength(FoundAlbums,0);
  SetLength(FoundTracks,0);
  Status.AlbumID:=-1;
  Status.TrackID:=-1;
end;

destructor TMServCData.Destroy();
begin
  ClearAlbums;
  ClearQueueTracks;

  inherited Destroy;
end;

function TMServCData.GetAlbumIdx(AlbumID:Integer):Integer;
var
  i : Integer;
begin
  Result:=-1;
  for i:=0 to High(Albums) do begin
    if Albums[i].AlbumID=AlbumID then begin
      Result:=i;
      Break;
    end;
  end; // for i:=0 to High(Albums) do begin
end;

procedure TMServCData.SetAlbum(AlbumID:Integer;const AlbumAuthor,AlbumName:String);
var
  Idx    : Integer;
begin
  Idx:=GetAlbumIdx(AlbumID);

  if Idx>=0 then begin
    if AlbumAuthor<>'' then Albums[Idx].AlbumAuthor:=AlbumAuthor;
    if AlbumName<>'' then Albums[Idx].AlbumName:=AlbumName;
  end
  else begin
    SetLength(Albums,High(Albums)+2);
    Idx:=High(Albums);
    Albums[Idx]:=nil;
    try
      Albums[Idx]:=TAlbum.Create(AlbumID,AlbumAuthor,AlbumName);
    except
      SetLength(Albums,High(Albums));
      raise;
    end;
  end;
end;

procedure TMServCData.ClearAlbums;
var
  i : Integer;
begin
  for i:=0 to High(Albums) do begin
    if Albums[i]<>nil then Albums[i].Free;
  end;

  SetLength(Albums,0);
end;

procedure TMServCData.ClearQueueTracks;
begin
{  for i:=0 to High(QueueTracks) do begin
    if QueueTracks[i]<>nil then QueueTracks[i].Free;
  end;
}

  SetLength(QueueTracks,0);
end;

procedure TMServCData.ClearFoundAlbums;
begin
  SetLength(FoundAlbums,0);
end;

procedure TMServCData.ClearFoundTracks;
begin
  SetLength(FoundTracks,0);
end;

procedure TMServCData.AddToFoundAlbums(AlbumID : Integer);
var
  AlbumIdx         : Integer;
begin
  try
    AlbumIdx:=GetAlbumIdx(AlbumID);
    if AlbumIdx<0 then raise Exception.Create('No album with ID='+IntToStr(AlbumID)+' cached! => Unable to add album to found-list.');

    SetLength(FoundAlbums, High(FoundAlbums)+2);
    FoundAlbums[High(FoundAlbums)].AlbumID:=AlbumID;
  except
    on E:Exception do raise Exception.Create('TMServCData.AddToFoundAlbums: '+E.Message);
  end;
end;

procedure TMServCData.AddToFoundTracks(AlbumID, TrackID : Integer);
var
  AlbumIdx         : Integer;
  TrackIdx         : Integer;
begin
  try
    AlbumIdx:=GetAlbumIdx(AlbumID);
    if AlbumIdx<0 then raise Exception.Create('No album with ID='+IntToStr(AlbumID)+' cached! => Unable to add track to found-list.');
    if High(Albums[AlbumIdx].Tracks)<0 then raise Exception.Create('No tracks in album '+IntToStr(AlbumID)+' cached! => Unable to add track to found-list.');

    TrackIdx:=Albums[AlbumIdx].GetTrackIdx(TrackID);
    if TrackIdx<0 then raise Exception.Create('No track with ID='+IntToStr(TrackID)+' in album '+IntToStr(AlbumID)+' cached! => Unable to add track to found-list.');

    SetLength(FoundTracks, High(FoundTracks)+2);
    FoundTracks[High(FoundTracks)].AlbumID:=AlbumID;
    FoundTracks[High(FoundTracks)].TrackID:=TrackID;
  except
    on E:Exception do raise Exception.Create('TMServCData.AddToFoundTracks: '+E.Message);
  end;
end;

procedure TMServCData.AddToQueue(AlbumID, TrackID : Integer;const QueuedByUser:String);
var
  AlbumIdx         : Integer;
  TrackIdx         : Integer;
begin
  AlbumIdx:=GetAlbumIdx(AlbumID);
  if AlbumIdx<0 then raise Exception.Create('No album with ID='+IntToStr(AlbumID)+' cached! => Unable to enqueue track.');
  if High(Albums[AlbumIdx].Tracks)<0 then raise Exception.Create('No tracks in album '+IntToStr(AlbumID)+' cached! => Unable to enqueue track of this album.');

  TrackIdx:=Albums[AlbumIdx].GetTrackIdx(TrackID);
  if TrackIdx<0 then raise Exception.Create('No track with ID='+IntToStr(TrackID)+' in album '+IntToStr(AlbumID)+' cached! => Unable to enqueue track.');

  SetLength(QueueTracks,High(QueueTracks)+2);
  QueueTracks[High(QueueTracks)].AlbumID:=AlbumID;
  QueueTracks[High(QueueTracks)].TrackID:=TrackID;
  QueueTracks[High(QueueTracks)].QueuedByUser:=QueuedByUser;
{  QueueTracks[High(QueueTracks)]:=TTrack.Create(
    AlbumID,
    TrackID,
    Albums[AlbumIdx].Tracks[TrackIdx].TrackAuthor,
    Albums[AlbumIdx].Tracks[TrackIdx].TrackName,
    Albums[AlbumIdx].Tracks[TrackIdx].Rating,
    Albums[AlbumIdx].Tracks[TrackIdx].Length
  );
}
end;

procedure TMServCData.DeleteFromQueue(AlbumID, TrackID : Integer);
var
  i      : Integer;
  Idx    : Integer;
begin
  Idx:=-1;
  for i:=0 to High(QueueTracks) do begin
    if (QueueTracks[i].AlbumID=AlbumID) and
       (QueueTracks[i].TrackID=TrackID) then begin
      Idx:=i;
      Break;
    end;
  end;

  if Idx>=0 then begin
//    QueueTracks[Idx].Free;
    for i:=Idx to High(QueueTracks)-1 do QueueTracks[i]:=QueueTracks[i+1];
    SetLength(QueueTracks,High(QueueTracks));
  end; // if Idx>=0 then begin

end;

procedure TMServCData.SetStatus(
      NumberOfTracksIncluded,
      NumberOfTracksExcluded : Integer;
      Action                 : TMSAction;
      AlbumID, TrackID       : Integer;
      Position               : Integer; // seconds
      FetchPosDT             : TDateTime; // wann wurde diese Position abgefragt?);
      Ratings                : TMServRatings
    );
begin
  Status.NumberOfTracksIncluded:=NumberOfTracksIncluded;
  Status.NumberOfTracksExcluded:=NumberOfTracksExcluded;

  Status.Action:=Action;
  Status.AlbumID:=AlbumID;
  Status.TrackID:=TrackID;
  Status.Position:=Position;
  Status.FetchPosDT:=FetchPosDT;

  Status.Ratings:=Ratings;
end;
// ENDE Methoden für TMServCData

initialization
  SetLength(EmptyMServRatings,0);

end.
