function [outTable, outStruct] = localityMetGene_skinAging(model, fe, geneStruct, corrStruct, modelType, mode, permMode,corrType)
outTable = [];
outStruct = [];

if nargin < 5
    modelType = 'KEGGS';
end
if nargin < 6
    mode = 'linlin'; %options lin, linLog, loglog
end
if nargin < 7
    permMode = 'by gene';% 'all' or 'by_gene'
end
if nargin < 8
    corrType = 'spearman';
end
%% mappings of gene to met and data 2 model

% make gene to metabolite matrix

switch upper(modelType)
    case 'RECONX'
        geneMetMat = sparse(length(model.genes), length(model.mets));
        geneRev = zeros(length(model.genes),1);
        for i = 1:length(model.rxnGeneMat)
            idx = find(model.rxnGeneMat(i,:) ~= 0);
            if ~isempty(idx)
                for j = 1:length(idx)
                    geneMetMat(idx(j), model.S(:,i) ~= 0) = full(model.S(model.S(:,i) ~= 0,i));
                    geneRev(idx(j)) = model.rev(i);
                end
            end
        end
    case 'KEGGS'
        geneMetMat = sparse(length(model.Gene), length(model.Compounds));
        geneRev = ones(length(model.Gene),1);
        for i = 1:length(model.RP) %find all EC related to a RP
            idxRP = find(model.ECtoRP(:,i) ~= 0);
            if ~isempty(idxRP)
                for r = 1:length(idxRP) % go through all RPs and find all genes linked to those RPs
                    idxGene = find(model.GeneToEC(:,idxRP(r)) == 1);
                    if ~isempty(idxGene)
                        for g = 1:length(idxGene) % map gene to metabolite
                        geneMetMat(idxGene(g), model.CompoundstoRP(:,i) ~= 0) = full(model.CompoundstoRP(model.CompoundstoRP(:,i) ~= 0,i));
%                         geneRev(idx(j)) = model.rev(i);
                        end
                    end
                end
            end
        end
end


% map metIds of exp to model
ann = fe.merged.annotation;
allCpdIdfs = [ann.id];
allCpdNames = [ann.name];
nCmpds = length(unique(allCpdIdfs));
aHits = [ann.nHits];
mapVec = zeros(length(allCpdIdfs),1);
c = 0;
for i = 1:length(aHits)
    mapVec(c+1:c+aHits(i),1) = i;
    c = c+aHits(i);
end

switch upper(modelType)
    case 'RECONX'
        % map all model metabolites to data find extracellular metabolites
        modelMet2dataMet = zeros(length(model.mets),1);
        modelMet2fe = zeros(length(model.mets),1);
        metDetected = zeros(length(model.mets),1);
        metExtacellular = zeros(length(model.mets),1);
        for i = 1:length(model.mets)
            if isempty(regexp(model.mets{i},'[e]'))
                if ~isempty(model.metHMDB{i})
                    idx = find(strcmp(allCpdIdfs, model.metHMDB{i}) == 1);
                    if ~isempty(idx)
                        modelMet2dataMet(i) = idx(1);
                        modelMet2fe(i) = mapVec(idx(1));
                        metDetected(i) = 1;
                    end
                end
            else
                metExtacellular(i) = 1;
            end
        end
        
        % map geneIds of exp to model
        modelGene2dataGene  = zeros(length(model.genes),1);
        geneDetected = zeros(length(model.genes),1);
        for i = 1:length(geneStruct.EntrezId)
            if ~isempty(geneStruct.EntrezId{i})
                eIds{i,1} = num2str(geneStruct.EntrezId{i});
            else
                eIds{i,1} = '';
            end
        end
        for i = 1:length(model.genes)
            geneTemp = regexprep(model.genes{i}, '\.\d+','');
            idxTemp = find(strcmp(eIds, geneTemp) == 1);
            if ~isempty(idxTemp)
                modelGene2dataGene(i,1:length(idxTemp)) = idxTemp;
                geneDetected(i) = 1;
            end
        end
    case 'KEGGS'
        % map all model metabolites to data find extracellular metabolites
        modelMet2dataMet = zeros(length(model.Compounds),1);
        modelMet2fe = zeros(length(model.Compounds),1);
        metDetected = zeros(length(model.Compounds),1);
        metExtacellular = zeros(length(model.Compounds),1);
        for i = 1:length(model.Compounds)
            if isempty(regexp(model.Compounds{i},'[e]'))
                idx = find(strcmp(allCpdIdfs, model.Compounds{i}) == 1);
                if ~isempty(idx)
                    modelMet2dataMet(i) = idx(1);
                    modelMet2fe(i) = mapVec(idx(1));
                    metDetected(i) = 1;
                end
            else
                metExtacellular(i) = 1;
            end
        end
        
        % map geneIds of exp to model
        modelGene2dataGene  = zeros(length(model.GeneSymbol),1);
        geneDetected = zeros(length(model.GeneSymbol),1);
        for i = 1:length(geneStruct.GeneName)
            
            if ~isempty(geneStruct.GeneName{i})
                eIds{i,1} = geneStruct.GeneName{i};
            else
                eIds{i,1} = '';
            end
        end
        for i = 1:length(model.Gene)
            geneTemp = model.GeneSymbol{i};
            idxTemp = find(strcmp(eIds, geneTemp) == 1);
            if ~isempty(idxTemp)
                modelGene2dataGene(i,1:length(idxTemp)) = idxTemp;
                geneDetected(i) = 1;
            end
        end
