package fr.iri.thd.sonyengine.core;

import java.util.ArrayList;
import java.util.List;

import thd.Neighbor;
import thd.ThdEngine;
import thd.ThdMovieFragment;

import com.sleepycat.je.Transaction;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityIndex;

import core.Tag;
import core.TransformableItem;

public class EngineAccessor {

    private ThdEngine engine = null;
    private DbEnv dbenv = null;
    private int untrainedLimit = 0;
    
    private EngineAccessor() {
        this.engine = ThdEngine.getEngine();
    }
    
    private static class SingletonHolder {
        private final static EngineAccessor instance = new EngineAccessor();
    }
    
    public static EngineAccessor getInstance() {
        return SingletonHolder.instance;
    }

    public Object clone()
	    throws CloneNotSupportedException {
        throw new CloneNotSupportedException(); 
    }
    
    public ThdEngine getEngine() {
        return this.engine;
    }
    
    public void setDbEnv(DbEnv dbenv) {
        if(this.dbenv == null)
            this.dbenv = dbenv;
    }
    
    public void setUntrainedLimit(int untrainedLimit) {
        this.untrainedLimit = untrainedLimit;
    }
    
    public DbEnv getDbEnv() {
        return this.dbenv;
    }
    
    public synchronized void close() {
        if(this.dbenv != null) {
            this.dbenv.close();
            this.dbenv = null;
        }
        this.engine = null;
    }
    
    public void train() {
        this.train(true);
    }
    
    public void train(boolean force) {   

        final DataAccessor da = new DataAccessor(this.dbenv.getEntityStore());
        final EntityIndex<String, fr.iri.thd.sonyengine.core.Tag> ei = da.tagByTrained.subIndex(Boolean.FALSE);
        final EntityCursor<fr.iri.thd.sonyengine.core.Tag> cursor = ei.entities();
        final long untrained = ei.count();
        final List<fr.iri.thd.sonyengine.core.Tag> tagList = new ArrayList<fr.iri.thd.sonyengine.core.Tag>((int) untrained);
        
        try {
                    
            if(force || untrained>this.untrainedLimit)
            {
            
                this.getEngine().reTrain();                

                //final Transaction txn = this.dbenv.getEnv().beginTransaction(null, null);
                
                //try {
                    for (fr.iri.thd.sonyengine.core.Tag tag : cursor) {
                        tag.setTrained(Boolean.TRUE);
                        tagList.add(tag);
                        //da.tagById.put(txn,tag);
                    }
                    //txn.commit();
                //}
                //catch(Exception e) {
                //    if (txn != null)
                //        txn.abort();
                //}
            }
        }
        finally {
            cursor.close();
        }
        
        for (fr.iri.thd.sonyengine.core.Tag tag : tagList) {
            da.tagById.put(tag);
        }

    }
    
    public void train(String tagName) {
        this.getEngine().reTrain(tagName);
    }
    
    public long getUntrainedCount() {
        final DataAccessor da = new DataAccessor(this.dbenv.getEntityStore());
        final EntityIndex<String, fr.iri.thd.sonyengine.core.Tag> ei = da.tagByTrained.subIndex(Boolean.FALSE);
        return ei.count();        
    }
    
    public void clearAll() {
        this.getEngine().clearAll();
    }
    
    public Neighbor findMore(String movieSegmentRef, String tagName, float percent, boolean moreOrLess) {
        return this.getEngine().findMore(movieSegmentRef, tagName, percent, moreOrLess);
    }
    
    public void clearTags(String movieSegmentRef) {
        this.getEngine().clearTags(movieSegmentRef);
    }

    public ThdMovieFragment createMovieFragment(String ref) {
        return this.getEngine().createMovieFragment(ref);
    }
    
    
    public void addTag(String tagName, String movieSegmentRef) {
        this.getEngine().addTag(tagName, movieSegmentRef);
    }
    
    public List<TransformableItem> getAllMovieFragments() {
        return this.getEngine().getAllMovieFragments();
    }

    public void addTags(String[] tags, String ref) {
        this.getEngine().addTags(tags, ref);
    }
    
    public List<ThdMovieFragment> createMovieFragments(String refs) {
        return this.getEngine().createMovieFragments(refs);
    }
    
    public List<Neighbor> findSomeMore(String movieSegmentRef, String tagName, float percent, boolean moreOrLess, int nb) {
        return this.getEngine().findSomeMore(movieSegmentRef, tagName, percent, moreOrLess, nb);
    }
    
    public Tag tagNamed(String tagName) {
        return this.getEngine().tagNamed(tagName);
    }
    
    public ThdMovieFragment movieFragmentNamed(String movieSegmentRef) {
        return this.getEngine().movieFragmentNamed(movieSegmentRef);
    }
    
}
