/*
 * Copyright
 *   2009 axYus - www.axyus.com
 *   2009 C.Bosquet - charles.bosquet@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.dgfip.xemelios.batch;

import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import org.apache.log4j.Logger;

/**
 * Classe regroupant les elements communs aux traitements batch
 * @author CBO
 */
public abstract class Batch extends AbstractBatch {
    private Properties props;
    private List<String> postProcessors;
    private boolean started = false;

    /**
     * @param args Arguments éventuels de la ligne de commande
     */
    public Batch(String args[]) {
        super(args);
        BatchRunner.getInstance().registerBatch(this);
    }

    @Override
    protected void finalize() throws Throwable {
        BatchRunner.getInstance().unregisterBatch(this);
        super.finalize();
    }


    @Override
    protected void initialize() throws Exception {
        super.initialize();
        checkDirectories();
    }

    protected void checkDirectories() throws Exception { }

    @Override
    protected void processTerminaison() throws Exception {
//        Connection connection = null;
//        try {
//            connection = PoolManager.getInstance().getConnection();
//        } finally {
//            PoolManager.getInstance().releaseConnection(connection);
//        }
    }

    @Override
    protected boolean canStart() throws Exception {
        return true;
    }


    /**
     * Implémentation du traitement
     * @throws Exception
     */
    protected abstract void doProcess() throws Exception;

    /**
     * @return Resumé du traitement exemple: 35 fichiers traites avec succès, 3 dossiers en erreur
     */
    abstract public String getResumeTraitement();

    /**
     * @return Le refCode du type de traitement
     */
    abstract public String typeTraitementRefCode();

    @Override
    protected void process() throws Exception {
        startRapportTraitements();
        try {
            started = true;
            doProcess();
        } catch (Throwable e) {
        } finally {
            endRapportTraitements();
        }
    }

    public boolean isStarted() { return started; }

    /**
     * Démarre le rapport du traitement
     */
    private void startRapportTraitements() throws SQLException { }

    /**
     *  Met fin au rapport traitememt
     */
    private void endRapportTraitements() throws SQLException { }

    public Properties getProps() {
        return props;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

    public List<String> getPostProcessors() {
        return postProcessors;
    }

    public void setPostProcessors(List<String> postProcessors) {
        this.postProcessors = postProcessors;
    }

    public abstract String getInformations();

    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof  Batch)
            return hashCode()==obj.hashCode();
        else
            return obj.equals(this);
    }


    public abstract class RunnableBatch extends Thread {
        private ThreadPool notifier = null;
        public void setNotifier(ThreadPool th) {
            this.notifier=th;
        }
        public ThreadPool getNotifier() { return notifier; }
        public abstract String getInformations();
    }
    public static class ThreadPool<T extends RunnableBatch> {
        private static final Logger logger = Logger.getLogger(ThreadPool.class);
        private List<T> threads;
        private int maxConcurrentThreads;
        private int runningThreads = 0;
        public ThreadPool(List<T> threads) {
            super();
            this.threads=threads;
        }
        public void notifyThreadStop(T thread) {
            threads.remove(thread);
            runningThreads--;
            synchronized(this) {
                for(RunnableBatch aThread:threads) {
                    if(runningThreads==maxConcurrentThreads) break;
                    if(!aThread.isAlive()) {
                        aThread.setNotifier(this);
                        runningThreads++;
                        aThread.start();
                    }
                }
            }
        }
        public void start(int maxConcurrentThreads) {
            logger.debug("starting with "+maxConcurrentThreads+" max threads");
            this.maxConcurrentThreads=maxConcurrentThreads;
            while(runningThreads<maxConcurrentThreads && threads.size()>0) {
                for(int i=0;i<threads.size();i++) {
                    if(!threads.get(i).isAlive()) {
                        threads.get(i).setNotifier(this);
                        runningThreads++;
                        threads.get(i).start();
                        break;
                    }
                }
            }
        }
        public int getRunningThreadCount() { return runningThreads; }
        public List<T> getThreads() { return threads; }
    }

}
