// dbif.go
package dbif

import (
	"fmt"
	"log"
	"pool/internal/cache"
	"pool/internal/db"
	"pool/internal/server/coin"
	"strconv"

	//"strings"
	"time"
)

const MINER_UPDATE_MINERS_DB_DURATION time.Duration = 5

/*const MINER_UPDATE_MINERS_STATS_DB_DURATION time.Duration = 5
const MINER_UPDATE_USERS_DB_DURATION time.Duration = 5
const MINER_UPDATE_USERS_STATS_DB_DURATION time.Duration = 5
const MINER_UPDATE_POOL_DB_DURATION time.Duration = 5
const MINER_UPDATE_POOL_STATS_DB_DURATION time.Duration = 5
const MINER_UPDATE_ADDRESS_DB_DURATION time.Duration = 5*/

func Create_db_tables(DbCtx *db.DbContext, coinType string) {
	//Periodic
	db.CreateTable(DbCtx, "miners", coinType)
	db.CreateTable(DbCtx, "miners_stats", coinType)
	//Real time
	//db.CreateTable(DbCtx, "miner", coinType)
	//Periodic
	//db.CreateTable(DbCtx, "users", coinType)
	//db.CreateTable(DbCtx, "users_stats", coinType)
	//Real time
	//db.CreateTable(DbCtx, "users_blkstats", coinType)
	//Periodic
	//db.CreateTable(DbCtx, "pool", coinType)
	//db.CreateTable(DbCtx, "pool_stats", coinType)
	//Real time
	db.CreateTable(DbCtx, "pool_blkstats", coinType)
	db.CreateTable(DbCtx, "blk_detail", coinType)
	db.CreateTable(DbCtx, "blk_new", coinType)
	//Preset
	db.CreateTable(DbCtx, "address", coinType)
	//Real time
	db.CreateTable(DbCtx, "blk_height_detail", coinType)
	log.Println("create tables!")
}

func NotifyMinersDb(m *coin.MinerObj) {
	var msg db.Miners_db_msg
	msg.Id = 0
	msg.Msg = "miners"
	msg.Date = time.Now()
	msg.MinerType = m.Name
	msg.Fromip = m.FromIP
	if msg.Date.Sub(m.LastSubmitime).Seconds() > 300 {
		msg.State = coin.MINER_STATUS_DISCONNECTED
	} else {
		msg.State = m.Status
	}
	msg.Online = m.StartSubmitTime
	msg.Offline = m.OfflineTime
	msg.Retry = int(m.Retry)
	m.Duration = m.LastSubmitime.Sub(m.StartSubmitTime).Seconds()
	m.DurationTime = m.Duration
	msg.Duration = m.Duration
	msg.Protocol = m.Protocol
	msg.User = m.User
	msg.Miner = m.Miner
	msg.Index = fmt.Sprint(m.MinerIndex)
	msg.Diff = m.Difficulty
	msg.Height = m.CurHeight
	msg.Accepts = m.Accepts
	msg.Rejects = m.Rejects
	if (m.Accepts + m.Rejects) > 0 {
		msg.Ratio = m.Rejects / (m.Accepts + m.Rejects)
	} else {
		msg.Ratio = 0
	}
	msg.Staleds = float64(m.ErrStaleds)
	msg.Lows = float64(m.ErrLowDiffs)
	msg.Duplicates = float64(m.ErrDuplicates)
	msg.Formats = float64(m.ErrFormats)
	msg.Others = float64(m.ErrOthers)
	msg.Disabled = m.IsDisabled
	msg.Last_submit = m.LastSubmitime
	msg.Submits = int(m.Submits)
	msg.Blocks = int(m.Blocks)
	msg.Orphans = int(m.Orphans)
	if m.Submits > 0 {
		msg.Orphan_ratio = float64(m.Orphans) / float64(m.Submits)
	} else {
		msg.Orphan_ratio = 0
	}

	m.Server.DbCtx.Miners_ch <- msg
}

func NotifyMinersStatsDb(m *coin.MinerObj) {
	var msg db.MinersStats_db_msg
	msg.Id = 0
	msg.Msg = "miners_stats"
	msg.Date = time.Now()
	msg.MinerType = m.Name

	msg.User = m.User
	msg.Miner = m.Miner
	msg.Index = fmt.Sprint(m.MinerIndex)

	msg.Shares5m = m.Accepts5M
	msg.Shares15m = m.Accepts15M
	msg.Shares30m = m.Accepts30M
	msg.Shares1h = m.Accepts1h
	msg.Shares3h = m.Accepts3h
	msg.Shares6h = m.Accepts6h
	msg.Shares12h = m.Accepts12h
	msg.Shares24h = m.Accepts24h
	msg.Shares48h = m.Accepts48h

	msg.Rejects5m = m.Rejects5M
	msg.Rejects15m = m.Rejects15M
	msg.Rejects30m = m.Rejects30M
	msg.Rejects1h = m.Rejects1h
	msg.Rejects3h = m.Rejects3h
	msg.Rejects6h = m.Rejects6h
	msg.Rejects12h = m.Rejects12h
	msg.Rejects24h = m.Rejects24h
	msg.Rejects48h = m.Rejects48h

	msg.Mhs5m = m.Mhs5M
	msg.Mhs15m = m.Mhs15M
	msg.Mhs30m = m.Mhs30M
	msg.Mhs1h = m.Mhs1h
	msg.Mhs3h = m.Mhs3h
	msg.Mhs6h = m.Mhs6h
	msg.Mhs12h = m.Mhs12h
	msg.Mhs24h = m.Mhs24h
	msg.Mhs48h = m.Mhs48h

	msg.Ratio5m = m.RejectRatio5M
	msg.Ratio15m = m.RejectRatio15M
	msg.Ratio30m = m.RejectRatio30M
	msg.Ratio1h = m.RejectRatio1h
	msg.Ratio3h = m.RejectRatio3h
	msg.Ratio6h = m.RejectRatio6h
	msg.Ratio12h = m.RejectRatio12h
	msg.Ratio24h = m.RejectRatio24h
	msg.Ratio48h = m.RejectRatio48h

	m.Server.DbCtx.MinersStats_ch <- msg
}

