package hotime

import (
	"encoding/json"
	"strings"
	"time"
)

type CacheDb struct {
	Time int64
	Db   *HoTimeDB
	contextBase
	isInit bool
}

func (this *CacheDb) initDbTable() {
	if this.isInit {
		return
	}
	if this.Db.Type == "mysql" {

		dbNames := this.Db.Query("SELECT DATABASE()")

		if len(dbNames) == 0 {
			return
		}
		dbName := dbNames[0].GetString("DATABASE()")
		res := this.Db.Query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='" + dbName + "' AND TABLE_NAME='cached'")
		if len(res) != 0 {
			this.isInit = true
			return
		}

		_, e := this.Db.Exec("CREATE TABLE `cached` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `ckey` varchar(60) DEFAULT NULL, `cvalue` varchar(2000) DEFAULT NULL, `time` bigint(20) DEFAULT NULL, `endtime` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=198740 DEFAULT CHARSET=utf8")
		if e.GetError() == nil {
			this.isInit = true
		}

	}

	if this.Db.Type == "sqlite" {
		res := this.Db.Query(`select * from sqlite_master where type = 'table' and name = 'cached'`)

		if len(res) != 0 {
			this.isInit = true
			return
		}
		_, e := this.Db.Exec(`CREATE TABLE "cached" (
			"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
				"ckey" TEXT(60),
				"cvalue" TEXT(2000),
				"time" integer,
				"endtime" integer
			);`)
		if e.GetError() == nil {
			this.isInit = true
		}

	}

}

//获取Cache键只能为string类型
func (this *CacheDb) get(key string) interface{} {

	cached := this.Db.Get("cached", "*", Map{"ckey": key})

	if cached == nil {
		return nil
	}
	//data:=cacheMap[key];
	if cached.GetInt64("endtime") <= time.Now().Unix() {

		this.Db.Delete("cached", Map{"id": cached.GetString("id")})
		return nil
	}

	data := Map{}
	data.JsonToMap(cached.GetString("cvalue"))

	return data.Get("data")
}

//key value ,时间为时间戳
func (this *CacheDb) set(key string, value interface{}, tim int64) {

	bte, _ := json.Marshal(Map{"data": value})

	num := this.Db.Update("cached", Map{"cvalue": string(bte), "time": time.Now().UnixNano(), "endtime": tim}, Map{"ckey": key})
	if num == int64(0) {
		this.Db.Insert("cached", Map{"cvalue": string(bte), "time": time.Now().UnixNano(), "endtime": tim, "ckey": key})
	}

	//随机执行删除命令
	if Rand(1000) > 950 {
		this.Db.Delete("cached", Map{"endtime[<]": time.Now().Unix()})
	}
}

func (this *CacheDb) delete(key string) {

	del := strings.Index(key, "*")
	//如果通配删除
	if del != -1 {
		key = Substr(key, 0, del)
		this.Db.Delete("cached", Map{"ckey": key + "%"})

	} else {
		this.Db.Delete("cached", Map{"ckey": key})
	}
}

func (this *CacheDb) Cache(key string, data ...interface{}) *Obj {

	this.initDbTable()

	if len(data) == 0 {
		return &Obj{Data: this.get(key)}
	}
	tim := time.Now().Unix()

	if len(data) == 1 && data[0] == nil {
		this.delete(key)
		return &Obj{Data: nil}
	}

	if len(data) == 1 {
		if this.Time == 0 {
			this.Time = Config.GetInt64("cacheLongTime")
		}
		tim += this.Time
	}
	if len(data) == 2 {
		this.SetError(nil)
		tempt := ObjToInt64(data[1], &this.Error)

		if tempt > tim {
			tim = tempt
		} else if this.GetError() == nil {

			tim = tim + tempt
		}
	}
	this.set(key, data[0], tim)
	return &Obj{Data: nil}
}
