package xyz.wbsite.wsqlite;

import xyz.wbsite.wsqlite.anonation.TableField;

import java.io.File;
import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * xyz.wbsite.wsqlite.Client
 *
 * @author wangbing
 */
public class ObjectClient extends Client {

    private Map<String, Class> classMap = new HashMap();

    /**
     * 构造函数
     *
     * @param dbFile    文件
     * @param classList 注册对象
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    public ObjectClient(File dbFile, List<Class> classList) throws ClassNotFoundException, SQLException {
        super(dbFile);
        for (Class aClass : classList) {
            classMap.put(aClass.getName(), aClass);
        }
        for (String key : classMap.keySet()) {
            Class object = classMap.get(key);
            StringBuffer sql = new StringBuffer();
            String name = object.getSimpleName();

            sql.append("CREATE TABLE IF NOT EXISTS ");
            sql.append(name);
            sql.append(" (");

            Field[] fields = object.getDeclaredFields();
            for (Field f : fields) {
                if (f.isAnnotationPresent(TableField.class)) {
                    TableField bind = f.getAnnotation(TableField.class);
                    int length = bind.value();

                    if (f.getType() == String.class) {
                        sql.append(f.getName().toUpperCase());
                        sql.append(" VARCHAR(" + length + "),");
                    } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
                        sql.append(f.getName().toUpperCase());
                        sql.append(" BOOLEAN,");
                    }
                }
            }

            sql.replace(sql.length() - 1, sql.length(), "");
            sql.append(")");
            System.out.println("SQL ==> " + sql.toString());
            execute(sql.toString());
        }
    }

    public <T> void insert(Class<T> poClass, T po) throws SQLException, ClassNotFoundException {
        try {
            Class aClass = classMap.get(poClass.getName());
            if (aClass == null) {
                System.err.println(poClass.getName() + " not found.");
            } else {
                StringBuffer sql = new StringBuffer();
                sql.append("INSERT INTO ");
                sql.append(aClass.getSimpleName());
                sql.append("(");

                //获取字段列表
                List<Field> fs = getFields(poClass);

                StringBuffer fieldsSql = new StringBuffer();
                StringBuffer valueSql = new StringBuffer();

                for (int i = 0; i < fs.size(); i++) {
                    Field f = fs.get(i);
                    f.setAccessible(true);
                    fieldsSql.append(f.getName().toUpperCase());

                    Object value = f.get(po);
                    if (f.getType() == String.class) {
                        valueSql.append("'");
                        valueSql.append(value);
                        valueSql.append("'");
                    } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
                        valueSql.append("'");
                        valueSql.append(String.valueOf(value));
                        valueSql.append("'");
                    } else {
                        valueSql.append(value);
                    }
                    if (i != fs.size() - 1) {
                        fieldsSql.append(",");
                        valueSql.append(",");
                    }
                }

                sql.append(fieldsSql);
                sql.append(") VALUES (");
                sql.append(valueSql);
                sql.append(")");
                System.out.println("SQL ==> " + sql.toString());
                executeUpdate(sql.toString());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            destroyed();
        }
    }

    public <T> int delete(Class<T> poClass, String... wheres) throws SQLException, ClassNotFoundException {
        try {
            Class aClass = classMap.get(poClass.getName());
            if (aClass == null) {
                System.err.println(poClass.getName() + " not found.");
            } else {
                StringBuffer sql = new StringBuffer();
                sql.append("DELETE FROM ");
                sql.append(aClass.getSimpleName());

                if (wheres.length > 0) {
                    sql.append(" WHERE ");
                    for (int i = 0; i < wheres.length; i++) {
                        String where = wheres[i];
                        sql.append(where);
                        sql.append(i != wheres.length - 1 ? " AND " : "");
                    }
                }
                return executeUpdate(sql.toString());
            }
        } finally {
            destroyed();
        }
        return 0;
    }

    public <T> int update(Class<T> poClass, T po, String... wheres) throws SQLException, ClassNotFoundException {
        try {
            Class aClass = classMap.get(poClass.getName());
            if (aClass == null) {
                System.err.println(poClass.getName() + " not found.");
            } else {
                StringBuffer sql = new StringBuffer();
                sql.append("UPDATE ");
                sql.append(aClass.getSimpleName());
                sql.append(" SET ");

                //获取字段列表
                List<Field> fs = getFields(poClass);

                for (int i = 0; i < fs.size(); i++) {
                    Field f = fs.get(i);
                    f.setAccessible(true);
                    sql.append(f.getName());
                    sql.append(" = ");

                    Object value = f.get(po);
                    if (f.getType() == String.class) {
                        sql.append("'");
                        sql.append(value);
                        sql.append("'");
                    } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
                        sql.append("'");
                        sql.append(String.valueOf(value));
                        sql.append("'");
                    } else {
                        sql.append(value);
                    }
                    if (i != fs.size() - 1) {
                        sql.append(",");
                    }
                }

                if (wheres.length > 0) {
                    sql.append(" WHERE ");
                    for (int i = 0; i < wheres.length; i++) {
                        String where = wheres[i];
                        sql.append(where);
                        sql.append(i != wheres.length - 1 ? " AND " : "");
                    }
                }

                System.out.println("SQL ==> " + sql.toString());
                return executeUpdate(sql.toString());
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            destroyed();
        }
        return 0;
    }

    public <T> List<T> select(Class<T> poClass, int pageNumber, int pageSize, String... wheres) throws SQLException, ClassNotFoundException {
        ArrayList<T> list = new ArrayList();
        try {
            Class aClass = classMap.get(poClass.getName());
            if (aClass == null) {
                System.err.println(poClass.getName() + " not found.");
            } else {
                StringBuffer sql = new StringBuffer();
                sql.append("SELECT ");

                //获取字段列表
                List<Field> fs = getFields(poClass);

                for (int i = 0; i < fs.size(); i++) {
                    Field f = fs.get(i);
                    sql.append(f.getName().toUpperCase());
                    if (i != fs.size() - 1) {
                        sql.append(",");
                    }
                }

                sql.append(" FROM ");
                sql.append(aClass.getSimpleName());

                //条件参数
                if (wheres.length > 0) {
                    sql.append(" WHERE ");
                    for (int i = 0; i < wheres.length; i++) {
                        String where = wheres[i];
                        sql.append(where);
                        sql.append(i != wheres.length - 1 ? " AND " : "");
                    }
                }

                //分页参数
                sql.append(" LIMIT " + (pageNumber - 1) + "," + pageSize);

                System.out.println("SQL ==> " + sql.toString());
                list.addAll(executeQuery(sql.toString(), poClass));
            }
        } finally {
            destroyed();
        }
        return list;
    }

    /**
     * 执行select查询，返回结果列表
     *
     * @param sql     sql select 语句
     * @param poClass 结果集的行数据处理类对象
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public <T> List<T> executeQuery(String sql, Class<T> poClass) throws SQLException, ClassNotFoundException {
        List<T> rsList = new ArrayList<T>();
        try {
            resultSet = executeQuery(sql);

            //获取字段列表
            List<Field> fs = getFields(poClass);

            while (resultSet.next()) {
                try {
                    T o = poClass.newInstance();
                    for (int i = 0; i < fs.size(); i++) {
                        Field f = fs.get(i);
                        f.setAccessible(true);

                        if (f.getType() == String.class) {
                            String string = resultSet.getString(f.getName());
                            f.set(o, string);
                        } else if (f.getType() == Boolean.class || f.getType() == boolean.class) {
                            boolean b = resultSet.getBoolean(f.getName());
                            f.set(o, b);
                        } else {
                            String string = resultSet.getString(f.getName());
                            f.set(o, string);
                        }
                    }
                    rsList.add(o);
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            destroyed();
        }
        return rsList;
    }

    private List<Field> getFields(Class aClass) {
        List<Field> fs = new ArrayList();
        for (Field f : aClass.getDeclaredFields()) {
            if (f.isAnnotationPresent(TableField.class)) {
                fs.add(f);
            }
        }
        return fs;
    }
}