--
--  Copyright (c) 2020-2024, Adel Noureddine, Université de Pau et des Pays de l'Adour.
--  All rights reserved. This program and the accompanying materials
--  are made available under the terms of the
--  GNU General Public License v3.0 only (GPL-3.0-only)
--  which accompanies this distribution, and is available at:
--  https://www.gnu.org/licenses/gpl-3.0.en.html
--
--  Author : Adel Noureddine
--

with Ada.Text_IO; use Ada.Text_IO;
with GNAT.String_Split; use GNAT;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with GNAT.OS_Lib; use GNAT.OS_Lib;

package body CPU_STAT_PID is

    procedure Calculate_PID_Time (PID_Data : in out CPU_STAT_PID_Data; Is_Before : in Boolean) is
        F : File_Type; -- File handle
        File_Name : constant String := "/proc/" & Trim(Integer'Image(PID_Data.PID_Number), Ada.Strings.Left) & "/stat"; -- File name /proc/pid/stat
        Subs : String_Split.Slice_Set; -- Used to slice the read data from stat file
        Seps : constant String := " "; -- Seperator (space) for slicing string
        Utime : Long_Integer; -- User time
        Stime : Long_Integer; -- System time
    begin
        Open (F, In_File, File_Name);
        String_Split.Create (S          => Subs, -- Store sliced data in Subs
                             From       => Get_Line (F), -- Read data to slice. We only need the first line of the stat file
                             Separators => Seps, -- Separator (here space)
                             Mode       => String_Split.Multiple);
        Close (F);

        -- Reading cpu time from /proc/pid/stat
        -- We only need utime and stime (user and system time)
        -- utime is at index 13, stime at index 14 (assuming index starts at 0)
        -- utime  %lu : Amount of time that this process has been scheduled in user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). This includes guest time, guest_time (time spent running a virtual CPU, see below), so that applications that are not aware of the guest time field do not lose that time from their calculations.
        -- stime  %lu :  Amount of time that this process has been scheduled in kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
        -- Example of line: 25152 (java) S 12564 1685 1685 0 -1 1077960704 155132 412 478 2 11617 1816 0 0 20 0 61 0 2001362 3813126144 99139 18446744073709551615 4194304 4196724 140736365379696 140736365362368 140056419567211 0 0 4096 16796879 18446744073709551615 0 0 17 2 0 0 3 0 0 6294960 6295616 13131776 140736365387745 140736365388341 140736365388341 140736365391821 0
        -- fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu", &cpu_process_data->utime, &cpu_process_data->stime);
        Utime := Long_Integer'Value (String_Split.Slice (Subs, 14)); -- Index 13 in file. Slice function starts index at 1, so it is 14
        Stime := Long_Integer'Value (String_Split.Slice (Subs, 15)); -- Index 14 in file. Slice function starts index at 1, so it is 15
        if (Is_Before) then
            PID_Data.Before_Time := Utime + Stime; -- Total time
        else
            PID_Data.After_Time := Utime + Stime; -- Total time
            PID_Data.Monitored_Time := PID_Data.After_Time - PID_Data.Before_Time;
        end if;
    exception
        when others =>
            Put_Line ("Error reading " & File_Name & " file");
            OS_Exit (0);
    end;

end CPU_STAT_PID;
