package base

import (
	"Server-Core/Server/Base/Log"
	"sync"
	"time"
)

const (
	TimerNearShift  = 8
	TimerNear       = 1 << TimerNearShift
	TimerNearMask   = TimerNear - 1
	TimerLevelShift = 6
	TimerLevel      = 1 << TimerLevelShift
	TimerLevelMask  = TimerLevel - 1
)

type Timer struct {
	near      [TimerNear]linkList
	t         [4][TimerLevel]linkList
	lock      sync.Locker
	time      uint32
	startTime uint32
	current   uint64
}

type timerNode struct {
	next   *timerNode
	expire uint32
	f      func([]interface{})
	argv   []interface{}
}

type linkList struct {
	head timerNode
	tail *timerNode
}

func CreateTimer() (timer *Timer) {
	timer = new(Timer)

	timer.lock = NewSpinLock()

	for i := range timer.near {
		linkClear(&timer.near[i])
	}

	for i := range timer.t {
		for j := range timer.t[i] {
			linkClear(&timer.t[i][j])
		}
	}

	timer.startTime, timer.current = sysTime()

	return
}

func (timer *Timer) Run() {
	_, cs := sysTime()
	if cs < timer.current {
		log.Error("time diff error from:%d", timer.current)
	} else {
		diff := cs - timer.current
		timer.current += diff
		for i := 0; i < int(diff); i++ {
			timer.update()
		}
	}
}

func (timer *Timer) Add(time int, f func([]interface{}), argv ...interface{}) {
	node := new(timerNode)
	timer.lock.Lock()
	defer timer.lock.Unlock()

	node.expire = uint32(time) + timer.time
	node.f = f
	node.argv = argv
	timer.addNode(node)
}

func (timer *Timer) update() {
	timer.lock.Lock()
	defer timer.lock.Unlock()

	timer.execute()
	timer.shift()
	timer.execute()
}

func (timer *Timer) execute() {
	idx := timer.time & TimerNearMask

	for timer.near[idx].head.next != nil {
		node := linkClear(&timer.near[idx])
		timer.lock.Unlock()
		dispatch(node)
		timer.lock.Lock()
	}
}

func (timer *Timer) shift() {
	mask := uint32(TimerNear)
	timer.time++
	ct := timer.time
	if ct == 0 {
		timer.moveList(3, 0)
	} else {
		time := ct >> TimerNearShift
		for i := 0; (ct & (mask - 1)) == 0; i++ {
			idx := time & TimerLevelMask
			if idx != 0 {
				timer.moveList(i, idx)
				break
			}
			mask <<= TimerLevelShift
			time >>= TimerLevelShift
		}
	}
}

func (timer *Timer) moveList(level int, idx uint32) {
	current := linkClear(&timer.t[level][idx])
	for current != nil {
		next := current.next
		timer.addNode(current)
		current = next
	}
}

func (timer *Timer) addNode(node *timerNode) {
	time := node.expire
	currentTime := timer.time

	if (time | TimerNearMask) == (currentTime | TimerNearMask) {
		link(&timer.near[time&TimerNearMask], node)
	} else {
		var i int
		var mask uint32 = TimerNear << TimerLevelShift
		for i = 0; i < 3; i++ {
			if (time | (mask - 1)) == (currentTime | (mask - 1)) {
				break
			}
			mask <<= TimerLevelShift
		}
		link(&timer.t[i][((time>>(TimerNearShift+i*TimerLevelShift))&TimerLevelMask)], node)
	}
}

func sysTime() (sec uint32, cs uint64) {
	t := time.Now()
	sec = uint32(t.Unix())
	cs = uint64(t.UnixNano() / 10000000)
	return
}

func linkClear(list *linkList) (node *timerNode) {
	node = list.head.next
	list.head.next = nil
	list.tail = &list.head
	return
}

func link(list *linkList, node *timerNode) {
	list.tail.next = node
	list.tail = node
	node.next = nil
}

func dispatch(node *timerNode) {
	for node != nil {
		node.f(node.argv)
		node = node.next
	}
}
