function allWaveforms = sac2waveform(sacStructure)
   %SAC2WAVEFORM fill a waveform object from a sac header
   %   waveform = sac2waveform(sacInfo)
   %     sacInfo is the output from readsacfile.m
   %
   %    Each field from the header be either incorporated into the basic
   %    structure of each waveform or will be added as user-defined fields.
   %
   %    See also:  waveform/private/readsacfile,
   %    waveform/private/waveform2sacheader
   
   % VERSION: 1.1 of waveform objects
   % AUTHOR: Celso Reyes (celso@gi.alaska.edu)
   %    modified from Michael Thorne (4/2004)  mthorne@asu.edu
   % LASTUPDATE: 9/1/2009, improving readability in effort to be able to
   % better maintain this code.
   
   % first test to see if the sacInfo is indeed a sacfile
   %---------------------------------------------------------------------------
   
   allWaveforms = repmat(waveform,size(sacStructure));
   
   for eachSacFile = 1:numel(sacStructure)
      sacInfo = sacStructure(eachSacFile);
      
      [fieldNames, fieldValues] =  parseHeader(sacInfo.header);
      
      % Take these results and create a structure with them
      %   fieldsPairedWithValues puts it all in an order that "struct()"
      %   understands. like so: {fieldname1,fieldval1,...,fieldNameN,fieldvalN}
      invalidFields = strcmp(fieldNames,'DUMMYVARIABLE');
      fieldNames = fieldNames(~invalidFields);
      fieldValues = fieldValues(~invalidFields);
      fieldsPairedWithValues = [fieldNames(:)'; fieldValues(:)'];
      headerDetails = struct(fieldsPairedWithValues{:});
      
      
      chanTag = getChanneltag(headerDetails);
      w = set(waveform,'channelinfo',chanTag);
      
      for nrecs = 1:numel(fieldNames)
         thisfield = fieldNames{nrecs};
         thisvalue = fieldValues{nrecs};
         if ~isempty(thisvalue)
            w = addfield(w,thisfield,headerDetails.(thisfield));
         end
      end
      
      w = set(w,'start',getDate(headerDetails));
      w = set(w,'data',sacInfo.amplitudes);
      w = set(w,'freq', 1 ./ headerDetails.DELTA); %doesn't take into account ODELTA (observed freq)
      w = set(w,'units', idep2units(headerDetails.IDEP));
      w = clearhistory(w);
      allWaveforms(eachSacFile) = w;
   end
end
% varargout = headerDetails;

%{
function scnl = getSCNL(header)
   %make scnl object from station channel and network.  no location info
   %exists
   scnl = scnlobject(deblank(header.KSTNM),... station
      deblank(header.KCMPNM), ... channel
      deblank(header.KNETWK)); %network
end
%}

function chanT = getChanneltag(header)
   chanT = ChannelTag(deblank(header.KNETWK), ... network
      deblank(header.KSTNM),... station
      deblank(header.KHOLE), ... location
      deblank(header.KCMPNM)); % channel
end

function mydate = getDate(header)
   mydate= datenum(header.NZYEAR, 0, header.NZJDAY, ...
      header.NZHOUR, header.NZMIN, ...
      header.NZSEC + .001 * header.NZMSEC + header.B);
end

function measurementUnits = idep2units(IDEP)
   % look up the proper units based on the SAC IDEP value
   if isempty(IDEP), IDEP = 5; end
   switch IDEP
      case 6 %idisp
         measurementUnits = 'nm';
      case 7 %ivel
         measurementUnits = 'nm / sec';
      case 8 %iacc
         measurementUnits = 'nm / sec / sec';
      case 50 %ivolts
         measurementUnits = 'volts';
      otherwise %case 5 = iunkn
         measurementUnits = 'Counts';
   end
end

function [headerFields,value] = parseHeader(h)
   emptyNumber = -12345;
   emptyString = '-12345';
   
   headerDefinitions = getHeaderDefinitions();
   headerFields = headerDefinitions(:,1);
   fieldType = headerDefinitions(:,2);
   %startPositions = [headerDefinitions{:,3}];
   %endPositions = (startPositions - 1) + [ headerDefinitions{:,4}];
   value = cell(size(headerFields));
   
   for thisField=1:numel(headerFields)
      %ensure each field is of the right type, and get rid of any default
      %values, replacing with '' or [] as appropriate
      
      value(thisField) = h(thisField);
      
      switch (fieldType{thisField})
         case 'double'
            if value{thisField} == emptyNumber
               value(thisField) = {[]};
            end
            
         case 'char'
            %get rid of all beginning/ending whitespace
            value(thisField) = {strtrim(char(value{thisField}))};
            
            if strcmpi(value(thisField),emptyString)
               value(thisField) = {''};
            end
            
         case 'integer'
            value(thisField) = {round(value{thisField})};
            if value{thisField} == emptyNumber
               value(thisField) = {[]};
            end
            
         case 'logical'
            if strcmp(value{thisField},emptyString)
               value(thisField) = {false};
            end
            value(thisField) = {logical(value{thisField})};
            
         otherwise
            error('Waveform:sac2waveform:unknownHeaderTypedef',...
               'Unknown type definition within the SAC header');
      end
   end
end

