function writeFileImpact(output,arControllerOutputs,stFolder,stFileName)
%
%   writeFileImpact(output,arControllerOutputs,stFolder,stFileName)
%
%   This function creates IMPACT simulation files from WEC-Sim simulations.
%   At the end of a WEC-Sim simulation the standard results are stored in a
%   response class "output".  Additional variables to be saved can be added
%   to a structure "arControllerOutputs".
%
%   This function takes the data from output and arCOntrollerOutputs and
%   saves the data in the format set by the string stFileName followed by
%   the file types starting with "%" signs given below.  The data is saved
%   in the folder stFolder.
%
% Percent files and contents:
%
% %01
%
%     Elevation
%
%     TIMEX
%
%
% %02
%
%     Position
%
%     Velocity
%
%     Acceleration
%
%     ForceTotal
%
%     ForceExcitation
%
%     ForceRadiationDamping
%
%     ForceAddedMass
%
%     ForceRestoring
%
%     ForceMorrisonAndViscous
%
%     ForceLinearDamping
%
%     TIMEX
%
% %03
%     Position
%
%     Velocity
%
%     Acceleration
%
%     ForceTotal
%
%     ForceActuation
%
%     ForceConstraint
%
%     ForceInternalMechanics
%
%     PowerInternalMechanics
%
%     TIMEX
%
% %08
%
%     ArEkfFrequency
%
%     ArReferenceVelocity
%
%     ArForceDemand
%
%     ArWecPower
%
%     ArWecEnergy
%
%     ArAccelerationComponent
%
%     ArError
%
%     ArForceDemandIn
%
%     ArPositionComponent
%
%     ArPtoForceMeasurement
%
%     ArPtoVelocity
%
%     ArVelocityComponent
%
%     TIMEX
  
%   SgurrControl 2018
%   Project: IMPACT
%   Title of Code: writeFileImpact
%   Relevant additional documentation: 
%   Developer: Carlos Gonzalez
%   External Dependencies: NA
%
%   Disclaimer
%   CAUTION: It is strongly recommended that changes to this code
%   should be avoided without first consulting with SgurrControl
%   and acquiring permission. SgurrControl is not liable for any
%   damage caused as a result of unauthorised changes to this
%   document.

% Bring in the WECSim standard field names
if isstruct(output)
    zFieldNames = fieldnames(output);
else
    zFieldNames=[];
end