/*func NotifyMinerDb2(m *coin.MinerObj, block *coin.BlockMsg) {
	var msg db.Miner_db_msg
	msg.Id = 0
	msg.Msg = "miner"
	msg.Date = time.Now()
	msg.MinerType = m.Name

	msg.User = m.User
	msg.Miner = m.Miner
	msg.Index = fmt.Sprint(m.MinerIndex)

	msg.Target = block.Target
	msg.Submit_target = block.Submit_target
	msg.Height = block.Height
	if block.Success {
		msg.Success = 1
	} else {
		msg.Success = 0
	}
	msg.Pow = block.Pow
	msg.Net_target = block.Net_target
	msg.Submit = block.Submit
	msg.Hash = block.Hash
	msg.Header = block.Header
	msg.Accepts = block.Accepts
	msg.Total_accepts = block.Total_accepts
	msg.Rejects = block.Rejects
	msg.Total_rejects = block.Total_rejects
	msg.Reward = block.Reward
	msg.Fee = block.Fee
	msg.Nonce = block.Nonce
	msg.SubIdx = block.SubIdx

	m.Server.DbCtx.Miner_ch <- msg

}*/

/*func NotifyUsersDb(u *coin.UserObj) {
	var msg db.Users_db_msg
	msg.Id = 0
	msg.Msg = "users"
	msg.Date = time.Now()
	msg.MinerType = u.Name

	msg.User = u.User

	msg.Normal = u.Normal
	msg.Abnormal = u.Abnormal
	msg.Offline = u.Offline

	msg.MhsZero = u.MhsZero
	msg.MhsLow = u.MhsLow
	msg.HighRejects = u.HighRejects
	msg.Unstable = u.Unstable

	msg.Submits = u.Submits
	msg.Blocks = u.Blocks
	msg.Orphans = u.Orphans
	if u.Submits > 0 {
		msg.Orphan_ratio = float64(u.Orphans) / float64(u.Submits)
	} else {
		msg.Orphan_ratio = 0
	}
	msg.Reward = u.Reward
	msg.Fee = u.Fee

	u.Server.DbCtx.Users_ch <- msg
}*/

/*func NotifyUsersStatsDb(u *coin.UserObj) {
	var msg db.UsersStats_db_msg
	msg.Id = 0
	msg.Msg = "users_stats"
	msg.Date = time.Now()
	msg.MinerType = u.Name

	msg.User = u.User

	msg.Shares5m = u.Accepts5M
	msg.Shares15m = u.Accepts15M
	msg.Shares30m = u.Accepts30M
	msg.Shares1h = u.Accepts1h
	msg.Shares3h = u.Accepts3h
	msg.Shares6h = u.Accepts6h
	msg.Shares12h = u.Accepts12h
	msg.Shares24h = u.Accepts24h
	msg.Shares48h = u.Accepts48h

	msg.Rejects5m = u.Rejects5M
	msg.Rejects15m = u.Rejects15M
	msg.Rejects30m = u.Rejects30M
	msg.Rejects1h = u.Rejects1h
	msg.Rejects3h = u.Rejects3h
	msg.Rejects6h = u.Rejects6h
	msg.Rejects12h = u.Rejects12h
	msg.Rejects24h = u.Rejects24h
	msg.Rejects48h = u.Rejects48h

	msg.Mhs5m = u.Mhs5M
	msg.Mhs15m = u.Mhs15M
	msg.Mhs30m = u.Mhs30M
	msg.Mhs1h = u.Mhs1h
	msg.Mhs3h = u.Mhs3h
	msg.Mhs6h = u.Mhs6h
	msg.Mhs12h = u.Mhs12h
	msg.Mhs24h = u.Mhs24h
	msg.Mhs48h = u.Mhs48h

	msg.Ratio5m = u.RejectRatio5M
	msg.Ratio15m = u.RejectRatio15M
	msg.Ratio30m = u.RejectRatio30M
	msg.Ratio1h = u.RejectRatio1h
	msg.Ratio3h = u.RejectRatio3h
	msg.Ratio6h = u.RejectRatio6h
	msg.Ratio12h = u.RejectRatio12h
	msg.Ratio24h = u.RejectRatio24h
	msg.Ratio48h = u.RejectRatio48h

	u.Server.DbCtx.UsersStats_ch <- msg
}*/

/*func NotifyUsersBlkStatsDb2(m *coin.MinerObj, block *coin.UserBlockMsg) {
	var msg db.UsersBlkStats_db_msg
	msg.Id = 0
	msg.Msg = "users_blkstats"
	msg.Date = time.Now()
	msg.MinerType = m.Name

	msg.User = m.User

	msg.Miner = block.Miner
	msg.Index = block.Index
	msg.Height = block.Height
	msg.Hash = block.Hash
	msg.Pow = block.Pow
	msg.Net_target = block.Net_target
	msg.Submit = block.Submit
	if block.Success {
		msg.Success = 1
	} else {
		msg.Success = 0
	}
	msg.Accepts = block.Accepts
	msg.Rejects = block.Rejects
	msg.Reward = block.Reward
	msg.Fee = block.Fee
	msg.Nonce = block.Nonce
	msg.SubIdx = block.SubIdx

	m.Server.DbCtx.UsersBlkStats_ch <- msg

}*/

/*func NotifyPoolDb(server *coin.ServerContext) {
	var msg db.Pool_db_msg
	msg.Id = 0
	msg.Msg = "pool"
	msg.Date = time.Now()
	msg.MinerType = server.MinerType

	msg.Miners = server.TotalMiners
	msg.Normal = server.Normal
	msg.Abnormal = server.Abnormal
	msg.Offline = server.Offline

	msg.MhsZero = server.MhsZero
	msg.MhsLow = server.MhsLow
	msg.HighRejects = server.HighRejects
	msg.Unstable = server.Unstable

	msg.Net_target = server.NetTarget
	msg.Height = server.NetHight
	msg.Submits = server.Submits
	msg.Blocks = server.Blocks
	msg.Orphans = server.Orphans

	if server.Submits > 0 {
		msg.Orphan_ratio = float64(server.Orphans) / float64(server.Submits)
	} else {
		msg.Orphan_ratio = 0
	}
	msg.Reward = server.Reward
	msg.Fee = server.Fee

	server.DbCtx.Pool_ch <- msg
}*/