end

%% prepare matrices for calculations

%reduce gene to metabolite matrix and add+1 remove inf
switch upper(modelType)
    case 'RECONX'
        gene2metDistMat = model.gene2metDistance;
    case 'KEGGS'
        gene2metDistMat = model.DistCompoundstoGenes';
end

gene2metDistMat = gene2metDistMat +1;
gene2metDistMatRed = gene2metDistMat(geneDetected == 1,:);
gene2metDistMatRed = gene2metDistMatRed(:,metDetected == 1);

noOfInf = sum(isinf(gene2metDistMatRed),2);
idxIsNotOnlyInf = find(noOfInf < size(gene2metDistMatRed,2));

gene2metDistMatRed = gene2metDistMatRed(idxIsNotOnlyInf,:);

%get ids of detected genes and metabolites
idxGeneDetected = find(geneDetected == 1);
idxGeneDetected = idxGeneDetected(idxIsNotOnlyInf);
idxMetDetected = find(metDetected == 1);
% idxMetDetected = idxMetDetected(idxIsNotOnlyInf);

%reduce gene2metMat to only detected metabolites and gene
geneMetMatRed = geneMetMat(idxGeneDetected,:);
geneMetMatRed = geneMetMatRed(:,metDetected == 1);

%reduce modelGene2dataGene
modelGene2dataGeneRed = modelGene2dataGene(idxGeneDetected,:);
modelMet2feRed = modelMet2fe(metDetected == 1);
modelMet2dataMetRed = modelMet2dataMet(metDetected == 1);

%get pval and corr matrix and sort columns according to model
switch corrType
    case 'pearson'
        switch mode
            case 'loglog'
                pvalMat = corrStruct.pMetLogGeneLogPearson(modelMet2feRed,:)';
                rhoMat = corrStruct.rhoMetLogGeneLogPearson(modelMet2feRed,:)';
            case 'linlog'
                pvalMat = corrStruct.pMetGeneLogPearson(modelMet2feRed,:)';
                rhoMat = corrStruct.rhoMetGeneLogPearson(modelMet2feRed,:)';
            case 'linlin'
                pvalMat = corrStruct.pMetGenePearson(modelMet2feRed,:)';
                rhoMat = corrStruct.rhoMetGenePearson(modelMet2feRed,:)';
        end
    case 'spearman'
        switch mode
            case 'loglog'
                
            case 'linlog'
                
            case 'linlin'
                pvalMat = corrStruct.pMetGeneSpearman(modelMet2feRed,:)';
                rhoMat = corrStruct.rhoMetGeneSpearman(modelMet2feRed,:)';
        end
end



%% start calculating the locality scores
s_true = nan(length(idxGeneDetected),1);
p = ones(length(idxGeneDetected),1);
s_true_DataMatId = zeros(length(idxGeneDetected),1);

% parameter for distance function 1/(D^n)
n = 2; %

%go through every gene and calculate the locality score
for i = 1:size(geneMetMatRed,1)
%     idxMet = modelMet2dataMetRed(geneMetMatRed(i,:) ~= 0);
    idxGene = modelGene2dataGeneRed(i,modelGene2dataGeneRed(i,:) ~= 0);
    s_true_temp = zeros(length(idxGene),1);
    for j = 1:length(idxGene)
        s_true_denom = (1./gene2metDistMatRed(i,~isinf(gene2metDistMatRed(i,:)))).^n ...
            .*(1-pvalMat(idxGene(j),~isinf(gene2metDistMatRed(i,:))));
        s_true_num = s_true_denom.*abs(rhoMat(idxGene(j),~isinf(gene2metDistMatRed(i,:))));
        s_true_temp(j) = sum(s_true_num)/sum(s_true_denom);
    end
    [s_true(i),tempIdx] = max(s_true_temp);
    s_true_DataMatId(i) = idxGene(tempIdx);
end