% For each field name use the relevant IMPACT file extension
for iCntFieldNames=1:numel(zFieldNames)
    switch zFieldNames{iCntFieldNames}
        
        case 'wave'
            stFileExtension='%01';
        case 'bodies'
            stFileExtension ='%02';
        case 'ptos'
            stFileExtension='%03';
        case 'constraints'
            stFileExtension='%04';
        case 'ptosim'
            stFileExtension='%05';
        case 'mooring'
            stFileExtension='%06';
        case 'moorDyn'
            stFileExtension = '%07';
        case 'controller'
            stFileExtension = '%08';
    end
    
    % If it is not empty and is not 'wave' then look at the secondary field
    if ~isempty(output.(zFieldNames{iCntFieldNames})) &&...
            ~strcmpi(output.(zFieldNames{iCntFieldNames}),'wave')
        
        % If it is a single body WEC...
        if numel(output.(zFieldNames{iCntFieldNames})) == 1
            zSecondaryField = fieldnames(output.(zFieldNames{iCntFieldNames}));
            iCntFields = 0;
            stVariable = '';
            stVariableUnit = '';
            arData = [];
            
            for iCntSecondaryFields=1:numel(zSecondaryField)
                
                % If the secondary field isn't time and has values then record
                % it as a vector
                if ~strcmpi(zSecondaryField{iCntSecondaryFields},'time') &&...
                        isnumeric(output.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields}))
                    
                    iCntFields = iCntFields+1;
                    stVariable = [stVariable,'''',zSecondaryField{iCntSecondaryFields},'''  '];
                    stVariableUnit = [stVariableUnit,'F '];
                    [iNumRows,iNumColumns]= size(output.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields}));
                    arVector = reshape(output.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields})',iNumRows*iNumColumns,1);
                    arData(iCntFields,:) = arVector';
                    
                end
            end
            
            % If the number of secondary fields is greater than 0 then create
            % an IMPACT "%" file and write the data to it.
            if numel(zSecondaryField) > 0
                xFile = fopen(fullfile(stFolder,[stFileName,'.',stFileExtension]),'w+');
                iNumElements = numel(output.(zFieldNames{iCntFieldNames}).time);
                
                % Set all the required headers for the data
                fprintf(xFile,'FILE     %s.$%s\n',stFileName,stFileExtension(2:end));
                fprintf(xFile,'ACCESS    D\n');
                fprintf(xFile,'FORM      U\n');
                fprintf(xFile,'RECL               4\n');
                fprintf(xFile,'FORMAT    R*4\n');
                fprintf(xFile,'CONTENT  POWPROD\n');
                fprintf(xFile,'CONFIG   STATIONARY\n');
                fprintf(xFile,'NDIMENS 3\n');
                fprintf(xFile,'DIMENS %d\t6\t%d\n',iCntFields,iNumElements);
                fprintf(xFile,'GENLAB   ''%s''\n',zFieldNames{iCntFieldNames});
                fprintf(xFile,'VARIAB   %s\n',stVariable);
                fprintf(xFile,'VARUNIT  %s\n',stVariableUnit);
                fprintf(xFile,'AXISLAB   ''Component''\n');
                fprintf(xFile,'AXIUNIT L\n');
                fprintf(xFile,'AXIMETH  3\n');
                fprintf(xFile,'AXIVAL 1 2 3 4 5 6\n');
                fprintf(xFile,'AXISLAB  ''Time''\n');
                fprintf(xFile,'AXIUNIT  T\n');
                fprintf(xFile,'AXIMETH  2\n');
                fprintf(xFile,'MIN        %f\n',output.(zFieldNames{iCntFieldNames}).time(1));
                fprintf(xFile,'STEP       %f\n',output.(zFieldNames{iCntFieldNames}).time(2)-output.(zFieldNames{iCntFieldNames}).time(1));
                fprintf(xFile,'NVARS    0\n');
                fclose(xFile);
                
                % Write the data
                xFile = fopen(fullfile(stFolder,[stFileName,'.$',stFileExtension(2:end)]),'wb');
                fwrite(xFile,arData,'float');
                fclose(xFile);
            end
            
        % for multiple-body WECs
        else
            for iCntBodies=1:numel(output.(zFieldNames{iCntFieldNames}))
                
                zSecondaryField = fieldnames(output.(zFieldNames{iCntFieldNames}));
                iCntFields = 0;
                stVariable = '';
                stVariableUnit = '';
                arData = [];
                
                for iCntSecondaryFields=1:numel(zSecondaryField)
                    % If the secondary field isn't time and has values then record
                % it as a vector
                    if ~strcmpi(zSecondaryField{iCntSecondaryFields},'time') &&...
                            isnumeric(output.(zFieldNames{iCntFieldNames})(iCntBodies).(zSecondaryField{iCntSecondaryFields}))
                        
                        
                        if ~isempty(output.(zFieldNames{iCntFieldNames})(iCntBodies).(zSecondaryField{iCntSecondaryFields}))
                            [iRows,iColumns] = size(output.(zFieldNames{iCntFieldNames})(iCntBodies).(zSecondaryField{iCntSecondaryFields}));
                            arVector = reshape(output.(zFieldNames{iCntFieldNames})(iCntBodies).(zSecondaryField{iCntSecondaryFields})',iRows*iColumns,1);
                            iCntFields = iCntFields+1;
                            stVariable = [stVariable,'''',zSecondaryField{iCntSecondaryFields},'''  '];
                            stVariableUnit = [stVariableUnit,'F '];
                        
                            arData(iCntFields,:) = arVector';
                        end
                        
                    end
                end
                if numel(zSecondaryField)>0
                    xFile = fopen(fullfile(stFolder,[stFileName,'.',[stFileExtension,num2str(iCntBodies)]]),'w+');
                    iNumElements = numel(output.(zFieldNames{iCntFieldNames})(iCntBodies).time);
                    fprintf(xFile,'FILE     %s.$%s\n',stFileName,[stFileExtension(2:end),num2str(iCntBodies)]);
                    fprintf(xFile,'ACCESS    D\n');
                    fprintf(xFile,'FORM      U\n');
                    fprintf(xFile,'RECL               4\n');
                    fprintf(xFile,'FORMAT    R*4\n');
                    fprintf(xFile,'CONTENT  POWPROD\n');
                    fprintf(xFile,'CONFIG   STATIONARY\n');
                    fprintf(xFile,'NDIMENS 3\n');
                    fprintf(xFile,'DIMENS %d\t6\t%d\n',iCntFields,iNumElements);
                    if isempty(output.(zFieldNames{iCntFieldNames})(iCntBodies).name)
                        stGenLab = sprintf('%s_%d',zFieldNames{iCntFieldNames},iCntBodies);
                    else
                        stGenLab = output.(zFieldNames{iCntFieldNames})(iCntBodies).name;
                    end
                    fprintf(xFile,'GENLAB   ''%s''\n',stGenLab);
                    fprintf(xFile,'VARIAB   %s\n',stVariable);
                    fprintf(xFile,'VARUNIT  %s\n',stVariableUnit);
                    fprintf(xFile,'AXISLAB   ''Component''\n');
                    fprintf(xFile,'AXIUNIT L\n');
                    fprintf(xFile,'AXIMETH  3\n');
                    fprintf(xFile,'AXIVAL 1 2 3 4 5 6\n');
                    fprintf(xFile,'AXISLAB  ''Time''\n');
                    fprintf(xFile,'AXIUNIT  T\n');
                    fprintf(xFile,'AXIMETH  2\n');
                    fprintf(xFile,'MIN        %f\n',output.(zFieldNames{iCntFieldNames})(iCntBodies).time(1));
                    fprintf(xFile,'STEP       %f\n',output.(zFieldNames{iCntFieldNames})(iCntBodies).time(2)-output.(zFieldNames{iCntFieldNames})(iCntBodies).time(1));
                    fprintf(xFile,'NVARS    0\n');
                    fclose(xFile);
                    
                    
                    xFile = fopen(fullfile(stFolder,[stFileName,'.$',[stFileExtension(2:end),num2str(iCntBodies)]]),'wb');
                    fwrite(xFile,arData,'float');
                    fclose(xFile);
                end
                
            end
        end
    end
end

% Bring in the WECSim controller output field names
if ~isstruct(arControllerOutputs)
    zFieldNames= [];
else
    zFieldNames = fieldnames(arControllerOutputs);
end

% Set the appropriate file extension to be written
for iCntFieldNames=1:numel(zFieldNames)
    switch zFieldNames{iCntFieldNames}
        case 'wave'
            stFileExtension='%01';
        case 'bodies'
            stFileExtension ='%02';
        case 'ptos'
            stFileExtension='%03';
        case 'constraints'
            stFileExtension='%04';
        case 'ptosim'
            stFileExtension='%05';
        case 'mooring'
            stFileExtension='%06';
        case 'moorDyn'
            stFileExtension = '%07';
        case 'controller'
            stFileExtension = '%08';
    end
    
    % If it is not empty and is not 'wave' then look at the secondary field
    if ~isempty(arControllerOutputs.(zFieldNames{iCntFieldNames})) &&...
            ~strcmpi(arControllerOutputs.(zFieldNames{iCntFieldNames}),'wave')
        
        % This looks at all the data recorded by the user in
        % arControllerOutputs 
        
        zSecondaryField = fieldnames(arControllerOutputs.(zFieldNames{iCntFieldNames}));
        iCntFields = 0;
        stVariable = '';
        stVariableUnit = '';
        arData = [];
        
        for iCntSecondaryFields=1:numel(zSecondaryField)
            
            % If the dtaa isn't time and is numeric then put in a vector
            if ~strcmpi(zSecondaryField{iCntSecondaryFields},'time') &&...
                    isnumeric(arControllerOutputs.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields}))
                
                iCntFields = iCntFields+1;
                stVariable = [stVariable,'''',zSecondaryField{iCntSecondaryFields},'''  '];
                stVariableUnit = [stVariableUnit,'F '];
                [iNumRows,iNumColumns]= size(arControllerOutputs.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields}));
                arVector = reshape(arControllerOutputs.(zFieldNames{iCntFieldNames}).(zSecondaryField{iCntSecondaryFields})',iNumRows*iNumColumns,1);
%                 zFieldNames{iCntFieldNames}
%                 zSecondaryField{iCntSecondaryFields}
%                 iCntSecondaryFields
                arData(iCntFields,:) = arVector';
            
            end
        end
        
        % If there is data to record then record it in the appropriate "%"
        % file
        if numel(zSecondaryField) > 0
            
            % Set up all the headings
            xFile = fopen(fullfile(stFolder,[stFileName,'.',stFileExtension]),'w+');
            if xFile~=-1
                iNumElements = numel(arControllerOutputs.(zFieldNames{iCntFieldNames}).time);
                fprintf(xFile,'FILE     %s.$%s\n',stFileName,stFileExtension(2:end));
                fprintf(xFile,'ACCESS    D\n');
                fprintf(xFile,'FORM      U\n');
                fprintf(xFile,'RECL               4\n');
                fprintf(xFile,'FORMAT    R*4\n');
                fprintf(xFile,'CONTENT  POWPROD\n');
                fprintf(xFile,'CONFIG   STATIONARY\n');
                fprintf(xFile,'NDIMENS 2\n');
                fprintf(xFile,'DIMENS %d\t%d\n',iCntFields,iNumElements);
                fprintf(xFile,'GENLAB   ''%s''\n',zFieldNames{iCntFieldNames});
                fprintf(xFile,'VARIAB   %s\n',stVariable);
                fprintf(xFile,'VARUNIT  %s\n',stVariableUnit);
                fprintf(xFile,'AXISLAB  ''Time''\n');
                fprintf(xFile,'AXIUNIT  T\n');
                fprintf(xFile,'AXIMETH  2\n');
                fprintf(xFile,'MIN        %f\n',...
                    arControllerOutputs.(zFieldNames{iCntFieldNames}).time(1));
                fprintf(xFile,'STEP       %f\n',...
                    arControllerOutputs.(zFieldNames{iCntFieldNames}).time(2)-arControllerOutputs.(zFieldNames{iCntFieldNames}).time(1));
                fprintf(xFile,'NVARS    0\n');
                fclose(xFile);
                
                % Write the actual data
                xFile = fopen(fullfile(stFolder,[stFileName,'.$',stFileExtension(2:end)]),'wb');
                fwrite(xFile,arData,'float');
                fclose(xFile);
            else
                warning(sprintf('File %s.%%08 cannot be created',stFileName))
            end
        end
    end
end
pf = fopen(fullfile(stFolder,[stFileName,'.$PJ']),'w+');
if pf~=-1
    fprintf(pf,'VERSION	1.0\n');
    fprintf(pf,'CALCULATION	10\n');
    fclose(pf);
end

