/* 
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information 
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC. 
 */

namespace iStatVball3;

/*
 * Provides utility methods for calculating variables and computed statistics for Skill metrics from previously
 * accumulated values.
 */ 
public static class MetricsSkillCalculator
{
	/* Methods */

	// Calculates all Skill statistics
	public static void Calculate( MetricsSkill metrics )
	{
		CalculateServe( metrics );
		CalculateReceive( metrics );
		CalculateSet( metrics );
		CalculateAttack( metrics );
		CalculateFree( metrics );
		CalculateBlock( metrics );
		CalculateDefense( metrics );
		CalculateFreeball( metrics );
		CalculatePass( metrics );
		CalculatePassOther( metrics );

		// Must be last (based on other categories)
		CalculateScoring( metrics );
	}

	// Calculates all Serve statistics
	private static void CalculateServe( MetricsSkill metrics )
	{
		int sets = metrics.General_SetsPlayed;

		int zeros = metrics.Serve_Zeros;
		int aces = metrics.Serve_Aces;
		int errors = metrics.Serve_Errors;

		int rating0 = metrics.Serve_Rating0;
		int rating1 = metrics.Serve_Rating1;
		int rating2 = metrics.Serve_Rating2;
		int rating3 = metrics.Serve_Rating3;
		int rating4 = metrics.Serve_Rating4;

		int points = metrics.Serve_Points;

		int firstZeroes = metrics.Serve_First_Zeroes;
		int firstAces = metrics.Serve_First_Aces;
		int firstErrors = metrics.Serve_First_Errors;

		// Calculated variables
		metrics.Serve_Attempts = (zeros + aces + errors);
		metrics.Serve_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

		metrics.Serve_First_Attempts = (firstZeroes + firstAces + firstErrors);

		int rotations = metrics.General_Rotations;
		int attempts = metrics.Serve_Attempts;
		int ratings = metrics.Serve_Ratings;

		int firstAttempts = metrics.Serve_First_Attempts;

		// Statistics
		metrics.Serve_Efficiency = (attempts == 0) ? float.NaN : ((aces - errors) / (float)attempts);
        metrics.Serve_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Serve_AcePercentage = (attempts == 0) ? float.NaN : (aces / (float)attempts);

        metrics.Serve_AcesPerSet = (sets == 0) ? float.NaN : (aces / (float)sets);
		metrics.Serve_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);

		metrics.Serve_PointPercentage = (attempts == 0) ? float.NaN : (points / (float)attempts);
		metrics.Serve_PointsPerRotation = (rotations == 0) ? float.NaN : (points / (float)rotations);

