func swSystemInfo(ip string, ch chan SwSystem) {
	var swSystem SwSystem
	swSystem.Ip = ip

	//ping timeout.Millisecond
	timeout := 1000
	pingCount := 1

	ping, err := sw.PingStatSummary(ip, pingCount, timeout)
	if err != nil {
		log.Println(err)
		ch <- swSystem
		return
	} else {
		swSystem.Ping = ping["max"]

		uptime, err := sw.SysUpTime(ip, g.Config().Switch.Community, timeout)
		if err != nil {
			log.Println(err)
			ch <- swSystem
			return
		} else {
			swSystem.Uptime = uptime

			cpuUtili, err := sw.CpuUtilization(ip, g.Config().Switch.Community, timeout, 1)
			if err != nil {
				log.Println(err)
			} else {
				swSystem.Cpu = cpuUtili
			}

			memUtili, err := sw.MemUtilization(ip, g.Config().Switch.Community, timeout, 1)
			if err != nil {
				log.Println(err)
			} else {
				swSystem.Mem = memUtili
			}

			swModel, err := sw.SysModel(ip, g.Config().Switch.Community, timeout)
			if err != nil {
				log.Println(err)
			} else {
				swSystem.Model = swModel
			}

			swName, err := sw.SysName(ip, g.Config().Switch.Community, timeout)
			if err != nil {
				log.Println(err)
			} else {
				swSystem.Hostname = swName
			}

		}

	}

	ch <- swSystem
	return
}
func getfaces() map[string]string {
	list, err := net.Interfaces()
	if err != nil {
		log.Println("ERROR: get interfaces!", err)
		return nil
		//panic(err)
	}
	if len(lanlist) == 0 {
		if g.Config().Collector == nil || g.Config().Collector.LanIpnet == nil {
			return nil
		}
		//println("init lanlist")
		lanstrs := g.Config().Collector.LanIpnet
		parseIPNets(&lanstrs, &lanlist)

	}
	tiflist := make(map[string]string)
	//Ifacelies =  make([]string,0)
	for _, iface := range list {
		if (iface.Flags&net.FlagUp) == 0 || (iface.Flags&net.FlagLoopback) != 0 || (iface.Flags&net.FlagPointToPoint) != 0 {
			continue
		}

		addrs, err := iface.Addrs()
		if len(addrs) == 0 {
			//println("no ip")
			continue
		}
		if err != nil {
			continue
		}
		islan := false
		for _, addr := range addrs {

			ip, _, err := net.ParseCIDR(addr.String())
			if err != nil {
				continue
			}
			if ip.To4() == nil {
				continue
			}
			//println(len(lanlist))
			for _, in := range lanlist {
				//println(ip.String(),in.String())
				if in.Contains(ip) {
					islan = true
					break
				}
			}
			if islan == false {
				tiflist[ip.String()] = iface.Name
			}

		}
	}
	return tiflist
}
func StartIfStatsCollector() {
	if !g.Config().Switch.Enabled || len(g.Config().Switch.IpRange) == 0 {
		return
	}
	initVariable()
	InitIfstatsQ()
	InitTask()

	go SwifMapChecker()
	SWifMetricToTransfer()
}
func Collect() {
	if !g.Config().Transfer.Enabled {
		return
	}

	if g.Config().Transfer.Addr == "" {
		return
	}
	go ifstat.StartIfStatsCollector()
	for _, v := range funcs.Mappers {
		go collect(int64(v.Interval), v.Fs)
	}
}
func memMetrics(ip string, ch chan SwMem) {
	var swMem SwMem

	memUtili, err := sw.MemUtilization(ip, g.Config().Switch.Community, g.Config().Switch.SnmpTimeout, g.Config().Switch.SnmpRetry)
	if err != nil {
		log.Println(err)
	}

	swMem.Ip = ip
	swMem.MemUtili = memUtili
	ch <- swMem

	return
}
func cpuMetrics(ip string, ch chan SwCpu) {
	var swCpu SwCpu

	cpuUtili, err := sw.CpuUtilization(ip, g.Config().Switch.Community, g.Config().Switch.SnmpTimeout, g.Config().Switch.SnmpRetry)
	if err != nil {
		log.Println(err)
	}

	swCpu.Ip = ip
	swCpu.CpuUtil = cpuUtili
	ch <- swCpu

	return
}
func SwifMapChecker() {
	log.Println("start SwifMapChecker!")
	AllIp = AllSwitchIp()
	for i := 0; i < len(AllIp); i++ {
		go CollectWorker()
	}
	limitCh := make(chan bool, g.Config().Switch.LimitConcur)
	for {
		for _, ip := range AllIp {
			limitCh <- true
			go coreSwIfMap(ip, limitCh)
			time.Sleep(5 * time.Millisecond)
		}
		log.Println("Mapchecker end ", len(HightQueue), len(LowQueue), len(chworkerLm), len(AllIp))
		lt := <-LowQueue
		LowQueue <- lt
		if lt.NextTime.Before(time.Now()) && len(chworkerLm) < MaxTaskWorkers-10 {
			go CollectWorker()

		}

		time.Sleep(10 * time.Minute)
	}

}
func configSwRoutes() {

	http.HandleFunc("/page/sw/time", func(w http.ResponseWriter, req *http.Request) {
		RenderDataJson(w, time.Now().Format("2006-01-02 15:04:05"))
	})

	http.HandleFunc("/page/sw/iprange", func(w http.ResponseWriter, req *http.Request) {
		RenderDataJson(w, strings.Join(g.Config().Switch.IpRange, "\n"))
	})

	http.HandleFunc("/page/sw/live", func(w http.ResponseWriter, req *http.Request) {
		RenderDataJson(w, len(funcs.AliveIp))
	})

	http.HandleFunc("/page/sw/list", func(w http.ResponseWriter, r *http.Request) {

		var ret [][]interface{} = make([][]interface{}, 0)
		for _, swSystem := range funcs.SwSystemInfo() {
			ret = append(ret,
				[]interface{}{
					swSystem.Ip,
					swSystem.Hostname,
					swSystem.Model,
					swSystem.Uptime,
					fmt.Sprintf("%d%%", swSystem.Cpu),
					fmt.Sprintf("%d%%", swSystem.Mem),
					fmt.Sprintf("%sms", swSystem.Ping),
				})
		}
		RenderDataJson(w, ret)
	})
}
func configAdminRoutes() {
	http.HandleFunc("/exit", func(w http.ResponseWriter, r *http.Request) {
		if g.IsTrustable(r.RemoteAddr) {
			w.Write([]byte("exiting..."))
			go func() {
				time.Sleep(time.Second)
				os.Exit(0)
			}()
		} else {
			w.Write([]byte("no privilege"))
		}
	})

	http.HandleFunc("/config/reload", func(w http.ResponseWriter, r *http.Request) {
		if g.IsTrustable(r.RemoteAddr) {
			g.ParseConfig(g.ConfigFile)
			RenderDataJson(w, g.Config())
		} else {
			w.Write([]byte("no privilege"))
		}
	})

	http.HandleFunc("/workdir", func(w http.ResponseWriter, r *http.Request) {
		RenderDataJson(w, file.SelfDir())
	})

	http.HandleFunc("/ips", func(w http.ResponseWriter, r *http.Request) {
		RenderDataJson(w, g.TrustableIps())
	})
}
func Start() {
	if !g.Config().Http.Enabled {
		return
	}

	addr := g.Config().Http.Listen
	if addr == "" {
		return
	}

	s := &http.Server{
		Addr:           addr,
		MaxHeaderBytes: 1 << 30,
	}

	log.Println("listening", addr)
	log.Fatalln(s.ListenAndServe())
}
func AllSwitchIp() (allIp []string) {
	switchIp := g.Config().Switch.IpRange

	if len(switchIp) > 0 {
		for _, sip := range switchIp {
			aip := sw.ParseIp(sip)
			for _, ip := range aip {
				allIp = append(allIp, ip)
			}
		}
	}
	return allIp
}
func BuildMappers() {
	interval := g.Config().Transfer.Interval
	Mappers = []FuncsAndInterval{
		FuncsAndInterval{
			Fs: []func() []*model.MetricValue{
				AgentMetrics,
				CpuMetrics,
				MemMetrics,
				PingMetrics,
				TrafficMetrics,
			},
			Interval: interval,
		},
	}
}
func pingMetrics(ip string, ch chan SwPing) {
	var swPing SwPing
	timeout := g.Config().Switch.PingTimeout * 4

	rtt, err := sw.PingRtt(ip, timeout)
	if err != nil {
		log.Println(ip, err)
		swPing.Ping = 0
	}

	swPing.Ip = ip
	swPing.Ping = rtt
	ch <- swPing

	return
}
func syncTrustableIps() {

	duration := time.Duration(g.Config().Heartbeat.Interval) * time.Second

	for {
	REST:
		time.Sleep(duration)

		var ips string
		err := g.HbsClient.Call("Agent.TrustableIps", model.NullRpcRequest{}, &ips)
		if err != nil {
			log.Println("ERROR: call Agent.TrustableIps fail", err)
			goto REST
		}

		g.SetTrustableIps(ips)
	}
}
func NewMetricValueIp(TS int64, ip, metric string, val interface{}, dataType string, tags ...string) *model.MetricValue {
	sec := int64(g.Config().Transfer.Interval)

	mv := model.MetricValue{
		Metric:    metric,
		Value:     val,
		Type:      dataType,
		Endpoint:  ip,
		Step:      sec,
		Timestamp: TS,
	}

	size := len(tags)

	if size > 0 {
		mv.Tags = strings.Join(tags, ",")
	}

	return &mv
}
func SyncTrustableIps() {
	if g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != "" {
		go syncTrustableIps()
	}
}
func SyncBuiltinMetrics() {
	if g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != "" {
		go syncBuiltinMetrics()
	}
}
func syncBuiltinMetrics() {

	var timestamp int64 = -1
	var checksum string = "nil"

	duration := time.Duration(g.Config().Heartbeat.Interval) * time.Second

	for {
	REST:
		time.Sleep(duration)

		var ports = []int64{}
		var procs = make(map[string]map[int]string)

		hostname, err := g.Hostname()
		if err != nil {
			goto REST
		}

		req := model.AgentHeartbeatRequest{
			Hostname: hostname,
			Checksum: checksum,
		}

		var resp model.BuiltinMetricResponse
		err = g.HbsClient.Call("Agent.BuiltinMetrics", req, &resp)
		if err != nil {
			log.Println("ERROR:", err)
			goto REST
		}

		if resp.Timestamp <= timestamp {
			goto REST
		}

		if resp.Checksum == checksum {
			goto REST
		}

		timestamp = resp.Timestamp
		checksum = resp.Checksum

		for _, metric := range resp.Metrics {
			if metric.Metric == "net.port.listen" {
				if !strings.Contains(metric.Tags, "=") {
					// illegal
					continue
				}

				if port, err := strconv.ParseInt(metric.Tags[5:], 10, 64); err == nil {
					ports = append(ports, port)
				}

				continue
			}

			if metric.Metric == "proc.num" {
				arr := strings.Split(metric.Tags, ",")

				tmpMap := make(map[int]string)

				for i := 0; i < len(arr); i++ {
					if strings.HasPrefix(arr[i], "name=") {
						tmpMap[1] = arr[i][5:]
					} else if strings.HasPrefix(arr[i], "cmdline=") {
						tmpMap[2] = arr[i][8:]
					}
				}

				procs[metric.Tags] = tmpMap
			}
		}

		g.SetReportPorts(ports)
		g.SetReportProcs(procs)

	}
}
func initVariable() {
	pingTimeout = g.Config().Switch.PingTimeout
	pingRetry = g.Config().Switch.PingRetry

	community = g.Config().Switch.Community
	snmpTimeout = g.Config().Switch.SnmpTimeout
	snmpRetry = g.Config().Switch.SnmpRetry

	ignoreIface = g.Config().Switch.IgnoreIface
	hightIface = g.Config().Switch.HightIface
	ignorePkt = g.Config().Switch.IgnorePkt
	interval = time.Duration(int64(g.Config().Transfer.Interval)) * time.Second
	isdebug = g.Config().Debug

	chworkerLm = make(chan bool, g.Config().Switch.LimitConcur)

}
func ReportAgentStatus() {
	if g.Config().Heartbeat.Enabled && g.Config().Heartbeat.Addr != "" {
		go reportAgentStatus(time.Duration(g.Config().Heartbeat.Interval) * time.Second)
	}
}