package hoowe.locationmanagerlibrary.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.util.List;

import hoowe.locationmanagerlibrary.hoowe.HooweLocation;
import hoowe.locationmanagerlibrary.hoowe.HooweLocationProvider;

/**
 * Created by Admin on 2017/8/28.
 */

public class LocationDBHelper extends SQLiteOpenHelper {

    private static final String TAG = "DBHelper";

    private static SQLiteDatabase db = null;

    private Context mContext = null;

    private volatile static LocationDBHelper dbHelper = null;

    private TableLocation tableLocation = TableLocation.getInstance(this);

    private boolean isDBReading = false;

    private boolean isDBWriting = false;
    /**
     * 处理数据库写入消息事件
     */
    private Handler dbWriteHandler = null;
    /**
     * 数据库写入操作 - 插入
     */
    private static final int DB_WRITE_ACTION_TYPE_INSERT_CV = 0;
    /**
     * 数据库写入操作 - 批量插入
     */
    private static final int DB_WRITE_ACTION_TYPE_INSERT_CV_LIST = 1;
    /**
     * 数据库写入操作 - 更新
     */
    private static final int DB_WRITE_ACTION_TYPE_UPDATE = 2;
    /**
     * 数据库写入操作 - 删除
     */
    private static final int DB_WRITE_ACTION_TYPE_DELETE = 3;

    public static LocationDBHelper getHelper(Context context) {
        //先检查实例是否存在,如果不存在才进入下面的同步块
        if(dbHelper == null){
            //同步块,线程安全的创建实例
            synchronized (LocationDBHelper.class) {
                //再次检查实例是否存在,如果不存在才真正的创建实例
                dbHelper = new LocationDBHelper(context);
            }
        }
        return dbHelper;
    }

