%
% function ToIgor(Handle, options)
%
% https://bitbucket.org/SailBlue5/matlab2igor/overview
%
% Date:     7-1-2013
%
% Purpose    : This function generates an Igor Text (.itx) file
%              that will reproduce the figure with the passed in Handle
%              ub WaveMetrics IGOR Pro.
%
% Parameters : Handle - a Handle to a figure or axes.  If not a handle gcf
%                       is uses.
%
%              options - a list of options to use.
%
% Return     : A IgorText.itx file is created in the working directory.
%
% Examples of Usage:
%
%    >> figure; plot(1:100,(1:100.^2,'r*'))
%    >> ToIgor();
%
%

function ToIgor( Handle, UserOptions )
%TOIGOR This function generates an Igor Text (.itx) file.
%   This will produce a Igor Text file that will reproduce a matlab figure
%   in igor.  Run ToIgor() on a figure, then in Igor under Data->Load->Igor
%   Text load the file generated by this function.

if(~exist('Handle', 'var') || ~ishandle(Handle))
    Handle = gcf;
end
if(~exist('UserOptions', 'var'))
    UserOptions = '';
end

%Options
UserOptions = regexp(UserOptions,'\s','split');

options = '';
% -f filename
Index = find(not(cellfun('isempty', strfind(UserOptions,'-f'))));
if(length(Index) == 1)
    options.FileName = UserOptions{Index+1};
else
    options.FileName = 'IgorText.itx';
end
% -v version
Index = find(not(cellfun('isempty', strfind(UserOptions,'-v'))));
if(length(Index) == 1)
    disp 'Version 0.3'
    return;
end


%Initializations
LineStruct = GetLines(Handle);

%Determine the size of the figure
PrevUnits = get(Handle, 'Units');
set(Handle, 'Units', 'Inches');
WinSize = get(Handle, 'Position');
set(Handle, 'Units', PrevUnits);
SizeString = ['(0,0,' num2str(WinSize(3)) ',' num2str(WinSize(4)) ')'];

IgorText = ['IGOR\n' WriteIgorWaves(LineStruct) 'X display /I/W=' SizeString '\n' CreatePlot(Handle, LineStruct, options)];

%Write File
fid = fopen(options.FileName,'w');
fprintf(fid,IgorText);       %# Print the string
fclose(fid);
end

%
% function IgorText = CreatePlot(Handle, LineStruct, options)
%
% Creates IgorText that reproduces the plot(s) in Handle.  This function
% expects an Igor window has already been opened with Display command.
% This can be recurrsively called for subplots.

function IgorText = CreatePlot(Handle, LineStruct, options)
IgorText = '';
if(strcmp(get(Handle,'Type'),'figure') && length(get(Handle,'Children'))==1)
    %A figure with one child
    IgorText = CreatePlot(get(Handle,'Children'),LineStruct, options);  %just pass the axes in
elseif(strcmp(get(Handle,'Type'),'figure') && length(get(Handle,'Children'))>1)
    %A figure with subplots
    IgorText = '';
    children = get(Handle,'Children');
    Host = '#';
    %Loop through each subplot
    for i = 1: length(children)
        %Get size of subplot
        PrevUnits = get(children(i), 'Units');
        set(children(i), 'Units', 'normalized');
        WinSize = get(children(i), 'Position');
        set(children(i), 'Units', PrevUnits);
        SizeString = ['(' num2str(WinSize(1)-.13*WinSize(3)) ','  num2str(1-WinSize(2)-1.13*WinSize(4)) ',' num2str(WinSize(1)+1.13*WinSize(3)) ',' num2str(1-WinSize(2)+.13*WinSize(4)) ')'];
        %Open subwindow
        IgorText=[IgorText 'X Display/HOST=' Host '/W=' SizeString '\n' CreatePlot(children(i),LineStruct, options)]; %#ok<AGROW>
        Host = '##';
    end
elseif(strcmp(get(Handle,'Type'),'axes'))
    %An axes to plot
    IgorText = [IgorText FromAxes(Handle, LineStruct)];
end
end

% function IgorText = FromAxes(axesH, LineStruct)
%
% Creates IgorText for an Axes given by axesH.

