/*
 *    LearningManager.java
 *    Copyright (C) 2012-2013 Aristotle University of Thessaloniki, Greece
 */
package dbn;

import dbn.classifier.neural.DBLearner;
import dbn.data.OptionsHandler;
import mulan.classifier.MultiLabelLearnerBase;
import mulan.classifier.meta.thresholding.OneThreshold;
import mulan.data.InvalidDataFormatException;
import mulan.data.MultiLabelInstances;
import mulan.evaluation.measure.SubsetAccuracy;

/**
 * A control class that manages the learning task. It sets up the {@link Learner}
 * using the {@link OptionsHandler} of the user's options and trains the {@link DeepBeliefNetwork}.
 *
 * @see OptionsHandler
 * @see DBLearner
 * @author Evripidis Gkanias
 */
public class LearningManager {
    /**
     * The Threshold Learner.
     */
    private OneThreshold learner;
    /**
     * The Learner of the neural network.
     */
    private DBLearner dblearner;
    /**
     * Informs if learner has been initialized.
     */
    private boolean isSetLearnerParameters = false;
    /**
     * The training set.
     */
    private MultiLabelInstances trainigSet;
    
    /**
     * The constructor. It initializes the {@link Learner}.
     */
    public LearningManager() {
        this.dblearner = new DBLearner();
        this.learner = null;
    }
    
    /**
     * Sets up the {@link Learner}. If this method is not called, the 
     * learning task cannot start.<br />
     * Throws an exception when the training data are not in the appropriate
     * format.
     * 
     * @param argHandler the handler of the user's options.
     * @throws InvalidDataFormatException 
     */
    public void SetLearnerParameters(OptionsHandler argHandler) throws InvalidDataFormatException, Exception {
        this.dblearner.setDBN(argHandler.getNN());
        this.dblearner.setPreTrainingEpochs(argHandler.getGreedyEpochs());
        this.dblearner.setBPEpochs(argHandler.getBPEpochs());
        this.dblearner.setLearningRate(argHandler.getLearningRate());
        this.dblearner.setMomentum(argHandler.getMomentum());
        this.dblearner.setWeightCost(argHandler.getWeightCost());
        if (argHandler.getThreshold() > 0)
            this.dblearner.setThreshold(argHandler.getThreshold());
        this.dblearner.setDebug(argHandler.getDebug());
        this.trainigSet = argHandler.getTrainSet();
        this.isSetLearnerParameters = true;
        try {
            this.dblearner.getThreshold();
        } catch (NullPointerException ex) {
            this.learner = new OneThreshold(this.dblearner.makeCopy(), new SubsetAccuracy());
            this.learner.setDebug(argHandler.getDebug());
        }
    }
    
    /**
     * This method starts the learning task. <br />
     * It throws an exception if the {@link Learner} has not been set.
     * 
     * @return the duration of the learning task in milliseconds
     * @throws Exception 
     */
    public long startLearning() throws Exception {
        if (!this.isSetLearnerParameters) throw new Exception("Learner not setted!");
        
        long start = System.currentTimeMillis();
        if (this.learner != null) {
            this.learner.build(this.trainigSet);
        } else {
            this.dblearner.build(this.trainigSet);
        }
        
        return System.currentTimeMillis() - start;
        
    }
    
    /**
     * Gets the {@link MultiLabelLearnerBase} (trained or not).
     * 
     * @return the {@link MultiLabelLearnerBase}
     */
    public MultiLabelLearnerBase getLearner() {
        try {
            this.dblearner.getThreshold();
            return this.dblearner;
        } catch (Exception ex) {
            return this.learner;
        }
    }
    
    /**
     * Gets the {@link DBLearner} (trained or not).
     * 
     * @return the {@link DBLearner}
     */
    public DBLearner getDBLearner() {
        return this.dblearner;
    }
    
}
