function Plink_View(listfile,lookup,ref)
% Plink List View (Plink_View.m)
%
% This script reads in a .list file created with the software program
% "Plink" and allows the user to select SNPs that he/she is interested in,
% as well as a subject ID lookup table, and a gene reference table,  
% The user has the choice to add all subjects in the lookup table that
% aren't present in the .list file. The output will be a .csv file for 
% easy import into Excel, SPSS, etc. The output name will be the name 
% of the list file appended with the date.
%
% Vanessa Sochat
% Duke University 2010
%--------------------------------------------------------------------------
% VARIABLES
% listfile: Must be a .list file generated by plink, with each row listing
% the gene identifier, the SNP name, the allele combo, and then groups of 
% family IDs followed by individual IDs.  The script expects various allele 
% combos for each SNP (11, 12, 22, 00) and each family IDs to be followed by 
% a single individual ID.
%
% lookup (ID): must be an excel file (.xls/.xlsx) with two columns - it is 
% OPTIONAL.the individual identifier in the first column, and the "other_ID" 
% in the second column.  In the case of using a lookup table, the user is
% given the option to lookup by individual, family, or family_individual
% ID.
%
% ref: is an rs_gene_reference excel (.xls/.xlsx) document that is OPTIONAL.  
% It should be formatted so that the first column has the SNP name, and the 
% second column has the gene symbol.  If the user specifies a gene reference 
% file, then the gene symbol is appended to the SNP name in the output table.  
% If not, the output table will only have the SNP name.
%--------------------------------------------------------------------------
% INSTRUCTIONS:
% To run, simply type "Plink_View" on the MATLAB command line.  You can
% either run with no input arguments, or specify your listfile and lookup
% table as arguments 1 and 2, respectively.  Here are your choices:
%
% Plink_View  - will be prompted for listfile, lookup, and ref
% Plink_View(listfile) - will not have gene names and other_IDs
% Plink_View(listfile,lookup) - will not have gene names
% Plink_View(listfile,lookup,ref) - will have gene names and other_IDs
%
%--------------------------------------------------------------------------
% 
%--------------------------------------------------------------------------
%
% Read in Files from Command Line or GUI
%
%--------------------------------------------------------------------------

if nargin == 1
    % check to make sure that the user has input the correct file types.
    % Here we use regexp to find the correct extension for each variable.
    % If not found, we exit with an error.
    ext_markers=regexp(listfile, '.list', 'once');
    if isempty(ext_markers)==1
        error('The first argument must be a listfile ending in .list');
    end
    add_subjects='No';
end    

if nargin == 2
    % check to make sure that the user has input the correct file types.
    % Here we use regexp to find the correct extension for each variable.
    % If not found, we exit with an error.
    ext_markers=regexp(listfile, '.list', 'once');
    if isempty(ext_markers)==1
        error('The first argument must be a listfile ending in .list');
    end
    
    ext_markers=regexp(lookup, '.xls', 'once');
    if isempty(ext_markers)==1
        error('The second argument (lookup table) must be an excel file!');
    end
    lookup_choice = questdlg('Look up based on Individual, Family, or concatenated Family_Individual ID?', 'Lookup Based on...', 'Individual', 'Family', 'Family_Individual', 'Individual');
    add_subjects = questdlg('Would you like to add subjects from the lookup table NOT in the .list file to your results?', 'Add missing lookup subjects...', 'Yes', 'No','Yes');
end
    
if nargin == 3
    % check to make sure that the user has input the correct file types.
    % Here we use regexp to find the correct extension for each variable.
    % If not found, we exit with an error.
    ext_markers=regexp(listfile, '.list', 'once');
    if isempty(ext_markers)==1
        error('The first argument must be a listfile ending in .list');
    end
    
    ext_markers=regexp(lookup, '.xls', 'once');
    if isempty(ext_markers)==1
        error('The second argument (ID lookup table) must be an excel file!');
    end
    lookup_choice = questdlg('Look up based on Individual, Family, or concatenated Family_Individual ID?', 'Lookup Based on...', 'Individual', 'Family', 'Family_Individual', 'Individual');
    add_subjects = questdlg('Would you like to add subjects from the lookup table NOT in the .list file to your results?', 'Add missing lookup subjects...', 'Yes', 'No','Yes');
    
    ext_markers=regexp(ref, '.xls', 'once');
    if isempty(ext_markers)==1
        error('The third argument (gene reference table) must be an excel file!');
    end
    
    
