package easydo.technology.core.processors;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import easydo.technology.core.EasydoCore.EasydoEnterprise;
import easydo.technology.core.EasydoCore.EasydoMenu;
import easydo.technology.core.EasydoCore.EasydoProject;
import easydo.technology.core.EasydoCore.EasydoRole;
import easydo.technology.core.EasydoCore.EasydoUser;
import easydo.technology.core.EasydoCore.EasydoUserInfo;
import zmo.technology.lite.core.ZeroProcessor;
import zmo.technology.lite.core.ZeroRequestGuider;

public class EasydoCoreProcessor extends ZeroProcessor {

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

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

    /// ---- users and roles

    private PreparedStatement addRolePrepared() throws SQLException {
        final String addRole = "INSERT INTO easydo_roles(ID, features, role_name) VALUES (? ,? ,?)";
        if (!existsPreparedStatement(addRole))
            registeyPreparedStatement(addRole);
        return preparedStatement(addRole);
    }

    public void addRole(EasydoRole role) throws SQLException {
        role.reset();
        addRolePrepared().setString(1, role.uuIDString());
        addRolePrepared().setString(2, role.featuresJSONString());
        addRolePrepared().setString(3, role.getRoleName());
        addRolePrepared().execute();
    }

    private PreparedStatement upRolePrepared() throws SQLException {
        final String upRole = "UPDATE easydo_roles SET role_name = ?, features = ? WHERE ID = ?";
        if (!existsPreparedStatement(upRole))
            registeyPreparedStatement(upRole);
        return preparedStatement(upRole);
    }

    public void upRole(EasydoRole role) throws SQLException {
        upRolePrepared().setString(1, role.getRoleName());
        upRolePrepared().setString(2, role.featuresJSONString());
        upRolePrepared().setString(3, role.uuIDString());
        upRolePrepared().execute();
    }

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

    public void rmRole(EasydoRole role) throws SQLException {
        rmRolePrepared().setString(1, role.uuIDString());
        rmRolePrepared().execute();
    }

    private PreparedStatement fetchRoleByIDPrepared() throws SQLException {
        final String fetchRoleByID = "SELECT * FROM easydo_roles WHERE ID = ? LIMIT 1";
        if (!existsPreparedStatement(fetchRoleByID))
            registeyPreparedStatement(fetchRoleByID);
        return preparedStatement(fetchRoleByID);
    }

    public EasydoRole fetchRoleByID(String roleID) throws SQLException {
        fetchRoleByIDPrepared().setString(1, roleID);
        ResultSet set = fetchRoleByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("role '" + roleID + "' not found");
        return new EasydoRole(set);
    }

    private PreparedStatement addUserPrepared() throws SQLException {
        final String addUser = "INSERT INTO easydo_users(ID, features, username, password) VALUES (? ,? ,? ,md5(?))";
        if (!existsPreparedStatement(addUser))
            registeyPreparedStatement(addUser);
        return preparedStatement(addUser);
    }

    public void addUser(EasydoUser user) throws SQLException {
        user.reset();
        addUserPrepared().setString(1, user.uuIDString());
        addUserPrepared().setString(2, user.featuresJSONString());
        addUserPrepared().setString(3, user.getUsername());
        addUserPrepared().setString(4, user.getPassword());
        addUserPrepared().execute();
    }

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

    public void upUser(EasydoUser user) throws SQLException {
        upUserPrepared().setString(1, user.featuresJSONString());
        upUserPrepared().setString(2, user.uuIDString());
        upUserPrepared().execute();
    }

    private PreparedStatement resetUserPasswordPrepared() throws SQLException {
        final String resetUserPassword = "UPDATE easydo_users SET password = md5(?) WHERE ID = ?";
        if (!existsPreparedStatement(resetUserPassword))
            registeyPreparedStatement(resetUserPassword);
        return preparedStatement(resetUserPassword);
    }

    public void resetUserPassword(EasydoUser user) throws SQLException {
        resetUserPasswordPrepared().setString(1, user.getPassword());
        resetUserPasswordPrepared().setString(2, user.uuIDString());
        resetUserPasswordPrepared().execute();
    }

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

    public void rmUser(EasydoUser user) throws SQLException {
        rmUserPrepared().setString(1, user.uuIDString());
        rmUserPrepared().execute();
    }

