/****************************************************************************
*
*                                 M U E S L I   v 1.8
*
*
*     Copyright 2020 IMDEA Materials Institute, Getafe, Madrid, Spain
*     Contact: muesli.materials@imdea.org
*     Author: Ignacio Romero (ignacio.romero@imdea.org)
*
*     This file is part of MUESLI.
*
*     MUESLI 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.
*
*     MUESLI 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 MUESLI.  If not, see <http://www.gnu.org/licenses/>.
*
****************************************************************************/

#include "utils.h"


namespace muesli
{

    thPotentials::thPotentials()
    :
        chemical(0.0),
        deviatoric(0.0),
        dissipated(0.0),
        entropy(0.0),
        freeEnergy(0.0),
        freeEntropy(0.0),
        internalEnergy(0.0),
        kineticPotential(0.0),
        minimizing(0.0),
        volumetric(0.0)
    {}


    void thPotentials::setZero()
    {
        chemical       = 0.0;
        deviatoric     = 0.0;
        dissipated     = 0.0;
        entropy        = 0.0;
        freeEnergy     = 0.0;
        freeEntropy    = 0.0;
        internalEnergy = 0.0;
        kineticPotential= 0.0;
        minimizing     = 0.0;
        volumetric     = 0.0;
    }


    thPotentials& thPotentials::operator+=(const thPotentials &th)
    {
        chemical       += th.chemical;
        deviatoric     += th.deviatoric;
        dissipated     += th.dissipated;
        entropy        += th.entropy;
        freeEnergy     += th.freeEnergy;
        freeEntropy    += th.freeEntropy;
        internalEnergy += th.internalEnergy;
        kineticPotential+=th.kineticPotential;
        minimizing     += th.minimizing;
        volumetric     += th.volumetric;

        return (*this);
    }



    thPotentials& thPotentials::operator*=(double a)
    {
        chemical       *= a;
        deviatoric     *= a;
        dissipated     *= a;
        entropy        *= a;
        freeEnergy     *= a;
        freeEntropy    *= a;
        internalEnergy *= a;
        kineticPotential*= a;
        minimizing     *= a;
        volumetric     *= a;

        return (*this);
    }




    thPotentials operator+(const thPotentials& left, const thPotentials& right)
    {
        thPotentials t(left);
        t += right;
        return t;
    }




    thPotentials operator*(const thPotentials& left, double a)
    {
        thPotentials t(left);
        t *= a;
        return t;
    }




    thPotentials operator*(double a, const thPotentials& right)
    {
        thPotentials t(right);
        t *= a;
        return t;
    }




    bool assignValue(const materialProperties& cl,
                     const std::string& key,
                     double& v)
    {
        bool found=false;
        materialProperties::const_iterator iter = cl.find(key);

        if (iter != cl.end())
        {
            v = iter->second;
            found = true;
        }
        return found;
    }




    bool assignValue(const materialProperties& cl,
                     const std::string& key,
                     std::vector<double>& v)
    {
        std::pair <materialProperties::const_iterator, materialProperties::const_iterator> foundObjects = cl.equal_range(key);

        materialProperties::const_iterator iter = foundObjects.first;
        while (iter != foundObjects.second)
        {
            v.push_back( iter->second );
            ++iter;
        }

        return !v.empty();
    }




    // keywords with a string option are stored in a strange way: keyword[space]option
    // since keywords can not contain spaces, the [space] is a unique separator
    bool assignValue(const materialProperties& cl,
                     const std::string& key,
                     std::string& v)
    {
        bool found=false;
        materialProperties::const_iterator iter = cl.begin();

        while ( iter != cl.end())
        {
            if ( iter->first.compare(0, key.length(), key) == 0)
            {
                v = iter->first.substr( key.length()+1, iter->first.length());
                found = true;
                break;
            }
            ++iter;
        }

        return found;
    }





    bool hasKeyword(const materialProperties& cl, const std::string& key)
    {
        bool found=false;
        materialProperties::const_iterator iter = cl.begin();

        while (iter != cl.end())
        {
            if ( iter->first.compare(0, key.length(), key) == 0)
            {
                found = true;
                break;
            }
            ++iter;
        }

        return found;
    }





    double randomUniform(const double low, const double up)
    {
        static bool initialized = false;

        if (!initialized)
        {
            srand((unsigned)time(0));
            initialized = true;
        }

        int     random_int = rand();
        double  random_dou = ( static_cast<double_t>(random_int))/ static_cast<double_t>(RAND_MAX);

        return random_dou * (up-low) + low;
    }




    int discreteUniform(const int low, const int up)
    {
        int r;
        if (up == low)
            r = low;
        else
            r = low + rand() % (up + 1 -low);
        return r;
    }

}

