<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Classes\Util;

/**
 * A class to measure performance of php code
 *
 * Do not use this class in productive code.
 *
 * Example Usage:
 *
 * <code>
 * <?php
 * PerformanceUtil::beginMeasuring('measureSomething');
 * doSomething()
 * PerformanceUtil::checkPoint('doSomething');
 * doSomethingElse()
 * PerformanceUtil::checkPoint('doSomethingElse');
 * someShutdown()
 * PerformanceUtil:endMeasuring();
 * ?>
 * </code>
 *
 * Creates a csv file at measureSomething_1234567890.csv with performance and memory information
 */
class PerformanceUtil
{
    /**
     * @var int Counter for checkpoint calls
     */
    private static $checkPointCounter = 0;

    /**
     * @var float Unix timestamp in seconds since start of measuring
     */
    private static $startUpTime = 0.0;

    /**
     * @var bool|resource
     */
    private static $fileHandle = false;

    /**
     * Counts the visits of a checkpoint
     *
     * Array of the kind: [[<checkPointName> => <int>], ...]
     *
     * @var array
     */
    private static $checkPointVisits = [];

    /**
     * @var array text width of each column, used for justification
     */
    private static $columnWidths = [];

    /**
     * @var float Seconds since last checkpoint visit
     */
    private static $lastCheckPointTime = 0.0;

    /**
     * Begin a performance measuring.
     *
     * The results will be saved in a file called <$fileNamePrefix>_<unix_timestamp()>.csv
     *
     * @param string $fileNamePrefix
     */
    public static function beginMeasuring($fileNamePrefix = 'PerformanceTest')
    {
        if (self::$fileHandle !== false) {
            self::endMeasuring();
        }

        self::$startUpTime = microtime(true);
        self::$checkPointCounter = 0;
        self::$checkPointVisits = [];
        self::$lastCheckPointTime = microtime(true);

        $fileName = $fileNamePrefix . '_' . time() . '.csv';

        self::$fileHandle = fopen($fileName, 'w');
        if (self::$fileHandle === false) {
            throw new \RuntimeException('Could not open file $fileName');
        }

        $columnHeaders = [
            ' checkpointNumber',
            str_pad('checkpointName', '32'),
            ' numberOfCalls',
            ' secondsSinceStart',
            ' secondsSinceLastNode',
            ' currentMemoryKilobytes',
        ];

        fputcsv(
            self::$fileHandle,
            $columnHeaders,
            ';' // Use semicolon since our data contains thousands separators (',')
        );

        self::$columnWidths = array_map(function ($columnHeader) {
            return mb_strlen($columnHeader);
        }, $columnHeaders);

        self::checkPoint('START');
    }

    /**
     * End a measuring
     */
    public static function endMeasuring()
    {
        self::checkPoint('END');
        fclose(self::$fileHandle);
    }

    /**
     * Take a measuring snap shot of time and memory
     *
     * @param $name
     */
    public static function checkPoint($name)
    {
        self::$checkPointCounter++;
        self::$checkPointVisits[$name]++;

        $totalElapsedTime = microtime(true) - self::$startUpTime;
        $timeElapsedSinceLastCheckpoint = microtime(true) - self::$lastCheckPointTime;

        fputcsv(
            self::$fileHandle,
            [
                str_pad(self::$checkPointCounter, self::$columnWidths[0], ' ', STR_PAD_LEFT),
                str_pad($name, self::$columnWidths[1]),
                str_pad(self::$checkPointVisits[$name], self::$columnWidths[2], ' ', STR_PAD_LEFT),
                str_pad(sprintf('%.3f', $totalElapsedTime), self::$columnWidths[3], ' ', STR_PAD_LEFT),
                str_pad(sprintf('%.3f', $timeElapsedSinceLastCheckpoint), self::$columnWidths[4], ' ', STR_PAD_LEFT),
                str_pad(number_format(memory_get_usage() / 1024), self::$columnWidths[5], ' ', STR_PAD_LEFT),
            ],
            ';' // Use semicolon since our data contains thousands separators (',')
        );

        self::$lastCheckPointTime = microtime(true);
    }
}
