package org.intermine.bio.dataconversion;

/*
 * Copyright (C) 2002-2009 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */

import java.io.Reader;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.intermine.dataconversion.ItemWriter;
import org.intermine.metadata.Model;
import org.intermine.objectstore.ObjectStoreException;
import org.intermine.util.FormattedTextParser;
import org.intermine.xml.full.Item;


/**
 * 
 * @author
 */
public class HgncConverter extends BioFileConverter
{
    protected static final Logger LOG = Logger.getLogger(HgncConverter.class);

    private static final String DATASET_TITLE = "HGNC approved gene symbols";
    private static final String DATA_SOURCE_NAME = "HUGO Gene Nomenclature Committee ";

    /**
     * Constructor
     * @param writer the ItemWriter used to handle the resultant items
     * @param model the Model
     */
    public HgncConverter(ItemWriter writer, Model model) {
        super(writer, model, DATA_SOURCE_NAME, DATASET_TITLE);
    }

    /**
     * This converter is designed to load a file generated by the HGNC custom downloader with URL:
     * http://www.genenames.org/cgi-bin/hgnc_downloads.cgi?title=HGNC+output+data&hgnc_dbtag=on
     * &col=gd_hgnc_id&col=gd_app_sym&col=gd_app_name&col=gd_status&col=gd_prev_sym&col=gd_aliases
     * &col=gd_pub_eg_id&col=gd_pub_ensembl_id&col=md_eg_id&col=md_ensembl_id&status=Approved
     * &status=Entry+Withdrawn&status_opt=2&level=pri&=on&where=&order_by=gd_app_sym_sort&limit=
     * &format=text&submit=submit&.cgifields=&.cgifields=level&.cgifields=chr&.cgifields=status
     * &.cgifields=hgnc_dbtag
     *
     * {@inheritDoc}
     */
    public void process(Reader reader) throws Exception {
        Iterator lineIter = FormattedTextParser.parseTabDelimitedReader(reader);

        Item organism = createItem("Organism");
        organism.setAttribute("taxonId", "9606");
        store(organism);

        Set<String> symbols = new HashSet<String>();
        Set<String> seenEnsembl = new HashSet<String>();
        Set<String> seenEntrez = new HashSet<String>();

        Set<String> duplicateEntrez = new HashSet<String>();
        Set<String> duplicateEnsembl = new HashSet<String>();

        Set<GeneRecord> records = new HashSet<GeneRecord>();

        // Read all lines into gene records
        while (lineIter.hasNext()) {
            String[] line = (String[]) lineIter.next();

            String status = line[3];
            if (!status.equals("Approved")) {
                continue;
            }
            String symbol = line[1];
            String name = line[2];
            String previous = line[4];
            String aliases = line[5];
            
            String entrez = null;
            if (line.length > 8) {
                entrez = line[8];
            }
            String ensembl = null;
            if (line.length > 9) {
                ensembl = line[9];
            }
            if (symbols.contains(symbol)) {
                LOG.warn("HGNC seen same symbol already: " + symbol);
            } else {
                symbols.add(symbol);

                if (!StringUtils.isBlank(entrez)) {
                    if (seenEntrez.contains(entrez)) {
                        duplicateEntrez.add(entrez);
                    }
                }

                if (!StringUtils.isBlank(ensembl)) {
                    if (seenEnsembl.contains(ensembl)) {
                        duplicateEnsembl.add(ensembl);
                    }
                }
                seenEntrez.add(entrez);
                seenEnsembl.add(ensembl);

                GeneRecord record = new GeneRecord(symbol, name, entrez, ensembl);
                record.previous = readCommaSeparated(previous);
                record.aliases = readCommaSeparated(aliases);
                
                records.add(record);
            }
        }
        if (!duplicateEnsembl.isEmpty()) {
            LOG.warn("Found " + duplicateEnsembl.size() + " duplicate ensembl ids, not using "
                    + " duplicates for primaryIdentifier: " + duplicateEnsembl);
        }

        if (!duplicateEntrez.isEmpty()) {
            LOG.warn("Found " + duplicateEntrez.size() + " duplicate entrez ids, not using "
                    + " duplicates for ncbiGeneNumber: " + duplicateEntrez);
        }

        // store genes and synonyms, avoid setting duplicate ensembl and entrez ids
        for (GeneRecord record : records) {
            Item gene = createItem("Gene");
            gene.setReference("organism", organism);
            gene.setAttribute("symbol", record.symbol);
            if (StringUtils.isBlank(record.name)) {
                LOG.warn("HGNC no name for symbol: " + record.name);
            } else {
                gene.setAttribute("name", record.name);
            }

            if (!StringUtils.isBlank(record.entrez)) {
                if (!duplicateEntrez.contains(record.entrez)) {
                    gene.setAttribute("ncbiGeneNumber", record.entrez);
                    gene.setAttribute("secondaryIdentifier", record.entrez);
                } else {
                    createSynonym(record.entrez, gene);
                }
            }
            if (!StringUtils.isBlank(record.ensembl)) {
                if (!duplicateEnsembl.contains(record.ensembl)) {
                    gene.setAttribute("primaryIdentifier", record.ensembl);
                } else {
                    createSynonym(record.ensembl, gene);
                }
            }

            // store previous symbols and aliases as synonyms
            for (String previous : record.previous) {
                createSynonym(previous, gene);
            }

            for (String alias : record.aliases) {
                createSynonym(alias, gene);
            }

            store(gene);
        }
    }

    private void createSynonym(String value, Item gene) throws ObjectStoreException {
        Item synonym = createItem("Synonym");
        synonym.setAttribute("value", value);
        synonym.setReference("subject", gene);
        store(synonym);
    }

    private Set<String> readCommaSeparated(String input) {
        Set<String> retval = new HashSet<String>();
        if (!StringUtils.isBlank(input)) {
            for (String s : input.split(",")) {
                retval.add(s.trim());
            }
        }
        return retval;
    }

    private class GeneRecord
    {
        protected String symbol;
        protected String name;
        protected String entrez;
        protected String ensembl;
        protected Set<String> previous;
        protected Set<String> aliases;

        public GeneRecord(String symbol, String name, String entrez, String ensembl) {
            this.symbol = symbol;
            this.name = name;
            this.entrez = entrez;
            this.ensembl = ensembl;
            this.previous = new HashSet<String>();
            this.aliases = new HashSet<String>();
        }
    }
}

@@ -740,17 +740,16 @@
 %0A%0A/**%0A *
- 
 %0A * @aut
@@ -3004,28 +3004,16 @@
 ine%5B5%5D;%0A
-            
 %0A       
@@ -4112,32 +4112,16 @@
 iases);%0A
-                
 %0A       
@@ -5014,36 +5014,38 @@
 bol: %22 + record.
-name
+symbol
 );%0A            %7D

fix error message