		metrics.Serve_First_Percentage = (firstAttempts == 0) ? float.NaN : ((firstAttempts - firstErrors) / (float)firstAttempts);
	}

	// Calculates all Set statistics
	private static void CalculateSet( MetricsSkill metrics )
	{
		int sets = metrics.General_SetsPlayed;

		int zeros = metrics.Set_Zeros;
		int errors = metrics.Set_Errors;

		int rating0 = metrics.Set_Rating0;
		int rating1 = metrics.Set_Rating1;
		int rating2 = metrics.Set_Rating2;
		int rating3 = metrics.Set_Rating3;
		int rating4 = metrics.Set_Rating4;

		// Calculated variables
		metrics.Set_TotalAssists = (metrics.Set_Assists + metrics.Set_OtherAssists);

		int assists = metrics.Set_TotalAssists;

		metrics.Set_Attempts = (zeros + assists + errors);
		metrics.Set_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

		int attempts = metrics.Set_Attempts;
		int ratings = metrics.Set_Ratings;

		// Statistics
		metrics.Set_Efficiency = (attempts == 0) ? float.NaN : ((assists - errors) / (float)attempts);
        metrics.Set_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Set_AssistsPerSet = (sets == 0) ? float.NaN : (assists / (float)sets);
		metrics.Set_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
	}

	// Calculates all Attack statistics
	private static void CalculateAttack( MetricsSkill metrics )
	{
		int sets = metrics.General_SetsPlayed;

		// Calculated variables
		metrics.Attack_Attempts = (metrics.Attack_Zeros + metrics.Attack_Kills + metrics.Attack_Errors);
		metrics.Attack_OtherAttempts = (metrics.Attack_OtherZeros + metrics.Attack_OtherKills + metrics.Attack_OtherErrors);
		metrics.Attack_TotalZeros = (metrics.Attack_Zeros + metrics.Attack_OtherZeros);

		metrics.Attack_TotalKills = (metrics.Attack_Kills + metrics.Attack_OtherKills);
		int kills = metrics.Attack_TotalKills;

		metrics.Attack_TotalErrors = (metrics.Attack_Errors + metrics.Attack_OtherErrors);
		int errors = metrics.Attack_TotalErrors;

		metrics.Attack_TotalAttempts = (metrics.Attack_Attempts + metrics.Attack_OtherAttempts);
		int attempts = metrics.Attack_TotalAttempts;

		// Statistics
		metrics.Attack_Efficiency = (attempts == 0) ? float.NaN : ((kills - errors) / (float)attempts);
        metrics.Attack_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Attack_KillsPerSet = (sets == 0) ? float.NaN : (kills / (float)sets);

		metrics.Attack_KillPercentage = (attempts == 0) ? float.NaN : (kills / (float)attempts);
		metrics.Attack_ErrorPercentage = (attempts == 0) ? float.NaN : (errors / (float)attempts);
	}

    // Calculates all Free (offense) statistics
    private static void CalculateFree( MetricsSkill metrics )
    {
        // Calculated variables
        metrics.Free_Attempts = (metrics.Free_Zeros + metrics.Free_Kills + metrics.Free_Errors);
		metrics.Free_TotalAttempts = (metrics.Free_Attempts + metrics.Attack_Attempts);

		int attempts = metrics.Free_Attempts;
		int kills = metrics.Free_Kills;
		int errors = metrics.Free_Errors;
		int totalAttempts = metrics.Free_TotalAttempts;

        // Statistics
        metrics.Free_Efficiency = (attempts == 0) ? float.NaN : ((kills - errors) / (float)attempts);
        metrics.Free_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
		metrics.Free_Percentage = (totalAttempts == 0) ? float.NaN : (attempts / (float)totalAttempts);
    }

    // Calculates all Block statistics
    private static void CalculateBlock( MetricsSkill metrics )
	{
		int sets = metrics.General_SetsPlayed;

		int zeros = metrics.Block_Zeros;
		int blocks = metrics.Block_Blocks;
		int assists = metrics.Block_Assists;
		int errors = metrics.Block_Errors;

		// Calculated variables
		metrics.Block_Attempts = (zeros + blocks + assists + errors);

		int attempts = metrics.Block_Attempts;

		metrics.Block_TotalBlocks = (attempts == 0) ? float.NaN : (blocks + (metrics.IsTotal ? (assists * 0.5f) : assists));

		float totalBlocks = metrics.Block_TotalBlocks;

		// Statistics
		metrics.Block_Efficiency = (attempts == 0) ? float.NaN : ((totalBlocks - errors) / (float)attempts);
        metrics.Block_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Block_BlocksPerSet = (sets == 0) ? float.NaN : (totalBlocks / (float)sets);
	}

    // Calculates all Serve Receive statistics
    private static void CalculateReceive( MetricsSkill metrics )
    {
        int zeros = metrics.Receive_Zeros;
        int errors = metrics.Receive_Errors;

        int rating0 = metrics.Receive_Rating0;
        int rating1 = metrics.Receive_Rating1;
        int rating2 = metrics.Receive_Rating2;
        int rating3 = metrics.Receive_Rating3;
        int rating4 = metrics.Receive_Rating4;

        // Calculated variables
        metrics.Receive_Attempts = (zeros + errors);
        metrics.Receive_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

        int attempts = metrics.Receive_Attempts;
        int ratings = metrics.Receive_Ratings;
		int converts = metrics.Receive_Converts;

        // Statistics
        metrics.Receive_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Receive_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
		metrics.Receive_Conversion = (attempts == 0) ? float.NaN : (converts / (float)attempts);
    }

    // Calculates all Defense statistics
    private static void CalculateDefense( MetricsSkill metrics )
	{
		int sets = metrics.General_SetsPlayed;

		int zeros = metrics.Defense_Zeros;
		int digs = metrics.Defense_Digs;
		int errors = metrics.Defense_Errors;

		int rating0 = metrics.Defense_Rating0;
		int rating1 = metrics.Defense_Rating1;
		int rating2 = metrics.Defense_Rating2;
		int rating3 = metrics.Defense_Rating3;
		int rating4 = metrics.Defense_Rating4;

		// Calculated variables
		metrics.Defense_Attempts = (zeros + digs + errors);
		metrics.Defense_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

		int attempts = metrics.Defense_Attempts;
		int ratings = metrics.Defense_Ratings;
		int converts = metrics.Defense_Converts;

		// Statistics
		metrics.Defense_Efficiency = (attempts == 0) ? float.NaN : ((digs - errors) / (float)attempts);
        metrics.Defense_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Defense_DigsPerSet = (sets == 0) ? float.NaN : (digs / (float)sets);
		metrics.Defense_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
		metrics.Defense_Conversion = (attempts == 0) ? float.NaN : (converts / (float)attempts);
	}

    // Calculates all Freeball (defense) statistics
    private static void CalculateFreeball( MetricsSkill metrics )
    {
        int zeros = metrics.Freeball_Zeros;
        int errors = metrics.Freeball_Errors;

        int rating0 = metrics.Freeball_Rating0;
        int rating1 = metrics.Freeball_Rating1;
        int rating2 = metrics.Freeball_Rating2;
        int rating3 = metrics.Freeball_Rating3;
        int rating4 = metrics.Freeball_Rating4;

        // Calculated variables
        metrics.Freeball_Attempts = (zeros + errors);
        metrics.Freeball_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

        int attempts = metrics.Freeball_Attempts;
        int ratings = metrics.Freeball_Ratings;
        int converts = metrics.Freeball_Converts;

        // Statistics
        metrics.Freeball_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
        metrics.Freeball_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
        metrics.Freeball_Conversion = (attempts == 0) ? float.NaN : (converts / (float)attempts);
    }

    // Calculates all Pass (First Ball, Putback) statistics
    private static void CalculatePass( MetricsSkill metrics )
	{
		int zeros = metrics.Pass_Zeros;
		int errors = metrics.Pass_Errors;

		int rating0 = metrics.Pass_Rating0;
		int rating1 = metrics.Pass_Rating1;
		int rating2 = metrics.Pass_Rating2;
		int rating3 = metrics.Pass_Rating3;
		int rating4 = metrics.Pass_Rating4;

		// Calculated variables
		metrics.Pass_Attempts = (zeros + errors);
		metrics.Pass_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

		int attempts = metrics.Pass_Attempts;
		int ratings = metrics.Pass_Ratings;
		int converts = metrics.Pass_Converts;

		// Statistics
		metrics.Pass_Completion = (attempts == 0) ? float.NaN : ((attempts - errors) / (float)attempts);
		metrics.Pass_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
		metrics.Pass_Conversion = (attempts == 0) ? float.NaN : (converts / (float)attempts);
	}

	// Calculates ALL non-Serve Receive pass statistics (Freeball Defense, First Ball, Putback)
	private static void CalculatePassOther( MetricsSkill metrics )
	{
        int rating0 = (metrics.Freeball_Rating0 + metrics.Pass_Rating0);
        int rating1 = (metrics.Freeball_Rating1 + metrics.Pass_Rating1);
        int rating2 = (metrics.Freeball_Rating2 + metrics.Pass_Rating2);
        int rating3 = (metrics.Freeball_Rating3 + metrics.Pass_Rating3);
        int rating4 = (metrics.Freeball_Rating4 + metrics.Pass_Rating4);

		// Calculated variables
        metrics.PassOther_Ratings = (rating0 + rating1 + rating2 + rating3 + rating4);

        int ratings = metrics.PassOther_Ratings;

		// Statistics
        metrics.PassOther_Rating = (ratings == 0) ? float.NaN : (((rating0 * 0) + (rating1 * 1) + (rating2 * 2) + (rating3 * 3) + (rating4 * 4)) / (float)ratings);
    }

    // Calculates all Scoring category statistics
    private static void CalculateScoring( MetricsSkill metrics )
	{
		float blocks = metrics.Block_TotalBlocks;

		// Protect against '--' when no blocks
		blocks = float.IsNaN( blocks ) ? 0.0f : blocks;

		// Calculated variables
		metrics.Scoring_Points = (metrics.Attack_TotalKills + metrics.Serve_Aces + blocks);
	}
}

//