elseif nargin == 0
    % Here we ask the user to select the listfile
    [filename, pathname] = uigetfile('*.list', 'Select a .list file');
    if isequal(filename,0) || isequal(pathname,0)
       disp('You pressed cancel!')
       error('You canceled out of the file selector.  Please run Plink_View again!');
    else
       disp(['You have selected ', fullfile(pathname, filename) ' for your listfile'])
       listfile = fullfile(pathname,filename);
    end
    
    
    % Here we ask the user if he wants a lookup table, and if so, 
    % to select the lookup table
    choice = questdlg('Would you like to use an Excel ID lookup table?', 'ID Lookup Table', 'Yes', 'No', 'Yes');
    if strcmp(choice,'Yes')
        lookup_choice = questdlg('Look up based on Individual, Family, or concatenated Family_Individual ID?', 'Lookup Based on...', 'Individual', 'Family', 'Family_Individual', 'Individual');
        [filename, pathname] = uigetfile({'*.xlsx','Microsoft Excel (.xlsx)';'*.xls', 'Microsoft Excel 1997-2003 (.xls)'},'Select Lookup Table');
        if isequal(filename,0) || isequal(pathname,0)
            disp('You pressed cancel!')
            error('You canceled out of the file selector.  Please run Plink_View again!');
        else
           disp(['You have selected ', fullfile(pathname, filename) ' for your lookup table'])
           lookup = fullfile(pathname,filename);
        end
        add_subjects = questdlg('Would you like to add subjects from the lookup table NOT in the .list file to your results?', 'Add missing lookup subjects...', 'Yes', 'No','Yes');
    end
    
    %Here we ask the user if he wants a gene reference table, and if so, 
    % to select the gene reference table
    choice = questdlg('Would you like to use a Excel gene reference table?', 'Gene Reference Table', 'Yes', 'No', 'Yes');
    
    if strcmp(choice,'Yes')
        [filename, pathname] = uigetfile({'*.xlsx','Microsoft Excel (.xlsx)';'*.xls', 'Microsoft Excel 1997-2003 (.xls)'},'Select Gene Reference Table');
        if isequal(filename,0) || isequal(pathname,0)
           disp('You pressed cancel!')
           error('You canceled out of the file selector.  Please run Plink_View again!');
        else
           disp(['You have selected ', fullfile(pathname, filename) ' for your gene reference table'])
           ref = fullfile(pathname,filename);
        end
    end
    
elseif nargin ~= 2 && nargin ~= 3 && nargin ~=0 && nargin ~=1
    error('Error with input arguments. Either specify Plink_View(listfile,lookup,ref), Plink_View(listfile,lookup), Plink_View(listfile), or run with no arguments.');
end

%--------------------------------------------------------------------------
%
% Read SNP Names
%
%--------------------------------------------------------------------------

% open the listfile
fid = fopen(listfile);

% We put the first column of values (Gene ID) into C{1} and the second
% column (SNPs) into C{2} and ignore the rest
C = textscan(fid, '%f %s %*[^\n]');
% Now we convert a cell array into a matrix of strings so we can read each
% one
B = C{2};
fclose(fid);
clear C;

% Create variable to store user choices, throw in the first SNP
SNPs='';

% Now we cycle through the list file and read in all the unique SNP names
% to present to the user.  We can't be sure that there are always 4 alleles 
% (and headers)for each SNP name, so we have to check every single one. 
% We compare the current to a running list to present to the user, and 
% only add the current to the list if it does not already appear in the list.
for i = 1:size(B,1)
    toadd = 'yes';
    current = B(i,:);
    
    if size(SNPs,1)~=0
        for j = 1:size(SNPs,1)
            if strcmp(current,SNPs(j,:))==1
                toadd = 'no';
            end
        end
    end
    
    if strcmp(toadd,'yes')
        SNPs = [ SNPs;current ];
    end
end

clear assigned;

%--------------------------------------------------------------------------
%
% Allow User to Select Desired SNPs
%
%--------------------------------------------------------------------------

% We now present the list of SNPs to the user for him/her to choose to
% include each in the output file:
str = SNPs;
[s,v] = listdlg('PromptString','Select SNPs to include:','SelectionMode','multiple','ListString',str);
clear SNPs
     
% Place choices in SNPs variable
for i = 1:size(s,2)
    SNPs(i,:) = str(s(i),:);
end