/*func NotifyPoolStatsDb(server *coin.ServerContext) {
	var msg db.PoolStats_db_msg
	msg.Id = 0
	msg.Msg = "pool_stats"
	msg.Date = time.Now()
	msg.MinerType = server.MinerType

	msg.Shares5m = server.Accepts5M
	msg.Shares15m = server.Accepts15M
	msg.Shares30m = server.Accepts30M
	msg.Shares1h = server.Accepts1h
	msg.Shares3h = server.Accepts3h
	msg.Shares6h = server.Accepts6h
	msg.Shares12h = server.Accepts12h
	msg.Shares24h = server.Accepts24h
	msg.Shares48h = server.Accepts48h

	msg.Rejects5m = server.Rejects5M
	msg.Rejects15m = server.Rejects15M
	msg.Rejects30m = server.Rejects30M
	msg.Rejects1h = server.Rejects1h
	msg.Rejects3h = server.Rejects3h
	msg.Rejects6h = server.Rejects6h
	msg.Rejects12h = server.Rejects12h
	msg.Rejects24h = server.Rejects24h
	msg.Rejects48h = server.Rejects48h

	msg.Mhs5m = server.Mhs5M
	msg.Mhs15m = server.Mhs15M
	msg.Mhs30m = server.Mhs30M
	msg.Mhs1h = server.Mhs1h
	msg.Mhs3h = server.Mhs3h
	msg.Mhs6h = server.Mhs6h
	msg.Mhs12h = server.Mhs12h
	msg.Mhs24h = server.Mhs24h
	msg.Mhs48h = server.Mhs48h

	msg.Ratio5m = server.RejectRatio5M
	msg.Ratio15m = server.RejectRatio15M
	msg.Ratio30m = server.RejectRatio30M
	msg.Ratio1h = server.RejectRatio1h
	msg.Ratio3h = server.RejectRatio3h
	msg.Ratio6h = server.RejectRatio6h
	msg.Ratio12h = server.RejectRatio12h
	msg.Ratio24h = server.RejectRatio24h
	msg.Ratio48h = server.RejectRatio48h

	server.DbCtx.PoolStats_ch <- msg
}*/

func NotifyPoolBlkStatsDb2(server *coin.ServerContext, block *coin.PoolBlkMsg) {
	var msg db.PoolBlkStats_db_msg
	msg.Id = 0
	msg.Msg = "pool_blkstats"
	msg.Date = time.Now()
	msg.MinerType = server.MinerType

	msg.Height = block.Height
	msg.Hash = block.Hash
	msg.Pow = block.Pow
	msg.Net_target = block.Net_target
	msg.Submit = block.Submit
	if block.Success {
		msg.Success = 1
	} else {
		msg.Success = 0
	}
	msg.Accepts = block.Accepts
	msg.Rejects = block.Rejects
	msg.Reward = block.Reward
	msg.Fee = block.Fee
	msg.Nonce = block.Nonce
	msg.SubIdx = block.SubIdx

	server.DbCtx.PoolBlkStats_ch <- msg

}

func NotifyBlkDetailDb(m *coin.MinerObj, height int64, hash string, success bool, miner_diff float64, pool_diff float64, nonce string, subidx int64) {
	var msg db.BlkDetail_db_msg
	msg.Id = 0
	msg.Msg = "blk_detail"
	msg.Date = time.Now()
	msg.MinerType = m.Name

	msg.User = m.User
	msg.Miner = m.Miner
	msg.Index = fmt.Sprint(m.MinerIndex)

	msg.Height = height
	msg.Hash = hash
	if success {
		msg.Success = 1
	} else {
		msg.Success = 0
	}

	msg.Miner_diff = miner_diff
	msg.Pool_diff = pool_diff
	msg.Nonce = nonce
	msg.SubIdx = subidx

	//m.Server.DbCtx.BlkDetail_ch <- msg
	db.Save_blk_detail(m.Server.DbCtx, &msg)
}

func notify_miners_db(server *coin.ServerContext, DbCtx *db.DbContext) {
	online_map := make(map[string]int)
	server.Miners.Range(func(k, v interface{}) bool {
		m, ok := v.(*(coin.MinerObj))
		if ok {
			if m.User == "" || m.Miner == "" || fmt.Sprint(m.MinerIndex) == "" {
				return true
			}
			if (m.Accepts > 0) && (m.Status == coin.MINER_STATUS_RUNNING) {
				if time.Now().Sub(m.LastSubmitime).Seconds() <= 300 {
					online_k := m.User + "." + m.Miner + "_" + fmt.Sprint(m.MinerIndex)
					online_map[online_k] = 1
				}
			}
		}
		return true
	})

	server.Miners.Range(func(k, v interface{}) bool {
		m, ok := v.(*(coin.MinerObj))
		if ok {
			if m.User == "" || m.Miner == "" || fmt.Sprint(m.MinerIndex) == "" {
				return true
			}
			if m.Accepts > 0 /* || (m.Rejects > 0)*/ {
				if (m.Status == coin.MINER_STATUS_DISCONNECTED) || (time.Now().Sub(m.LastSubmitime).Seconds() > 300) {
					online_k := m.User + "." + m.Miner + "_" + fmt.Sprint(m.MinerIndex)
					_, exists := online_map[online_k]
					if !exists {
						NotifyMinersDb(m)
					}
				} else {
					NotifyMinersDb(m)
				}
			}
		}
		return true
	})
}

