package zmo.technology.lite.processors;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import zmo.technology.lite.core.ZeroEnum;
import zmo.technology.lite.core.ZeroProcessor;
import zmo.technology.lite.core.ZeroRequestGuider;

public class ZeroEnumProcessor extends ZeroProcessor {

    protected ZeroEnumProcessor(ZeroRequestGuider guider) {
        super(guider);
    }

    public static ZeroEnumProcessor build(ZeroRequestGuider guider) {
        return new ZeroEnumProcessor(guider);
    }

    private PreparedStatement addEnumPrepared() throws SQLException {
        final String addEnum = "INSERT INTO zero_enums(ID, enum_name, features) VALUES (? ,? ,? ,?)";
        if (!existsPreparedStatement(addEnum))
            registeyPreparedStatement(addEnum);
        return preparedStatement(addEnum);
    }

    private PreparedStatement upEnumPrepared() throws SQLException {
        final String upEnum = "UPDATE zero_enums SET features = ? WHERE ID = ?";
        if (!existsPreparedStatement(upEnum))
            registeyPreparedStatement(upEnum);
        return preparedStatement(upEnum);
    }

    private PreparedStatement rmEnumPrepared() throws SQLException {
        final String rmEnum = "DELETE FROM zero_enums WHERE ID = ?";
        if (!existsPreparedStatement(rmEnum))
            registeyPreparedStatement(rmEnum);
        return preparedStatement(rmEnum);
    }

    private PreparedStatement addEnumGenealogyPrepared() throws SQLException {
        final String addEnumGenealogy = "INSERT INTO zero_enums_genealogy(enum_id ,option_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addEnumGenealogy))
            registeyPreparedStatement(addEnumGenealogy);
        return preparedStatement(addEnumGenealogy);
    }

    private PreparedStatement fetchEnumByNamePrepared() throws SQLException {
        final String fetchEnumByName = "SELECT * FROM zero_enums WHERE enum_name = ?";
        if (!existsPreparedStatement(fetchEnumByName))
            registeyPreparedStatement(fetchEnumByName);
        return preparedStatement(fetchEnumByName);
    }

    private PreparedStatement fetchEnumByParentPrepared() throws SQLException {
        final String fetchByParentEnum = "SELECT * FROM zero_enums_view WHERE group_id = ?";
        if (!existsPreparedStatement(fetchByParentEnum))
            registeyPreparedStatement(fetchByParentEnum);
        return preparedStatement(fetchByParentEnum);
    }

    public void save(ZeroEnum enums) throws SQLException {
        addEnumPrepared().setString(1, enums.uuIDString());
        addEnumPrepared().setString(2, enums.getEnumName());
        addEnumPrepared().setString(3, enums.featuresJSONString());
        addEnumPrepared().execute();
    }

    public void saveGenealogy(String enumID, String optionID) throws SQLException {
        addEnumGenealogyPrepared().setString(1, enumID);
        addEnumGenealogyPrepared().setString(2, optionID);
        addEnumGenealogyPrepared().execute();
    }

    public void addEnum(ZeroEnum enums) throws SQLException {
        addEnum(null, enums);
    }

    public void addEnum(String parentID, ZeroEnum enums) throws SQLException {
        enums.reset();
        save(enums);

        if (parentID != null)
            saveGenealogy(parentID, enums.uuIDString());

        if (enums.getEnumOptions() != null && !enums.getEnumOptions().isEmpty())
            for (ZeroEnum option : enums.getEnumOptions())
                addEnum(enums.uuIDString(), option);
    }

    public void upEnum(ZeroEnum enums) throws SQLException {
        upEnumPrepared().setString(1, enums.featuresJSONString());
        upEnumPrepared().setString(2, enums.uuIDString());
        upEnumPrepared().execute();
    }

    public void rmEnum(ZeroEnum enums) throws SQLException {
        rmEnumPrepared().setString(1, enums.uuIDString());
        rmEnumPrepared().execute();
    }

    public void fetchEnumOptions(ZeroEnum enums, int level) throws SQLException {
        if (level != -1 && level == 0)
            return;

        fetchEnumByParentPrepared().setString(1, enums.uuIDString());
        ResultSet set = fetchEnumByParentPrepared().executeQuery();
        while (set.next())
            enums.addEnumOption(new ZeroEnum(set));

        if (enums.getEnumOptions() != null)
            for (ZeroEnum option : enums.getEnumOptions())
                fetchEnumOptions(option, level == -1 ? level : level - 1);
    }

    public ZeroEnum fetchEnum(String enumName, int level) throws SQLException {
        fetchEnumByNamePrepared().setString(1, enumName);
        ResultSet set = fetchEnumByNamePrepared().executeQuery();
        if (!set.next())
            throw new SQLException("err : '" + enumName + "' not found");
        ZeroEnum enums = new ZeroEnum(set);
        fetchEnumOptions(enums, level);
        return enums;
    }

    public ZeroEnum fetchEnum(String enumName) throws SQLException {
        return fetchEnum(enumName, 0);
    }
}
