function varargout = nc_cf_standard_names(varargin)
%NC_CF_STANDARD_NAMES  Routine facilitates adding variables that are part of standard-name glossaries
%
%   Routine facilitates adding variables that are part of standard-name glossaries (CF-1.4, OE-1.0, VO-1.0).
%   Works with both the Maltab and SNC netcdf libraries.   
%
%   Syntax:
%      nc_cf_standard_names(varargin)
%
%   Example:
%
%      nc_cf_standard_names('outputfile', outputfile, ...
%                           'varname',   {'x'}, ...
%                           'cf_standard_name', {'projection_x_coordinate'}, ...
%                           'dimension', {'time'})
%
%   Standard names supported:
%        (CF-1.4) 'altitude'
%        (CF-1.4) 'depth'
%        (CF-1.4) 'latitude'
%        (CF-1.4) 'longitude'
%        (CF-1.4) 'projection_x_coordinate'
%        (CF-1.4) 'projection_y_coordinate'
%        (CF-1.4) 'sea_surface_swell_wave_mean_period_from_variance_spectral_density_first_frequency_moment'
%        (CF-1.4) 'sea_surface_swell_wave_significant_height'
%        (CF-1.4) 'sea_surface_swell_wave_to_direction'
%        (CF-1.4) 'sea_surface_wave_zero_upcrossing_period'
%        (CF-1.4) 'sea_surface_wave_mean_period_from_variance_spectral_density_first_frequency_moment'
%        (CF-1.4) 'sea_surface_wave_mean_period_from_variance_spectral_density_second_frequency_moment'
%        (CF-1.4) 'sea_surface_wave_significant_height'
%        (CF-1.4) 'sea_surface_wave_to_direction'
%        (CF-1.4) 'sea_surface_wind_wave_mean_period_from_variance_spectral_density_first_frequency_moment'
%        (CF-1.4) 'sea_surface_wind_wave_significant_height'
%        (CF-1.4) 'sea_surface_wind_wave_to_direction'
%        (CF-1.4) 'wind_speed'
%        (CF-1.4) 'wind_to_direction'
%        (CF-1.4) 'sea_water_x_velocity'
%        (CF-1.4) 'sea_water_y_velocity'
%        (CF-1.4) 'northward_sea_water_velocity'
%        (CF-1.4) 'eastward_sea_water_velocity'
%        (CF-1.4) 'direction_of_sea_water_velocity'
%        (CF-1.4) 'radial_sea_water_velocity_away_from_instrument'
%        (CF-1.4) 'mass_concentration_of_suspended_matter_in_sea_water'
%        (CF-1.4) 'water_surface_height_above_reference_datum'
%        (CF-1.4) 'water_surface_reference_datum_altitude'
%
%   See also nc_cf_standard_names_generate

%% Copyright notice
%   --------------------------------------------------------------------
%   Copyright (C) 2009 Van Oord
%       Mark van Koningsveld
%
%       mrv@vanoord.com
%
%       Watermanweg 64
%       POBox 8574
%       3009 AN Rotterdam
%       Netherlands
%
%   This library is free software: you can redistribute it and/or
%   modify it under the terms of the GNU Lesser General Public
%   License as published by the Free Software Foundation, either
%   version 2.1 of the License, or (at your option) any later version.
%
%   This library is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
%   Lesser General Public License for more details.
%
%   You should have received a copy of the GNU Lesser General Public
%   License along with this library. If not, see <http://www.gnu.org/licenses/>.
%   --------------------------------------------------------------------

% This tools is part of VOTools which is the internal clone of <a href="http://OpenEarth.Deltares.nl">OpenEarthTools</a>.
% OpenEarthTools is an online collaboration to share and manage data and
% programming tools in an open source, version controlled environment.
% Sign up to recieve regular updates of this function, and to contribute
% your own tools.

%% Version <http://svnbook.red-bean.com/en/1.5/svn.advanced.props.special.keywords.html>
% Created: 13 Nov 2009
% Created with Matlab version: 7.7.0.471 (R2008b)

