% ---
% This is the class for magnatagatune clips
% ---

classdef Clip < handle
    
    % ---
    % here come the internal clip properties.
    % the database is stored as a global variable
    % ---
    properties (SetAccess = private)

       % magnatagatune clip id
       my_id;
    end
    
    % do not save whole db into mat file
    properties (Hidden, Transient)
        
        my_db;
    end
    
    properties (Hidden)

        my_dbpos;
    end
    
    % ---
    % here come the clip functions.
    % ---
    methods
        
        % ---
        % simple constructor
        % ---
        function clip = Clip(varargin)
            
            % usual or empty constructor ?
            if (nargin > 0) && isnumeric(varargin{1})
                id = varargin{1};
                db_type = varargin{2};
                
                % ---
                % check for magnatagatunedatabase 
                % and load it if not present
                % ---
                evalc(sprintf('global %s;',db_type));
                evalc(sprintf('thisdb = %s;',db_type));
                
                if ~isempty(thisdb)% exist('clip_info_proper')
                    clip.my_db = thisdb;
                else

                    error 'db not found';
                    % dbload;
                end
 
                % ---
                % recursive call for creating multiple clips
                % ---
                if numel(id) > 1
                    
                    % multi-id case
                    
                    % ---
                    % @todo: use class names as db names
                    % ---
                    if strcmp(db_type,'db_MTTClip')
                        clip = MTTClip();
                        for i = 1:numel(id)
                            clip(i) = MTTClip(id(i));
                        end
                    elseif strcmp(db_type,'db_MSDClip')
                        clip = MSDClip();
                        for i = 1:numel(id)
                            clip(i) = MSDClip(id(i));
                        end
                    elseif strcmp(db_type,'db_CASIMIRClip')
                        clip = CASIMIRClip();
                        for i = 1:numel(id)
                            clip(i) = CASIMIRClip(id(i));
                        end
                    end
                    
                    
                elseif ~isempty(id)
                    % ---
                    % actual constructor
                    % ---
                    clip.my_id = id;
                    clip.my_dbpos = clip.dbpos();

                    if isempty(clip.my_dbpos)
                        error ('Clip %d not found in DB', full(id))
                    end
                end
            else
                
                % ---
                % TODO: deal with empty constructor
                % ---
            end
        end
        
        % ---
        % member functions
        % ---
        
        % returns the id (function neccessary for 
        % multi-clip environments)
        function out = id(this)
            
            out = [this.my_id];
        end
        
        function out = comparison_id(this)
            
            out = [this(1).my_db.comparison_ids(this)];
        end
        
        function out = title(this)
        % returns name strings for given genre position ids

            out = this.my_db.clip_info_proper{this.my_dbpos,3};
        end
        
        function out = album(this)
        % returns name strings for given genre position ids
        
            out = this.my_db.clip_info_proper{this.my_dbpos,5};
        end
        
        function out = artist(this)
        % returns name strings for given genre position ids

            out = this(1).my_db.artistdb.annots(this.id);
            out = out{1};
        end
        
        function out = artist_id(this)
        % returns name strings for given genre position ids

            out = this(1).my_db.artistdb.annotids_for_owner(this.id);
        end
        
        function my_tag_ids = tag_ids(this)
        % returns clip tag posids for given clip id 
                
            my_tag_ids = this.my_db.tagdb.annotids_for_owner(this.id);
        end
        
        function out = tags(this)
        % returns name strings for given genre position ids

            out = this.my_db.tagdb.annots(this.id);
        end
        
        
        % this is for ocompability with 
        function out = raw_annots(this)
            
            out  = this.my_db.clip_info_proper(this.my_dbpos,:);
        end
        
        function [out] = isrc(this)
        % returns name strings for given genre position ids
            out = this(1).my_db.clip_info_proper{this.my_dbpos,11};
        end  
        
        function [out] = artist_mbid(this)
        % returns name strings for given genre position ids
            out = this(1).my_db.clip_info_proper{this.my_dbpos,12};
        end  
        
        function [out] = mbtags(this)
        % returns nmusicbrainz tags for the artist related to this clip
        
        [out, score] = this(1).my_db.mbtagdb.annots(this(1).artist_id());
        end  
        
         % @todo: generalise mg tags
        function [out, score] = mbtag_ids(this)
            
            [out, score] = this(1).my_db.mbtagdb.annotids_for_owner(this(1).artist_id());
        end


        function len = play(clips, plen)
        % len = play(clips)
        %
        % plays magnatune clip given by clip id, and
        % returns full playback length
        
        if nargin <2 
            plen = 0; %seconds play
        end
        
        len = 0;
            for i = 1:numel(clips)
                
                % get sample rate
                [null,sr] = mp3read(clips(i).mp3file_full(),0);
                
                if plen > 0
                    
                    % read mp3 file
                    [src,sr,NBITS,OPTS] = mp3read(clips(i).mp3file_full(), plen*sr);
                else
                    % read full mp3 file
                    [src,sr,NBITS,OPTS] = mp3read(clips(i).mp3file_full());
                end
                
                % ---
                % NOTE: sound() seems to pause the  system when trying to
                % play a clip while still playing another one
                % ---
                sound(src,sr);
                
                fprintf('\n--- now playing ---\n');
                clips(i).print();
                
                % add clip lengths
                len = len + length(src) / sr;
            end
        end
        
        function skip(clips)
        % skips through given clips
            
            clips.play(5);
        end
        
        function out = dbpos(this)
            % returns matrix position for given clip id

            out = find(this.my_db.annots_ids == this.id, 1 ,'first');
        end
          
        % ---
        % Generic Features
        % ---
        function feature = features(clip, type, varargin)
        % feature = features(clip, type, varargin)
        %
        % returns the features of type "type" for given clips and
        % parameters
        % e.g.    feature = clip.features('MTTAudioFeatureRAW')
        
            db_name = MTTAudioFeatureDBgen.db_name(type);
            
            % global database
            eval( sprintf( 'global %s;', db_name));
            
            % create database if neccesary
            if eval(sprintf('isempty(%s);', db_name));
                
                eval(sprintf('%s = MTTAudioFeatureDBgen(''%s'');', db_name, type));
            end
            
            % retrieve features from db
            feature = eval(sprintf('%s.get_features(clip, varargin{:});', db_name));
        end
        
        % ---
        % Audio Features Section
        % ---
        function features = audio_features_raw(clip)
            % get the features from the global database
            
            features = clip.features('MTTAudioFeatureRAW');
        end
        
        function features = audio_features_basicsm(clip, varargin)
            % get the features from the global database

            features = clip.features('MTTAudioFeatureBasicSm', varargin{:});
        end
        
        function features = genre_features_basic(clip, varargin)
            % get the features from the global database
            
            features = clip.features('MTTTagFeatureGenreBasic', varargin{:});
               
        end
        
        function features = mixed_features_genrebasicsm(clip, varargin)
            % get the features from the global database
            
            features = clip.features('MTTMixedFeatureGenreBasicSm', varargin{:});
        end
        
         function features = mixed_features_genrebasicsm_pca(clip, varargin)
            % get the features from the global database
            
            features = clip.features('MTTMixedFeatureGenreBasicSmPCA', varargin{:});
        end
        
        function features = random_features(clip, varargin)
            % get the features from the global database

            features = clip.features('MTTRandomFeature', varargin{:});
        end
        
    end
    
    % ---
    % static methods
    % ---
    methods(Static = true)
        
    end
end