/*
 * The Gemma project
 * 
 * Copyright (c) 2007 University of British Columbia
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package ubic.gemma.loader.genome;

import java.util.Collection;
import java.util.HashSet;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ubic.gemma.loader.util.parser.BasicLineParser;
import ubic.gemma.model.genome.Chromosome;
import ubic.gemma.model.genome.Gene;
import ubic.gemma.model.genome.PhysicalLocation;
import ubic.gemma.model.genome.Taxon;
import ubic.gemma.model.genome.gene.GeneProduct;

/**
 * Simple parser for GFF format (version 2). See http://www.sanger.ac.uk/Software/formats/GFF/GFF_Spec.shtml.
 * <p>
 * Fields are: &lt;seqname&gt; &lt;source&gt; &lt;feature&gt; &lt;start&lt; &lt;end&gt; &lt;score&gt; &lt;strand&gt;
 * &lt;frame&gt; [attributes] [comments]. A header can be present.
 * <p>
 * Implementation note: Currently each line is converted to a Gene with an associated GeneProduct; this will have to be
 * expanded/changed.
 * 
 * @author pavlidis
 * @version $Id$
 */
public class GffParser extends BasicLineParser {
    private static Log log = LogFactory.getLog( GffParser.class.getName() );
    Collection<Gene> results = new HashSet<Gene>();

    Taxon taxon;

    public Taxon getTaxon() {
        return taxon;
    }

    public void setTaxon( Taxon taxon ) {
        this.taxon = taxon;
    }

    @Override
    protected void addResult( Object obj ) {
        results.add( ( Gene ) obj );
    }

    @Override
    public Collection getResults() {
        return results;
    }

    public Object parseOneLine( String line ) {

        if ( this.taxon == null ) {
            throw new IllegalStateException( "You must set the taxon first" );
        }

        String[] fields = StringUtils.splitPreserveAllTokens( line, '\t' );
        Gene newGene = Gene.Factory.newInstance();
        GeneProduct gp = GeneProduct.Factory.newInstance();

        String seqName = fields[0]; // chromosome
        // String source = fields[1];
        String featureType = fields[2];
        long start = Long.parseLong( fields[3] );
        long end = Long.parseLong( fields[4] );
        int length = ( int ) ( end - start );
        String strand = fields[6];

        String attributes = fields[8];

        newGene.setDescription( featureType );
        gp.setDescription( featureType );

        String[] attFields = StringUtils.splitPreserveAllTokens( attributes, ';' );
        for ( int i = 0; i < attFields.length; i++ ) {

            String f = attFields[i];
            f = StringUtils.strip( f );
            log.debug( f );
            String[] subf = StringUtils.split( f, '=' );

            if ( subf.length == 2 ) {
                String ti = subf[0];
                String val = subf[1];

                if ( ti.equals( "ID" ) ) {
                    newGene.setName( val );
                    gp.setName( val );
                } else if ( ti.equals( "ACC" ) ) {
                    // don't know what database!
                }
            }
        }

        // String comments = fields[9];

        Chromosome chromosome = Chromosome.Factory.newInstance();
        chromosome.setName( seqName );
        chromosome.setTaxon( taxon );
        PhysicalLocation pl = PhysicalLocation.Factory.newInstance();
        pl.setChromosome( chromosome );
        pl.setNucleotide( start );
        pl.setNucleotideLength( length );
        pl.setStrand( strand );

        newGene.setPhysicalLocation( pl );
        gp.setPhysicalLocation( pl );

        newGene.getProducts().add( gp );
        gp.setGene( newGene );

        return newGene;

    }

}

@@ -3128,16 +3128,76 @@
 lds%5Bi%5D;%0A
+%0A            if ( f == null %7C%7C f.length() == 0 ) continue;%0A%0A
         
@@ -3343,17 +3343,17 @@
 .length 
-=
+!
 = 2 ) %7B%0A
@@ -3348,32 +3348,127 @@
 th != 2 ) %7B%0A    
+            throw new IllegalArgumentException( %22Couldn't parse '%22 + f + %22'%22 );%0A            %7D%0A%0A
             Stri
@@ -3492,28 +3492,24 @@
             
-    
 String val =
@@ -3515,28 +3515,24 @@
 = subf%5B1%5D;%0A%0A
-    
             
@@ -3578,41 +3578,132 @@
     
-    newGene.setName( val );%0A     
+val = val.replaceAll( %22%5C%22%22, %22%22 );%0A                newGene.setName( val );%0A                newGene.setOfficialSymbol( val );%0A
     
@@ -3709,24 +3709,25 @@
             
+ 
 gp.setName( 
@@ -3725,36 +3725,32 @@
 setName( val );%0A
-    
             %7D el
@@ -3796,20 +3796,16 @@
         
-    
 // don't
@@ -3829,26 +3829,8 @@
 se!%0A
-                %7D%0A
     
@@ -4030,24 +4030,25 @@
 n( taxon );%0A
+%0A
         Phys
@@ -4250,33 +4250,32 @@
 ( strand );%0A
-%0A
         
 newGene.setP
@@ -4258,31 +4258,26 @@
  );%0A        
-newGene
+gp
 .setPhysical
@@ -4306,36 +4306,142 @@
   gp.set
-PhysicalLocation( pl
+Gene( newGene );%0A%0A        PhysicalLocation gpl = PhysicalLocation.Factory.newInstance();%0A        gpl.setChromosome( chromosome
  );%0A%0A   
@@ -4457,60 +4457,108 @@
 ene.
-getProducts().add( gp );%0A        gp.setGene( newGene
+setTaxon( taxon );%0A        newGene.setPhysicalLocation( gpl );%0A        newGene.getProducts().add( gp
  );%0A

fix so fields filled in allow 'find' to locate pre-existing GoldenPath miRNAs.