func notify_miners_stats_db(server *coin.ServerContext, DbCtx *db.DbContext) {
	var pool_accepts_5m float64 = 0
	var pool_accepts_15m float64 = 0
	var pool_accepts_30m float64 = 0
	var pool_accepts_1h float64 = 0
	var pool_accepts_3h float64 = 0
	var pool_accepts_6h float64 = 0
	var pool_accepts_12h float64 = 0
	var pool_accepts_24h float64 = 0
	var pool_accepts_48h float64 = 0

	var pool_rejects_5m float64 = 0
	var pool_rejects_15m float64 = 0
	var pool_rejects_30m float64 = 0
	var pool_rejects_1h float64 = 0
	var pool_rejects_3h float64 = 0
	var pool_rejects_6h float64 = 0
	var pool_rejects_12h float64 = 0
	var pool_rejects_24h float64 = 0
	var pool_rejects_48h float64 = 0

	var pool_mhs_5m float64 = 0
	var pool_mhs_15m float64 = 0
	var pool_mhs_30m float64 = 0
	var pool_mhs_1h float64 = 0
	var pool_mhs_3h float64 = 0
	var pool_mhs_6h float64 = 0
	var pool_mhs_12h float64 = 0
	var pool_mhs_24h float64 = 0
	var pool_mhs_48h float64 = 0

	var pool_ratio_5m float64 = 0
	var pool_ratio_15m float64 = 0
	var pool_ratio_30m float64 = 0
	var pool_ratio_1h float64 = 0
	var pool_ratio_3h float64 = 0
	var pool_ratio_6h float64 = 0
	var pool_ratio_12h float64 = 0
	var pool_ratio_24h float64 = 0
	var pool_ratio_48h float64 = 0

	var total_miners int64 = 0
	var miner_all []string
	cmp := time.Now()
	server.MMhs.Range(func(k, v interface{}) bool {
		m, ok := v.(coin.MhsObj)
		if ok {
			//server.Logg.Info("[mhs save]", zap.String("miner", m.User+"."+m.Miner), zap.Int("accepts", len(m.Accepts)), zap.Int("algo", m.Algo))

			if m.User == "" || m.Miner == "" || m.Index == "" {
				return true
			}

			uminer, umok := server.Miners.Load(m.MinerId)
			if !umok {
				return true
			}

			var miner coin.MinerObj
			var thisCoin = server.CoinCtx.Coin
			miner.Server = server
			miner_all = append(miner_all, m.User+"."+m.Miner+"_"+m.Index)

			var accepts_1h float64 = 0
			var accepts_24h float64 = 0

			var accepts_m5 float64 = 0
			var accepts_m15 float64 = 0
			var accepts_m30 float64 = 0
			var accepts_3h float64 = 0
			var accepts_6h float64 = 0
			var accepts_12h float64 = 0
			var accepts_48h float64 = 0

			var accepts_1h_cnt int64 = 0
			var accepts_24h_cnt int64 = 0

			var accepts_m5_cnt float64 = 0
			var accepts_m15_cnt float64 = 0
			var accepts_m30_cnt float64 = 0
			var accepts_3h_cnt float64 = 0
			var accepts_6h_cnt float64 = 0
			var accepts_12h_cnt float64 = 0
			var accepts_48h_cnt float64 = 0

			if len(m.Accepts) > 0 {
				var i int = -1
				for i = len(m.Accepts) - 1; i >= 0; i-- {
					tdiff := cmp.Sub(m.Accepts[i].Tt).Seconds()
					if tdiff <= 3600 {
						accepts_1h = accepts_1h + m.Accepts[i].Diff
						accepts_1h_cnt++
					}
					if tdiff <= 5*60 {
						accepts_m5 = accepts_m5 + m.Accepts[i].Diff
						accepts_m5_cnt++
					}
					if tdiff <= 15*60 {
						accepts_m15 = accepts_m15 + m.Accepts[i].Diff
						accepts_m15_cnt++
					}
					if tdiff <= 30*60 {
						accepts_m30 = accepts_m30 + m.Accepts[i].Diff
						accepts_m30_cnt++
					}
					if tdiff <= 3*3600 {
						accepts_3h = accepts_3h + m.Accepts[i].Diff
						accepts_3h_cnt++
					}
					if tdiff <= 6*3600 {
						accepts_6h = accepts_6h + m.Accepts[i].Diff
						accepts_6h_cnt++
					}
					if tdiff <= 12*3600 {
						accepts_12h = accepts_12h + m.Accepts[i].Diff
						accepts_12h_cnt++
					}
					if tdiff <= 24*3600 {
						accepts_24h = accepts_24h + m.Accepts[i].Diff
						accepts_24h_cnt++
					}
					if tdiff <= 48*3600 {
						accepts_48h = accepts_48h + m.Accepts[i].Diff
						accepts_48h_cnt++
					}
				}

				miner.Accepts5M = accepts_m5
				miner.Accepts15M = accepts_m15
				miner.Accepts30M = accepts_m30
				miner.Accepts1h = accepts_1h
				miner.Accepts3h = accepts_3h
				miner.Accepts6h = accepts_6h
				miner.Accepts12h = accepts_12h
				miner.Accepts24h = accepts_24h
				miner.Accepts48h = accepts_48h

				var diffOneShareHashesAvg uint64
				if thisCoin != "alph" {
					diffOneShareHashesAvg = uint64(0x00000000FFFFFFFF)
				} else {
					diffOneShareHashesAvg = uint64(0xFFFFFFFFF)
				}

				var coefficient float64 = 1
				miner.Mhs1h = accepts_1h * float64(diffOneShareHashesAvg) / coefficient / float64(3600) / 1000000
				//server.Logg.Info("[mhs save]", zap.Float64("mhs1h", msg.Mhs), zap.Float64("duration", mhs_duration), zap.Float64("diff", m.Difficulty))

				miner.Mhs5M = accepts_m5 * float64(diffOneShareHashesAvg) / coefficient / float64(5*60) / 1000000
				miner.Mhs15M = accepts_m15 * float64(diffOneShareHashesAvg) / coefficient / float64(15*60) / 1000000
				miner.Mhs30M = accepts_m30 * float64(diffOneShareHashesAvg) / coefficient / float64(30*60) / 1000000
				miner.Mhs3h = accepts_3h * float64(diffOneShareHashesAvg) / coefficient / float64(3*3600) / 1000000
				miner.Mhs6h = accepts_6h * float64(diffOneShareHashesAvg) / coefficient / float64(6*3600) / 1000000
				miner.Mhs12h = accepts_12h * float64(diffOneShareHashesAvg) / coefficient / float64(12*3600) / 1000000
				miner.Mhs48h = accepts_48h * float64(diffOneShareHashesAvg) / coefficient / float64(48*3600) / 1000000
				miner.Mhs24h = accepts_24h * float64(diffOneShareHashesAvg) / coefficient / float64(3600*24) / 1000000

				//server.Logg.Info("[mhs save]", zap.Int("accepts_24h", accepts_24h), zap.Float64("Mhs24h", msg.Mhs24h))
			} else {
				miner.Mhs1h = 0
				miner.Mhs24h = 0

				miner.Mhs5M = 0
				miner.Mhs15M = 0
				miner.Mhs30M = 0
				miner.Mhs3h = 0
				miner.Mhs6h = 0
				miner.Mhs12h = 0
				miner.Mhs24h = 0
			}

			var rejects_1h_cnt int64 = 0
			var rejects_24h_cnt int64 = 0

			var rejects_m5_cnt int64 = 0
			var rejects_m15_cnt int64 = 0
			var rejects_m30_cnt int64 = 0
			var rejects_3h_cnt int64 = 0
			var rejects_6h_cnt int64 = 0
			var rejects_12h_cnt int64 = 0
			var rejects_48h_cnt int64 = 0

			if len(m.Rejects) > 0 {
				var j int = -1
				for j = 0; j < len(m.Rejects); j++ {
					tdiff := cmp.Sub(m.Rejects[j].Tt).Seconds()
					if tdiff <= 3600 {
						rejects_1h_cnt++
					}
					if tdiff <= 5*60 {
						rejects_m5_cnt++
					}
					if tdiff <= 15*60 {
						rejects_m15_cnt++
					}
					if tdiff <= 30*60 {
						rejects_m30_cnt++
					}
					if tdiff <= 3*3600 {
						rejects_3h_cnt++
					}
					if tdiff <= 6*3600 {
						rejects_6h_cnt++
					}
					if tdiff <= 12*3600 {
						rejects_12h_cnt++
					}
					if tdiff <= 24*3600 {
						rejects_24h_cnt++
					}
					if tdiff <= 48*3600 {
						rejects_48h_cnt++
					}
				}
			}

			miner.Rejects5M = float64(rejects_m5_cnt)
			miner.Rejects15M = float64(rejects_m15_cnt)
			miner.Rejects30M = float64(rejects_m30_cnt)
			miner.Rejects1h = float64(rejects_1h_cnt)
			miner.Rejects3h = float64(rejects_3h_cnt)
			miner.Rejects6h = float64(rejects_6h_cnt)
			miner.Rejects12h = float64(rejects_12h_cnt)
			miner.Rejects24h = float64(rejects_24h_cnt)
			miner.Rejects48h = float64(rejects_48h_cnt)

			miner.RejectRatio5M = 0
			if rejects_m5_cnt > 0 {
				miner.RejectRatio5M = miner.Rejects5M / (miner.Rejects5M + float64(accepts_m5_cnt))
			}
			miner.RejectRatio15M = 0
			if rejects_m15_cnt > 0 {
				miner.RejectRatio15M = miner.Rejects15M / (miner.Rejects15M + float64(accepts_m15_cnt))
			}
			miner.RejectRatio30M = 0
			if rejects_m30_cnt > 0 {
				miner.RejectRatio30M = miner.Rejects30M / (miner.Rejects30M + float64(accepts_m30_cnt))
			}
			miner.RejectRatio1h = 0
			if rejects_1h_cnt > 0 {
				miner.RejectRatio1h = miner.Rejects1h / (miner.Rejects1h + float64(accepts_1h_cnt))
			}
			miner.RejectRatio3h = 0
			if rejects_3h_cnt > 0 {
				miner.RejectRatio3h = miner.Rejects3h / (miner.Rejects3h + float64(accepts_3h_cnt))
			}
			miner.RejectRatio6h = 0
			if rejects_6h_cnt > 0 {
				miner.RejectRatio6h = miner.Rejects6h / (miner.Rejects6h + float64(accepts_6h_cnt))
			}
			miner.RejectRatio12h = 0
			if rejects_12h_cnt > 0 {
				miner.RejectRatio12h = miner.Rejects12h / (miner.Rejects12h + float64(accepts_12h_cnt))
			}
			miner.RejectRatio24h = 0
			if rejects_24h_cnt > 0 {
				miner.RejectRatio24h = miner.Rejects24h / (miner.Rejects24h + float64(accepts_24h_cnt))
			}
			miner.RejectRatio48h = 0
			if rejects_48h_cnt > 0 {
				miner.RejectRatio48h = miner.Rejects48h / (miner.Rejects48h + float64(accepts_48h_cnt))
			}

			pool_accepts_5m = pool_accepts_5m + miner.Accepts5M
			pool_accepts_15m = pool_accepts_15m + miner.Accepts15M
			pool_accepts_30m = pool_accepts_30m + miner.Accepts30M
			pool_accepts_1h = pool_accepts_1h + miner.Accepts1h
			pool_accepts_3h = pool_accepts_3h + miner.Accepts3h
			pool_accepts_6h = pool_accepts_6h + miner.Accepts6h
			pool_accepts_12h = pool_accepts_12h + miner.Accepts12h
			pool_accepts_24h = pool_accepts_24h + miner.Accepts24h
			pool_accepts_48h = pool_accepts_48h + miner.Accepts48h

			pool_rejects_5m = pool_rejects_5m + miner.Rejects5M
			pool_rejects_15m = pool_rejects_15m + miner.Rejects15M
			pool_rejects_30m = pool_rejects_30m + miner.Rejects30M
			pool_rejects_1h = pool_rejects_1h + miner.Rejects1h
			pool_rejects_3h = pool_rejects_3h + miner.Rejects3h
			pool_rejects_6h = pool_rejects_6h + miner.Rejects6h
			pool_rejects_12h = pool_rejects_12h + miner.Rejects12h
			pool_rejects_24h = pool_rejects_24h + miner.Rejects24h
			pool_rejects_48h = pool_rejects_48h + miner.Rejects48h

			pool_mhs_5m = pool_mhs_5m + miner.Mhs5M
			pool_mhs_15m = pool_mhs_15m + miner.Mhs15M
			pool_mhs_30m = pool_mhs_30m + miner.Mhs30M
			pool_mhs_1h = pool_mhs_1h + miner.Mhs1h
			pool_mhs_3h = pool_mhs_3h + miner.Mhs3h
			pool_mhs_6h = pool_mhs_6h + miner.Mhs6h
			pool_mhs_12h = pool_mhs_12h + miner.Mhs12h
			pool_mhs_24h = pool_mhs_24h + miner.Mhs24h
			pool_mhs_48h = pool_mhs_48h + miner.Mhs48h

			pool_ratio_5m = pool_ratio_5m + miner.RejectRatio5M
			pool_ratio_15m = pool_ratio_15m + miner.RejectRatio15M
			pool_ratio_30m = pool_ratio_30m + miner.RejectRatio30M
			pool_ratio_1h = pool_ratio_1h + miner.RejectRatio1h
			pool_ratio_3h = pool_ratio_3h + miner.RejectRatio3h
			pool_ratio_6h = pool_ratio_6h + miner.RejectRatio6h
			pool_ratio_12h = pool_ratio_12h + miner.RejectRatio12h
			pool_ratio_24h = pool_ratio_24h + miner.RejectRatio24h
			pool_ratio_48h = pool_ratio_48h + miner.RejectRatio48h

			miner.Name = m.Name
			miner.User = m.User
			miner.Miner = m.Miner
			miner.MinerIndex, _ = strconv.ParseInt(m.Index, 10, 64)

			NotifyMinersStatsDb(&miner)

			//fmt.Printf("notify_miners_stats_db store miner miner %v, miner_id %v, umok %v\n", uminer, m.MinerId, umok)
			if umok {
				up_miner := uminer.(*coin.MinerObj)
				up_miner.Accepts5M = miner.Accepts5M
				up_miner.Accepts15M = miner.Accepts15M
				up_miner.Accepts30M = miner.Accepts30M
				up_miner.Accepts1h = miner.Accepts1h
				up_miner.Accepts3h = miner.Accepts3h
				up_miner.Accepts6h = miner.Accepts6h
				up_miner.Accepts12h = miner.Accepts12h
				up_miner.Accepts24h = miner.Accepts24h
				up_miner.Accepts48h = miner.Accepts48h

				up_miner.Rejects5M = miner.Rejects5M
				up_miner.Rejects15M = miner.Rejects15M
				up_miner.Rejects30M = miner.Rejects30M
				up_miner.Rejects1h = miner.Rejects1h
				up_miner.Rejects3h = miner.Rejects3h
				up_miner.Rejects6h = miner.Rejects6h
				up_miner.Rejects12h = miner.Rejects12h
				up_miner.Rejects24h = miner.Rejects24h
				up_miner.Rejects48h = miner.Rejects48h

				up_miner.Mhs5M = miner.Mhs5M
				up_miner.Mhs15M = miner.Mhs15M
				up_miner.Mhs30M = miner.Mhs30M
				up_miner.Mhs1h = miner.Mhs1h
				up_miner.Mhs3h = miner.Mhs3h
				up_miner.Mhs6h = miner.Mhs6h
				up_miner.Mhs12h = miner.Mhs12h
				up_miner.Mhs24h = miner.Mhs24h
				up_miner.Mhs48h = miner.Mhs48h

				up_miner.RejectRatio5M = miner.RejectRatio5M
				up_miner.RejectRatio15M = miner.RejectRatio15M
				up_miner.RejectRatio30M = miner.RejectRatio30M
				up_miner.RejectRatio1h = miner.RejectRatio1h
				up_miner.RejectRatio3h = miner.RejectRatio3h
				up_miner.RejectRatio6h = miner.RejectRatio6h
				up_miner.RejectRatio12h = miner.RejectRatio12h
				up_miner.RejectRatio24h = miner.RejectRatio24h
				up_miner.RejectRatio48h = miner.RejectRatio48h
				//fmt.Printf("notify_miners_stats_db store miner mhs5m %v, miner_id %v, %v\n", up_miner.Mhs5M, up_miner.MinerId, up_miner)
			}

			total_miners++

		}
		return true
	})

	server.Accepts5M = pool_accepts_5m
	server.Accepts15M = pool_accepts_15m
	server.Accepts30M = pool_accepts_30m
	server.Accepts1h = pool_accepts_1h
	server.Accepts3h = pool_accepts_3h
	server.Accepts6h = pool_accepts_6h
	server.Accepts12h = pool_accepts_12h
	server.Accepts24h = pool_accepts_24h
	server.Accepts48h = pool_accepts_48h

	server.Rejects5M = pool_rejects_5m
	server.Rejects15M = pool_rejects_15m
	server.Rejects30M = pool_rejects_30m
	server.Rejects1h = pool_rejects_1h
	server.Rejects3h = pool_rejects_3h
	server.Rejects6h = pool_rejects_6h
	server.Rejects12h = pool_rejects_12h
	server.Rejects24h = pool_rejects_24h
	server.Rejects48h = pool_rejects_48h

	server.Mhs5M = pool_mhs_5m
	server.Mhs15M = pool_mhs_15m
	server.Mhs30M = pool_mhs_30m
	server.Mhs1h = pool_mhs_1h
	server.Mhs3h = pool_mhs_3h
	server.Mhs6h = pool_mhs_6h
	server.Mhs12h = pool_mhs_12h
	server.Mhs24h = pool_mhs_24h
	server.Mhs48h = pool_mhs_48h

	server.RejectRatio5M = pool_ratio_5m / float64(total_miners)
	server.RejectRatio15M = pool_ratio_15m / float64(total_miners)
	server.RejectRatio30M = pool_ratio_30m / float64(total_miners)
	server.RejectRatio1h = pool_ratio_1h / float64(total_miners)
	server.RejectRatio3h = pool_ratio_3h / float64(total_miners)
	server.RejectRatio6h = pool_ratio_6h / float64(total_miners)
	server.RejectRatio12h = pool_ratio_12h / float64(total_miners)
	server.RejectRatio24h = pool_ratio_24h / float64(total_miners)
	server.RejectRatio48h = pool_ratio_48h / float64(total_miners)

	//NotifyPoolStatsDb(server)

	//NotifyPoolDb(server)

	//server.Logg.Info("[mhs save]", zap.Int("24hupdate", len(miner_all)))
	var total int = 0
	for miner_idx := 0; miner_idx < len(miner_all); miner_idx++ {
		v, ok := server.MMhs.Load(miner_all[miner_idx])
		if ok {
			var m coin.MhsObj = v.(coin.MhsObj)
			if cmp.Sub(m.StartDayTime).Seconds() >= 3600*52 {
				//server.Logg.Info("[mhs save 1]", zap.String("miner", m.User+"."+m.Miner), zap.Int("accepts", len(m.Accepts)), zap.Int("rejects", len(m.Rejects)))
				m.StartDayTime = m.StartDayTime.Add(time.Hour * 4)
				if len(m.Accepts) > 0 {
					var i int = 0
					for i = 0; i < len(m.Accepts); i++ {
						if cmp.Sub(m.Accepts[i].Tt).Seconds() <= 3600*48 {
							break
						}
					}
					if i > 0 {
						as := m.Accepts[i:]
						m.Accepts = as
						for cnt := 0; cnt < len(m.Accepts); cnt++ {
							cache.RemoveMhsCache(server.RedisClient, server.MinerType, m.User, m.Miner, m.Index, "accepts")
						}
					}
				}
				if len(m.Rejects) > 0 {
					var i int = 0
					for i = 0; i < len(m.Rejects); i++ {
						if cmp.Sub(m.Rejects[i].Tt).Seconds() <= 3600*48 {
							break
						}
					}
					if i > 0 {
						rs := m.Rejects[i:]
						m.Rejects = rs
						for cnt := 0; cnt < len(m.Rejects); cnt++ {
							cache.RemoveMhsCache(server.RedisClient, server.MinerType, m.User, m.Miner, m.Index, "rejects")
						}
					}
				}
				//server.Logg.Info("[mhs save 1]", zap.String("miner", m.User+"."+m.Miner), zap.Int("accepts", len(m.Accepts)), zap.Int("rejects", len(m.Rejects)))
			}

			server.MMhs.Store(miner_all[miner_idx], m)
			cache.StoreMhsCache(server.RedisClient, server.MinerType, m.User, m.Miner, m.Index, "starttime", m.StartDayTime)
			total++
		}
	}
	//server.Logg.Info("[mhs save]", zap.Int("24hupdate", total))
}

