<commit_before>'use strict';

import React from 'react';
import _ from 'underscore';
import PropTypes from 'prop-types';
import ReactTooltip from 'react-tooltip';
import { object } from '@hms-dbmi-bgm/shared-portal-components/es/components/util';
import { ItemFooterRow } from '@hms-dbmi-bgm/shared-portal-components/es/components/ui/ItemFooterRow';
import { StackedBlockTable, StackedBlock, StackedBlockList, StackedBlockName, StackedBlockNameLabel } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/components/StackedBlockTable';
import { FormattedInfoBlock, WrappedCollapsibleList } from './FormattedInfoBlock';
import { Publications } from './Publications';
import { FileEntryBlock } from '../../browse/components/FileEntryBlock';



// TODO memoized component
export function generateAddressString(lab) {
    const { city, state, postal_code, country } = lab;
    const address = [];
    if (city) { address.push(city); }
    if (state || postal_code) { address.push(((state || '') + ' ' + (postal_code || '')).trim()); }
    if (country) { address.push(country); }

    return address.join(', ');
}

/**
 * Generate a list element for a contact person.
 * We base64-encode emails for security against scrapers;
 * instead of providing a mailto: link, we make the email
 * visible only when email icon is hovered over.
 *
 * @param {Object} contactPerson - Faux Item representation of User.
 * @param {string} contactPerson.display_title - Name of User
 * @param {string} contactPerson.contact_email - Base64-encoded email of User.
 * @param {number} [idx] - Index of person in correspondence list.
 * @returns {JSX.Element} A `li` JSX element.
 */
export const ContactPersonListItem = React.memo(function ContactPersonListItem({ contactPerson }){
    const { contact_email = null, display_title = "Unknown Person" } = contactPerson;
    const decodedEmail = (typeof atob === 'function' && contact_email && atob(contact_email)) || null;
    const decodedEmailParts = decodedEmail && decodedEmail.split('@');
    const onClick = (decodedEmail && function(e){
        if (typeof window.location.assign !== 'function') return false;
        window.location.assign('mailto:' + decodedEmail);
        return false;
    }) || null;
    const dataTip = (decodedEmailParts && (
        '<span class="text-300">Click to send e-mail message to</span><br/>' +
        '<div class="text-center">' +
            '<span class="text-500">' +
                decodedEmailParts[0] +
            '</span> <span class="text-400 small">(at)</span> <span class="text-500">' +
                decodedEmailParts[1] +
            '</span>' +
        '</div>'
    )) || null;

    return (
        <li className="contact-person">
            <div className="inline-block clickable" data-html data-tip={dataTip} onClick={onClick}>
                <i className="icon icon-fw icon-envelope far" />
                &nbsp;&nbsp;
                { display_title }
            </div>
        </li>
    );
});

/**
 * expSetId, expId, fileId, externalRefs
 * @param {Object} context
 */
