function frame = plotFrame(varargin)
% f   : the structure containing the data to build the frame
% fig : the figure (if we are updating it rather than building it
frame = varargin{1}; % input structure
mechanics = varargin{2}; % mechanics
f = varargin{3};
im = varargin{4};
if nargin == 5
    frame.fig = varargin{5}; % if first we should build, otherwise update.
    figure(frame.fig);
    %  set(f.TileHandle,'String',['Frame ' num2str(f.frame)]);
else
    frame.first = true; % we need to build the figure instead of update it
    frame.fig = figure; % make a figure to start with.
    [row,col] = size(frame.axes); % get the number of rows and columns
    frame.AxesHandles = tight_subplot(row,col,[frame.spacing frame.spacing],[frame.spacing frame.spacing], ...
        [frame.spacing frame.spacing]); % setup the figure and save it to the function
    set(frame.fig,'Renderer','OpenGL'); % set the proper render device
    set(frame.fig,'Color','w'); % white background is nicer.
    scrsz = get(0,'ScreenSize');
    set(frame.fig,'Position',[1+5,1+5,scrsz(3)-20,scrsz(4)-100]); % position the figure to take up the entire screen
    %  pause % wait for user confirmation.
end

for cAxes = 1:numel(frame.AxesHandles) % loop through and plot each axes for the frame
    % choose the current axes
    axes(frame.AxesHandles(cAxes)) %#ok<LAXES>
    hold on
    set(frame.AxesHandles(cAxes),'FontSize',frame.FontSize);
    title(frame.axes(cAxes).title)
    switch frame.axes(cAxes).type % switch between types of axes
        case 'image'   % image type
            frame.axes(cAxes) = plotImage(frame.axes(cAxes),mechanics,im,f,frame.first);
        case 'heatmap' % heatmap type
            frame.axes(cAxes) = plotHeat(frame.axes(cAxes),mechanics,f,frame.first);
        case 'composite' % need to just get rid of the figure, it's a placeholder
            frame.axes(cAxes) = plotComposite(frame.axes(cAxes),mechanics,f,im,frame.first);
        case 'DTI'
            frame.axes(cAxes) = plotDTI(frame.axes(cAxes),mechanics,f,im,frame.first);
        case 'placeholder' % need to just get rid of the figure, it's a placeholder
            frame.axes(cAxes) = plotPlaceholder(frame.axes(cAxes),frame.first);
    end

end % end loop
frame.first = false; % no longer the first loop, set this false!
end % end function

function a = plotImage(a,data,im,f,first) % plotting an image

if first
    if a.limits.on
        a.CDataIm = imshow(im(a.limits.lims(3):a.limits.lims(4), ...
            a.limits.lims(1):a.limits.lims(2),:)); % show the image
        set(a.CDataIm,'XData',a.limits.lims(1))
        set(a.CDataIm,'YData',a.limits.lims(3))
        xlim([a.limits.lims(1) a.limits.lims(2)]); % set x and y limits
        ylim([a.limits.lims(3) a.limits.lims(4)]);
        axis equal
        axis off
        axis ij
        cbar = colorbar;
        set(cbar,'Visible','off')
    else
        a.CDataIm = imshow(im); % show the image
    end
    % axis image % square it up
else
    if a.limits.on
        set(a.CDataIm,'CData',im(a.limits.lims(3):a.limits.lims(4), ...
            a.limits.lims(1):a.limits.lims(2),:));
    else
        set(a.CDataIm,'CData',im);
    end
end

if a.points.on
    xdata = squeeze(data.x(2,:,f));
    ydata = squeeze(data.x(1,:,f));
    if first
        a.trustplot = plot(gca,xdata,ydata,'b.');
        set(a.trustplot,'MarkerSize',16)
    else
        set(a.trustplot,'XData',xdata,'YData',ydata);
    end
end
if a.deformations.on % do we want to plot the current deformations
    type = a.dataType; % what type of data do we want to use for the deformations (must be field in data)
    newVertices = zeros(4,2,data.npts);
    xydata = [xdata ydata];
    v = a.deformations.vertices;
    for cFi = 1:data.npts % if so we need to loop through the points
        % calculate the new vertices
        newVertices(:,:,cFi) = (data.(type).F(1:2,1:2,cFi)*v)'+repmat(xydata(cFi,:),4,1);
        % set the new veritices
        if first % first time, we need to draw them
            a.deformations.boxes(cFi) = fill(newVertices(:,1,cFi),newVertices(:,2,cFi),...
                'r','FaceColor','none','EdgeAlpha',a.deformations.Alpha);
        else % instead of plotting them just update them with new vertices
            set(a.deformations.boxes(cFi),'Vertices',newVertices(:,:,cFi))
        end
    end
end

end

function a = plotHeat(a,data,frame,first)

cdat = data.(a.dataType); % get the data we're explicity dealing with!
if strcmp(a.dataType,'SIMPLE')
    a.StrainDataType = 'delta';
end
switch a.StrainDataType
    case 'PrincipleE'
        if any(a.Direction == [1 2])
            dat = squeeze(cdat.EI(a.Direction,a.Direction,:,frame))';
        elseif a.Direction == 0 % determinant
            dat = zeros(1,size(cdat.eigE,3));
            for p = 1:size(cdat.EI,3)
                dat(p) = det(cdat.EI(:,:,p,frame));
            end
        elseif a.Direction == 12 % shear strain
            dat = squeeze(cdat.EI(1,1,:,frame))'-squeeze(cdat.EI(2,2,:,frame))';
        elseif a.Direction == 1.5 % mean strain
            dat = (squeeze(cdat.EI(1,1,:,frame))'+squeeze(cdat.EI(2,2,:,frame))')/2;         
        end
    case 'E'
        if any(a.Direction == [1 2])
            dat = squeeze(cdat.E(a.Direction,a.Direction,:,frame))';
        elseif a.Direction == 0 % determinant
            dat = zeros(1,size(cdat.eigE,3));
            for p = 1:size(cdat.eigE,3)
                dat(p) = det(cdat.E(:,:,p,frame));
            end
        elseif a.Direction == 12 % shear strain
            dat = squeeze(cdat.E(1,1,:,frame))'-squeeze(cdat.E(2,2,:,frame))';
        end
    case 'F'
        if any(a.Direction == [1 2])
            dat = squeeze(cdat.F(a.Direction,a.Direction,:,frame))';
        elseif a.Direction == 0 % determinant
            dat = zeros(1,size(cdat.eigE,3));
            for p = 1:size(cdat.eigE,3)
                dat(p) = det(cdat.F(:,:,p,frame));
            end
        elseif a.Direction == 12 % shear strain
            dat = squeeze(cdat.E(1,1,:,frame))'-squeeze(cdat.E(2,2,:,frame))';
        end
    case 'delta'
        if any(a.Direction == [1 2])
            dat = squeeze(cdat.DeltaI(a.Direction,a.Direction,:,frame))';
        elseif a.Direction == 0 % determinant
            dat = zeros(1,size(cdat.DeltaI,3));
            for p = 1:size(cdat.DeltaI,3)
                dat(p) = det(cdat.DeltaI(:,:,p,frame));
            end
        elseif a.Direction == 12 % shear strain
            dat = squeeze(cdat.DeltaI(1,1,:,frame))'-squeeze(cdat.DeltaI(2,2,:,frame))';
        end

end

if isfield(data,'trust') % if there are trrusted values include them
    keep = data.trust(frame,:) & (abs(dat)<=abs(mean(dat))+4*std(dat));
else
    keep = (abs(dat)<=abs(mean(dat))+4*std(dat));
end

% make interpolant for the data
switch a.type
    case 'heatmap' % in heatmap use original coordinates
        xdata = data.XY.x(keep);
        ydata = data.XY.x(keep);
        zdata = dat(keep)';
        Xinterp = data.XY.Xinterp;
        Yinterp = data.XY.Yinterp;
    case 'composite' % incomposite use coordinates of midpoints
        xdata = data.x(2,keep,frame); % get the positional xdata in the current frame
        ydata = data.x(1,keep,frame); % " y data
        zdata = dat(keep); % z data is just the dat of interest
        xmin = floor(min(xdata)); xmax = ceil(max(xdata)); % get x and y
        ymin = floor(min(ydata)); ymax = ceil(max(ydata)); % min and max
        xres = round((xmax-xmin)/1); % get an x resolution to interpolate
        yres = round((ymax-ymin)/1); % get a y res
        xv = linspace(xmin, xmax, xres); % create x and y vectors
        yv = linspace(ymin, ymax, yres);
        [Xinterp,Yinterp] = meshgrid(xv,yv); % mesh them for the interpolation
end

Zinterpolant = scatteredInterpolant(xdata',ydata',zdata'); % create interpolant
Zinterp = Zinterpolant(Xinterp,Yinterp); % interpolate

% plot the results
if ~isreal(Zinterp)
    Zinterp = abs(Zinterp);
end
minX = min(xdata); %-a.limits.lims(1);
minY = min(ydata); %-a.limits.lims(3);
if first
    a.CData = imagesc(minX,minY,Zinterp); % plot the heatmap
    if a.limits.on
        xlim([a.limits.lims(1) a.limits.lims(2)]); % set x and y limits
        ylim([a.limits.lims(3) a.limits.lims(4)]);
    end
    colormap jet
else
    set(a.CData,'CData',Zinterp);
    set(a.CData,'XData',minX);
    set(a.CData,'YData',minY);
    %    xlim([a.limits.lims(1) a.limits.lims(2)]);
    %    ylim([a.limits.lims(3) a.limits.lims(4)]);
end
if strcmp(a.type,'composite') % lets check if we are in composite mode and if we need to make the heatmap transparent
    a.Adata = ones(size(Zinterp))*a.HeatMapAlpha; % template alpha map
    a.Adata(isnan(Zinterp)) = 0; % now set any NANS to 0 so they're hidden
    set(a.CData,'AlphaData',a.Adata); % now set transparency to the heatmap
end

% colorbar stuff
if a.cbar.on % if using the colorbar
    % get the limits
    if any(~isreal(zdata))
        cLimMin = min(abs(zdata));
        cLimMax = max(abs(zdata));
    else
        cLimMin = min(zdata);%
        cLimMax = max(zdata);%
    end
    if isfield(a.cbar,'lims') % && strcmp('direct',a.dataType) && a.PrincipleDirection ~= 0
        cLims = a.cbar.lims;
    else
        cLims = [cLimMin cLimMax];
    end

    if first
        a.CbarHeat = colorbar('peer',gca); % make the colorbar
    end
    if cLims(1)~=cLims(2)
        caxis(cLims);
    end
    % set up the colorbar ticks
    set(gca,'FontSize',14);
    ticks = get(a.CbarHeat,'YTick');
    nticks = numel(ticks);
    cbarTicks = linspace(cLims(1),cLims(2),nticks);
    set(a.CbarHeat,'YTickLabel',arrayfun(@(x) num2str(x,'%0.3f'),cbarTicks,'UniformOutput', false))
    
end


end

function a = plotComposite(a,data,frame,im,first)
% plot the image first
a = plotImage(a,data,im,frame,first);
% then plot the heatmap
a = plotHeat(a,data,frame,first);
% if a.limits.on % check if it's on
%     xlim([a.limits.lims(1) a.limits.lims(2)]) % set the limits
%     ylim([a.limits.lims(3) a.limits.lims(4)]) % set the limits
% end
if first && a.scale.on 
    a = add_scalebar(a,data,frame,first);
end
end

function a = plotDTI(a,data,frame,im,first)

a = plotImage(a,data,im,frame,first);
a = plot_cross(a,data,frame,first);
if first % add a colorbar to make the image the same size as the rest
    c1 = colorbar;
    set(gca,'FontSize',14);
    set(c1,'Visible','off')
   
end
if  a.scale.on
    a = add_scalebar(a,data,frame,first);
end
end

function a = plotPlaceholder(a,first)
if first
    set(gca,'Visible','off') % turn the visibility off
end
end

function a = add_scalebar(a,data,frame,first);
cdata = get(a.CDataIm,'CData');
px = size(cdata);
scalebar = zeros(px(1),px(2),3);
start = round([.95 .95].*px(1:2));
thickness = round(0.04*px(2));
width = round(a.scale.scale*a.scale.BarLengthum);
scalebar(start(1)-thickness:start(1),start(2)-width:start(2),[1:3])=1;
hsb = image(a.limits.lims(1),a.limits.lims(3),scalebar*0);
set(hsb,'AlphaData',scalebar(:,:,1));

end