function IgorText = FromAxes(axesH, LineStruct)
IgorText = '';
LineH = findall(axesH,'Type','line');
YCounter = zeros(length(LineStruct.YLines),1);
for i=length(LineH):-1:1
    YdataNum = LineStruct.(getHandleString(LineH(i))).YLineLocation;
    Ydata = ['ydata' num2str(YdataNum)];
    if(YCounter(YdataNum) > 0)
        Ydata = [Ydata '#' num2str(YCounter(YdataNum))];
    end
    YCounter(YdataNum) = YCounter(YdataNum)+1;
    %Display plot
    IgorText = [IgorText 'X AppendToGraph ydata' num2str(YdataNum) ' vs xdata'...
        num2str(LineStruct.(getHandleString(LineH(i))).XLineLocation) ...
        '\n'];
    %Set color
    Color = get(LineH(i), 'Color');
    IgorText = [IgorText 'X ModifyGraph rgb(' Ydata ')=(' num2str(65535*Color(1)) ...
        ',' num2str(65535*Color(2)) ',' num2str(65535*Color(3)) ')\n'];
    %Set Display Type
    if(strcmp(get(LineH(i),'LineStyle'), 'none'))
        Mode = 3;%Points
    elseif(strcmp(get(LineH(i),'Marker'), 'none'))
        Mode = 0;%Line
    else
        Mode = 4;%Marker and Line
    end
    IgorText = [IgorText 'X ModifyGraph mode(' Ydata ')=' num2str(Mode) '\n'];
    
    %Set Line type
    if(strcmp(get(LineH(i),'LineStyle'), '--'))
        lstyle = 8;%Dashed Line
    elseif(strcmp(get(LineH(i),'LineStyle'), ':'))
        lstyle = 2;%dotted
    elseif(strcmp(get(LineH(i),'LineStyle'), '-.'))
        lstyle = 9;%Dash-dot
    else
        lstyle = 0;%Solid Line
    end
    IgorText = [IgorText 'X ModifyGraph lstyle(' Ydata ')=' num2str(lstyle) '\n'];
    
    %Line Width
    lsize = get(LineH(i),'LineWidth');
    IgorText = [IgorText 'X ModifyGraph lsize(' Ydata ')=' num2str(lsize) '\n'];
    
    %Set Point Type
    if(strcmp(get(LineH(i),'Marker'), '+'))
        marker = 0;
    elseif(strcmp(get(LineH(i),'Marker'), 'o'))
        marker = 8;
    elseif(strcmp(get(LineH(i),'Marker'), '*'))
        marker = 2;
    elseif(strcmp(get(LineH(i),'Marker'), 'x'))
        marker = 1;
    elseif(strcmp(get(LineH(i),'Marker'), 's') || strcmp(get(LineH(i),'Marker'), 'square'))
        marker = 5;
    elseif(strcmp(get(LineH(i),'Marker'), 'd') || strcmp(get(LineH(i),'Marker'), 'diamond'))
        marker = 7;
    elseif(strcmp(get(LineH(i),'Marker'), '^'))
        marker = 6;
    elseif(strcmp(get(LineH(i),'Marker'), 'v'))
        marker = 22;
    elseif(strcmp(get(LineH(i),'Marker'), '>'))
        marker = 45;
    elseif(strcmp(get(LineH(i),'Marker'), '<'))
        marker = 48;
    elseif(strcmp(get(LineH(i),'Marker'), 'p') || strcmp(get(LineH(i),'Marker'), 'pentagram'))
        marker = 51;
    elseif(strcmp(get(LineH(i),'Marker'), 'h') || strcmp(get(LineH(i),'Marker'), 'hexagram'))
        marker = 54;
    else
        marker = 19;%Dot
    end
    IgorText = [IgorText 'X ModifyGraph marker(' Ydata ')=' num2str(marker) '\n'];
end

%X and Y limits
XLim = get(axesH,'XLim');
IgorText = [IgorText 'X SetAxis bottom ' num2str(XLim(1)) ',' num2str(XLim(2)) '\n'];
YLim = get(axesH,'YLim');
IgorText = [IgorText 'X SetAxis left ' num2str(YLim(1)) ',' num2str(YLim(2)) '\n'];

%X and Y axis Labels
IgorText = [IgorText 'X Label bottom "' get(get(axesH,'XLabel'),'String') '"\n'];
IgorText = [IgorText 'X Label left "' get(get(axesH,'YLabel'),'String') '"\n'];

