/****************************************************************************
*
*                                 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 "muesli/material.h"
#include <string>
#include <map>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <stdexcept>

using namespace muesli;


std::ostream* material::materialLog(0);


material::material() :
_name("unnamed material"),
_label(0),
_rho(1.0),
_refTemp(273)
{
    if (materialLog == 0) materialLog = &(std::cout);
}




material::material(const std::string& name) :
_name(name),
_label(0),
_rho(1.0),
_refTemp(273)
{
    if (materialLog == 0) materialLog = &(std::cout);
}




material::material(const std::string& name,
                     const materialProperties& cl)
:
_name(name),
_label(0),
_rho(1.0),
_refTemp(273)
{
    if (materialLog == 0) materialLog = &(std::cout);

    double dlabel;
    muesli::assignValue(cl, "label", dlabel);
    muesli::assignValue(cl, "density", _rho);
    muesli::assignValue(cl, "reference_temperature", _refTemp);

    _label = static_cast<size_t>(dlabel);
}




material::~material()
{}




std::ostream& material::material::getLogger()
{
    if (materialLog == 0) materialLog = &(std::cout);
    return *materialLog;
}




bool material::check() const
{
    bool isok = true;

    if (_label == 0) isok = false;
    if (_name.empty()) isok = false;

    return isok;
}




void material::setLogger(std::ostream &of)
{
    material::materialLog = &of;
}




void material::setRandom()
{
    _rho     = muesli::randomUniform(1.0, 10.0);
    _refTemp = muesli::randomUniform(260.0, 400.0);
}




materialPoint::materialPoint()
{}




materialPoint::materialPoint(material &m)
{
}




void  materialDB::addMaterial(const size_t label, material& m)
{
    theDB[label] = &m;
}




void materialDB::free()
{
    for (auto mat : theDB) delete mat.second;
}




materialDB& materialDB::getDB()
{
    static materialDB instance;
    return instance;
}




/* retrieves a material structure given its number in the static list of materials */
material& materialDB::getMaterial(const size_t label) const
{
    std::map<size_t,material*>::const_iterator iter = theDB.find(label);

    if (iter == theDB.end())
    {
        std::ostream& mlog = material::getLogger();
        mlog << "Material with label " << label << " not defined";
    }
    return *(iter->second);
}




material& materialDB::getMaterial(const std::string& name) const
{
    material *s(0);
    std::map<size_t,material*>::const_iterator iter = theDB.begin();

    while( iter != theDB.end() )
    {
        if ( iter->second->name() == name)
        {
            s = iter->second;
            break;
        }
        ++iter;
    }

    if (s == 0) throw std::runtime_error("Material not found in global list.");
    return *s;
}




void materialDB::print(std::ostream &of) const
{
    of << "\n\n\n\n                M a t e r i a l s  (" << theDB.size() << ")";
    for (auto mat : theDB)
    {
        of << "\n\nMaterial #" << mat.first << ": " << mat.second->name();
        mat.second->print(of);
    }
}