    private PreparedStatement fetchUserByIDPrepared() throws SQLException {
        final String fetchUserByID = "SELECT * FROM easydo_users WHERE ID = ? LIMIT 1";
        if (!existsPreparedStatement(fetchUserByID))
            registeyPreparedStatement(fetchUserByID);
        return preparedStatement(fetchUserByID);
    }

    public EasydoUser fetchUserByID(String userID) throws SQLException {
        fetchUserByIDPrepared().setString(1, userID);
        ResultSet set = fetchUserByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("user '" + userID + "' not found");
        return new EasydoUser(set);
    }

    private PreparedStatement addUserInfoPrepared() throws SQLException {
        final String addUserInfo = "INSERT INTO easydo_user_info(ID, features, user_id, nick_name, birthday) VALUES (? ,? ,? ,? ,?)";
        if (!existsPreparedStatement(addUserInfo))
            registeyPreparedStatement(addUserInfo);
        return preparedStatement(addUserInfo);
    }

    public void addUserInfo(EasydoUserInfo userInfo) throws SQLException {
        userInfo.reset();
        addUserInfoPrepared().setString(1, userInfo.uuIDString());
        addUserInfoPrepared().setString(2, userInfo.featuresJSONString());
        addUserInfoPrepared().setString(3, userInfo.getUser().uuIDString());
        addUserInfoPrepared().setString(4, userInfo.getNickName());
        addUserInfoPrepared().setTimestamp(5, new Timestamp(userInfo.getBirthday().getTime()));
        addUserInfoPrepared().execute();
    }

    private PreparedStatement upUserInfoPrepared() throws SQLException {
        final String upUserInfo = "UPDATE easydo_user_info SET features = ? ,nick_name = ? ,birthday = ? WHERE ID = ?";
        if (!existsPreparedStatement(upUserInfo))
            registeyPreparedStatement(upUserInfo);
        return preparedStatement(upUserInfo);
    }

    public void upUserInfo(EasydoUserInfo userInfo) throws SQLException {
        upUserInfoPrepared().setString(1, userInfo.featuresJSONString());
        upUserInfoPrepared().setString(2, userInfo.getNickName());
        upUserInfoPrepared().setTimestamp(3, new Timestamp(userInfo.getBirthday().getTime()));
        upUserInfoPrepared().setString(4, userInfo.uuIDString());
        upUserInfoPrepared().execute();
    }

    private PreparedStatement fetchUserInfoByUserIDPrepared() throws SQLException {
        final String fetchUserInfoByUserID = "SELECT * FROM easydo_user_info WHERE user_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchUserInfoByUserID))
            registeyPreparedStatement(fetchUserInfoByUserID);
        return preparedStatement(fetchUserInfoByUserID);
    }

    public EasydoUserInfo fetchUserInfoByUserID(EasydoUser user) throws SQLException {
        fetchUserInfoByUserIDPrepared().setString(1, user.uuIDString());
        ResultSet set = fetchUserInfoByUserIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("user '" + user.uuIDString() + "' userinfo not found");
        user.setUserInfo(new EasydoUserInfo(set));
        return user.getUserInfo();
    }

    /// ---- menus

    private PreparedStatement addMenusPrepared() throws SQLException {
        final String addMenus = "INSERT INTO easydo_menus(ID, features, sort) VALUES (? ,? ,?)";
        if (!existsPreparedStatement(addMenus))
            registeyPreparedStatement(addMenus);
        return preparedStatement(addMenus);
    }

    public void addMenus(EasydoMenu menu) throws SQLException {
        menu.reset();
        addMenusPrepared().setString(1, menu.uuIDString());
        addMenusPrepared().setString(2, menu.featuresJSONString());
        addMenusPrepared().setInt(3, menu.getSort());
        addMenusPrepared().execute();
    }

    private PreparedStatement upMenuPrepared() throws SQLException {
        final String upMenu = "UPDATE easydo_menus SET sort = ?, features = ? WHERE ID = ?";
        if (!existsPreparedStatement(upMenu))
            registeyPreparedStatement(upMenu);
        return preparedStatement(upMenu);
    }

    public void upMenu(EasydoMenu menu) throws SQLException {
        upMenuPrepared().setInt(1, menu.getSort());
        upMenuPrepared().setString(2, menu.featuresJSONString());
        upMenuPrepared().setString(3, menu.uuIDString());
        upMenuPrepared().execute();
    }

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