/*func notify_users_db(server *coin.ServerContext, DbCtx *db.DbContext) {
	server.Users.Range(func(k, v interface{}) bool {
		u_sets, ok := v.(coin.UserMinerContainer)
		if ok {
			var u coin.UserObj
			u.Server = server
			u.User = k.(string)
			user := strings.TrimSuffix(u.User, "00000000")
			u.User = user
			u.Name = server.MinerType

			u.Normal = 0
			u.Abnormal = 0

			u.Offline = 0
			u.MhsZero = 0
			u.MhsLow = 0
			u.HighRejects = 0
			u.Unstable = 0

			u.Submits = 0
			u.Blocks = 0
			u.Orphans = 0

			u.Reward = 0
			u.Fee = 0
			//fmt.Printf("-->notify_users_db user %v data %v", u.User, u_sets.Data)
			for _, miner_id := range u_sets.Data {
				mobj, mok := server.Miners.Load(miner_id)
				//fmt.Printf("-->notify_users_db miner_id %v, miner_obj %v\n", miner_id, mobj)
				if mok {
					m := mobj.(*coin.MinerObj)
					u.Submits = u.Submits + int64(m.Submits)
					u.Blocks = u.Blocks + int64(m.Blocks)
					u.Orphans = u.Orphans + int64(m.Orphans)

					u.Reward = u.Reward + m.Reward
					u.Fee = u.Fee + m.Fee
				}
			}

			NotifyUsersDb(&u)
		}
		return true
	})
}*/

