package primerdb;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import org.biojava.bio.BioException;
import org.biojavax.Namespace;
import org.biojavax.RichObjectFactory;
import org.biojavax.SimpleNamespace;
import org.biojavax.bio.BioEntry;
import org.biojavax.bio.db.RichSequenceDB;
import org.biojavax.bio.db.biosql.BioSQLRichSequenceDB;
import org.biojavax.bio.seq.RichSequence;
import org.biojavax.bio.seq.RichSequenceIterator;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class SequenceLoaderNew {

    private SessionFactory sessionFactory;
    private Session session = null;

    private void initSession() {
        sessionFactory = new Configuration().configure().buildSessionFactory();
        session = sessionFactory.openSession();
        RichObjectFactory.connectToBioSQL(session);
    }

    public static ArrayList getFiles(File filePath) {
        FileFilter fileFilter = new FileFilter() {

            public boolean accept(File pathname) {
                return pathname.isFile();
            }
        };
        return getFiles(filePath, fileFilter);
    }

    public static ArrayList getFiles(File filePath, FileFilter fileFilter) {
        ArrayList rtn = new ArrayList();
        if (filePath.isFile()) {
            if (fileFilter.accept(filePath)) {
                rtn.add(filePath);
            }
        } else if (filePath.isDirectory()) {
            File[] flist = filePath.listFiles();
            for (int i = 0; i < flist.length; i++) {
                ArrayList subRtn = getFiles(flist[i], fileFilter);
                for (int k = 0; k < subRtn.size(); k++) {
                    rtn.add(subRtn.get(k));
                }
            }
        }
        return rtn;
    }

    public void loadGenbankSeq(String[] filePaths, String namespace) throws FileNotFoundException, BioException, SQLException, InterruptedException, IOException {
        File[] files = new File[filePaths.length];
        for (int i = 0; i < filePaths.length; i++) {
            files[i] = new File(filePaths[i]);
        }
        loadGenbankSeq(files, namespace);
    }

    public void loadGenbankSeq(File[] files, String namespace) throws FileNotFoundException, BioException, SQLException, InterruptedException, IOException {
        if (session == null) {
            initSession();
        }
        Namespace ns = (Namespace) RichObjectFactory.getObject(SimpleNamespace.class, new Object[]{namespace});
        RichSequenceDB db = new BioSQLRichSequenceDB(session);
        for (int i = 0; i < files.length; i++) {
            File file = files[i];
            System.out.println("Start loading file " + file.getAbsolutePath() + " at " + System.currentTimeMillis());
            BufferedReader br = new BufferedReader(new FileReader(file));
            RichSequenceIterator rsi = RichSequence.IOTools.readGenbankDNA(br, ns);
            try {
                while (rsi.hasNext()) {
                    Transaction tx = session.beginTransaction();
                    try {
                        RichSequence sequence = rsi.nextRichSequence();
                        System.out.println("Loaded sequence" + sequence.getAccession() + ", identifier: " + sequence.getIdentifier());
                        Query q = session.createQuery("from BioEntry as s where s.name = :acc");
                        q.setString("acc", sequence.getAccession());
                        BioEntry be = (BioEntry) q.uniqueResult();
                        if (be != null) {
                            session.delete(be);
                            tx.commit();
                            tx = session.beginTransaction();
                        }
                        System.out.println("Save sequence " + sequence.getAccession());
                        session.saveOrUpdate("Sequence", sequence);
                        tx.commit();
                        System.out.println("Finished savig sequence " + sequence.getAccession() + "\n");
                    } catch (HibernateException ex) {
                        tx.rollback();
                        ex.printStackTrace();
                    }
                }
            } finally {
            //session.flush();
            //RichObjectFactory.clearLRUCache();
            //session.clear();
            }
            br.close();
        }
    }

    public static void main(String[] args) throws BioException, FileNotFoundException, InterruptedException, SQLException, IOException {
        SequenceLoaderNew sl = new SequenceLoaderNew();
        FileFilter ff = new FileFilter() {
            public boolean accept(File pathname) {
                return pathname.isFile() &&
                        (pathname.getName().toLowerCase().endsWith("gbk") || pathname.getName().toLowerCase().endsWith("gb"));
            }
        };
        ArrayList flist = SequenceLoaderNew.getFiles(new File("/genomeseq/bacteria"), ff);
        File[] files = new File[flist.size()];
        for (int i = 0; i < flist.size(); i++) {
            files[i] = (File) flist.get(i);
        }
        for (int i = 0; i < files.length; i++) {
            System.out.println(files[i].getAbsolutePath() + ", size: " + files[i].length());
        }
        sl.loadGenbankSeq(files, "genbank");
    }
}