    public void rmMenu(EasydoMenu menu) throws SQLException {
        rmMenuPrepared().setString(1, menu.uuIDString());
        rmMenuPrepared().execute();
    }

    private PreparedStatement fetchMenuByIDPrepared() throws SQLException {
        final String fetchMenuByID = "SELECT * FROM easydo_menus WHERE ID = ? LIMIT 1";
        if (!existsPreparedStatement(fetchMenuByID))
            registeyPreparedStatement(fetchMenuByID);
        return preparedStatement(fetchMenuByID);
    }

    public EasydoMenu fetchMenuByID(String menuID) throws SQLException {
        fetchMenuByIDPrepared().setString(1, menuID);
        ResultSet set = fetchMenuByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("menu '" + menuID + "' not found");
        return new EasydoMenu(set);
    }

    private PreparedStatement addMenusRelevancyPrepared() throws SQLException {
        final String addMenusRelevancy = "INSERT INTO easydo_menus_relevancy(menu_id, sub_menu_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addMenusRelevancy))
            registeyPreparedStatement(addMenusRelevancy);
        return preparedStatement(addMenusRelevancy);
    }

    public void addMenusRelevancy(String menuID, String subMenuID) throws SQLException {
        addMenusRelevancyPrepared().setString(1, menuID);
        addMenusRelevancyPrepared().setString(2, subMenuID);
        addMenusRelevancyPrepared().execute();
    }

    private PreparedStatement rmMenusRelevancyPrepared() throws SQLException {
        final String rmMenusRelevancy = "DELETE FROM easydo_menus_relevancy WHERE menu_id = ? AND sub_menu_id = ?";
        if (!existsPreparedStatement(rmMenusRelevancy))
            registeyPreparedStatement(rmMenusRelevancy);
        return preparedStatement(rmMenusRelevancy);
    }

    public void rmMenusRelevancy(String menuID, String subMenuID) throws SQLException {
        rmMenusRelevancyPrepared().setString(1, menuID);
        rmMenusRelevancyPrepared().setString(2, subMenuID);
        rmMenusRelevancyPrepared().execute();
    }

    private PreparedStatement fetchSubMenusPrepared() throws SQLException {
        final String fetchSubMenus = "SELECT * FROM easydo_menus_view WHERE menu_id = ?";
        if (!existsPreparedStatement(fetchSubMenus))
            registeyPreparedStatement(fetchSubMenus);
        return preparedStatement(fetchSubMenus);
    }

    public List<EasydoMenu> fetchSubMenus(EasydoMenu menu) throws SQLException {
        fetchSubMenusPrepared().setString(1, menu.uuIDString());
        ResultSet set = fetchSubMenusPrepared().executeQuery();
        menu.setSubMenus(new ArrayList<>());
        while (set.next())
            menu.getSubMenus().add(new EasydoMenu(set));
        return menu.getSubMenus();
    }

    /// ---- enterprise

    private PreparedStatement addEnterprisePrepared() throws SQLException {
        final String addEnterprise = "INSERT INTO easydo_enterprise(ID, features, enterprise_name, enterprise_code, enterprise_type) VALUES (? ,? ,? ,? ,?)";
        if (!existsPreparedStatement(addEnterprise))
            registeyPreparedStatement(addEnterprise);
        return preparedStatement(addEnterprise);
    }

    public void addEnterprise(EasydoEnterprise enterprise) throws SQLException {
        enterprise.reset();
        addEnterprisePrepared().setString(1, enterprise.uuIDString());
        addEnterprisePrepared().setString(2, enterprise.featuresJSONString());
        addEnterprisePrepared().setString(3, enterprise.getEnterpriseName());
        addEnterprisePrepared().setString(4, enterprise.getEnterpriseCode());
        addEnterprisePrepared().setString(5, enterprise.getEnterpriseType());
        addEnterprisePrepared().execute();
    }

    private PreparedStatement upEnterprisePrepared() throws SQLException {
        final String upEnterprise = "UPDATE easydo_enterprise SET enterprise_name = ?, enterprise_code = ?, enterprise_type = ?, features = ? WHERE ID = ?";
        if (!existsPreparedStatement(upEnterprise))
            registeyPreparedStatement(upEnterprise);
        return preparedStatement(upEnterprise);
    }