function headerDefinitions = getHeaderDefinitions()
   % Create a cell with one row for each variable represented in the SAC
   % header.  Each row contains the information required to decode the header
   % into a matlab variable.
   %
   % columns : variablename, type, startPos, length
   % startPos is no longer used.
   
   headerDefinitions={
      'DELTA','double',1,1;
      'DEPMIN','double',2,1;
      'DEPMAX','double',3,1;
      'SCALE','double',4,1;
      'ODELTA','double',5,1;
      'B','double',6,1;
      'E','double',7,1;
      'O','double',8,1;
      'A','double',9,1; %10 not represented
      'DUMMYVARIABLE','double',10,1;
      'T0','double',11,1;
      'T1','double',12,1;
      'T2','double',13,1;
      'T3','double',14,1;
      'T4','double',15,1;
      'T5','double',16,1;
      'T6','double',17,1;
      'T7','double',18,1;
      'T8','double',19,1;
      'T9','double',20,1;
      'F','double',21,1;
      'RESP0','double',22,1;
      'RESP1','double',23,1;
      'RESP2','double',24,1;
      'RESP3','double',25,1;
      'RESP4','double',26,1;
      'RESP5','double',27,1;
      'RESP6','double',28,1;
      'RESP7','double',29,1;
      'RESP8','double',30,1;
      'RESP9','double',31,1;
      'STLA','double',32,1;
      'STLO','double',33,1;
      'STEL','double',34,1;
      'STDP','double',35,1;
      'EVLA','double',36,1;
      'EVLO','double',37,1;
      'EVEL','double',38,1;
      'EVDP','double',39,1;
      'MAG','double',40,1;
      'USER0','double',41,1;
      'USER1','double',42,1;
      'USER2','double',43,1;
      'USER3','double',44,1;
      'USER4','double',45,1;
      'USER5','double',46,1;
      'USER6','double',47,1;
      'USER7','double',48,1;
      'USER8','double',49,1;
      'USER9','double',50,1;
      'DIST','double',51,1;
      'AZ','double',52,1;
      'BAZ','double',53,1;
      'GCARC','double',54,1; %55 - 56 not represented
      'DUMMYVARIABLE','double',55,1;
      'DUMMYVARIABLE','double',56,1;
      'DEPMEN','double',57,1;
      'CMPAZ','double',58,1;
      'CMPINC','double',59,1;
      'XMINIMUM','double',60,1;
      'XMAXIMUM','double',61,1;
      'YMINIMUM','double',62,1;
      'YMAXIMUM','double',63,1; %64 - 70 not represented
      'DUMMYVARIABLE','double',64,1;
      'DUMMYVARIABLE','double',65,1;
      'DUMMYVARIABLE','double',66,1;
      'DUMMYVARIABLE','double',67,1;
      'DUMMYVARIABLE','double',68,1;
      'DUMMYVARIABLE','double',69,1;
      'DUMMYVARIABLE','double',70,1;
      'NZYEAR','integer',71,1;
      'NZJDAY','integer',72,1;
      'NZHOUR','integer',73,1;
      'NZMIN','integer',74,1;
      'NZSEC','integer',75,1;
      'NZMSEC','integer',76,1;
      'NVHDR','integer',77,1;
      'NORID','integer',78,1;
      'NEVID','integer',79,1;
      'NPTS','integer',80,1; %81 not represented
      'DUMMYVARIABLE','integer',81,1;
      'NWFID','integer',82,1;
      'NXSIZE','integer',83,1;
      'NYSIZE','integer',84,1; %85 not represented
      'DUMMYVARIABLE','integer',85,1;
      'IFTYPE','integer',86,1;
      'IDEP','integer',87,1;
      'IZTYPE','integer',88,1; %89 not represented
      'DUMMYVARIABLE','integer',89,1;
      'IINST','integer',90,1;
      'ISTREG','integer',91,1;
      'IEVREG','integer',92,1;
      'IEVTYP','integer',93,1;
      'IQUAL','integer',94,1;
      'ISYNTH','integer',95,1;
      'IMAGTYP','integer',96,1;
      'IMAGSRC','integer',97,1; %98 - 105 not represeneted
      'DUMMYVARIABLE','integer',98,1;
      'DUMMYVARIABLE','integer',99,1;
      'DUMMYVARIABLE','integer',100,1;
      'DUMMYVARIABLE','integer',101,1;
      'DUMMYVARIABLE','integer',102,1;
      'DUMMYVARIABLE','integer',103,1;
      'DUMMYVARIABLE','integer',104,1;
      'DUMMYVARIABLE','integer',105,1;
      'LEVEN','logical',106,1;
      'LPSPOL','logical',107,1;
      'LOVROK','logical',108,1;
      'LCALDA','logical',109,1; %110 not represented.
      'DUMMYVARIABLE','integer',110,1;
      'KSTNM','char',111,8;
      'KEVNM','char',119,16;
      'KHOLE','char',135,8;
      'KO','char',143,8;
      'KA','char',151,8;
      'KT0','char',159,8;
      'KT1','char',167,8;
      'KT2','char',175,8;
      'KT3','char',183,8;
      'KT4','char',191,8;
      'KT5','char',199,8;
      'KT6','char',207,8;
      'KT7','char',215,8;
      'KT8','char',223,8;
      'KT9','char',231,8;
      'KF','char',239,8;
      'KUSER0','char',247,8;
      'KUSER1','char',255,8;
      'KUSER2','char',263,8;
      'KCMPNM','char',271,8;
      'KNETWK','char',279,8;
      'KDATRD','char',287,8;
      'KINST','char',295,8};
end