// Copyright 2018 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package procfs

import (
	
	
	
	
	

	
)

// ProcStatus provides status information about the process,
// read from /proc/[pid]/status.
type ProcStatus struct {
	// The process ID.
	PID int
	// The process name.
	Name string

	// Thread group ID.
	TGID int
	// List of Pid namespace.
	NSpids []uint64

	// Peak virtual memory size.
	VmPeak uint64 // nolint:revive
	// Virtual memory size.
	VmSize uint64 // nolint:revive
	// Locked memory size.
	VmLck uint64 // nolint:revive
	// Pinned memory size.
	VmPin uint64 // nolint:revive
	// Peak resident set size.
	VmHWM uint64 // nolint:revive
	// Resident set size (sum of RssAnnon RssFile and RssShmem).
	VmRSS uint64 // nolint:revive
	// Size of resident anonymous memory.
	RssAnon uint64 // nolint:revive
	// Size of resident file mappings.
	RssFile uint64 // nolint:revive
	// Size of resident shared memory.
	RssShmem uint64 // nolint:revive
	// Size of data segments.
	VmData uint64 // nolint:revive
	// Size of stack segments.
	VmStk uint64 // nolint:revive
	// Size of text segments.
	VmExe uint64 // nolint:revive
	// Shared library code size.
	VmLib uint64 // nolint:revive
	// Page table entries size.
	VmPTE uint64 // nolint:revive
	// Size of second-level page tables.
	VmPMD uint64 // nolint:revive
	// Swapped-out virtual memory size by anonymous private.
	VmSwap uint64 // nolint:revive
	// Size of hugetlb memory portions
	HugetlbPages uint64

	// Number of voluntary context switches.
	VoluntaryCtxtSwitches uint64
	// Number of involuntary context switches.
	NonVoluntaryCtxtSwitches uint64

	// UIDs of the process (Real, effective, saved set, and filesystem UIDs)
	UIDs [4]uint64
	// GIDs of the process (Real, effective, saved set, and filesystem GIDs)
	GIDs [4]uint64

	// CpusAllowedList: List of cpu cores processes are allowed to run on.
	CpusAllowedList []uint64
}

// NewStatus returns the current status information of the process.
func ( Proc) () (ProcStatus, error) {
	,  := util.ReadFileNoStat(.path("status"))
	if  != nil {
		return ProcStatus{}, 
	}

	 := ProcStatus{PID: .PID}

	 := strings.Split(string(), "\n")
	for ,  := range  {
		if !bytes.Contains([]byte(), []byte(":")) {
			continue
		}

		 := strings.SplitN(, ":", 2)

		// removes spaces
		 := strings.TrimSpace([0])
		 := strings.TrimSpace([1])
		// removes "kB"
		 = strings.TrimSuffix(, " kB")

		// value to int when possible
		// we can skip error check here, 'cause vKBytes is not used when value is a string
		,  := strconv.ParseUint(, 10, 64)
		// convert kB to B
		 :=  * 1024

		 = .fillStatus(, , , )
		if  != nil {
			return ProcStatus{}, 
		}
	}

	return , nil
}

func ( *ProcStatus) ( string,  string,  uint64,  uint64) error {
	switch  {
	case "Tgid":
		.TGID = int()
	case "Name":
		.Name = 
	case "Uid":
		var  error
		for ,  := range strings.Split(, "\t") {
			.UIDs[],  = strconv.ParseUint(, 10, bits.UintSize)
			if  != nil {
				return 
			}
		}
	case "Gid":
		var  error
		for ,  := range strings.Split(, "\t") {
			.GIDs[],  = strconv.ParseUint(, 10, bits.UintSize)
			if  != nil {
				return 
			}
		}
	case "NSpid":
		,  := calcNSPidsList()
		if  != nil {
			return 
		}
		.NSpids = 
	case "VmPeak":
		.VmPeak = 
	case "VmSize":
		.VmSize = 
	case "VmLck":
		.VmLck = 
	case "VmPin":
		.VmPin = 
	case "VmHWM":
		.VmHWM = 
	case "VmRSS":
		.VmRSS = 
	case "RssAnon":
		.RssAnon = 
	case "RssFile":
		.RssFile = 
	case "RssShmem":
		.RssShmem = 
	case "VmData":
		.VmData = 
	case "VmStk":
		.VmStk = 
	case "VmExe":
		.VmExe = 
	case "VmLib":
		.VmLib = 
	case "VmPTE":
		.VmPTE = 
	case "VmPMD":
		.VmPMD = 
	case "VmSwap":
		.VmSwap = 
	case "HugetlbPages":
		.HugetlbPages = 
	case "voluntary_ctxt_switches":
		.VoluntaryCtxtSwitches = 
	case "nonvoluntary_ctxt_switches":
		.NonVoluntaryCtxtSwitches = 
	case "Cpus_allowed_list":
		.CpusAllowedList = calcCpusAllowedList()
	}

	return nil
}

// TotalCtxtSwitches returns the total context switch.
func ( ProcStatus) () uint64 {
	return .VoluntaryCtxtSwitches + .NonVoluntaryCtxtSwitches
}

func calcCpusAllowedList( string) []uint64 {
	 := strings.Split(, ",")

	var  []uint64

	for ,  := range  {
		// parse cpu ranges, example: 1-3=[1,2,3]
		if  := strings.Split(strings.TrimSpace(), "-"); len() > 1 {
			,  := strconv.ParseUint([0], 10, 64)
			,  := strconv.ParseUint([1], 10, 64)

			for  := ;  <= ; ++ {
				 = append(, )
			}
		} else if len() == 1 {
			,  := strconv.ParseUint([0], 10, 64)
			 = append(, )
		}

	}

	sort.Slice(, func(,  int) bool { return [] < [] })
	return 
}

func calcNSPidsList( string) ([]uint64, error) {
	 := strings.Split(, "\t")
	var  []uint64

	for ,  := range  {
		,  := strconv.ParseUint(, 10, 64)
		if  != nil {
			return nil, 
		}
		 = append(, )
	}

	return , nil
}