%--------------------------------------------------------------------------
%
% Get Genetic_reference IDs from the lookup table
%
%--------------------------------------------------------------------------
SNP_count=1;

if exist('ref','var')
    if exist(ref,'file')
        [num, txt, raw] = xlsread(ref);
        for i = 1:size(SNPs,1)
            for j = 1:size(raw,1)
                % We have a slightly different strategy depending on if the
                % subject IDs and genetic references are doubles vs chars
                if strcmp(class(raw{j}),'double') && strcmp(class(raw{j,2}),'double')
                    if strcmp(SNPs{i,:},num2str(raw{j}))
                    SNPs_head{SNP_count}=[ SNPs{i,:} '_' num2str(raw{j,2}) ];
                    SNP_count = SNP_count + 1;
                    end         
                elseif strcmp(class(raw{j}),'double') && ischar(raw{j,2})
                    if strcmp(SNPs{i,:},num2str(raw{j}))
                    SNPs_head{SNP_count}=[ SNPs{i,:} '_' raw{j,2} ];
                    SNP_count = SNP_count + 1;
                    end        
                elseif ischar(raw{j}) && strcmp(class(raw{j,2}),'double')
                    if strcmp(SNPs{i,:},raw{j})
                    SNPs_head{SNP_count}=[ SNPs{i,:} '_' num2str(raw{j,2}) ];
                    SNP_count = SNP_count + 1;
                    end
                elseif ischar(raw{j}) && ischar(raw{j,2})
                    if strcmp(SNPs{i,:},raw{j})
                    SNPs_head{SNP_count}=[ SNPs{i,:} '_' raw{j,2} ];
                    SNP_count = SNP_count + 1;
                    end           
                end 
            end
        end
    end
else
    % in the case that the ref file doesn't exist, meaning that it wasn't
    % chosen by the user, we put the SNPs variable into SNPs_head to go
    % into the output file.
    SNPs_head=SNPs;
end
%--------------------------------------------------------------------------
%
% Read in data, one row at a time
%
%--------------------------------------------------------------------------

% Re-open the listfile
fin = fopen(listfile);

% Create a subject count variable
subj_count=1;

while ~feof(fin)
    % Read in line 
     currentline = fgetl(fin);
     
     % Get rid of first value, which is the gene identifier
     blank = regexp(currentline, ' ', 'once');
     currentline = regexprep(currentline, currentline(1:blank), '','once');
     
     %The next value is the SNP - pull it from the string.
     blank = regexp(currentline, ' ', 'once');
     SNP_name=currentline(1:blank-1);
     currentline = regexprep(currentline, currentline(1:blank), '','once');
     
     %The next value is the allele - we want to pull it from the string.
     %But we first need to check if there are any subjects behind it -
     %since there might not be any!
     if isempty(regexp(currentline, ' ', 'once'))==0
         blank = regexp(currentline, ' ', 'once');
         allele_name = currentline(1:blank-1);
         currentline = regexprep(currentline, currentline(1:blank), '','once');
     else
         allele_name = currentline;
         currentline = regexprep(currentline, currentline, '','once');
     end
                
     % Check to see if SNP is in list.  If it isn't, move on to the next
     % line.  If it is, then add it to the DATA array for the subject's
     % specified.
     
     found=0;
     for i = 1:size(SNPs,1)
         if strcmp(SNPs(i,:),SNP_name) && found ~= 1
            % Add SNP to DATA list for each subject.  Do while the current 
            % line is not empty
            
            while size(currentline,2)~=0
                % Find the next white space
                blank = regexp(currentline, ' ', 'once');
                % Read in the value from that, the genetic ID
                family_ID = currentline(1:blank-1);
                currentline = regexprep(currentline, currentline(1:blank), '','once');
                % Find the next white space, the family ID
                
                % If there IS another blank, then we record it and
                % continue.  If there ISN'T another blank, then we put the
                % remainder of the currentline variable into the last
                % individual_ID, and then empty the currentline variable.
                if isempty(regexp(currentline, ' ', 'once'))==0
                    blank = regexp(currentline, ' ', 'once');
                    individual_ID = currentline(1:blank-1);
                    currentline = regexprep(currentline, currentline(1:blank), '','once');
                else
                    individual_ID = currentline;
                    currentline = regexprep(currentline, currentline, '','once');
                end
                       
                % Add this info to the DATA structure for the subject
                % specified.  First see if the subject already exists.  If
                % he/she does, just add the SNP data.  If not, create a new
                % DATA object at the next available slot.
                
                % LOOP THROUGH DATA AND SEE IF SUBJECT EXISTS
                % If the DATA variable exists and we find the subject ID, 
                % then we add the SNP to that same structure:
                found_var=0;
                
                if exist('DATA','var')
                    for j=1:size(DATA,2)
                        if strcmp(DATA(j).Individual_ID,individual_ID) && strcmp(DATA(j).Family_ID,family_ID) 
                            DATA(j).(SNP_name)= allele_name;
                            found_var=1;
                        end
                    end
                end
                        
                % If we didn't find the subject we need to add them anew,
                % and add one to the subject count.
                if found_var ~= 1
                    DATA(subj_count)= struct('Study_ID','','Family_ID', family_ID, 'Individual_ID', individual_ID, 'Fam_Ind_ID', [ family_ID '_' individual_ID ], SNP_name, allele_name);
                    subj_count=subj_count+1;
                end

           end
            
            found = 1;
         end
     end
