classdef MTTMixedFeatureSon < MTTAudioFeature & handle
    % ---
    % This Class contains a wrapper for sons feature extraction
    %
    % The usual workflow for these features constist of three steps
    % 1. extract: extracts the basic single-file dependent features
    % 2. define_global_transform: calculates the global feature
    %       transformation parameters
    % 3. finalise: applies the common transformations to a specific feature
    % ---
    
    properties(Constant = true)
        
        % svn hook
        my_revision = str2double(substr('$Rev: 741 $',  5, -1));
    end

    properties
        % ---
        % Set default parameters
        % ---
        my_params = struct( ...
            'son_filename','features_rbm_50x1010', ...
            'son_conf', '' ...
        );
    end
    
    % ---
    % member functions
    % ---
    methods
        
        % ---
        % constructor: pointer to feature in database
        % ---
        function feature = MTTMixedFeatureSon(varargin)

            feature = feature@MTTAudioFeature(varargin{:});

        end
        % ---
        % extract feature data from raw audio features
        % ---
        function data = extract(feature, clip)
            % ---
            % get features. this includes possible
            % local normalisations
            % ---
            
            global globalvars;
            global comparison_ids;
            global sonfeatbase;
            global db_MTTClip;
            
            if isempty(sonfeatbase);
                sonfeatbase = load(feature.my_params.son_filename);
            end
            %
            
            % ---
            % note: this should reference clip.my_db
            % get the actual clip id
            idx = db_MTTClip.comparison_ids(clip.id);
            
            % ---
            % NOTE: we just copy everything in a big matrix and then
            % normalise the data later
            % ---
            if isfield(sonfeatbase,'nfvec')
                rawf = sonfeatbase.nfvec;
            elseif isfield(sonfeatbase,'sonfeatures')
                rawf = sonfeatbase.sonfeatures';
            end
            
            if idx <= size(rawf,2)
                
                 % get the vector from loaded data
                data.sonraw = rawf(:,idx);
                
            else
                % ---
                % CAVE: Clip indices outside 
                % the range  of the supplied mat file
                % are filled up with zeros
                % ---
                data.sonraw = zeros(size(rawf,1),1);
            end
            
           
            
            data.vector_info = {'Sonfeat'};
            % padd further info struct
            data.vector_info(end+1:size(data.sonraw,1)) =...
                cell(size(data.sonraw,1) - numel(data.vector_info) , 1); 
            
            % ---
            % prepare field for final features
            % ---
            data.final.vector = [];
            data.final.vector_info = struct(); 
            data.final.dim = 0;
           
            % save info data
            data.info.type = 'MTTMixedFeatureSon';
            data.info.owner_id = clip.id;
            data.info.creatorrev = feature.my_revision;
            
            % save parameters
            data.info.params = feature.my_params;
        end
        
        function define_global_transform(features)
        % calculate and set normalization factors from the group of 
        % input features. These features will be set for the full database
         
            final = zeros(size(features(1).data.sonraw,1), numel(features));
            for i = 1:numel(features)
                 if ~isempty(features(i).data.sonraw)
                    final(:,i) = features(i).data.sonraw;
                 end
            end
            
            % set common to 1 to tell normalisation is done
            features(1).my_db.set_common([1]);
            
            % save the normalised features straight away!
            features.finalise(final);
        end
        
        
        function finalise(features, final)
        % applies a final transformation and
        % collects the information of this feature within a single vector
        % see info for types in specific dimensions
        % check if features have been finalised already

        % ---
        % set feature labelling
        % ---
        
        info = {};
                
        % ---
        % construct resulting feature vector out of features
        % ---
            if nargin == 2 && isempty(final)
                
                % the final vector etc already are set to zero;
                return;
                
            elseif nargin == 2 && (numel(features) == size(final, 2))
                % the features have already been preassembled
                
                for i = 1:numel(features)

                    % check for neccesary parameters
                    if isempty(features(i).my_db.commondb)

                        error('Define the global transformation first')
                        return;
                    end

                    features(i).data.final.vector = final(:,i);
                    features(i).data.final.dim = size(final,1);

                    % fill up info struct and append to feature
                    features(i).data.final.vector_info.labels = ...
                        features(i).data.vector_info;
                end
            else
                % ---
                % if features have been added after gettin gnormalisation
                % parameters, ther should be still an option to include
                % them
                % ---
               
                 for i = 1:numel(features)

                    % check for neccesary parameters
                    if isempty(features(i).my_db.commondb)

                        error('Define the global transformation first')
                        return;
                    end
                    
                    final = zeros(numel(features(1).data.sonraw), numel(features));
                    for i = 1:numel(features)
                         if ~isempty(features(i).data.sonraw)
                            final(:,i) = features(i).data.sonraw;
                         end
                    end
                    features(i).data.final.vector = final;
                    features(i).data.final.dim = size(final,1);

                    % fill up info struct and append to feature
                    features(i).data.final.vector_info.labels = ...
                        features(i).data.vector_info;
                 end

            end
            
            % ---
            % TODO: Maybe delete more basic features again at this point?
            % ---
        end

        % ---
        % destructor: do we really want to remove this 
        % from the database? No, but 
        % TODO: create marker for unused objects in db, and a cleanup
        %  function
        % ---
        function delete(feature)
            
        end
    end
end