package cache

import (
	. "../common"
	"strings"
	"sync"
	"time"
)

type CacheMemory struct {
	TimeOut    int64
	DbSet      bool
	SessionSet bool
	Map
	*Error
	ContextBase
	mutex *sync.RWMutex
}

func (this *CacheMemory) GetError() *Error {

	return this.Error

}

func (this *CacheMemory) SetError(err *Error) {
	this.Error = err
}

//获取Cache键只能为string类型
func (this *CacheMemory) get(key string) interface{} {
	this.Error.SetError(nil)
	if this.Map == nil {
		this.Map = Map{}
	}

	if this.Map[key] == nil {
		return nil
	}
	data := this.Map.Get(key, this.Error).(cacheData)
	if this.Error.GetError() != nil {
		return nil
	}

	if data.time < time.Now().Unix() {
		delete(this.Map, key)
		return nil
	}
	return data.data
}

func (this *CacheMemory) refreshMap() {

	go func() {
		this.mutex.Lock()
		defer this.mutex.Unlock()
		for key, v := range this.Map {
			data := v.(cacheData)
			if data.time <= time.Now().Unix() {
				delete(this.Map, key)
			}
		}

	}()

}

//key value ,时间为时间戳
func (this *CacheMemory) set(key string, value interface{}, time int64) {
	this.Error.SetError(nil)
	var data cacheData

	if this.Map == nil {
		this.Map = Map{}
	}

	dd := this.Map[key]

	if dd == nil {
		data = cacheData{}
	} else {
		data = dd.(cacheData)
	}

	data.time = time
	data.data = value

	this.Map.Put(key, data)
}

func (this *CacheMemory) delete(key string) {
	del := strings.Index(key, "*")
	//如果通配删除
	if del != -1 {
		key = Substr(key, 0, del)
		for k, _ := range this.Map {
			if strings.Index(k, key) != -1 {
				delete(this.Map, k)

			}
		}

	} else {
		delete(this.Map, key)
	}

}

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

	x := RandX(1, 100000)
	if x > 99950 {
		this.refreshMap()
	}
	if this.mutex == nil {
		this.mutex = &sync.RWMutex{}
	}

	reData := &Obj{Data: nil}

	if len(data) == 0 {
		this.mutex.RLock()
		reData.Data = this.get(key)
		this.mutex.RUnlock()
		return reData
	}
	tim := time.Now().Unix()

	if len(data) == 1 && data[0] == nil {
		this.mutex.Lock()
		this.delete(key)
		this.mutex.Unlock()
		return reData
	}

	if len(data) == 1 {

		tim = tim + this.TimeOut

	}
	if len(data) == 2 {
		this.Error.SetError(nil)
		tempt := ObjToInt64(data[1], this.Error)

		if tempt > tim {

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

			tim = tim + tempt
		}
	}
	this.mutex.Lock()
	this.set(key, data[0], tim)
	this.mutex.Unlock()
	return reData

}