package main

import (
	"errors"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/net"
	"github.com/shirou/gopsutil/process"
	"time"
)

type MemInfo struct {
	Total       uint64
	Free        uint64
	Used        uint64
	Cached      uint64
	UsedPercent float64
}

/**
returns: Total, Free, Used, Cached, UsedPercent
*/
func getMem() (*MemInfo, error) {
	m, e := mem.VirtualMemory()
	if e == nil {
		data := &MemInfo{}
		data.Total = m.Total
		data.Free = m.Free
		data.Used = m.Used
		data.Cached = m.Buffers + m.Cached
		data.UsedPercent = m.UsedPercent
		return data, nil
	}
	return &MemInfo{}, errors.New("could not get memory data")
}

type CPUInfo struct {
	ModelName string
	Cores     int32
	Mhz       float64
	CacheSize int32
}

func getCPU() (*[]CPUInfo, error) {
	cpus, e := cpu.Info()
	if e == nil {
		data := make([]CPUInfo, len(cpus))
		for i := 0; i < len(cpus); i++ {
			c := cpus[i]
			data[i].ModelName = c.ModelName
			data[i].Cores = c.Cores
			data[i].Mhz = c.Mhz
			data[i].CacheSize = c.CacheSize
		}
		return &data, nil
	}
	return &[]CPUInfo{}, errors.New("could not found CPU info")
}

type Process struct {
	ProcessName          string
	ProcessCPUPercent    float64
	ProcessMemoryPercent float32
	ProcessUserName      string
}

//TODO: 返回值，错误处理，范围
func getAllProcess() *[]Process {
	pi, _ := process.Pids()
	data := make([]Process, len(pi))
	for i := 0; i < len(pi); i++ {
		p, _ := process.NewProcess(pi[i])
		pn, _ := p.Name()
		pc, _ := p.CPUPercent()
		pm, _ := p.MemoryPercent()
		pu, _ := p.Username()
		data[i].ProcessName = pn
		data[i].ProcessCPUPercent = pc
		data[i].ProcessMemoryPercent = pm
		data[i].ProcessUserName = pu
	}
	return &data
}

//TODO: per nic
/**
bytesRecv: 23530889
bytesSent: 6687155
dropin: 0
dropout: 0
errin: 0
errout: 0
fifoin: 0
fifoout: 0
NetIO: "all"
packetsRecv: 305999
packetsSent: 96951
*/
type NetIO struct {
	BytesRecv   uint64
	BytesSent   uint64
	PacketsRecv uint64
	PacketsSent uint64
}

func getNetIO() (*NetIO, error) {
	io := &NetIO{}
	b, e := net.IOCounters(false)
	if e == nil {
		data := b[0]
		io.BytesRecv = data.BytesRecv
		io.BytesSent = data.BytesSent
		io.PacketsRecv = data.PacketsRecv
		io.PacketsSent = data.PacketsSent
		return io, nil
	}
	return &NetIO{}, errors.New("could not get net IO")
}

// 获取CPU百分比
func getCPUPercent() (float64, error) {
	a, e := cpu.Percent(time.Duration(time.Second), false)
	if e == nil {
		return a[0], nil
	} else {
		return 0, errors.New("could not get cpu percent")
	}
}

/**
device: "/dev/dm-0"
fstype: "xfs"
mountpoint: "/"
opts: "rw,relatime"
*/
func getDiskPartition() ([]disk.PartitionStat, error) {
	d, err := disk.Partitions(false)
	if err == nil {
		return d, nil
	}
	return nil, errors.New("could not get disk partition")
}

/**
free: 15353872384
fstype: "xfs"
inodesFree: 8837809
inodesTotal: 8910848
inodesUsed: 73039
inodesUsedPercent: 0.8196638524189842
path: "/"
total: 18238930944
used: 2885058560
usedPercent: 15.818134126710358
*/
type DiskUsage struct {
	Path        string
	FsType      string
	Total       uint64
	Free        uint64
	Used        uint64
	UsedPercent float64
}

func getDiskUsage(path string) (*DiskUsage, error) {
	d, err := disk.Usage(path)
	if err != nil {
		return nil, errors.New("could not get disk usage")
	}
	usage := &DiskUsage{}
	usage.Path = d.Path
	usage.FsType = d.Fstype
	usage.Total = d.Total
	usage.Free = d.Free
	usage.Used = d.Used
	usage.UsedPercent = d.UsedPercent
	return usage, nil
}

type NetInterface struct {
	Name         string
	HardwareAddr string
}

func getFirstNetInterface() (*NetInterface, error) {
	n, e := net.Interfaces()
	data := &NetInterface{}
	if e != nil {
		return data, nil
	}
	for _, v := range n {
		if v.HardwareAddr == "" {
			continue
		}
		data.Name = v.Name
		data.HardwareAddr = v.HardwareAddr
	}
	return data, nil
}