end
     
fclose(fin);

% Clear the found variable so it can be used as a string later in the
% script
clear found;

%--------------------------------------------------------------------------
%
% Add Study_IDs from the lookup table
%
%--------------------------------------------------------------------------
% Check to see if the lookup table variable exists.  If yes, proceed with
% adding IDs.  If not, do nothing.  In the case that a particular subject
% ID exists in the lookup table but isn't found in the data from the .list
% file, if the user has selected to do so, we add it to our subject list
% anyway.

% set the missing count to 0 - this variable will be use to count the
% number of subjects that appear in the lookup table but not in the list
% file.

save BEFORELOOKUP.mat

miss_count=0;
found = 'no';

if exist('lookup','var')
    if exist(lookup,'file')
        [num, txt, raw] = xlsread(lookup);
        for i=1:size(DATA,2)
            for j=1:size(raw,1)
                switch lookup_choice
                    case 'Individual'
                        if strcmp(class(raw{j}),'double')
                            if strcmp(DATA(i).Individual_ID,num2str(raw{j}))
                                found = 'yes';
                                 if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                 elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                 end   
                            end
                        end
                        if ischar(raw{j})
                            if strcmp(DATA(i).Individual_ID,raw{j})
                                found = 'yes'; 
                                if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                 elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                 end
                            end
                        end
                    case 'Family'
                         if strcmp(class(raw{j}),'double')
                            if strcmp(DATA(i).Family_ID,num2str(raw{j}))
                                found = 'yes';
                                if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                end
                            end         
                         end
                        if ischar(raw{j})
                            if strcmp(DATA(i).Family_ID,raw{j})
                                found = 'yes';
                                if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                end
                            end   
                        end
                    case 'Family_Individual'
                         if strcmp(class(raw{j}),'double')
                            if strcmp([ DATA(i).Family_ID '_' DATA(i).Individual_ID ],num2str(raw{j}))
                                found = 'yes';
                                 if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                 elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                 end
                            end         
                         end
                        if ischar(raw{j})
                            if strcmp([ DATA(i).Family_ID '_' DATA(i).Individual_ID ],raw{j})
                                found = 'yes';
                                 if strcmp(class(raw{j,2}),'double')
                                        DATA(i).Study_ID=num2str(raw{j,2});
                                 elseif ischar(raw{j,2})
                                        DATA(i).Study_ID=(raw{j,2});
                                 end
                            end   
                        end
                end
            end
        end
  
  % Now we do the opposite and look for IDs in the lookup file
  % that don't have a match in our current data list.  When we
  % find one, we save it to be added to the output file later.
  for j=1:size(raw,1)
      for i=1:size(DATA,2)
          switch lookup_choice
              case 'Individual'
                  if strcmp(class(raw{j}),'double')
                      if strcmp(DATA(i).Individual_ID,num2str(raw{j}))
                          found = 'yes';   
                      end
                  end
                  if ischar(raw{j})
                      if strcmp(DATA(i).Individual_ID,raw{j})
                          found = 'yes'; 
                      end
                  end
              case 'Family'
                  if strcmp(class(raw{j}),'double')
                      if strcmp(DATA(i).Family_ID,num2str(raw{j}))
                         found = 'yes';
                      end         
                  end
                  if ischar(raw{j})
                      if strcmp(DATA(i).Family_ID,raw{j})
                         found = 'yes';
                      end   
                  end
             case 'Family_Individual'
                 if strcmp(class(raw{j}),'double')
                      if strcmp([ DATA(i).Family_ID '_' DATA(i).Individual_ID ],num2str(raw{j}))
                         found = 'yes';
                      end         
                 end
                 if ischar(raw{j})
                      if strcmp([ DATA(i).Family_ID '_' DATA(i).Individual_ID ],raw{j})
                         found = 'yes';
                      end   
                 end
          end
      end
      
      if strcmp(add_subjects,'Yes')
          if strcmp(found,'no')
              switch lookup_choice
                  case 'Individual'
                      if strcmp(class(raw{j}),'double')
                          if strcmp(class(raw{j,2}),'double')
                              MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', '', 'Individual_ID', num2str(raw{j}), 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                              MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', '', 'Individual_ID', num2str(raw{j}), 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          end   
                      end
                      if ischar(raw{j})
                          if strcmp(class(raw{j,2}),'double')
                              MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', '', 'Individual_ID', raw{j}, 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                              MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', '', 'Individual_ID', raw{j}, 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          end
                      end
                  case 'Family'       
                      if strcmp(class(raw{j}),'double')
                          if strcmp(class(raw{j,2}),'double')
                              MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', num2str(raw{j}), 'Individual_ID', '', 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                              MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', num2str(raw{j}), 'Individual_ID', '', 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          end   
                      end
                      if ischar(raw{j})
                          if strcmp(class(raw{j,2}),'double')
                              MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', raw{j}, 'Individual_ID', '', 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                              MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', raw{j}, 'Individual_ID', '', 'Fam_Ind_ID', '');
                              miss_count = miss_count+1;
                          end
                      end 
                  case 'Family_Individual'
                      if strcmp(class(raw{j}),'double')
                          if strcmp(class(raw{j,2}),'double')
                              MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', '', 'Individual_ID', '', 'Fam_Ind_ID', num2str(raw{j}));
                              miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                              MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', '', 'Individual_ID', '', 'Fam_Ind_ID', num2str(raw{j}));
                               miss_count = miss_count+1;
                          end   
                      end
                      if ischar(raw{j})
                          if strcmp(class(raw{j,2}),'double')
                             MISSING(miss_count+1)= struct('Study_ID',num2str(raw{j,2}),'Family_ID', '', 'Individual_ID', '', 'Fam_Ind_ID', raw{j});
                             miss_count = miss_count+1;
                          elseif ischar(raw{j,2})
                             MISSING(miss_count+1)= struct('Study_ID',raw{j,2},'Family_ID', '', 'Individual_ID', '', 'Fam_Ind_ID', raw{j});
                             miss_count = miss_count+1;
                          end
                      end
              end
          end
      end
      found='no';
  end
    end
