package org.mskcc.cbio.oncokb.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONObject;
import org.mskcc.cbio.oncokb.model.Gene;

/**
 *
 * @author jgao
 */
public final class GeneAnnotator {
    private GeneAnnotator() {
        throw new AssertionError();
    }

    private static final String URL_MY_GENE_INFO_3 = "http://mygene.info/v3/";
    private static final String CBIOPORTAL_GENES_ENDPOINT = "https://www.cbioportal.org/api/genes/";


    public static Gene findGene(String symbol) {
        Gene gene = findGeneFromCBioPortal(symbol);
        if (gene == null) {
            System.out.println("The gene does not exist in cBioPortal, looking in MyGeneInfo");
            try {
                gene = readByHugoSymbol(symbol);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (gene != null) {
            // Swap the hugo symbol with gene alias so that the gene is always using the hugo symbol from input
            if (!gene.getHugoSymbol().equals(symbol)) {
                gene.getGeneAliases().add(gene.getHugoSymbol());
                gene.getGeneAliases().remove(symbol);
                gene.setHugoSymbol(symbol);
            }
        }
        return gene;
    }

    private static Gene findGeneFromCBioPortal(String symbol) {
        try {
            String response = HttpUtils.getRequest(CBIOPORTAL_GENES_ENDPOINT + symbol);
            JSONObject jsonObj = new JSONObject(response);
            if (!jsonObj.has("hugoGeneSymbol") || !jsonObj.has("entrezGeneId")) {
                System.out.println("The gene model is not appropriate from cBioPortal" + response);
                return null;
            } else {
                Gene gene = new Gene();
                gene.setHugoSymbol(jsonObj.getString("hugoGeneSymbol"));
                gene.setEntrezGeneId(jsonObj.getInt("entrezGeneId"));

                includeGeneAlias(gene);

                return gene;
            }
        } catch (IOException e) {
            System.out.println("Something goes wrong while fetching cBioPortal service");
            e.printStackTrace();
            return null;
        }
    }

    private static Gene readByHugoSymbol(String symbol) throws IOException {
        String url = URL_MY_GENE_INFO_3 + "query?species=human&q=" + symbol;
        String json = FileUtils.readRemote(url);

        List<Gene> genes = parseMyGeneResponse(json);

        if (genes.isEmpty()) {
            return null;
        }

        if (genes.size()>1) {
            System.out.println("More than one hits:\n"+url);
        }

        Gene gene = genes.get(0);
        includeGeneAlias(gene);

        return gene;
    }

    private static List<Gene> parseMyGeneResponse(String json) {
        final String HITS = "hits";
        final String ENTREZ_GENE_KEY = "entrezgene";
        final String HUGO_SYMBOL_KEY = "symbol";

        JSONObject map = new JSONObject(json);
        if (!map.has(HITS)) {
            return Collections.emptyList();
        }
        JSONArray hits = map.getJSONArray(HITS);

        List<Gene> genes = new ArrayList<>();
        for (int i = 0; i < hits.length(); i++) {
            JSONObject hit = hits.getJSONObject(i);
            if (hit.has(ENTREZ_GENE_KEY) && hit.has(HUGO_SYMBOL_KEY)) {
                int entrez = hit.getInt(ENTREZ_GENE_KEY);
                String symbol = hit.getString(HUGO_SYMBOL_KEY);

                Gene gene = new Gene(entrez, symbol);
                genes.add(gene);
            }
        }

        return genes;
    }

    private static void includeGeneAlias(Gene gene) throws IOException {
        String url = URL_MY_GENE_INFO_3 + "gene/" + gene.getEntrezGeneId()
                + "?fields=alias";
        String json = FileUtils.readRemote(url);

        Map<String,Object> map = JsonUtils.jsonToMap(json);
        Object objAlias = map.get("alias");
        if (objAlias!=null) {
            if (objAlias instanceof String) {
                String alias = String.class.cast(objAlias);
                gene.setGeneAliases(Collections.singleton(alias));
            } else if (objAlias instanceof List) {
                List<String> aliases = List.class.cast(objAlias);
                gene.setGeneAliases(new HashSet<>(aliases));
            }
        }
    }
}

@@ -79,120 +79,56 @@
 til.
-ArrayList;%0Aimport java.util.Collections;%0Aimport java.util.HashSet;%0Aimport java.util.List;%0Aimport java.util.Map;%0A
+*;%0A%0Aimport org.apache.commons.lang3.StringUtils;
 %0Aimp
@@ -229,11 +229,8 @@
 /**%0A
- *%0A
  * @
@@ -1118,16 +1118,50 @@
 (symbol)
+ && !StringUtils.isNumeric(symbol)
 ) %7B%0A    
@@ -2645,17 +2645,19 @@
 s.size()
-%3E
+ %3E 
 1) %7B%0A   
@@ -2707,17 +2707,19 @@
 hits:%5Cn%22
-+
+ + 
 url);%0A  
@@ -3851,20 +3851,16 @@
         
-    
 + %22?fiel
@@ -3939,16 +3939,17 @@
 %3CString,
+ 
 Object%3E 
@@ -4049,18 +4049,20 @@
 lias
+ 
 !=
+ 
 null) %7B%0A
     
@@ -4049,32 +4049,83 @@
 lias != null) %7B%0A
+            Set%3CString%3E aliases = new HashSet%3C%3E();%0A
             if (
@@ -4234,57 +4234,26 @@
     
-gene.setGeneAliases(Collections.singleton
+aliases.add
 (alias)
-)
 ;%0A  
@@ -4335,18 +4335,20 @@
 g%3E alias
-es
+List
  = List.
@@ -4389,50 +4389,32 @@
     
-gene.setGeneAliases(new HashSet%3C%3E
+aliases.addAll
 (alias
-es)
+List
 );%0A 
@@ -4418,32 +4418,74 @@
 ;%0A            %7D%0A
+            gene.setGeneAliases(aliases);%0A
         %7D%0A    %7D%0A

Fix issue that gene aliases is immutable