function [text, readable] = gettext(source)
% gettext - returns text from a ComparisonSource
%
% [text, readable] = gettext(source)
%
% source can be an instance of ComparisonSource or a string, in which
% case it is assumed to be a filename.
%
% The text is returned as a cell array, with one cell for each name.
% If the source is a file, "readable" is the location of that file.

%   Copyright 2010-2017 The MathWorks, Inc.

    if ischar(source) || (isstring(source) && isscalar(source))
        % If the input is a string, treat it as a file name.
        source = char(source);
        [text, readable] = i_ReadFromFile(source);
        return
    end
    
    assert(isa(source,'com.mathworks.comparisons.source.ComparisonSource'),...
            'Inputs to textdiff must be file names or ComparisonSources');
    absnameprop = com.mathworks.comparisons.source.property.CSPropertyAbsoluteName.getInstance();
    textprop = com.mathworks.comparisons.source.property.CSPropertyText.getInstance();
    readableprop = com.mathworks.comparisons.source.property.CSPropertyReadableLocation.getInstance();

    % Depending on which properties this source has, we'll need to use
    % different approaches to get at the text.
    if source.hasProperty(textprop)
        readable = [];
        % Text property present.  Get the text and convert it to a 
        % cell array of individual lines, preserving whitespace
        text = char(source.getPropertyValue(textprop,[]));
        if ~isempty(text)
            text = i_textscan(text);
            if source.hasProperty(absnameprop)
                readable = char(source.getPropertyValue(absnameprop, []));
            end
        end
    elseif source.hasProperty(readableprop)
        % ReadableLocation property present.  Read that file.
        try
            readable = char(source.getPropertyValue(readableprop,[]));
        catch E %#ok<NASGU>
            if source.hasProperty(absnameprop)
                filename = char(source.getPropertyValue(absnameprop,[]));
            else
                nameprop = com.mathworks.comparisons.source.property.CSPropertyName.getInstance();
                filename = char(source.getPropertyValue(nameprop,[]));
            end
            comparisons.internal.message('error', 'comparisons:comparisons:FileReadError', filename)
        end
        [text,readable] = i_ReadFromFile(readable);
    elseif source.hasProperty(absnameprop)
        % No text or readable location.  Not a good sign, but try reading
        % the file indicated by the AbsoluteName property.
        absname = char(source.getPropertyValue(absnameprop,[]));
        [text,readable] = i_ReadFromFile(absname);
    end
end

%---------------------------------------------------------------------
function [text,filename] = i_ReadFromFile(filename)
    filename = comparisons.internal.resolvePath(filename);
    d = dir(filename);
    if numel(d)~=1 && exist(filename,'dir')~=0
        % fname specified a directory.  A directory listing will always
        % have at least two entries (even if the directory is empty). 
        % A user can only get here by requesting an output from visdiff.
        comparisons.internal.message('error', 'comparisons:comparisons:FolderNotAllowed');
    else
        % If the specified name resolves to more than one file, we'll get
        % a file-not-found error from gettextfromfile.
        text = i_GetTextFromFile(filename);
    end
end

%---------------------------------------------------------------------
function txt = i_GetTextFromFile(filename)
% Returns a cell array of the text in a file
%   textCellArray = gettextfromfile(filename)
%   textCellArray = gettextfromfile(filename, bufferSize)
% Throws an error if the file is binary (specifically,
% contains bytes with value zero).

    % Try to determine the encoding for XML or HTML files
    is = java.io.FileInputStream(java.io.File(filename));
    enc = com.mathworks.xml.EncodingParser.getEncoding(is);
    is.close();

    fid = fopen(filename,'r','native',char(enc));
    if fid < 0
        comparisons.internal.message('error', 'comparisons:comparisons:FileReadError', filename)
    end
    
    % Scan the text
    try
        data = fread(fid,'*char')';
        txt = i_textscan(data);
        fclose(fid);
    catch exception
        fclose(fid);
        rethrow(exception)
    end
end

%---------------------------------------------------------------------
function txt = i_textscan(data)
    % Get rid of any carriage returns, if this is a Windows text file.
    data = strrep(data, [char(13) newline], newline);
    % Get rid of carriage returns for MAC text files.
    data = strrep(data, char(13), newline);
    
    % textscan loses foreign characters, and repeated calls to strtok are
    % slow.  regexp('split') seems to be the best option.
    txt = regexp(data, newline, 'split');
    txt = txt';
end