end

clear num txt raw

save MISSING.mat

%--------------------------------------------------------------------------
%
% Print all Data to CSV file!
%
%--------------------------------------------------------------------------
% Pull the name of the listfile to use as the output file name.  The name
% will be between the last '\' and the '.list'
dashlocs = regexp(listfile,'\');
start=dashlocs(size(dashlocs,2));
listloc = regexp(listfile,'.list');
output_name = listfile(start+1:listloc-1);
clear perlocs dashlocs start

% Initialize and print to file
fed = fopen([ output_name '_' date '.csv' ], 'wt');
fprintf(fed, 'Study_ID,Family_ID,Indivdual_ID,Fam_Ind_ID');
for i=1:numel(SNPs_head)
    fprintf(fed, '%s%s', ',',SNPs_head{i});
end
fprintf(fed, '\n');
for i=1:numel(DATA)
    fprintf(fed, '%s%s%s%s%s%s%s', DATA(i).Study_ID,',', DATA(i).Family_ID,',', DATA(i).Individual_ID, ',',DATA(i).Fam_Ind_ID);
    for j=1:numel(SNPs)
        fprintf(fed, '%s%s', ',',DATA(i).(SNPs{j,:}));
    end
    fprintf(fed, '\n');
end

if miss_count ~= 0
    for k=1:numel(MISSING)
        fprintf(fed, '%s%s%s%s%s%s%s', MISSING(k).Study_ID,',', MISSING(k).Family_ID,',', MISSING(k).Individual_ID, ',',MISSING(k).Fam_Ind_ID);
        for j=1:numel(SNPs)
            fprintf(fed, '%s%s', ',','');
        end
        fprintf(fed, '\n');
    end
end

fclose(fed);

fprintf('%s\n','Done running Plink_View!');
fprintf('%s\n','Thank you come again!');

end