package executor

import (
	"encoding/json"
	"fmt"
	"sync/atomic"
	"time"
)

const (
	TASK_IDLE 	= 0
	TASK_ACTIVE = 1
	TASK_DONE	= 2

	TASK_CMD_DEFAULT 	= 0
	TASK_CMD_PAUSE 		= 1
)

type conf_params struct{
	Guid int64
	GameId int
}

type task struct {
	Id int64
	Conf *TaskConf
	Cmd int32
	Status int32
	LastActive int64
	LastReturn int32
	ExecutedTimes int64
	StartedAt int64
}

func NewTask(c *TaskConf) *task {
	t := &task{
		Id:             int64(c.Params.(map[string]interface{})["guid"].(float64)),
		Conf:           c,
	}
	return t
}

func NewTaskFromJson(j string) (*task, error) {
	t := &task{}
	err := json.Unmarshal([]byte(j), t)
	if err != nil {
		return nil, err
	}
	// 修复一些值，因为 snapshot 的保存，状态可能不再静止状态
	if t.Status == TASK_ACTIVE {
		t.Status = TASK_IDLE
	}
	return t, nil
}

func (self *task)run(delay int64) {
	now := time.Now().Unix()
	self.LastActive = now

	if delay > 0 {
		self.LastActive += int64(delay)
		time.Sleep(time.Duration(delay) * time.Second)
	}

	status := self.GetStatus()
	if status != TASK_IDLE {
		self.LastReturn = CONDITION_IGNORE
		log(fmt.Sprintf("task quit failed. status=%v", status))
		return
	}

	cmd := self.GetCmd()
	if cmd != TASK_CMD_DEFAULT {
		self.LastReturn = CONDITION_IGNORE
		log(fmt.Sprintf("task quit failed. cmd=%v", cmd))
		return
	}

	executor, err := RegisterGetFunc(self.Conf.Fn)
	if nil != err {
		self.LastReturn = CONDITION_IGNORE
		log(fmt.Sprintf("cannot find executor. err=%v", err))
		return
	}

	if self.StartedAt <= 0 {
		self.StartedAt = now
	}
	self.setStatus(TASK_ACTIVE)

	self.LastReturn = executor.Execute(self.Conf.Params)
	self.setStatus(TASK_IDLE)

	self.ExecutedTimes += 1

	if self.Conf.ValidCondition() {
		if self.LastReturn == self.Conf.Condition {
			self.setStatus(TASK_DONE)
		}
	}
	if self.Conf.ValidTimes() {
		if self.ExecutedTimes >= self.Conf.Times {
			self.setStatus(TASK_DONE)
		}
	}
}

// @return: task's previous status
func (self *task)pause() int32 {
	log(fmt.Sprintf("paused task %v", self.Id))
	return self.setCmd(TASK_CMD_PAUSE)
}

func (self *task)resume() int32 {
	log(fmt.Sprintf("resumed task %v", self.Id))
	return self.setCmd(TASK_CMD_DEFAULT)
}

func (self *task) ToJson() ([]byte, error) {
	return json.Marshal(self)
}

func (self *task)setStatus(newStatus int32) int32 {
	r := self.GetStatus()
	atomic.StoreInt32(&self.Status, newStatus)
	return r
}

func (self *task)GetStatus() int32 {
	return atomic.LoadInt32(&self.Status)
}

func (self *task)setCmd(newCmd int32) int32 {
	r := self.GetCmd()
	atomic.StoreInt32(&self.Cmd, newCmd)
	return r
}

func (self *task)GetCmd() int32 {
	return atomic.LoadInt32(&self.Cmd)
}