function combineExternalReferencesWithTitle(context) {
    const externalRefs = [];
    //add experiment set
    if (context.external_references.length > 0) {
        externalRefs.push(_.reduce(
            context.external_references,
            function (memo, extRef, idx) {
                memo['extRef' + (idx + 1)] = extRef;
                return memo;
            },
            { '@id': context['@id'], 'expSetId': { 'title': context.display_title, 'url': context['@id'] }, 'expId': null, 'fileId': null })
        );
    }
    //experiment set's processed files
    if (context.processed_files && context.processed_files.length > 0) {
        _.each(context.processed_files, function (file) {
            if (file.external_references && file.external_references.length > 0) {
                externalRefs.push(_.reduce(
                    file.external_references,
                    function (memo, extRef, idx) {
                        memo['extRef' + (idx + 1)] = extRef;
                        return memo;
                    },
                    { '@id': file['@id'], 'expSetId': { 'title': context.display_title, 'url': context['@id'] }, 'expId': { 'title': 'Multiple Experiments', 'url': null }, 'fileId': { 'title': file.display_title, 'url': file['@id'] } })
                );
            }
        });
    }
    //add experiment
    _.each(context.experiments_in_set, function (exp) {
        if (exp.external_references.length > 0) {
            externalRefs.push(_.reduce(
                exp.external_references,
                function (memo, extRef, idx) {
                    memo['extRef' + (idx + 1)] = extRef;
                    return memo;
                },
                { '@id': exp['@id'], 'expSetId': { 'title': context.display_title, 'url': context['@id'] }, 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': null })
            );
        }
        //experiment's processed files
        if (exp.processed_files && exp.processed_files.length > 0) {
            _.each(exp.processed_files, function (file) {
                if (file.external_references.length > 0) {
                    externalRefs.push(_.reduce(
                        file.external_references,
                        function (memo, extRef, idx) {
                            memo['extRef' + (idx + 1)] = extRef;
                            return memo;
                        },
                        { '@id': file['@id'], 'expSetId': { 'title': context.display_title, 'url': context['@id'] }, 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': { 'title': file.display_title, 'url': file['@id'] } })
                    );
                }
            });
        }
        //experiment's raw files
        if (exp.files && exp.files.length > 0) {
            _.each(exp.files, function (file) {
                if (file.external_references.length > 0) {
                    externalRefs.push(_.reduce(
                        file.external_references,
                        function (memo, extRef, idx) {
                            memo['extRef' + (idx + 1)] = extRef;
                            return memo;
                        },
                        { '@id': file['@id'], 'expSetId': { 'title': context.display_title, 'url': context['@id'] }, 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': { 'title': file.display_title, 'url': file['@id'] } })
                    );
                }
            });
        }
    });
    console.log('xxx externalRefs:', externalRefs);

    const columnHeaders = [
        { columnClass: 'experiment-set', title: 'Experiment Set', initialWidth: 200, className: 'experiment', field: "expSetId.title" },
        { columnClass: 'experiment', title: 'Experiment', initialWidth: 200, field: "expId.title" },
        { columnClass: 'file', title: 'File', initialWidth: 200, field: "fileId.title" },
        { columnClass: 'file-detail', title: 'External Reference', initialWidth: 200, field: "extRef1.ref" },
    ];

    const extRefsGroupByExp = _.groupBy(externalRefs, function (item) { return (item.expId && item.expId.title) || '-'; });

    const blocks = _.map(extRefsGroupByExp, function (item, idx) {
        const fileBlocks = _.map(item, function (ref) {
            return (<FileEntryBlock file={ref}></FileEntryBlock>);
        });
        return (
            <StackedBlock columnClass="experiment" hideNameOnHover={false} key={"exp-" + idx}
                label={<StackedBlockNameLabel title="Experiment" subtitle={'zzz'} accession={(item[0].expId && item[0].expId.accession) || '-'} subtitleVisible />}>
                <StackedBlockName relativePosition={true}>
                    <a href={(item[0].expId && item[0].expId.url) || '#'} className="name-title">{(item[0].expId && item[0].expId.accession) || '-'}</a>
                </StackedBlockName>
                <StackedBlockList className="experiments" title="Files">
                    {fileBlocks}
                </StackedBlockList>
            </StackedBlock>
        );
    });

    return (
        <React.Fragment>
            <hr className="mb-08 mt-1" />
            <div className="row">
                <div className="col">
                    <h4 className="text-300">External References</h4>
                    <div className="stacked-block-table-outer-container overflow-auto">
                        <StackedBlockTable columnHeaders={columnHeaders}
                            className="expset-processed-files" fadeIn handleFileCheckboxChange={null}>
                            <StackedBlockList className="sets" collapseLongLists={false}>
                                <StackedBlock columnClass="experiment-set" hideNameOnHover={false} key="expset"
                                    label={<StackedBlockNameLabel title="Experiment Set" subtitle={'zzz'} accession={context.accession} subtitleVisible />}>
                                    <StackedBlockName relativePosition={true}>
                                        <a href={context['@id']} className="name-title">{context.accession}</a>
                                    </StackedBlockName>
                                    <StackedBlockList className="experiments" title="Experiments">
                                        {blocks}
                                    </StackedBlockList>
                                </StackedBlock>
                            </StackedBlockList>
                        </StackedBlockTable>
                    </div>
                </div>
            </div>
        </React.Fragment><commit_msg>dbxrefs table implementation cont.<commit_after>'use strict';

import React from 'react';
import _ from 'underscore';
import PropTypes from 'prop-types';
import ReactTooltip from 'react-tooltip';
import { object } from '@hms-dbmi-bgm/shared-portal-components/es/components/util';
import { ItemFooterRow } from '@hms-dbmi-bgm/shared-portal-components/es/components/ui/ItemFooterRow';
import { StackedBlockTable, StackedBlock, StackedBlockList, StackedBlockName, StackedBlockNameLabel } from '@hms-dbmi-bgm/shared-portal-components/es/components/browse/components/StackedBlockTable';
import { FormattedInfoBlock, WrappedCollapsibleList } from './FormattedInfoBlock';
import { Publications } from './Publications';
import { FileEntryBlock } from '../../browse/components/FileEntryBlock';



// TODO memoized component
export function generateAddressString(lab) {
    const { city, state, postal_code, country } = lab;
    const address = [];
    if (city) { address.push(city); }
    if (state || postal_code) { address.push(((state || '') + ' ' + (postal_code || '')).trim()); }
    if (country) { address.push(country); }

    return address.join(', ');
}

/**
 * Generate a list element for a contact person.
 * We base64-encode emails for security against scrapers;
 * instead of providing a mailto: link, we make the email
 * visible only when email icon is hovered over.
 *
 * @param {Object} contactPerson - Faux Item representation of User.
 * @param {string} contactPerson.display_title - Name of User
 * @param {string} contactPerson.contact_email - Base64-encoded email of User.
 * @param {number} [idx] - Index of person in correspondence list.
 * @returns {JSX.Element} A `li` JSX element.
 */
export const ContactPersonListItem = React.memo(function ContactPersonListItem({ contactPerson }){
    const { contact_email = null, display_title = "Unknown Person" } = contactPerson;
    const decodedEmail = (typeof atob === 'function' && contact_email && atob(contact_email)) || null;
    const decodedEmailParts = decodedEmail && decodedEmail.split('@');
    const onClick = (decodedEmail && function(e){
        if (typeof window.location.assign !== 'function') return false;
        window.location.assign('mailto:' + decodedEmail);
        return false;
    }) || null;
    const dataTip = (decodedEmailParts && (
        '<span class="text-300">Click to send e-mail message to</span><br/>' +
        '<div class="text-center">' +
            '<span class="text-500">' +
                decodedEmailParts[0] +
            '</span> <span class="text-400 small">(at)</span> <span class="text-500">' +
                decodedEmailParts[1] +
            '</span>' +
        '</div>'
    )) || null;

    return (
        <li className="contact-person">
            <div className="inline-block clickable" data-html data-tip={dataTip} onClick={onClick}>
                <i className="icon icon-fw icon-envelope far" />
                &nbsp;&nbsp;
                { display_title }
            </div>
        </li>
    );
});

/**
 * expSetId, expId, fileId, externalRefs
 * @param {Object} context
 */
function combineExternalReferencesWithTitle(context) {
    const externalRefs = [];
    //add experiment set
    if (context.external_references.length > 0) {
        externalRefs.push(_.reduce(
            context.external_references,
            function (memo, extRef, idx) {
                memo['extRef' + (idx + 1)] = extRef;
                return memo;
            },
            { 'expId': null, 'fileId': null })
        );
    }
    //experiment set's processed files
    if (context.processed_files && context.processed_files.length > 0) {
        _.each(context.processed_files, function (file) {
            if (file.external_references && file.external_references.length > 0) {
                externalRefs.push(_.reduce(
                    file.external_references,
                    function (memo, extRef, idx) {
                        memo['extRef' + (idx + 1)] = extRef;
                        return memo;
                    },
                    { 'expId': { 'title': 'Multiple Experiments', 'url': null }, 'fileId': { '@id': file['@id'],  'title': file.display_title, 'url': file['@id'] } })
                );
            }
        });
    }
    //add experiment
    _.each(context.experiments_in_set, function (exp) {
        if (exp.external_references.length > 0) {
            externalRefs.push(_.reduce(
                exp.external_references,
                function (memo, extRef, idx) {
                    memo['extRef' + (idx + 1)] = extRef;
                    return memo;
                },
                { 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': null })
            );
        }
        //experiment's processed files
        if (exp.processed_files && exp.processed_files.length > 0) {
            _.each(exp.processed_files, function (file) {
                if (file.external_references.length > 0) {
                    externalRefs.push(_.reduce(
                        file.external_references,
                        function (memo, extRef, idx) {
                            memo['extRef' + (idx + 1)] = extRef;
                            return memo;
                        },
                        { 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': { '@id': file['@id'], 'title': file.display_title, 'url': file['@id'] } })
                    );
                }
            });
        }
        //experiment's raw files
        if (exp.files && exp.files.length > 0) {
            _.each(exp.files, function (file) {
                if (file.external_references.length > 0) {
                    externalRefs.push(_.reduce(
                        file.external_references,
                        function (memo, extRef, idx) {
                            memo['extRef' + (idx + 1)] = extRef;
                            return memo;
                        },
                        { 'expId': { 'title': exp.display_title, 'url': exp['@id'], accession: exp.accession }, 'fileId': { '@id': file['@id'], 'title': file.display_title, 'url': file['@id'] } })
                    );
                }
            });
        }
    });
    console.log('xxx externalRefs:', externalRefs);

    const columnHeaders = [
        { columnClass: 'experiment-set', title: 'Experiment Set', initialWidth: 200, className: 'text-left', field: "expSetId.title" },
        { columnClass: 'experiment', title: 'Experiment', initialWidth: 200, className: 'text-left', field: "expId.title" },
        { columnClass: 'file', title: 'File', initialWidth: 200, field: "fileId.title" },
        { columnClass: 'file-detail', title: 'External Reference #1', initialWidth: 200, field: "extRef1.ref" },
        { columnClass: 'file-detail', title: 'External Reference #2', initialWidth: 200, field: "extRef2.ref" },
    ];

    const extRefsGroupByExp = _.groupBy(externalRefs, function (item) { return (item.expId && item.expId.title) || '-'; });

    const blocks = _.map(extRefsGroupByExp, function (item, idx) {
        const fileBlocks = _.map(item, function (ref) {
            const fileObj = _.extend(_.pick(ref, function (value, key, object) { return key.startsWith('extRef'); }), ref.fileId || { 'accession': '-', '@id': '-' });
            return (<FileEntryBlock file={fileObj}></FileEntryBlock>);
        });
        return (
            <StackedBlock columnClass="experiment" hideNameOnHover={false} key={"exp-" + idx}
                label={<StackedBlockNameLabel title="Experiment" subtitle={'zzz'} accession={(item[0].expId && item[0].expId.accession) || '-'} subtitleVisible />}>
                <StackedBlockName relativePosition={true}>
                    <a href={(item[0].expId && item[0].expId.url) || '#'} className="name-title">{(item[0].expId && item[0].expId.accession) || '-'}</a>
                </StackedBlockName>
                <StackedBlockList className="experiments" title="Files">
                    {fileBlocks}
                </StackedBlockList>
            </StackedBlock>
        );
    });

    return (
        <React.Fragment>
            <hr className="mb-08 mt-1" />
            <div className="row">
                <div className="col">
                    <h4 className="text-300">External References</h4>
                    <div className="stacked-block-table-outer-container overflow-auto">
                        <StackedBlockTable columnHeaders={columnHeaders} className="expset-external-references" fadeIn>
                            <StackedBlockList className="sets" collapseLongLists={false}>
                                <StackedBlock columnClass="experiment-set" hideNameOnHover={false} key="expset"
                                    label={<StackedBlockNameLabel title="Experiment Set" subtitle={'zzz'} accession={context.accession} subtitleVisible />}>
                                    <StackedBlockName relativePosition={true}>
                                        <a href={context['@id']} className="name-title">{context.accession}</a>
                                    </StackedBlockName>
                                    <StackedBlockList className="experiments" title="Experiments" collapseLongLists={false}>
                                        {blocks}
                                    </StackedBlockList>
                                </StackedBlock>
                            </StackedBlockList>
                        </StackedBlockTable>
                    </div>
                </div>
            </div>
        </React.Fragment>
{'fraction_non_alphanumeric': 0.1432530924395627, 'fraction_numerical': 0.006261869321973002, 'mean_word_length': 2.0496165284082015, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 121, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2771539', 'n_tokens_mistral': 5497, 'n_tokens_neox': 5268, 'n_words': 1150}