    public void upEnterprise(EasydoEnterprise enterprise) throws SQLException {
        upEnterprisePrepared().setString(1, enterprise.getEnterpriseName());
        upEnterprisePrepared().setString(2, enterprise.getEnterpriseCode());
        upEnterprisePrepared().setString(3, enterprise.getEnterpriseType());
        upEnterprisePrepared().setString(4, enterprise.featuresJSONString());
        upEnterprisePrepared().setString(5, enterprise.uuIDString());
        upEnterprisePrepared().execute();
    }

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

    public void rmEnterprise(EasydoEnterprise enterprise) throws SQLException {
        rmEnterprisePrepared().setString(1, enterprise.uuIDString());
        rmEnterprisePrepared().execute();
    }

    private PreparedStatement fetchEnterpriseByIDPrepared() throws SQLException {
        final String fetchEnterpriseByID = "SELECT * FROM easydo_enterprise WHERE ID = ? LIMIT 1";
        if (!existsPreparedStatement(fetchEnterpriseByID))
            registeyPreparedStatement(fetchEnterpriseByID);
        return preparedStatement(fetchEnterpriseByID);
    }

    public EasydoEnterprise fetchEnterpriseByID(String enterpriseID) throws SQLException {
        fetchEnterpriseByIDPrepared().setString(1, enterpriseID);
        ResultSet set = fetchEnterpriseByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("enterprise '" + enterpriseID + "' not found");
        return new EasydoEnterprise(set);
    }

    private PreparedStatement addEnterpriseRelevancyPrepared() throws SQLException {
        final String addEnterpriseRelevancy = "INSERT INTO easydo_enterprise_relevancy(enterprise_id, sub_enterprise_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addEnterpriseRelevancy))
            registeyPreparedStatement(addEnterpriseRelevancy);
        return preparedStatement(addEnterpriseRelevancy);
    }

    public void addEnterpriseRelevancy(String enterpriseID, String subEnterpriseID) throws SQLException {
        addEnterpriseRelevancyPrepared().setString(1, enterpriseID);
        addEnterpriseRelevancyPrepared().setString(2, subEnterpriseID);
        addEnterpriseRelevancyPrepared().execute();
    }

    private PreparedStatement rmEnterpriseRelevancyPrepared() throws SQLException {
        final String rmEnterpriseRelevancy = "DELETE FROM easydo_enterprise_relevancy WHERE enterprise_id = ? AND sub_enterprise_id = ?";
        if (!existsPreparedStatement(rmEnterpriseRelevancy))
            registeyPreparedStatement(rmEnterpriseRelevancy);
        return preparedStatement(rmEnterpriseRelevancy);
    }

    public void rmEnterpriseRelevancy(String enterpriseID, String subEnterpriseID) throws SQLException {
        rmEnterpriseRelevancyPrepared().setString(1, enterpriseID);
        rmEnterpriseRelevancyPrepared().setString(2, subEnterpriseID);
        rmEnterpriseRelevancyPrepared().execute();
    }

    private PreparedStatement fetchSubEnterprisesPrepared() throws SQLException {
        final String fetchSubEnterprises = "SELECT * FROM easydo_enterprise_view WHERE enterprise_id = ?";
        if (!existsPreparedStatement(fetchSubEnterprises))
            registeyPreparedStatement(fetchSubEnterprises);
        return preparedStatement(fetchSubEnterprises);
    }

    public List<EasydoEnterprise> fetchSubEnterprises(EasydoEnterprise enterprise) throws SQLException {
        fetchSubEnterprisesPrepared().setString(1, enterprise.uuIDString());
        ResultSet set = fetchSubEnterprisesPrepared().executeQuery();
        enterprise.setChilds(new ArrayList<>());
        while (set.next())
            enterprise.getChilds().add(new EasydoEnterprise(set));
        return enterprise.getChilds();
    }

    private PreparedStatement fetchEnterpriseMenusPrepared() throws SQLException {
        final String fetchEnterpriseMenus = "SELECT b.* FROM easydo_enterprise_menus a, easydo_menus b WHERE a.enterprise_id = ? AND a.menu_id = b.ID";
        if (!existsPreparedStatement(fetchEnterpriseMenus))
            registeyPreparedStatement(fetchEnterpriseMenus);
        return preparedStatement(fetchEnterpriseMenus);
    }