% make permutations to calculate p-values...

k = 10000; %no of permutations
s_perm = zeros(length(s_true),k);
disp('start')
h = waitbar(0, ['0 of ' num2str(k) ' permutations done']);
tic
idxNotNan = find(isinf(gene2metDistMatRed) == 0);
for j = 1:k % go through all permutations and make a new distance matrix
    gene2metDistMatRed_perm = inf(size(gene2metDistMatRed));
    switch permMode
        case 'all'
            idx = randperm(length(idxGeneDetected)*length(idxMetDetected));
            gene2metDistMatRed_perm(:,:) = reshape(gene2metDistMatRed(idx),size(gene2metDistMatRed));
        case 'by gene'
            idx = randperm(length(idxMetDetected));
            gene2metDistMatRed_perm(:,:) = gene2metDistMatRed(:,idx);
        case 'all - only connected'
            idx = randperm(length(idxNotNan));
            gene2metDistMatRed_perm(idxNotNan) = gene2metDistMatRed(idxNotNan(idx));
        case 'by gene - only connected'
            for i = 1:size(gene2metDistMatRed,1)
                idxNotNan = find(isinf(gene2metDistMatRed(i,:)) == 0);
                idx = randperm(length(idxNotNan));
                gene2metDistMatRed_perm(i,idxNotNan) = gene2metDistMatRed(i,idxNotNan(idx));
            end
            
    end
    idx = randperm(length(idxGeneDetected)*length(idxMetDetected));
    gene2metDistMatRed_perm(:,:) = reshape(gene2metDistMatRed(idx),size(gene2metDistMatRed));
    for i = 1:size(geneMetMatRed,1)
        if ~isnan(s_true(i))
            s_perm_denom = (1./gene2metDistMatRed_perm(i,~isinf(gene2metDistMatRed_perm(i,:)))).^n ...
                .*(1-pvalMat(s_true_DataMatId(i),~isinf(gene2metDistMatRed_perm(i,:))));
            s_perm_num = s_perm_denom.*abs(rhoMat(s_true_DataMatId(i),~isinf(gene2metDistMatRed_perm(i,:))));
            s_perm(i,j) = sum(s_perm_num)/sum(s_perm_denom);
        end
    end
    waitbar(j/k, h, [num2str(j) ' of ' num2str(k) ' permutations done']);
end

for i = 1:length(s_true)
    if ~isnan(s_true(i))
        p(i) = length(find(s_true(i) <= s_perm(i,:)))/k;
    end
end
toc
delete(h)

%% make output

outStruct.geneIdxModel = idxGeneDetected;
outStruct.geneIdxData = s_true_DataMatId;
outStruct.geneIdxDataAllProbes = modelGene2dataGeneRed;
outStruct.gene2metDistMatRed = gene2metDistMatRed;
outStruct.metIdxModel = idxMetDetected;
outStruct.metIdxData = modelMet2feRed;
outStruct.score = s_true;
outStruct.p = p;
outStruct.corrMode = mode;

outmatHeader = {'GeneIdx_model' 'GeneSymbol' 'GeneName' 'Score' 'p'};
switch upper(modelType)
    case 'RECONX'
        a = geneStruct.GeneName(s_true_DataMatId);
        b = geneStruct.Description(s_true_DataMatId);
        outmat = [num2cell(idxGeneDetected) a b num2cell(s_true) num2cell(p)];
        outStruct.geneName = geneStruct.GeneName(s_true_DataMatId);
        outStruct.geneDescription = geneStruct.Description(s_true_DataMatId);
        outStruct.probeId = geneStruct.ID(s_true_DataMatId);
        outStruct.entrezId = geneStruct.EntrezId(s_true_DataMatId);
    case 'KEGGS'
        outmat = [num2cell(idxGeneDetected) model.GeneSymbol(idxGeneDetected) model.GeneName(idxGeneDetected) num2cell(s_true) num2cell(p)];
        outStruct.geneName = geneStruct.GeneName(s_true_DataMatId);
        outStruct.geneDescription = geneStruct.Description(s_true_DataMatId);
        outStruct.probeId = geneStruct.ProbeUID(s_true_DataMatId);
%         outStruct.entrezId = geneStruct.EntrezId(s_true_DataMatId);
end

outStruct.parameters.modelType = modelType;
outStruct.parameters.permutations = k;
outStruct.parameters.nDistance = n;
outStruct.parameters.corrType = corrType;
outStruct.parameters.mode = mode;

[psort, idxp] = sort(p);
outTable = [outmatHeader; outmat(idxp,:)];
xlswrite(['locality_' modelType '_perm=' num2str(k) '_nDIst=' num2str(n) '_' permMode '.xlsx'], outTable)
end