% $Id$
% $Date$
% $Author$
% $Revision$
% $HeadURL$
% $Keywords: $

%% settings

% defaults
fillValues.double =  typecast(uint8([0    0    0    0    0    0  158   71]),'DOUBLE');            
fillValues.float  =  typecast(uint8([                    0    0  240  124]),'SINGLE');
fillValues.int    =  typecast(uint8([                    1    0    0  128]),'INT32' );
fillValues.short  =  typecast(uint8([                              1  128]),'INT16' );
fillValues.byte   =  typecast(uint8(                                  129 ),'INT8'  );
fillValues.char   =  char(0);

OPT = struct(...
    'nc_library',       'snc', ...                           % snc or matlab 
    'ncid',             '', ...                              % nectdf id (only for matlab library)
    'outputfile',       {[]}, ...                            % name of the nc file. 
    'varname',          {{{'test1'};{'test2'}}}, ...         % variable name
    'cf_standard_name', {{{'test1'};{'test2'}}}, ...         % cf (climate forecasting) standard name
    'dimension',        {{{'test1'};{'test2'}}}, ...	     % dimension names					
    'dimid',            [], ...                              % dimension id's for use with matlab nc library only
    ...                                                      %   It is (a little) faster to indicate dimid's than dimension names
    'timezone',         '+01:00' , ...                       % timezone
    'deflate',          false , ...                          % only for netcdf4 files, internally deflates (compresses) variables in NC file
    'additionalAtts',   {[]}, ...                            % append these attributes to the default attributes. Must be in form
    ...                                                      %    {'name1','name2','name3';'value1','value2','value3'}
    'fillValues',       fillValues, ...                      % fill values for different variable classes     
    'ncType',           {{'default'}} ...                        % nc type     
    ); 

% overrule default settings by property pairs, given in varargin
OPT = setproperty(OPT, varargin{:});

%% check some basic input properties
if size(OPT.cf_standard_name,1) ~= size(OPT.dimension,1)
    error('nc_cf_standard_names:argChk', 'Input arguments not of equal length')
end

switch OPT.nc_library
    case 'snc'
        if isempty(OPT.outputfile)
            error('nc_cf_standard_names:outputChk',  'No outputfilename indicated')
        end
    case 'matlab'
        if isempty(OPT.ncid)
            error('nc_cf_standard_names:outputChk',  'No ncid indicated')
        end
    otherwise
        error('nc_cf_standard_names:outputChk',  'unknown nc_library, only snc and matlab are supported')
end

standardNames = { ...
            'altitude', ...
            'depth', ...
            'latitude', ...
            'longitude', ...
            'projection_x_coordinate', ...
            'projection_y_coordinate', ...
            'sea_surface_swell_wave_mean_period_from_variance_spectral_density_first_frequency_moment', ...
            'sea_surface_swell_wave_significant_height', ...
            'sea_surface_swell_wave_to_direction', ...
            'sea_surface_wave_zero_upcrossing_period', ...
            'sea_surface_wave_mean_period_from_variance_spectral_density_first_frequency_moment', ...
            'sea_surface_wave_mean_period_from_variance_spectral_density_second_frequency_moment', ...
            'sea_surface_wave_significant_height', ...
            'sea_surface_wave_to_direction', ...
            'sea_surface_wind_wave_mean_period_from_variance_spectral_density_first_frequency_moment', ...
            'sea_surface_wind_wave_significant_height', ...
            'sea_surface_wind_wave_to_direction', ...
            'wind_speed', ...
            'wind_to_direction', ...
            'wind_to_direction', ...
            'sea_water_x_velocity', ...
            'sea_water_y_velocity', ...
            'northward_sea_water_velocity', ...
            'eastward_sea_water_velocity', ...
            'direction_of_sea_water_velocity', ...
            'radial_sea_water_velocity_away_from_instrument', ...
            'mass_concentration_of_suspended_matter_in_sea_water', ...
            'water_surface_height_above_reference_datum', ...
            'water_surface_reference_datum_altitude', ...
           };

