package logSqlSync

import (
	"database/sql"
	"fmt"
	"time"

	"goutil/logUtil"
)

// 同步信息表是否已经被初始化
var ifSyncingTableInited bool = false

// 同步信息项，保存已经处理过的文件的信息
type syncingModel struct {
	// 服务器组Id
	ServerGroupId int32

	// 待处理文件的绝对路径
	FilePath string

	// 待处理文件的偏移量
	FileOffset int64

	// 更新时间
	UpdateTime time.Time
}

// 同步信息对象
type syncingInfo struct {
	// 服务器组Id
	ServerGroupId int32

	// 同步信息项
	item *syncingModel

	// 数据库连接对象
	db *sql.DB
}

// 获取同步信息
// filePath:正在同步的文件
// fileOffset:同步到的位置
func (this *syncingInfo) GetSyncingInfo() (filePath string, fileOffset int64) {
	return this.item.FilePath, this.item.FileOffset
}

// 更新正在同步的位置和文件信息
// filePath:文件路径
// offset:当前同步到的位置
// tran:事务对象，可以为nil
// 返回值:
// error:处理的错误信息
func (this *syncingInfo) Update(filePath string, offset int64, tran *sql.Tx) error {
	this.item.FilePath = filePath
	this.item.FileOffset = offset
	this.item.UpdateTime = time.Now()

	// 更新到数据库
	return this.update(this.item, tran)
}

// 初始化同步信息
// 返回值:
// error:错误信息
func (this *syncingInfo) init() error {
	// 数据表初始化
	if ifSyncingTableInited == false {
		if err := this.initSyncingInfoTable(this.db); err == nil {
			ifSyncingTableInited = true
		} else {
			return err
		}
	}

	// 获取此表的同步信息
	data, exist, err := this.get()
	if err != nil {
		return err
	}

	// 2. 如果同步信息不存在，则初始化一条到此表
	if exist == false {
		data = &syncingModel{
			ServerGroupId: this.ServerGroupId,
			FilePath:      "",
			FileOffset:    0,
			UpdateTime:    time.Now(),
		}
	}

	this.item = data
	return nil
}

// 初始化同步信息表结构
// db:数据库连接对象
func (this *syncingInfo) initSyncingInfoTable(db *sql.DB) error {
	// 创建同步信息表
	createTableSql := `CREATE TABLE IF NOT EXISTS syncing_info (
    ServerGroupId int NOT NULL COMMENT '服务器组Id',
    FilePath varchar(500) NOT NULL COMMENT '正在同步的文件路径',
    FileOffset bigint(20) NOT NULL COMMENT '偏移量',
    UpdateTime datetime NOT NULL COMMENT '最后一次更新时间',
    PRIMARY KEY (ServerGroupId)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正在同步的文件信息';`
	if _, err := db.Exec(createTableSql); err != nil {
		logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.initSyncingInfoTable Error:%s", err.Error()))
		return err
	}

	return nil
}

// 从数据库获取数据
// 返回值:
// data:获取到的数据
// exist:是否存在此数据
// err:错误信息
func (this *syncingInfo) get() (data *syncingModel, exist bool, err error) {
	//// 从数据库查询
	querySql := fmt.Sprintf("SELECT FilePath,FileOffset,UpdateTime FROM syncing_info WHERE ServerGroupId ='%v'", this.ServerGroupId)
	var rows *sql.Rows
	rows, err = this.db.Query(querySql)
	if err != nil {
		logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
		return
	}
	defer rows.Close()

	if rows.Next() == false {
		exist = false
		return
	}
	exist = true

	// 读取数据
	data = &syncingModel{
		ServerGroupId: this.ServerGroupId,
	}
	err = rows.Scan(&data.FilePath, &data.FileOffset, &data.UpdateTime)
	if err != nil {
		logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.get.Query ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
		return
	}

	return
}

// 把同步信息更新到数据库
// data:待更新的数据
// tran:事务处理对象
// 返回值:
// error:错误信息
func (this *syncingInfo) update(data *syncingModel, tran *sql.Tx) error {
	updateSql := "REPLACE INTO `syncing_info` SET `ServerGroupId` = ?, `FilePath` = ?,`FileOffset` = ?, `UpdateTime` = ?;"
	var err error
	if tran != nil {
		_, err = tran.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
	} else {
		_, err = this.db.Exec(updateSql, data.ServerGroupId, data.FilePath, data.FileOffset, data.UpdateTime)
	}

	if err != nil {
		logUtil.ErrorLog(fmt.Sprintf("logSqlSync/syncingInfo.update ServerGroupId:%v error:%s", this.ServerGroupId, err.Error()))
	}

	return err
}

// 创建同步信息对象
// _dirPath:目录的路径
// _identifier:当前数据的唯一标识（可以使用数据库表名）
// _db:数据库连接对象
// 返回值:
// 同步信息对象
func newSyncingInfoObject(serverGroupId int32, _db *sql.DB) (result *syncingInfo, err error) {
	result = &syncingInfo{
		ServerGroupId: serverGroupId,
		db:            _db,
	}

	err = result.init()

	return result, err
}
