package usda.weru.weps.reports.query;

import de.schlichtherle.truezip.file.TFile;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import usda.weru.mcrew.ManageData;
import usda.weru.util.ConfigData;
import usda.weru.util.WepsFileTypes;

/**
 *
 * @author joelevin
 */
public class DatabaseManagementsResultSet extends WepsResultSet {

    private static final Logger LOGGER = Logger.getLogger(DatabaseManagementsResultSet.class);

    /**
     *
     */
    public static final String NAME = "databasemanagements";

    /**
     *
     */
    public static final String COLUMN_NAME = "name";

    /**
     *
     */
    public static final String COLUMN_NOTES = "notes";

    /**
     *
     */
    public static final String COLUMN_PATH = "path";

    /**
     *
     */
    public static final String COLUMN_FILE = "file";
    private final WepsConnection c_con;
    private boolean c_filled;
    private String c_path = "";

    private final Object LOCK_UP = new Object();

    int up;

    /**
     *
     * @param con
     * @throws SQLException
     */
    public DatabaseManagementsResultSet(WepsConnection con) throws SQLException {
        c_con = con;
        addColumn(COLUMN_NAME, Types.VARCHAR, 100, 0);
        addColumn(COLUMN_NOTES, Types.VARCHAR, 5000, 0);
        addColumn(COLUMN_PATH, Types.VARCHAR, 256, 0);
        addColumn(COLUMN_FILE, Types.VARCHAR, 256, 0);
    }

    /**
     *
     * @return
     */
    @Override
    public String getName() {
        return NAME;
    }

    /**
     *
     * @throws SQLException
     */
    @Override
    public synchronized void fill() throws SQLException {
        String dbPath = ConfigData.getDefault().getDataParsed(ConfigData.ManTemp);
        if(c_path.equals(dbPath))
        {
            if (c_filled) {
                return;
            }
        }
        c_path = dbPath;
        
        if (dbPath == null || dbPath.trim().length() == 0) {
            LOGGER.warn("Management database path not found:" + (dbPath != null ? dbPath : "null"));
            return;
        }

        final TFile db = new TFile(dbPath);

        final Queue<TFile> stack = new ConcurrentLinkedQueue<TFile>();

        ExecutorService workers = Executors.newFixedThreadPool(5);
        up();
        Future<?> futureTraverse = workers.submit(new Runnable() {

            @Override
            public void run() {
                try {
                    traverse(stack, db);
                } finally {
                    down();
                }
            }
        });

        while (!stack.isEmpty() || !futureTraverse.isDone()) {
            final TFile file = stack.poll();
            if (file == null) {
                continue;
            }

            up();
            workers.execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        ManageData man = new ManageData();
                        int result = man.readDataFile(file.getAbsolutePath());
                        if (result == ManageData.kSuccess) {
                            addManToResultSet(db, file, man);
                        }
                    } finally {
                        down();
                    }
                }
            });
        }

        untilDown();

        c_filled = true;
    }

    private void up() {
        synchronized (LOCK_UP) {
            up++;
        }

    }

    private void down() {
        synchronized (LOCK_UP) {
            up--;

            LOCK_UP.notifyAll();
        }
    }

    private void untilDown() {
        while (up > 0) {
            try {
                synchronized (LOCK_UP) {
                    LOCK_UP.wait();
                }

            } catch (Exception e) {
                LOGGER.error("Unable to wait.", e);
            }
        }
    }

    private void addManToResultSet(TFile db, TFile file, ManageData man) {
        try {
            Object[] row = createNewRow(true);
            setRowValue(row, COLUMN_NAME, file.getName().subSequence(0, file.getName().lastIndexOf(".")));

            //chop off the db path
            String path = file.getParentFile().getAbsolutePath().substring(db.getAbsolutePath().length());
            if (path.trim().length() == 0) {
                path = "/";
            }
            path = path.replace("\\", "/");
            setRowValue(row, COLUMN_PATH, path);
            setRowValue(row, COLUMN_FILE, file.getName());
            String notes = man.getWepsManFileNotes();
            if (notes == null || notes.trim().equalsIgnoreCase("Enter notes here.")) {
                notes = "";
            }
            setRowValue(row, COLUMN_NOTES, notes);

        } catch (SQLException se) {
            LOGGER.error("Unable to add management to resultset: " + file.getAbsolutePath(), se);
        }

    }

    private void traverse(final Collection<TFile> addTo, TFile file) {
        if (WepsFileTypes.Management.accept(file)) {
            addTo.add(file);
        } else if (file.isDirectory()) {
            for (TFile child : file.listFiles()) {
                traverse(addTo, child);
            }
        }
    }

}