    public List<EasydoMenu> fetchEnterpriseMenus(EasydoEnterprise enterprise) throws SQLException {
        fetchEnterpriseMenusPrepared().setString(1, enterprise.uuIDString());
        ResultSet set = fetchEnterpriseMenusPrepared().executeQuery();
        enterprise.setMenus(new ArrayList<>());
        while (set.next())
            enterprise.getMenus().add(new EasydoMenu(set));
        return enterprise.getMenus();
    }

    private PreparedStatement fetchEnterpriseProjectsPrepared() throws SQLException {
        final String fetchEnterpriseProjects = "SELECT * FROM easydo_project WHERE enterprise_id = ?";
        if (!existsPreparedStatement(fetchEnterpriseProjects))
            registeyPreparedStatement(fetchEnterpriseProjects);
        return preparedStatement(fetchEnterpriseProjects);
    }

    public List<EasydoProject> fetchEnterpriseProjects(EasydoEnterprise enterprise) throws SQLException {
        fetchEnterpriseProjectsPrepared().setString(1, enterprise.uuIDString());
        ResultSet set = fetchEnterpriseProjectsPrepared().executeQuery();
        enterprise.setProjects(new ArrayList<>());
        while (set.next())
            enterprise.getProjects().add(new EasydoProject(set));
        return enterprise.getProjects();
    }

    /// ---- project

    private PreparedStatement addProjectPrepared() throws SQLException {
        final String addProject = "INSERT INTO easydo_project(ID, features, enterprise_id, project_code, project_name, project_type, project_status, project_scale) VALUES (? ,? ,? ,? ,? ,? ,? ,?)";
        if (!existsPreparedStatement(addProject))
            registeyPreparedStatement(addProject);
        return preparedStatement(addProject);
    }

    public void addProject(EasydoProject project) throws SQLException {
        project.reset();
        addProjectPrepared().setString(1, project.uuIDString());
        addProjectPrepared().setString(2, project.featuresJSONString());
        addProjectPrepared().setString(3, project.getEnterprise().uuIDString());
        addProjectPrepared().setString(4, project.getProjectCode());
        addProjectPrepared().setString(5, project.getProjectName());
        addProjectPrepared().setString(6, project.getProjectType());
        addProjectPrepared().setString(7, project.getProjectStatus());
        addProjectPrepared().setString(8, project.getProjectScale());
        addProjectPrepared().execute();
    }

    private PreparedStatement upProjectPrepared() throws SQLException {
        final String upProject = "UPDATE easydo_project SET project_code = ?, project_name = ?, project_type = ?, project_status = ?, project_scale = ?, features = ? WHERE ID = ?";
        if (!existsPreparedStatement(upProject))
            registeyPreparedStatement(upProject);
        return preparedStatement(upProject);
    }

    public void upProject(EasydoProject project) throws SQLException {
        upProjectPrepared().setString(1, project.getProjectCode());
        upProjectPrepared().setString(2, project.getProjectName());
        upProjectPrepared().setString(3, project.getProjectType());
        upProjectPrepared().setString(4, project.getProjectStatus());
        upProjectPrepared().setString(5, project.getProjectScale());
        upProjectPrepared().setString(6, project.featuresJSONString());
        upProjectPrepared().setString(7, project.uuIDString());
        upProjectPrepared().execute();
    }

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

    public void rmProject(EasydoProject project) throws SQLException {
        rmProjectPrepared().setString(1, project.uuIDString());
        rmProjectPrepared().execute();
    }

    private PreparedStatement fetchProjectByIDPrepared() throws SQLException {
        final String fetchProjectByID = "SELECT * FROM easydo_project WHERE ID = ? LIMIT 1";
        if (!existsPreparedStatement(fetchProjectByID))
            registeyPreparedStatement(fetchProjectByID);
        return preparedStatement(fetchProjectByID);
    }

    public EasydoProject fetchProjectByID(String projectID) throws SQLException {
        fetchProjectByIDPrepared().setString(1, projectID);
        ResultSet set = fetchProjectByIDPrepared().executeQuery();
        if (!set.next())
            throw new SQLException("project '" + projectID + "' not found");
        return new EasydoProject(set);
    }

    /// ---- enterprise menus

    private PreparedStatement addEnterpriseMenusPrepared() throws SQLException {
        final String addEnterpriseMenus = "INSERT INTO easydo_enterprise_menus(enterprise_id, menu_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addEnterpriseMenus))
            registeyPreparedStatement(addEnterpriseMenus);
        return preparedStatement(addEnterpriseMenus);
    }

