/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* L2J Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jserver.gameserver.model.stats;
import java.util.ArrayList;
import java.util.List;
import com.l2jserver.gameserver.model.actor.L2Character;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.model.stats.functions.AbstractFunction;
/**
* A calculator is created to manage and dynamically calculate the effect of a character property (ex : MAX_HP, REGENERATE_HP_RATE...).<br>
* In fact, each calculator is a table of Func object in which each Func represents a mathematical function:<br>
* FuncAtkAccuracy -> Math.sqrt(_player.getDEX())*6+_player.getLevel()<br>
* When the calc method of a calculator is launched, each mathematical function is called according to its priority <B>_order</B>.<br>
* Indeed, Func with lowest priority order is executed first and Funcs with the same order are executed in unspecified order.<br>
* The result of the calculation is stored in the value property of an Env class instance.<br>
* Method addFunc and removeFunc permit to add and remove a Func object from a Calculator.
*/
public final class Calculator
{
/** Empty Func table definition */
private static final AbstractFunction[] EMPTY_FUNCS = new AbstractFunction[0];
/** Table of Func object */
private AbstractFunction[] _functions;
/**
* Constructor of Calculator (Init value : emptyFuncs).
*/
public Calculator()
{
_functions = EMPTY_FUNCS;
}
/**
* Constructor of Calculator (Init value : Calculator c).
* @param c
*/
public Calculator(Calculator c)
{
_functions = c._functions;
}
/**
* Check if 2 calculators are equals.
* @param c1
* @param c2
* @return
*/
public static boolean equalsCals(Calculator c1, Calculator c2)
{
if (c1 == c2)
{
return true;
}
if ((c1 == null) || (c2 == null))
{
return false;
}
AbstractFunction[] funcs1 = c1._functions;
AbstractFunction[] funcs2 = c2._functions;
if (funcs1 == funcs2)
{
return true;
}
if (funcs1.length != funcs2.length)
{
return false;
}
if (funcs1.length == 0)
{
return true;
}
for (int i = 0; i < funcs1.length; i++)
{
if (funcs1[i] != funcs2[i])
{
return false;
}
}
return true;
}
/**
* Return the number of Funcs in the Calculator.
* @return
*/
public int size()
{
return _functions.length;
}
/**
* Adds a function to the Calculator.
* @param function the function
*/
public synchronized void addFunc(AbstractFunction function)
{
AbstractFunction[] funcs = _functions;
AbstractFunction[] tmp = new AbstractFunction[funcs.length + 1];
final int order = function.getOrder();
int i;
for (i = 0; (i < funcs.length) && (order >= funcs[i].getOrder()); i++)
{
tmp[i] = funcs[i];
}
tmp[i] = function;
for (; i < funcs.length; i++)
{
tmp[i + 1] = funcs[i];
}
_functions = tmp;
}
/**
* Removes a function from the Calculator.
* @param function the function
*/
public synchronized void removeFunc(AbstractFunction function)
{
AbstractFunction[] funcs = _functions;
AbstractFunction[] tmp = new AbstractFunction[funcs.length - 1];
int i;
for (i = 0; (i < (funcs.length - 1)) && (function != funcs[i]); i++)
{
tmp[i] = funcs[i];
}
if (i == funcs.length)
{
return;
}
for (i++; i < funcs.length; i++)
{
tmp[i - 1] = funcs[i];
}
if (tmp.length == 0)
{
_functions = EMPTY_FUNCS;
}
else
{
_functions = tmp;
}
}
/**
* Remove each Func with the specified owner of the Calculator.
* @param owner the owner
* @return a list of modified stats
*/
public synchronized List<Stats> removeOwner(Object owner)
{
List<Stats> modifiedStats = new ArrayList<>();
for (AbstractFunction func : _functions)
{
if (func.getFuncOwner() == owner)
{
modifiedStats.add(func.getStat());
removeFunc(func);
}
}
return modifiedStats;
}
/**
* Run each function of the Calculator.
* @param caster the caster
* @param target the target
* @param skill the skill
* @param initVal the initial value
* @return the calculated value
*/
public double calc(L2Character caster, L2Character target, Skill skill, double initVal)
{
double value = initVal;
for (AbstractFunction func : _functions)
{
value = func.calc(caster, target, skill, value);
}
return value;
}
/**
* Get array of all function, dont use for add/remove
* @return
*/
public AbstractFunction[] getFunctions()
{
return _functions;
}
}