package zciyon

import (
	"bufio"
	"fmt"
	"net"
	"os"
	"runtime"
	"strings"
	"time"
)

type ciyLogMsg struct {
	tim    int
	level  int
	fnname string
	msg    string
	track  string
}
type CiyLog struct {
	Filename string
	tkver    string
	tkname   string

	chfile chan ciyLogMsg
	wrfile *bufio.Writer
	lvfile int
	bfile  bool

	chtcp   chan ciyLogMsg
	socktcp net.Conn
	lvtcp   int
	//btcp    bool
}

func NewCiyLog(maxchan int) *CiyLog {
	log := &CiyLog{}
	log.Filename = ""
	log.chfile = make(chan ciyLogMsg, maxchan)
	log.chtcp = make(chan ciyLogMsg, maxchan)
	return log
}

func (thos *CiyLog) InitFile(files string, level int) { //打开文件句柄，每隔2秒写一次磁盘
	thos.lvfile = level
	thos.Filename = files
	f, err := os.OpenFile(files, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0640)
	if err != nil {
		Clog("OpenFile err:", err)
		return
	}
	thos.wrfile = bufio.NewWriter(f)

	thos.bfile = false
	go func() {
		defer func() {
			if conv := recover(); conv != nil {
				Clog("Log File fatal:", conv)
			}
		}()
		for {
			msg := <-thos.chfile
			_, err := thos.wrfile.WriteString(fmt.Sprintf("%v;;%v;;%v;;%v;;%v\n", msg.level, Todate(msg.tim, "Y-m-d H:i:s"), msg.fnname, msg.msg, msg.track))
			if err != nil {
				Clog("Log File Write err:", err)
			}
			thos.bfile = true
		}
	}()
	go func() {
		defer func() {
			if conv := recover(); conv != nil {
				Clog("Log File fatal:", conv)
			}
		}()
		for {
			if thos.bfile {
				err := thos.wrfile.Flush()
				if err != nil {
					Clog("Log File Flush err:", err)
				}
				thos.bfile = false
			}
			time.Sleep(2 * time.Second)
		}
	}()
}
func (thos *CiyLog) InitTCP(ipport string, level int) { //打开TCP客户端，自动重连
	thos.lvtcp = level
	thos.socktcp, _ = net.Dial("tcp", "log.ciy.cn:4005")
	go func() {
		for {
			select {
			case msg := <-thos.chtcp:
				Clog("tcp go", msg)
				//写文件
			default:
				time.Sleep(2 * time.Second)
			}
		}
	}()
}
func (thos *CiyLog) SupportStack(ver string) {
	// vernums := strings.Split(ver, ".")
	// thos.tkver = "V" + vernums[len(vernums)-1]
	thos.tkver = "V" + ver
	thos.tkname = "/" + CiyWebDir[strings.LastIndex(CiyWebDir, "/")+1:] + "/"
}
func (thos *CiyLog) Debug(fnname, msg string) {
	Clog("LOG Debug", fnname, msg)
	if thos == nil {
		return
	}
	thos.setlog(1, fnname, msg)
}
func (thos *CiyLog) Info(fnname, msg string) {
	Clog("LOG Info", fnname, msg)
	if thos == nil {
		return
	}
	thos.setlog(2, fnname, msg)
}
func (thos *CiyLog) Warn(fnname, msg string) {
	Clog("LOG Warn", fnname, msg)
	if thos == nil {
		return
	}
	thos.setlog(3, fnname, msg)
}
func (thos *CiyLog) Error(fnname, msg string) {
	Clog("LOG Error", fnname, msg)
	if thos == nil {
		return
	}
	thos.setlog(4, fnname, msg)
}
func (thos *CiyLog) Fatal(fnname, msg string) {
	Clog("LOG Fatal", fnname, msg)
	if thos == nil {
		return
	}
	thos.setlog(5, fnname, msg)
}
func (thos *CiyLog) setlog(level int, fnname, msg string) {
	track := ""
	if thos.tkname != "" {
		track += thos.tkver
		systrack := 3 //记录框架及系统调用深度
		for i := 2; i < 20; i++ {
			_, file, line, ok := runtime.Caller(i)
			if !ok {
				break
			}
			if ind := strings.Index(file, thos.tkname); ind > -1 {
				if strings.Contains(file, "zciyon") {
					systrack--
					if systrack == 0 {
						break
					}
				} else {
					systrack = 3
				}
				track += fmt.Sprintf("~%v:%v", file[ind+len(thos.tkname):], line)
			} else {
				systrack--
				if systrack == 0 {
					break
				}
				ind := strings.LastIndex(file, "/")
				if ind > -1 {
					ind2 := strings.LastIndex(file[:ind], "/")
					if ind2 > -1 {
						ind = ind2
					}
					track += fmt.Sprintf("~%v:%v", file[ind:], line)
				} else {
					track += fmt.Sprintf("~%v:%v", file, line)
				}
			}
		}
	}
	if thos.wrfile != nil && thos.lvfile <= level {
		thos.chfile <- ciyLogMsg{tim: Tostamp(), level: level, fnname: fnname, msg: msg, track: track}
	}
	if thos.socktcp != nil && thos.lvtcp <= level {
		thos.chtcp <- ciyLogMsg{tim: Tostamp(), level: level, fnname: fnname, msg: msg, track: track}
	}
}