/*func notify_users_stats_db(server *coin.ServerContext, DbCtx *db.DbContext) {
	server.Users.Range(func(k, v interface{}) bool {
		//fmt.Printf("notify_users_stats_db user=%v, value=%v\n", k, v)
		u_sets, ok := v.(coin.UserMinerContainer)
		if ok {
			var u coin.UserObj
			u.Server = server
			u.User = k.(string)
			user := strings.TrimSuffix(u.User, "00000000")
			u.User = user
			u.Name = server.MinerType

			u.Accepts5M = 0
			u.Accepts15M = 0
			u.Accepts30M = 0
			u.Accepts1h = 0
			u.Accepts3h = 0
			u.Accepts6h = 0
			u.Accepts12h = 0
			u.Accepts24h = 0
			u.Accepts48h = 0

			u.Rejects5M = 0
			u.Rejects15M = 0
			u.Rejects30M = 0
			u.Rejects1h = 0
			u.Rejects3h = 0
			u.Rejects6h = 0
			u.Rejects12h = 0
			u.Rejects24h = 0
			u.Rejects48h = 0

			u.Mhs5M = 0
			u.Mhs15M = 0
			u.Mhs30M = 0
			u.Mhs1h = 0
			u.Mhs3h = 0
			u.Mhs6h = 0
			u.Mhs12h = 0
			u.Mhs24h = 0
			u.Mhs48h = 0

			u.RejectRatio5M = 0
			u.RejectRatio15M = 0
			u.RejectRatio30M = 0
			u.RejectRatio1h = 0
			u.RejectRatio3h = 0
			u.RejectRatio6h = 0
			u.RejectRatio12h = 0
			u.RejectRatio24h = 0
			u.RejectRatio48h = 0

			var total_miners int64 = 0
			for _, miner_id := range u_sets.Data {
				//fmt.Printf("notify_users_stats_db user=%v, miner=%v\n", k, miner_id)
				mobj, mok := server.Miners.Load(miner_id)
				//fmt.Printf("notify_users_stats_db miner=%v,mobj=%v, mok=%v\n", miner_id, mobj, mok)
				if mok {
					m := mobj.(*coin.MinerObj)
					u.Accepts5M = u.Accepts5M + m.Accepts5M
					//fmt.Printf("notify_users_stats_db, Accepts5M %v, %v", u.Accepts5M, m.Accepts5M)
					u.Accepts15M = u.Accepts15M + m.Accepts15M
					u.Accepts30M = u.Accepts30M + m.Accepts30M
					u.Accepts1h = u.Accepts1h + m.Accepts1h
					u.Accepts3h = u.Accepts3h + m.Accepts3h
					u.Accepts6h = u.Accepts6h + m.Accepts6h
					u.Accepts12h = u.Accepts12h + m.Accepts12h
					u.Accepts24h = u.Accepts24h + m.Accepts24h
					u.Accepts48h = u.Accepts48h + m.Accepts48h

					u.Rejects5M = u.Rejects5M + m.Rejects5M
					u.Rejects15M = u.Rejects15M + m.Rejects15M
					u.Rejects30M = u.Rejects30M + m.Rejects30M
					u.Rejects1h = u.Rejects1h + m.Rejects1h
					u.Rejects3h = u.Rejects3h + m.Rejects3h
					u.Rejects6h = u.Rejects6h + m.Rejects6h
					u.Rejects12h = u.Rejects12h + m.Rejects12h
					u.Rejects24h = u.Rejects24h + m.Rejects24h
					u.Rejects48h = u.Rejects48h + m.Rejects48h

					u.Mhs5M = u.Mhs5M + m.Mhs5M
					u.Mhs15M = u.Mhs15M + m.Mhs15M
					u.Mhs30M = u.Mhs30M + m.Mhs30M
					u.Mhs1h = u.Mhs1h + m.Mhs1h
					u.Mhs3h = u.Mhs3h + m.Mhs3h
					u.Mhs6h = u.Mhs6h + m.Mhs6h
					u.Mhs12h = u.Mhs12h + m.Mhs12h
					u.Mhs24h = u.Mhs24h + m.Mhs24h
					u.Mhs48h = u.Mhs48h + m.Mhs48h

					u.RejectRatio5M = u.RejectRatio5M + m.RejectRatio5M
					u.RejectRatio15M = u.RejectRatio15M + m.RejectRatio15M
					u.RejectRatio30M = u.RejectRatio30M + m.RejectRatio30M
					u.RejectRatio1h = u.RejectRatio1h + m.RejectRatio1h
					u.RejectRatio3h = u.RejectRatio3h + m.RejectRatio3h
					u.RejectRatio6h = u.RejectRatio6h + m.RejectRatio6h
					u.RejectRatio12h = u.RejectRatio12h + m.RejectRatio12h
					u.RejectRatio24h = u.RejectRatio24h + m.RejectRatio24h
					u.RejectRatio48h = u.RejectRatio48h + m.RejectRatio48h

					total_miners++
				}
			}
			if total_miners > 0 {
				u.RejectRatio5M = u.RejectRatio5M / float64(total_miners)
				u.RejectRatio15M = u.RejectRatio15M / float64(total_miners)
				u.RejectRatio30M = u.RejectRatio30M / float64(total_miners)
				u.RejectRatio1h = u.RejectRatio1h / float64(total_miners)
				u.RejectRatio3h = u.RejectRatio3h / float64(total_miners)
				u.RejectRatio6h = u.RejectRatio6h / float64(total_miners)
				u.RejectRatio12h = u.RejectRatio12h / float64(total_miners)
				u.RejectRatio24h = u.RejectRatio24h / float64(total_miners)
				u.RejectRatio48h = u.RejectRatio48h / float64(total_miners)
				//fmt.Printf("notify_users_stats_db, total %v, accept %v", total_miners, u.Accepts5M)
				NotifyUsersStatsDb(&u)
			}
		}
		return true
	})
}*/