longNames = { ...
             'altitude', ...
             'depth', ...
             'latitude', ...
             'longitude', ...
             'x_coordinate', ...
             'y_coordinate', ...
             'Mean wave period T-10 (Swell)', ...
             'Significant wave height (Swell)', ...
             'Mean wave direction Theta (Swell)', ...
             'Mean period time Tz', ...
             'Mean wave period (1st frequency moment)', ...
             'Mean wave period (2nd frequency moment)', ...
             'Significant wave height (Sea and Swell)', ...
             'Mean wave direction Theta (Sea and Swell)', ...
             'Mean wave period T-10 (Sea)', ...
             'Significant wave height (Sea)', ...
             'Mean wave direction Theta (Sea)', ...
             'Wind speed', ...
             'Wind direction', ...
             'Sea water x velocity', ...
             'Sea water y velocity', ...
             'Sea water northward velocity', ...
             'Sea water eastward velocity', ...
             'Sea water velocity direction', ...
             'Radial sea water velocity away from instrument', ...
             'Mass concentration of suspended matter in sea water', ...
             'Water surface height above reference datum', ...
             'Water surface referernce datum altitude', ...
};


units = { ...
         'm', ...
         'm', ...
         'degree_north', ...
         'degree_east', ...
         'm', ...
         'm', ...
         's', ...
         'm', ...
         'degree', ...
         's', ...
         's', ...
         's', ...
         'm', ...
         'degree', ...
         's', ...
         'm', ...
         'degree', ...
         'm/s', ...
         'degree', ...
         'm/s', ...
         'm/s', ...
         'm/s', ...
         'm/s', ...
         'degree', ...
         'm/s', ...
         'kg/m3', ...
         'm', ...
         'm', ...
         };

nctypes = { ...
         'float', ...
         'float', ...
         'double', ...
         'double', ...
         'double', ...
         'double', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
         'float', ...
};

%% one by one add each variable
for i = 1:size(OPT.cf_standard_name,1)

    % Find index of matching standard name
    ist=strmatch(OPT.cf_standard_name{i},standardNames,'exact');
    
    if ~isempty(ist);
        % Standard name found
        standardname=standardNames{ist};
        longname=longNames{ist};
        unit=units{ist};
        if strcmpi(OPT.ncType{i},'default')
            nctype=nctypes{ist};
        else
            nctype=OPT.ncType{i};
        end
    else
        % Could not find matching name, assuming standard name is "unknown"
        standardname='unknown';
        longname=OPT.varname{i};
        unit='unknown';
        nctype=OPT.ncType{i};
        fillValue=OPT.fillValues.float;
    end

    % Set fill values
    switch nctype
        case{'double'}
            fillValue=OPT.fillValues.double;
        case{'float'}
            fillValue=OPT.fillValues.float;
        case{'int'}
            fillValue=OPT.fillValues.int;
        case{'short'}
            fillValue=OPT.fillValues.short;
        case{'byte'}
            fillValue=OPT.fillValues.byte;
        case{'char'}
            fillValue=OPT.fillValues.char;
    end

    Variable = struct(...
               'Name',       OPT.varname{i} , ...
               'Nctype',    nctype, ... 
               'Dimension', {OPT.dimension(i,:)}, ... 
               'Attribute', struct( ... 
                   'Name', ... 
                   {'standard_name', 'long_name', 'units', '_FillValue'}, ...
                   'Value', ... 
                   {standardname, longname, unit, fillValue} ...
                   ) ...
                );
    
    % append additional attributes
    for jj = 1:size(OPT.additionalAtts,2)
        Variable.Attribute(end+1).Name  = OPT.additionalAtts{1,jj};
        Variable.Attribute(end+0).Value = OPT.additionalAtts{2,jj};
    end
    
    % add variable to output file
    switch OPT.nc_library
        case 'snc'
            nc_addvar(OPT.outputfile, Variable);
            varargout = {[]};
        case 'matlab'
            try
                varid = netcdf_addvar(OPT.ncid, Variable );
            catch
                shite=1;
            end
            if OPT.deflate
                netcdf.defVarDeflate(OPT.ncid,varid,false,true,2);
            end
            varargout = {varid};
    end
end