%X and Y grid lines
if(strcmp(get(axesH,'XGrid'),'on'))
    IgorText = [IgorText 'X ModifyGraph grid(bottom)=1\n'];
else
    IgorText = [IgorText 'X ModifyGraph grid(bottom)=0\n'];
end
if(strcmp(get(axesH,'YGrid'),'on'))
    IgorText = [IgorText 'X ModifyGraph grid(left)=1\n'];
else
    IgorText = [IgorText 'X ModifyGraph grid(left)=0\n'];
end

%Graph Title
IgorText = [IgorText 'X TextBox/C/N=text0/F=0/A=MT/E "' get(get(axesH,'Title'),'String') '"\n'];

%Log or linear
if(strcmp(get(axesH,'YScale'),'log'))
    IgorText = [IgorText 'X ModifyGraph log(left)=1\n'];
else
    IgorText = [IgorText 'X ModifyGraph log(left)=0\n'];
end
if(strcmp(get(axesH,'XScale'),'log'))
    IgorText = [IgorText 'X ModifyGraph log(bottom)=1\n'];
else
    IgorText = [IgorText 'X ModifyGraph log(bottom)=0\n'];
end

%Tick Labels
if(strcmp(get(axesH,'XTickLabelMode'),'manual'))
    IgorText = [IgorText 'X ModifyGraph userticks(bottom)={tick' num2str(LineStruct.(getHandleString(axesH)).Xtick) ',tickLabel' num2str(LineStruct.(getHandleString(axesH)).XtickLabel) '}\n'];
end
if(strcmp(get(axesH,'YTickLabelMode'),'manual'))
    IgorText = [IgorText 'X ModifyGraph userticks(left)={tick' num2str(LineStruct.(getHandleString(axesH)).Ytick) ',tickLabel' num2str(LineStruct.(getHandleString(axesH)).YtickLabel) '}\n'];
end

%default cosmetics
IgorText = [IgorText 'X ModifyGraph tick=2,mirror=1,axThick=2,fStyle=1,standoff=0\n'];
end

% function LineStruct = GetLines(Handle)
%
% Creates a LineStruct that contains all of the waves/Lines within the figure
% given by Handle and a map of how to index to them given a handle.

function LineStruct = GetLines(Handle)
%Initialize
%Line Lookups
LineStruct = [];

%For lines
LineStruct.YLines = [];
LineStruct.XLines = [];
%For Axes
LineStruct.Ticks = [];
LineStruct.TickLabels = [];

LineH = findall(Handle,'Type','line');
Xnumber = 0;
Ynumber = 0;
% loop through the lines
for i=1:length(LineH)
    ThisX = get(LineH(i),'XData');
    FoundX = 0;
    for X = 1:Xnumber
        % See if an identical line is already included in X.
        if(isequal(ThisX,LineStruct.XLines(X).array))
            LineStruct.(getHandleString(LineH(i))).XLineLocation=X;
            FoundX=1;
            break
        end
    end
    %Add current array to LineStructXLines
    if(FoundX == 0)
        Xnumber = Xnumber+1;
        LineStruct.XLines(Xnumber).array = ThisX;
        LineStruct.(getHandleString(LineH(i))).XLineLocation=Xnumber;
    end
    
    ThisY = get(LineH(i),'YData');
    FoundY = 0;
    for Y = 1:Ynumber
        % See if an identical line is already included in Y.
        if(isequal(ThisY,LineStruct.YLines(Y).array))
            LineStruct.(getHandleString(LineH(i))).YLineLocation=Y;
            FoundY=1;
            break
        end
    end
    %Add current array to LineStructYLines
    if(FoundY == 0)
        Ynumber = Ynumber+1;
        LineStruct.YLines(Ynumber).array = ThisY;
        LineStruct.(getHandleString(LineH(i))).YLineLocation=Ynumber;
    end
end