func Handle_miners_timer(server *coin.ServerContext, DbCtx *db.DbContext) {
	timer := time.NewTimer(time.Minute * MINER_UPDATE_MINERS_DB_DURATION)
	for {
		select {
		case <-timer.C:
			notify_miners_db(server, DbCtx)
			notify_miners_stats_db(server, DbCtx)
			//notify_users_db(server, DbCtx)
			//notify_users_stats_db(server, DbCtx)
			timer.Reset(time.Minute * MINER_UPDATE_MINERS_DB_DURATION)
		case <-(server.ExitDbMiners):
			log.Println("[server]", "Handle_user_timer exited.")
			timer.Stop()
			return
		}
	}
}

/*
func Handle_miners_stats_timer(server *coin.ServerContext, DbCtx *db.DbContext) {
	timer := time.NewTimer(time.Minute * MINER_UPDATE_MINERS_STATS_DB_DURATION)
	for {
		select {
		case <-timer.C:
			notify_miners_stats_db(server, DbCtx)
			timer.Reset(time.Minute * MINER_UPDATE_MINERS_STATS_DB_DURATION)
		case <-(server.ExitDbMinersStats):
			log.Println("[server]", "Handle_miners_stats_timer exited.")
			timer.Stop()

			return
		}
	}
}*/
/*
func Handle_users_timer(server *coin.ServerContext, DbCtx *db.DbContext) {
	timer := time.NewTimer(time.Minute * MINER_UPDATE_USERS_DB_DURATION)
	for {
		select {
		case <-timer.C:

			notify_users_db(server, DbCtx)
			timer.Reset(time.Minute * MINER_UPDATE_USERS_DB_DURATION)
		case <-(server.ExitDbUser):
			log.Println("[server]", "Handle_users_timer exited.")
			timer.Stop()

			return
		}
	}
}*/
/*
func Handle_users_stats_timer(server *coin.ServerContext, DbCtx *db.DbContext) {
	timer := time.NewTimer(time.Minute * MINER_UPDATE_USERS_STATS_DB_DURATION)
	for {
		select {
		case <-timer.C:
			notify_users_stats_db(server, DbCtx)
			timer.Reset(time.Minute * MINER_UPDATE_USERS_STATS_DB_DURATION)
		case <-(server.ExitDbUserStats):
			log.Println("[server]", "Handle_users_stats_timer exited.")
			timer.Stop()

			return
		}
	}
}*/