    public void addEnterpriseMenus(String enterpriseID, String menuID) throws SQLException {
        addEnterpriseMenusPrepared().setString(1, enterpriseID);
        addEnterpriseMenusPrepared().setString(2, menuID);
        addEnterpriseMenusPrepared().execute();
    }

    private PreparedStatement rmEnterpriseMenusPrepared() throws SQLException {
        final String rmEnterpriseMenus = "DELETE FROM easydo_enterprise_menus WHERE enterprise_id = ? AND menu_id = ?";
        if (!existsPreparedStatement(rmEnterpriseMenus))
            registeyPreparedStatement(rmEnterpriseMenus);
        return preparedStatement(rmEnterpriseMenus);
    }

    public void rmEnterpriseMenus(String enterpriseID, String menuID) throws SQLException {
        rmEnterpriseMenusPrepared().setString(1, enterpriseID);
        rmEnterpriseMenusPrepared().setString(2, menuID);
        rmEnterpriseMenusPrepared().execute();
    }

    /// ---- role menus

    private PreparedStatement addRoleMenusPrepared() throws SQLException {
        final String addRoleMenus = "INSERT INTO easydo_role_menus(role_id, menu_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addRoleMenus))
            registeyPreparedStatement(addRoleMenus);
        return preparedStatement(addRoleMenus);
    }

    public void addRoleMenus(String roleID, String menuID) throws SQLException {
        addRoleMenusPrepared().setString(1, roleID);
        addRoleMenusPrepared().setString(2, menuID);
        addRoleMenusPrepared().execute();
    }

    private PreparedStatement rmRoleMenusPrepared() throws SQLException {
        final String rmRoleMenus = "DELETE FROM easydo_role_menus WHERE role_id = ? AND menu_id = ?";
        if (!existsPreparedStatement(rmRoleMenus))
            registeyPreparedStatement(rmRoleMenus);
        return preparedStatement(rmRoleMenus);
    }

    public void rmRoleMenus(String roleID, String menuID) throws SQLException {
        rmRoleMenusPrepared().setString(1, roleID);
        rmRoleMenusPrepared().setString(2, menuID);
        rmRoleMenusPrepared().execute();
    }

    private PreparedStatement fetchRoleMenusPrepared() throws SQLException {
        final String fetchRoleMenus = "SELECT b.* FROM easydo_role_menus a ,easydo_menus b WHERE a.role_id = ? AND a.menu_id = b.ID";
        if (!existsPreparedStatement(fetchRoleMenus))
            registeyPreparedStatement(fetchRoleMenus);
        return preparedStatement(fetchRoleMenus);
    }

    public List<EasydoMenu> fetchRoleMenus(EasydoRole role) throws SQLException {
        fetchRoleMenusPrepared().setString(1, role.uuIDString());
        ResultSet set = fetchRoleMenusPrepared().executeQuery();
        role.setMenus(new ArrayList<>());
        while (set.next())
            role.getMenus().add(new EasydoMenu(set));
        return role.getMenus();
    }

    /// ---- enterprise users

    private PreparedStatement addEnterpriseUsersPrepared() throws SQLException {
        final String addEnterpriseUsers = "INSERT INTO easydo_enterprise_users(enterprise_id, user_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addEnterpriseUsers))
            registeyPreparedStatement(addEnterpriseUsers);
        return preparedStatement(addEnterpriseUsers);
    }

    public void addEnterpriseUsers(String enterpriseID, String userID) throws SQLException {
        addEnterpriseUsersPrepared().setString(1, enterpriseID);
        addEnterpriseUsersPrepared().setString(2, userID);
        addEnterpriseUsersPrepared().execute();
    }

    private PreparedStatement rmEnterpriseUsersPrepared() throws SQLException {
        final String rmEnterpriseUsers = "DELETE FROM easydo_enterprise_users WHERE enterprise_id = ? AND user_id = ?";
        if (!existsPreparedStatement(rmEnterpriseUsers))
            registeyPreparedStatement(rmEnterpriseUsers);
        return preparedStatement(rmEnterpriseUsers);
    }

    public void rmEnterpriseUsers(String enterpriseID, String userID) throws SQLException {
        rmEnterpriseUsersPrepared().setString(1, enterpriseID);
        rmEnterpriseUsersPrepared().setString(2, userID);
        rmEnterpriseUsersPrepared().execute();
    }

    /// ---- project users