%loop through axes
AxesH = findall(Handle,'Type','axes');
for i = 1:length(AxesH)
    if(strcmp(get(AxesH(i),'XTickLabelMode'),'manual'))
        %Does X Ticks array already exist?
        Found = 0;
        Xtick = get(AxesH(i),'XTick');
        for j = 1:length(LineStruct.Ticks)
            if(isequal(LineStruct.Ticks(j).array,Xtick))
                Found = 1;
                LineStruct.(getHandleString(AxesH(i))).Xtick = j;
                break;
            end
        end
        if(Found == 0)
            LineStruct.(getHandleString(AxesH(i))).Xtick = length(LineStruct.Ticks)+1;
            LineStruct.Ticks(length(LineStruct.Ticks)+1).array=Xtick;
        end
        
        %Does X Tick Labels array already exist?
        Found = 0;
        tickLabel = get(AxesH(i),'XTickLabel');
        for j = 1:length(LineStruct.TickLabels)
            if(isequal(LineStruct.TickLabels(j).array,tickLabel))
                Found = 1;
                LineStruct.(getHandleString(AxesH(i))).XtickLabel = j;
                break;
            end
        end
        if(Found == 0)
            LineStruct.(getHandleString(AxesH(i))).XtickLabel = length(LineStruct.TickLabels)+1;
            LineStruct.TickLabels(length(LineStruct.TickLabels)+1).array=tickLabel;
        end
    end
    if(strcmp(get(AxesH(i),'YTickLabelMode'),'manual'))
        %Does Y Ticks array already exist?
        Found = 0;
        Ytick = get(AxesH(i),'YTick');
        for j = 1:length(LineStruct.Ticks)
            if(isequal(LineStruct.Ticks(j).array,Ytick))
                Found = 1;
                LineStruct.(getHandleString(AxesH(i))).Ytick = j;
                break;
            end
        end
        if(Found == 0)
            LineStruct.(getHandleString(AxesH(i))).Ytick = length(LineStruct.Ticks)+1;
            LineStruct.Ticks(length(LineStruct.Ticks)+1).array=Ytick;
        end
        %Does Y Tick Labels array already exist?
        Found = 0;
        tickLabel = get(AxesH(i),'YTickLabel');
        for j = 1:length(LineStruct.TickLabels)
            if(isequal(LineStruct.TickLabels(j).array,tickLabel))
                Found = 1;
                LineStruct.(getHandleString(AxesH(i))).YtickLabel = j;
                break;
            end
        end
        if(Found == 0)
            LineStruct.(getHandleString(AxesH(i))).YtickLabel = length(LineStruct.Ticks)+1;
            LineStruct.TickLabels(length(LineStruct.TickLabels)+1).array=tickLabel;
        end
    end
    
    
    
end
end

% function IgorText = WriteIgorWaves(LineStruct)
%
% Generates and returns the text to load all lines/waves in a LineStruct in to an Igor
% Text file.
function IgorText = WriteIgorWaves(LineStruct)
IgorText = '';
%Start with all Xs
for i = 1: length(LineStruct.XLines)
    IgorText = [IgorText 'WAVES/D/O xdata' num2str(i) '\nBEGIN\n'];
    for j = 1:length(LineStruct.XLines(i).array)
        IgorText = [IgorText num2str(LineStruct.XLines(i).array(j)) '\n'];
    end
    IgorText = [IgorText 'END\n'];
end
%all Ys.
for i = 1: length(LineStruct.YLines)
    IgorText = [IgorText 'WAVES/D/O ydata' num2str(i) '\nBEGIN\n'];
    for j = 1:length(LineStruct.YLines(i).array)
        IgorText = [IgorText num2str(LineStruct.YLines(i).array(j)) '\n'];
    end
    IgorText = [IgorText 'END\n'];
end
%ticks.
for i = 1: length(LineStruct.Ticks)
    IgorText = [IgorText 'WAVES/D/O tick' num2str(i) '\nBEGIN\n'];
    for j = 1:length(LineStruct.Ticks(i).array)
        IgorText = [IgorText num2str(LineStruct.Ticks(i).array(j)) '\n'];
    end
    IgorText = [IgorText 'END\n'];
end

%tick labels.
for i = 1: length(LineStruct.TickLabels)
    IgorText = [IgorText 'WAVES/T/O tickLabel' num2str(i) '\nBEGIN\n'];
    for j = 1:length(LineStruct.TickLabels(i).array)
        IgorText = [IgorText '"' strtrim(LineStruct.TickLabels(i).array(j,:)) '"\n'];
    end
    IgorText = [IgorText 'END\n'];
end


end

function HandleString = getHandleString(Handle)
HandleString = regexprep(num2str(Handle), '\.', 'p')
Type = get(Handle, 'type');
if(strcmp(Type,'line'))
    HandleString = ['L' HandleString];
elseif(strcmp(Type,'axes'))
    HandleString = ['A' HandleString];
end

end