    public LocationDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }
    public LocationDBHelper(Context context) {
        super(context, DBDefine.DBNAME, null, DBDefine.DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        db = database;
        //创建数据表
        createDBTable();
    }

    /**
     * 创建数据表
     */
    private void createDBTable() {
        Log.e(TAG ,":DB CREATE");
        db.execSQL(DBDefine.CREATE_T_LOCATION);
    }

    /**
     * 清除数据库
     */
    private void dropTable() {
        Log.e(TAG, ":DB DROP");
        if ((DBDefine.Tables != null) && (DBDefine.Tables.length > 0)) {
            for (int i = 0; i < DBDefine.Tables.length; i++) {
                String del = "DROP TABLE IF EXISTS " + DBDefine.Tables[i];
                db.execSQL(del);
            }
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
        Log.d(TAG,"database onUpgrade: old version:" + oldVersion
                + " newVersion: " + newVersion);
        if (database != null) {
            db = database;
            dropTable();
            db.setVersion(DBDefine.DBVERSION);
            onCreate(database);
        }else {
            Log.e(TAG,"### database null");
        }
    }

    /**
     * ********************DB属性操作************************
     */
    public void DatabaseReadableClose(SQLiteDatabase database) {
        try {
            database.close();
            this.isDBReading = false;
        } catch (Exception exception) {
            Log.e(TAG, ": [DB Exception->]" + exception.getMessage());
        }
    }

    public SQLiteDatabase DatabaseReadableGet() {
        try {
            if ((!this.isDBReading) && (!this.isDBWriting)) {
                this.isDBReading = true;
                return getReadableDatabase();
            }
        } catch (Exception exception) {
            Log.e(TAG, ":[DB Exception->]" + exception.getMessage());

            this.isDBReading = false;
        }

        return null;
    }

    public void DatabaseWritableClose(SQLiteDatabase database) {
        try {
            database.close();
            this.isDBWriting = false;
        } catch (Exception exception) {
            Log.e(TAG, ":[DB Exception->]" + exception.getMessage());
        }
    }

    public SQLiteDatabase DatabaseWritableGet() {
        try {
            if ((!this.isDBReading) && (!this.isDBWriting)) {
                this.isDBWriting = true;
                return getWritableDatabase();
            } else {
                Log.d(TAG, "[DB] get writeable database err");
                Thread.sleep(10);
            }
        } catch (Exception exception) {
            Log.e(TAG, "[DB Exception->]" + exception.getMessage());
            this.isDBWriting = false;
        }

        return null;
    }

    /**
     * ************************** DBProxy 方法*************************
     */

    public void DbActionRun() {
        dbActionRun();
    }

    /**
     * ********************发送DB写操作 Action************************
     */

    /**
     * 写操作类
     */
    private class DBWriteAction {
        public String command = "";
        public Object value = null;

        public DBWriteAction() {
        }
    }

    /**
     * 处理数据库操作
     *
     * @param action
     * @param command
     * @param value
     */
    private void dbActionDo(int action, String command, Object value) {
        for (int i = 400; i > 0; i--) {
            if (this.dbWriteHandler != null) {
                DBWriteAction writeAction = new DBWriteAction();
                writeAction.command = command;
                writeAction.value = value;

                Message message = this.dbWriteHandler.obtainMessage();
                message.arg1 = action;
                message.obj = writeAction;

                this.dbWriteHandler.sendMessage(message);
                return;
            } else {
                Log.i(TAG, "[DB Waiting ready!!]");
                try {
                    Thread.sleep(5L);
                } catch (Exception exception) {

                }
            }
        }
    }

    private void dbActionRun() {
        this.dbWriteThread.start();
    }

    /**
     * 数据库插入
     * @param table
     * @param values
     */
    protected void insert(String table, ContentValues values) {
        Log.d(TAG, ":[DB]insert  tableName=[" + table + "] cv = [" + values.toString() + "]");

        dbActionDo(DB_WRITE_ACTION_TYPE_INSERT_CV, table, values);
    }

    /**
     * 数据库批量插入
     * @param table
     * @param valuesList
     */
    protected void insert(String table, List<ContentValues> valuesList) {
        Log.d(TAG, ":[DB]insert  tableName=[" + table + "]");

        dbActionDo(DB_WRITE_ACTION_TYPE_INSERT_CV_LIST, table, valuesList);
    }

    /**
     * 数据库更新
     * @param command
     */
    protected void update(String command) {
        Log.d(TAG, ":[DB]update  sql=[" + command + "]");

        dbActionDo(DB_WRITE_ACTION_TYPE_UPDATE, command, null);
    }

    /**
     * 数据库删除
     * @param command
     */
    protected void del(String command) {
        Log.d(TAG, ":[DB]del sql=[" + command + "]");

        dbActionDo(DB_WRITE_ACTION_TYPE_DELETE, command, null);
    }

    /**
     * 数据库写线程
     */
    private Thread dbWriteThread = new Thread() {
        public void run() {
            Log.i(TAG, ":[DB Action Thread Begin]");

            Looper.prepare();

            dbWriteHandler = new Handler(Looper.myLooper()) {
                @Override
                public void handleMessage(Message inputMessage) {
                    Log.i(TAG, ":handle db write message");
                    DBWriteAction dbWriteAction = (DBWriteAction) inputMessage.obj;
                    int actionType = inputMessage.arg1;
                    String command = dbWriteAction.command;

                    try {
                        SQLiteDatabase database = DatabaseWritableGet();


                        if (database != null) {
                            try {
                                Log.i(TAG, "[DB Action Begin] actionType = " + actionType + "; command = " + command);

                                switch (actionType) {
                                    case DB_WRITE_ACTION_TYPE_INSERT_CV:
                                        ContentValues values = (ContentValues) dbWriteAction.value;

                                        if (values != null) {
                                            database.beginTransaction();
                                            database.insert(command, null, values);
                                            database.setTransactionSuccessful();
                                            database.endTransaction();
                                        }
                                        break;
                                    case DB_WRITE_ACTION_TYPE_INSERT_CV_LIST:
                                        @SuppressWarnings("unchecked")
                                        List<ContentValues> valuesList = (List<ContentValues>) dbWriteAction.value;

                                        if (valuesList != null) {
                                            for (ContentValues contentValue : valuesList) {
                                                database.beginTransaction();
                                                database.insert(command, null, contentValue);
                                                database.setTransactionSuccessful();
                                                database.endTransaction();
                                            }
                                        }
                                        break;
                                    case DB_WRITE_ACTION_TYPE_UPDATE:
                                        database.beginTransaction();
                                        database.execSQL(command);
                                        database.setTransactionSuccessful();
                                        database.endTransaction();
                                        break;
                                    case DB_WRITE_ACTION_TYPE_DELETE:
                                        database.beginTransaction();
                                        database.execSQL(command);
                                        database.setTransactionSuccessful();
                                        database.endTransaction();
                                        break;
                                }
                                Log.i(TAG, "[DB Action End]");
                            } catch (Exception exception) {
                                Log.e(TAG, "[DB Exception->]" + exception.getMessage() + ";[command->]" + command);
                            }

                            try {
                                DatabaseWritableClose(database);
                            } catch (Exception exception) {
                                Log.e(TAG, "ERROR close:" + exception.getMessage());
                            }
                        } else {
                            Log.e(TAG, "ERROR readable database is Null");
                        }

                    } catch (Exception exception) {
                        Log.e(TAG, "ERROR getWritableDatabase: " + exception.getMessage());
                    }
                }
            };

            try {
                Thread.sleep(10);
            } catch (Exception exception) {

            }
            Log.i(TAG, ":[DB Action Thread END]");
            Looper.loop();
            return;
        }
    };

    /***************** 位置信息操作 ****************/

    /**
     * 插入新数据
     *
     * @param location
     */
    public void locationInsert(HooweLocation location) {
        tableLocation.locationInsert(location);
    }

    /**
     * 删除位置信息
     *
     * @param locationID
     */
    public void locationRemove(String locationID) {
        tableLocation.locationRemove(locationID);
    }

    /**
     * 根据 locationID 更新位置
     *
     * @param location
     */
    public void locationUpdate(HooweLocation location) {
        tableLocation.locationUpdate(location);
    }

    /**
     * 获取最新的位置信息
     * @return
     */
    public HooweLocation getLatestLocation() {
        return tableLocation.getLatestLocation();
    }

    /**
     * 查询时间段的位置信息
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public List<HooweLocation> locDBLoadByPeriod(long startTime, long endTime) {
        return tableLocation.locDBLoadByPeriod(startTime, endTime);
    }

    /**
     * 查询时间段的位置信息
     *
     * @param time   指定时间
     * @return 返回值可能为 null ,注意处理该返回
     */
    public HooweLocation locDBLoadByTime(long time) {
        return tableLocation.locDBLoadByTime(time, HooweLocationProvider.getInstance().getmFrequency());
    }

}