    private PreparedStatement addProjectUsersPrepared() throws SQLException {
        final String addProjectUsers = "INSERT INTO easydo_project_users(project_id, user_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addProjectUsers))
            registeyPreparedStatement(addProjectUsers);
        return preparedStatement(addProjectUsers);
    }

    public void addProjectUsers(String projectID, String userID) throws SQLException {
        addProjectUsersPrepared().setString(1, projectID);
        addProjectUsersPrepared().setString(2, userID);
        addProjectUsersPrepared().execute();
    }

    private PreparedStatement rmProjectUsersPrepared() throws SQLException {
        final String rmProjectUsers = "DELETE FROM easydo_project_users WHERE project_id = ? AND user_id = ?";
        if (!existsPreparedStatement(rmProjectUsers))
            registeyPreparedStatement(rmProjectUsers);
        return preparedStatement(rmProjectUsers);
    }

    public void rmProjectUsers(String projectID, String userID) throws SQLException {
        rmProjectUsersPrepared().setString(1, projectID);
        rmProjectUsersPrepared().setString(2, userID);
        rmProjectUsersPrepared().execute();
    }

    /// ---- user role

    private PreparedStatement addUserRolePrepared() throws SQLException {
        final String addUserRole = "INSERT INTO easydo_user_role(user_id ,role_id) VALUES (? ,?)";
        if (!existsPreparedStatement(addUserRole))
            registeyPreparedStatement(addUserRole);
        return preparedStatement(addUserRole);
    }

    public void addUserRole(String userID, String roleID) throws SQLException {
        addUserRolePrepared().setString(1, userID);
        addUserRolePrepared().setString(2, roleID);
        addUserRolePrepared().execute();
    }

    private PreparedStatement rmUserRolePrepared() throws SQLException {
        final String rmUserRole = "DELETE FROM easydo_user_role WHERE user_id = ? AND role_id = ?";
        if (!existsPreparedStatement(rmUserRole))
            registeyPreparedStatement(rmUserRole);
        return preparedStatement(rmUserRole);
    }

    public void rmUserRole(String userID, String roleID) throws SQLException {
        rmUserRolePrepared().setString(1, userID);
        rmUserRolePrepared().setString(2, roleID);
        rmUserRolePrepared().execute();
    }

    private PreparedStatement fetchUserRolesPrepared() throws SQLException {
        final String fetchUserRoles = "SELECT b.* FROM easydo_user_role a ,easydo_roles b WHERE a.user_id = ? AND a.role_id = b.ID";
        if (!existsPreparedStatement(fetchUserRoles))
            registeyPreparedStatement(fetchUserRoles);
        return preparedStatement(fetchUserRoles);
    }

    public List<EasydoRole> fetchUserRoles(EasydoUser user) throws SQLException {
        fetchUserRolesPrepared().setString(1, user.uuIDString());
        ResultSet set = fetchUserRolesPrepared().executeQuery();
        user.setRoles(new ArrayList<>());
        while (set.next())
            user.getRoles().add(new EasydoRole(set));
        return user.getRoles();
    }

    /// ---- dept

    private PreparedStatement fetchProjectDeptIDPrepared() throws SQLException {
        final String fetchProjectDeptID = "SELECT dept_id FROM factory_project_belong WHERE project_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchProjectDeptID))
            registeyPreparedStatement(fetchProjectDeptID);
        return preparedStatement(fetchProjectDeptID);
    }

    public long fetchProjectDeptID(long projectID) throws SQLException {
        fetchProjectDeptIDPrepared().setLong(1, projectID);
        ResultSet set = fetchProjectDeptIDPrepared().executeQuery();
        if (!set.next())
            return -1;
        return set.getLong(1);
    }

    private PreparedStatement fetchDeptParentIDPrepared() throws SQLException {
        final String fetchDeptParentID = "SELECT ifnull(pid, -1) FROM sys_dept WHERE dept_id = ? LIMIT 1";
        if (!existsPreparedStatement(fetchDeptParentID))
            registeyPreparedStatement(fetchDeptParentID);
        return preparedStatement(fetchDeptParentID);
    }

    public long fetchDeptParentID(long deptID) throws SQLException {
        fetchDeptParentIDPrepared().setLong(1, deptID);
        ResultSet set = fetchDeptParentIDPrepared().executeQuery();
        if (!set.next())
            return -1;
        return set.getLong(1);
    }
}
